summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/ChangeLog36
-rw-r--r--src/aclocal.m4120
-rw-r--r--src/admin/create/ChangeLog7
-rw-r--r--src/admin/create/configure.in2
-rw-r--r--src/admin/create/kdb5_create.c9
-rw-r--r--src/admin/edit/ChangeLog13
-rw-r--r--src/admin/edit/configure.in2
-rw-r--r--src/admin/edit/cpw.c2
-rw-r--r--src/admin/edit/dump.c65
-rw-r--r--src/admin/edit/dumpv4.c10
-rw-r--r--src/admin/edit/kdb5_edit.c26
-rw-r--r--src/admin/edit/loadv4.c37
-rw-r--r--src/admin/stash/ChangeLog4
-rw-r--r--src/admin/stash/configure.in2
-rw-r--r--src/appl/gss-sample/ChangeLog5
-rw-r--r--src/appl/gss-sample/README39
-rw-r--r--src/appl/gss-sample/gss-client.c587
-rw-r--r--src/appl/gss-sample/gss-misc.c176
-rw-r--r--src/appl/gss-sample/gss-misc.h46
-rw-r--r--src/appl/gss-sample/gss-server.c570
-rw-r--r--src/appl/gssftp/ftp/ChangeLog7
-rw-r--r--src/appl/gssftp/ftp/cmds.c2
-rw-r--r--src/appl/gssftp/ftp/cmdtab.c4
-rw-r--r--src/appl/gssftp/ftpd/ChangeLog7
-rw-r--r--src/appl/gssftp/ftpd/ftpcmd.y8
-rw-r--r--src/appl/gssftp/ftpd/ftpd.c4
-rw-r--r--src/appl/telnet/libtelnet/ChangeLog15
-rw-r--r--src/appl/telnet/libtelnet/Makefile.in2
-rw-r--r--src/appl/telnet/libtelnet/enc-proto.h6
-rw-r--r--src/clients/kinit/ChangeLog5
-rw-r--r--src/clients/kinit/kinit.M5
-rw-r--r--src/clients/kinit/kinit.c36
-rw-r--r--src/config/ChangeLog5
-rw-r--r--src/config/pre.in5
-rw-r--r--src/configure.in5
-rw-r--r--src/include/ChangeLog5
-rw-r--r--src/include/k5-int.h80
-rw-r--r--src/include/krb5/ChangeLog7
-rw-r--r--src/include/krb5/adm.h1
-rw-r--r--src/include/krb5/kdb.h56
-rw-r--r--src/include/port-sockets.h72
-rw-r--r--src/kadmin/ChangeLog10
-rw-r--r--src/kadmin/Makefile.ov11
-rw-r--r--src/kadmin/cli/ChangeLog28
-rw-r--r--src/kadmin/cli/Makefile.in19
-rw-r--r--src/kadmin/cli/Makefile.ov28
-rw-r--r--src/kadmin/cli/attic/Makefile11
-rw-r--r--src/kadmin/cli/attic/Makefile.in45
-rw-r--r--src/kadmin/cli/attic/configure.in15
-rw-r--r--src/kadmin/cli/attic/getdate.y1006
-rw-r--r--src/kadmin/cli/attic/kadmin.c958
-rw-r--r--src/kadmin/cli/attic/kadmin_ct.ct67
-rw-r--r--src/kadmin/cli/attic/memmove.c144
-rw-r--r--src/kadmin/cli/attic/setenv.c165
-rw-r--r--src/kadmin/cli/attic/ss_wrapper.c56
-rw-r--r--src/kadmin/cli/configure.in20
-rw-r--r--src/kadmin/cli/dump.c1485
-rw-r--r--src/kadmin/cli/getdate.y1009
-rw-r--r--src/kadmin/cli/kadmin.1473
-rw-r--r--src/kadmin/cli/kadmin.c1322
-rw-r--r--src/kadmin/cli/kadmin_ct.ct79
-rw-r--r--src/kadmin/cli/keytab.c420
-rw-r--r--src/kadmin/cli/memmove.c144
-rw-r--r--src/kadmin/cli/setenv.c165
-rw-r--r--src/kadmin/cli/ss_wrapper.c61
-rw-r--r--src/kadmin/cli/strftime.c469
-rw-r--r--src/kadmin/config.mk/ChangeLog10
-rw-r--r--src/kadmin/config.mk/aix3.2.def40
-rw-r--r--src/kadmin/config.mk/architecture68
-rw-r--r--src/kadmin/config.mk/config141
-rw-r--r--src/kadmin/config.mk/hpux9.01.def32
-rw-r--r--src/kadmin/config.mk/irix5.2.def22
-rw-r--r--src/kadmin/config.mk/linux.def23
-rw-r--r--src/kadmin/config.mk/netbsd1.def22
-rw-r--r--src/kadmin/config.mk/rules538
-rw-r--r--src/kadmin/config.mk/site.def52
-rw-r--r--src/kadmin/config.mk/solaris2.3.def39
-rw-r--r--src/kadmin/config.mk/sunos4.1.def22
-rw-r--r--src/kadmin/config.mk/template142
-rw-r--r--src/kadmin/configure.in3
-rw-r--r--src/kadmin/create/ChangeLog9
-rw-r--r--src/kadmin/create/Makefile.in15
-rw-r--r--src/kadmin/create/Makefile.ov12
-rw-r--r--src/kadmin/create/attic/Makefile.in20
-rw-r--r--src/kadmin/create/attic/configure.in12
-rw-r--r--src/kadmin/create/attic/make_extern16
-rw-r--r--src/kadmin/create/attic/ovsec_adm_create.c663
-rw-r--r--src/kadmin/create/configure.in11
-rw-r--r--src/kadmin/create/kadm5_create.c241
-rw-r--r--src/kadmin/create/kdb5_create.c536
-rw-r--r--src/kadmin/create/string_table.c91
-rw-r--r--src/kadmin/create/string_table.h40
-rw-r--r--src/kadmin/dbutil/ChangeLog440
-rw-r--r--src/kadmin/dbutil/Makefile.in18
-rw-r--r--src/kadmin/dbutil/Makefile.ov19
-rw-r--r--src/kadmin/dbutil/configure.in13
-rw-r--r--src/kadmin/dbutil/dump.c1957
-rw-r--r--src/kadmin/dbutil/dumpv4.c411
-rw-r--r--src/kadmin/dbutil/kadm5_create.c241
-rw-r--r--src/kadmin/dbutil/kdb5_create.c449
-rw-r--r--src/kadmin/dbutil/kdb5_destroy.c117
-rw-r--r--src/kadmin/dbutil/kdb5_edit.M179
-rw-r--r--src/kadmin/dbutil/kdb5_stash.c153
-rw-r--r--src/kadmin/dbutil/kdb5_util.M122
-rw-r--r--src/kadmin/dbutil/kdb5_util.c416
-rw-r--r--src/kadmin/dbutil/kdb5_util.h49
-rw-r--r--src/kadmin/dbutil/kdb5_util_ct.ct56
-rw-r--r--src/kadmin/dbutil/loadv4.c881
-rw-r--r--src/kadmin/dbutil/ss_wrapper.c85
-rw-r--r--src/kadmin/dbutil/string_table.c91
-rw-r--r--src/kadmin/dbutil/string_table.h40
-rw-r--r--src/kadmin/dbutil/tcl_wrapper.c235
-rw-r--r--src/kadmin/dbutil/util.c155
-rw-r--r--src/kadmin/export/ChangeLog19
-rw-r--r--src/kadmin/export/Makefile.in20
-rw-r--r--src/kadmin/export/Makefile.ov24
-rw-r--r--src/kadmin/export/configure.in12
-rw-r--r--src/kadmin/export/export.c242
-rw-r--r--src/kadmin/export/export_err.et19
-rw-r--r--src/kadmin/export/local.h15
-rw-r--r--src/kadmin/export/ovsec_adm_export.c159
-rw-r--r--src/kadmin/export/unit-test/ChangeLog5
-rw-r--r--src/kadmin/export/unit-test/Makefile.ov19
-rw-r--r--src/kadmin/export/unit-test/add-to-db.sh55
-rw-r--r--src/kadmin/export/unit-test/config/unix.exp36
-rw-r--r--src/kadmin/export/unit-test/dotest.sh75
-rw-r--r--src/kadmin/export/unit-test/export.0/dotest.exp29
-rw-r--r--src/kadmin/export/unit-test/export.0/output.exp43
-rw-r--r--src/kadmin/export/unit-test/export.0/usage.exp25
-rw-r--r--src/kadmin/export/unit-test/helpers.exp126
-rw-r--r--src/kadmin/import/ChangeLog17
-rw-r--r--src/kadmin/import/Makefile.in18
-rw-r--r--src/kadmin/import/Makefile.ov24
-rw-r--r--src/kadmin/import/configure.in12
-rw-r--r--src/kadmin/import/import.c421
-rw-r--r--src/kadmin/import/import.h40
-rw-r--r--src/kadmin/import/import_err.et26
-rw-r--r--src/kadmin/import/misc.c95
-rw-r--r--src/kadmin/import/ovsec_adm_import.c164
-rw-r--r--src/kadmin/import/strtok.c131
-rw-r--r--src/kadmin/import/unit-test/Makefile.ov9
-rw-r--r--src/kadmin/import/unit-test/config/unix.exp36
-rw-r--r--src/kadmin/import/unit-test/helpers.exp93
-rw-r--r--src/kadmin/import/unit-test/import.0/usage.exp23
-rw-r--r--src/kadmin/import/unit-test/valid_export_file27
-rw-r--r--src/kadmin/kdbkeys/ChangeLog16
-rw-r--r--src/kadmin/kdbkeys/Makefile.in15
-rw-r--r--src/kadmin/kdbkeys/Makefile.ov21
-rw-r--r--src/kadmin/kdbkeys/configure.in11
-rw-r--r--src/kadmin/kdbkeys/do-test.pl56
-rw-r--r--src/kadmin/keytab/ChangeLog13
-rw-r--r--src/kadmin/keytab/Makefile.in19
-rw-r--r--src/kadmin/keytab/Makefile.ov30
-rw-r--r--src/kadmin/keytab/configure.in12
-rw-r--r--src/kadmin/keytab/keytab.c528
-rw-r--r--src/kadmin/keytab/unit-test/ChangeLog4
-rw-r--r--src/kadmin/keytab/unit-test/Makefile.ov21
-rw-r--r--src/kadmin/keytab/unit-test/add-princs.tcl12
-rw-r--r--src/kadmin/keytab/unit-test/config/unix.exp46
-rw-r--r--src/kadmin/keytab/unit-test/del-princs.tcl24
-rw-r--r--src/kadmin/keytab/unit-test/helpers.exp132
-rw-r--r--src/kadmin/keytab/unit-test/keytab.0/ChangeLog4
-rw-r--r--src/kadmin/keytab/unit-test/keytab.0/adding.exp119
-rw-r--r--src/kadmin/keytab/unit-test/keytab.0/keytab-spec.exp47
-rw-r--r--src/kadmin/keytab/unit-test/keytab.0/removing.exp125
-rw-r--r--src/kadmin/ktutil/ChangeLog4
-rw-r--r--src/kadmin/ktutil/configure.in1
-rw-r--r--src/kadmin/passwd/ChangeLog20
-rw-r--r--src/kadmin/passwd/Kpasswd46
-rw-r--r--src/kadmin/passwd/Makefile.in23
-rw-r--r--src/kadmin/passwd/Makefile.ov34
-rw-r--r--src/kadmin/passwd/configure.in13
-rw-r--r--src/kadmin/passwd/kpasswd.c280
-rw-r--r--src/kadmin/passwd/kpasswd_strings.et76
-rw-r--r--src/kadmin/passwd/tty_kpasswd.c80
-rw-r--r--src/kadmin/passwd/unit-test/Makefile.ov23
-rw-r--r--src/kadmin/passwd/unit-test/config/unix.exp36
-rw-r--r--src/kadmin/passwd/unit-test/helpers.exp217
-rw-r--r--src/kadmin/passwd/unit-test/kpasswd.0/changing.exp102
-rw-r--r--src/kadmin/passwd/unit-test/kpasswd.0/connecting.exp29
-rw-r--r--src/kadmin/passwd/unit-test/kpasswd.0/principal.exp55
-rw-r--r--src/kadmin/passwd/unit-test/kpasswd.0/usage.exp26
-rw-r--r--src/kadmin/passwd/xm_kpasswd.c450
-rw-r--r--src/kadmin/scripts/inst-hdrs.sh14
-rw-r--r--src/kadmin/server/Makefile.in15
-rw-r--r--src/kadmin/server/Makefile.ov39
-rw-r--r--src/kadmin/server/acls.l190
-rw-r--r--src/kadmin/server/configure.in17
-rw-r--r--src/kadmin/server/kadm_rpc_svc.c248
-rw-r--r--src/kadmin/server/misc.c138
-rw-r--r--src/kadmin/server/misc.h53
-rw-r--r--src/kadmin/server/ovsec_kadmd.c762
-rw-r--r--src/kadmin/server/server_glue_v1.c31
-rw-r--r--src/kadmin/server/server_stubs.c1045
-rw-r--r--src/kadmin/testing/Makefile.ov8
-rw-r--r--src/kadmin/testing/proto/ChangeLog9
-rw-r--r--src/kadmin/testing/proto/kdc.conf.proto20
-rw-r--r--src/kadmin/testing/proto/krb5.conf.proto17
-rw-r--r--src/kadmin/testing/proto/ovsec_adm.dict3
-rw-r--r--src/kadmin/testing/scripts/ChangeLog15
-rw-r--r--src/kadmin/testing/scripts/Makefile.ov19
-rw-r--r--src/kadmin/testing/scripts/compare_dump.pl.in242
-rw-r--r--src/kadmin/testing/scripts/compare_dump.plin242
-rw-r--r--src/kadmin/testing/scripts/find-make.sh18
-rw-r--r--src/kadmin/testing/scripts/fixup-conf-files.pl.in344
-rw-r--r--src/kadmin/testing/scripts/fixup-conf-files.plin344
-rw-r--r--src/kadmin/testing/scripts/init_db181
-rw-r--r--src/kadmin/testing/scripts/make-host-keytab.pl.in138
-rw-r--r--src/kadmin/testing/scripts/make-host-keytab.plin138
-rw-r--r--src/kadmin/testing/scripts/qualname18
-rw-r--r--src/kadmin/testing/scripts/save_files.sh67
-rw-r--r--src/kadmin/testing/scripts/simple_dump.pl.in88
-rw-r--r--src/kadmin/testing/scripts/simple_dump.plin88
-rw-r--r--src/kadmin/testing/scripts/start_servers70
-rw-r--r--src/kadmin/testing/scripts/start_servers_local196
-rw-r--r--src/kadmin/testing/scripts/stop_servers84
-rw-r--r--src/kadmin/testing/scripts/stop_servers_local49
-rw-r--r--src/kadmin/testing/scripts/verify_xrunner_report.pl.in38
-rw-r--r--src/kadmin/testing/scripts/verify_xrunner_report.plin38
-rw-r--r--src/kadmin/testing/tcl/util.t61
-rw-r--r--src/kadmin/testing/util/ChangeLog3
-rw-r--r--src/kadmin/testing/util/Makefile.ov34
-rw-r--r--src/kadmin/testing/util/bsddb_dump.c64
-rw-r--r--src/kadmin/testing/util/tcl_kadm5.c2312
-rw-r--r--src/kadmin/testing/util/tcl_krb5_hash.c163
-rw-r--r--src/kadmin/testing/util/tcl_ovsec_kadm.c2016
-rw-r--r--src/kadmin/testing/util/tcl_ovsec_kadm_syntax57
-rw-r--r--src/kadmin/testing/util/test.c32
-rw-r--r--src/kadmin/v4server/ChangeLog249
-rw-r--r--src/kadmin/v4server/Makefile.in23
-rw-r--r--src/kadmin/v4server/Makefile.ov42
-rw-r--r--src/kadmin/v4server/acl_files.c536
-rw-r--r--src/kadmin/v4server/acl_files.doc107
-rw-r--r--src/kadmin/v4server/admin_server.c684
-rw-r--r--src/kadmin/v4server/attic/ChangeLog25
-rw-r--r--src/kadmin/v4server/attic/Imakefile49
-rw-r--r--src/kadmin/v4server/attic/Makefile39
-rw-r--r--src/kadmin/v4server/attic/Makefile.in53
-rw-r--r--src/kadmin/v4server/attic/acl_files.c541
-rw-r--r--src/kadmin/v4server/attic/acl_files.doc107
-rw-r--r--src/kadmin/v4server/attic/aclocal.m43
-rw-r--r--src/kadmin/v4server/attic/admin_server.c668
-rw-r--r--src/kadmin/v4server/attic/configure.in22
-rw-r--r--src/kadmin/v4server/attic/kadm_err.et57
-rw-r--r--src/kadmin/v4server/attic/kadm_funcs.c876
-rw-r--r--src/kadmin/v4server/attic/kadm_ser_wrap.c288
-rw-r--r--src/kadmin/v4server/attic/kadm_server.c546
-rw-r--r--src/kadmin/v4server/attic/kadm_server.h64
-rw-r--r--src/kadmin/v4server/attic/kadm_stream.c276
-rw-r--r--src/kadmin/v4server/attic/kadm_supp.c114
-rw-r--r--src/kadmin/v4server/configure.in16
-rw-r--r--src/kadmin/v4server/kadm_err.et57
-rw-r--r--src/kadmin/v4server/kadm_funcs.c1066
-rw-r--r--src/kadmin/v4server/kadm_ser_wrap.c310
-rw-r--r--src/kadmin/v4server/kadm_server.c571
-rw-r--r--src/kadmin/v4server/kadm_server.h58
-rw-r--r--src/kadmin/v4server/kadm_stream.c277
-rw-r--r--src/kadmin/v4server/kadm_supp.c113
-rw-r--r--src/kadmin/v4server/unit-test/ChangeLog13
-rw-r--r--src/kadmin/v4server/unit-test/Makefile.ov19
-rw-r--r--src/kadmin/v4server/unit-test/config/ChangeLog7
-rw-r--r--src/kadmin/v4server/unit-test/config/unix.exp42
-rw-r--r--src/kadmin/v4server/unit-test/getpid.sh5
-rw-r--r--src/kadmin/v4server/unit-test/helpers.exp232
-rw-r--r--src/kadmin/v4server/unit-test/remove_changepw_perms.sh9
-rw-r--r--src/kadmin/v4server/unit-test/v4server.0/setup-srvtab.exp11
-rw-r--r--src/kadmin/v4server/unit-test/v4server.1/access.exp88
-rw-r--r--src/kadmin/v4server/unit-test/v4server.1/change-password.exp59
-rw-r--r--src/kadmin/v4server/unit-test/v4server.1/usage.exp26
-rw-r--r--src/kdc/ChangeLog4
-rw-r--r--src/kdc/configure.in2
-rw-r--r--src/krb524/ChangeLog8
-rw-r--r--src/krb524/configure.in8
-rw-r--r--src/krb524/krb524d.c191
-rw-r--r--src/lib/ChangeLog4
-rw-r--r--src/lib/configure.in2
-rw-r--r--src/lib/crypto/des/ChangeLog6
-rw-r--r--src/lib/crypto/des/cbc_cksum.c1
-rw-r--r--src/lib/gssapi/ChangeLog5
-rw-r--r--src/lib/gssapi/Makefile.in16
-rw-r--r--src/lib/gssapi/configure.in3
-rw-r--r--src/lib/gssapi/generic/ChangeLog20
-rw-r--r--src/lib/gssapi/generic/Makefile.in26
-rw-r--r--src/lib/gssapi/generic/disp_com_err_status.c4
-rw-r--r--src/lib/gssapi/generic/disp_major_status.c4
-rw-r--r--src/lib/gssapi/generic/gssapi.h77
-rw-r--r--src/lib/gssapi/generic/gssapiP_generic.h75
-rw-r--r--src/lib/gssapi/generic/gssapi_err_generic.et8
-rw-r--r--src/lib/gssapi/generic/gssapi_generic.c59
-rw-r--r--src/lib/gssapi/generic/gssapi_generic.h4
-rw-r--r--src/lib/gssapi/generic/oid_ops.c385
-rw-r--r--src/lib/gssapi/generic/release_buffer.c58
-rw-r--r--src/lib/gssapi/generic/release_oid_set.c62
-rw-r--r--src/lib/gssapi/generic/util_buffer.c4
-rw-r--r--src/lib/gssapi/generic/util_canonhost.c12
-rw-r--r--src/lib/gssapi/generic/util_dup.c4
-rw-r--r--src/lib/gssapi/generic/util_oid.c4
-rw-r--r--src/lib/gssapi/generic/util_token.c84
-rw-r--r--src/lib/gssapi/generic/util_validate.c123
-rw-r--r--src/lib/gssapi/krb5/ChangeLog97
-rw-r--r--src/lib/gssapi/krb5/Makefile.in31
-rw-r--r--src/lib/gssapi/krb5/accept_sec_context.c169
-rw-r--r--src/lib/gssapi/krb5/acquire_cred.c84
-rw-r--r--src/lib/gssapi/krb5/compare_name.c13
-rw-r--r--src/lib/gssapi/krb5/configure.in1
-rw-r--r--src/lib/gssapi/krb5/context_time.c12
-rw-r--r--src/lib/gssapi/krb5/delete_sec_context.c17
-rw-r--r--src/lib/gssapi/krb5/disp_name.c8
-rw-r--r--src/lib/gssapi/krb5/disp_status.c8
-rw-r--r--src/lib/gssapi/krb5/export_sec_context.c39
-rw-r--r--src/lib/gssapi/krb5/get_tkt_flags.c4
-rw-r--r--src/lib/gssapi/krb5/gssapiP_krb5.h167
-rw-r--r--src/lib/gssapi/krb5/gssapi_err_krb5.et2
-rw-r--r--src/lib/gssapi/krb5/gssapi_krb5.c76
-rw-r--r--src/lib/gssapi/krb5/gssapi_krb5.h12
-rw-r--r--src/lib/gssapi/krb5/import_name.c23
-rw-r--r--src/lib/gssapi/krb5/import_sec_context.c55
-rw-r--r--src/lib/gssapi/krb5/indicate_mechs.c7
-rw-r--r--src/lib/gssapi/krb5/init_sec_context.c225
-rw-r--r--src/lib/gssapi/krb5/inq_context.c10
-rw-r--r--src/lib/gssapi/krb5/inq_cred.c21
-rw-r--r--src/lib/gssapi/krb5/inq_names.c10
-rw-r--r--src/lib/gssapi/krb5/k5seal.c269
-rw-r--r--src/lib/gssapi/krb5/k5unseal.c322
-rw-r--r--src/lib/gssapi/krb5/krb5_gss_glue.c538
-rw-r--r--src/lib/gssapi/krb5/process_context_token.c14
-rw-r--r--src/lib/gssapi/krb5/rel_cred.c8
-rw-r--r--src/lib/gssapi/krb5/rel_name.c8
-rw-r--r--src/lib/gssapi/krb5/rel_oid.c1
-rw-r--r--src/lib/gssapi/krb5/seal.c39
-rw-r--r--src/lib/gssapi/krb5/ser_sctx.c464
-rw-r--r--src/lib/gssapi/krb5/sign.c20
-rw-r--r--src/lib/gssapi/krb5/unseal.c21
-rw-r--r--src/lib/gssapi/krb5/util_cksum.c36
-rw-r--r--src/lib/gssapi/krb5/util_crypt.c42
-rw-r--r--src/lib/gssapi/krb5/util_seed.c20
-rw-r--r--src/lib/gssapi/krb5/util_seqnum.c38
-rw-r--r--src/lib/gssapi/krb5/verify.c29
-rw-r--r--src/lib/gssapi/krb5/wrap_size_limit.c75
-rw-r--r--src/lib/gssapi/mechglue/mglueP.h11
-rw-r--r--src/lib/kadm/ChangeLog5
-rw-r--r--src/lib/kadm/alt_prof.c5
-rw-r--r--src/lib/kadm5/ChangeLog81
-rw-r--r--src/lib/kadm5/Makefile.in165
-rw-r--r--src/lib/kadm5/Makefile.ov61
-rw-r--r--src/lib/kadm5/adb.h141
-rw-r--r--src/lib/kadm5/adb_err.et16
-rw-r--r--src/lib/kadm5/adb_free.c71
-rw-r--r--src/lib/kadm5/adb_openclose.c338
-rw-r--r--src/lib/kadm5/adb_policy.c401
-rw-r--r--src/lib/kadm5/adb_principal.c408
-rw-r--r--src/lib/kadm5/adb_xdr.c132
-rw-r--r--src/lib/kadm5/admin.h649
-rw-r--r--src/lib/kadm5/admin_internal.h79
-rw-r--r--src/lib/kadm5/admin_xdr.h65
-rw-r--r--src/lib/kadm5/alt_prof.c861
-rw-r--r--src/lib/kadm5/chpass_util.c229
-rw-r--r--src/lib/kadm5/chpass_util_strings.et58
-rw-r--r--src/lib/kadm5/client_handle.c9
-rw-r--r--src/lib/kadm5/client_init.c554
-rw-r--r--src/lib/kadm5/client_internal.h93
-rw-r--r--src/lib/kadm5/client_principal.c307
-rw-r--r--src/lib/kadm5/client_rpc.c221
-rw-r--r--src/lib/kadm5/clnt_chpass_util.c15
-rw-r--r--src/lib/kadm5/clnt_policy.c151
-rw-r--r--src/lib/kadm5/clnt_privs.c66
-rw-r--r--src/lib/kadm5/configure.in49
-rw-r--r--src/lib/kadm5/get_admhst.c89
-rw-r--r--src/lib/kadm5/kadm_err.et54
-rw-r--r--src/lib/kadm5/kadm_rpc.h205
-rw-r--r--src/lib/kadm5/kadm_rpc_xdr.c830
-rw-r--r--src/lib/kadm5/logger.c940
-rw-r--r--src/lib/kadm5/misc_free.c96
-rw-r--r--src/lib/kadm5/ovsec_glue.c188
-rw-r--r--src/lib/kadm5/server_acl.c511
-rw-r--r--src/lib/kadm5/server_acl.h81
-rw-r--r--src/lib/kadm5/server_dict.c199
-rw-r--r--src/lib/kadm5/server_handle.c9
-rw-r--r--src/lib/kadm5/server_init.c330
-rw-r--r--src/lib/kadm5/server_internal.h103
-rw-r--r--src/lib/kadm5/server_kdb.c424
-rw-r--r--src/lib/kadm5/server_misc.c101
-rw-r--r--src/lib/kadm5/setenv.c163
-rw-r--r--src/lib/kadm5/str_conv.c397
-rw-r--r--src/lib/kadm5/svr_chpass_util.c15
-rw-r--r--src/lib/kadm5/svr_iters.c248
-rw-r--r--src/lib/kadm5/svr_misc_free.c37
-rw-r--r--src/lib/kadm5/svr_policy.c315
-rw-r--r--src/lib/kadm5/svr_principal.c1350
-rw-r--r--src/lib/kadm5/unit-test/ChangeLog18
-rw-r--r--src/lib/kadm5/unit-test/Makefile.ov154
-rw-r--r--src/lib/kadm5/unit-test/api.0/chpass-principal.exp176
-rw-r--r--src/lib/kadm5/unit-test/api.0/crte-policy.exp991
-rw-r--r--src/lib/kadm5/unit-test/api.0/crte-principal.exp1330
-rw-r--r--src/lib/kadm5/unit-test/api.0/destroy.exp203
-rw-r--r--src/lib/kadm5/unit-test/api.0/dlte-policy.exp207
-rw-r--r--src/lib/kadm5/unit-test/api.0/dlte-principal.exp329
-rw-r--r--src/lib/kadm5/unit-test/api.0/get-policy.exp199
-rw-r--r--src/lib/kadm5/unit-test/api.0/get-principal.exp346
-rw-r--r--src/lib/kadm5/unit-test/api.0/init.exp727
-rw-r--r--src/lib/kadm5/unit-test/api.0/mod-policy.exp703
-rw-r--r--src/lib/kadm5/unit-test/api.0/mod-principal.exp1942
-rw-r--r--src/lib/kadm5/unit-test/api.0/randkey-principal.exp319
-rw-r--r--src/lib/kadm5/unit-test/api.0/rename-principal.exp509
-rw-r--r--src/lib/kadm5/unit-test/api.1/lock.exp242
-rw-r--r--src/lib/kadm5/unit-test/api.2/chpass-principal-v2.exp68
-rw-r--r--src/lib/kadm5/unit-test/api.2/chpass-principal.exp176
-rw-r--r--src/lib/kadm5/unit-test/api.2/crte-policy.exp991
-rw-r--r--src/lib/kadm5/unit-test/api.2/crte-principal.exp1330
-rw-r--r--src/lib/kadm5/unit-test/api.2/destroy.exp203
-rw-r--r--src/lib/kadm5/unit-test/api.2/dlte-policy.exp207
-rw-r--r--src/lib/kadm5/unit-test/api.2/dlte-principal.exp329
-rw-r--r--src/lib/kadm5/unit-test/api.2/get-policy.exp199
-rw-r--r--src/lib/kadm5/unit-test/api.2/get-principal-v2.exp234
-rw-r--r--src/lib/kadm5/unit-test/api.2/get-principal.exp346
-rw-r--r--src/lib/kadm5/unit-test/api.2/init-v2.exp545
-rw-r--r--src/lib/kadm5/unit-test/api.2/init.exp731
-rw-r--r--src/lib/kadm5/unit-test/api.2/mod-policy.exp703
-rw-r--r--src/lib/kadm5/unit-test/api.2/mod-principal.exp1942
-rw-r--r--src/lib/kadm5/unit-test/api.2/randkey-principal-v2.exp62
-rw-r--r--src/lib/kadm5/unit-test/api.2/randkey-principal.exp319
-rw-r--r--src/lib/kadm5/unit-test/config/unix.exp113
-rw-r--r--src/lib/kadm5/unit-test/destroy-test.c42
-rw-r--r--src/lib/kadm5/unit-test/diff-files/destroy-12
-rw-r--r--src/lib/kadm5/unit-test/diff-files/no-diffs2
-rw-r--r--src/lib/kadm5/unit-test/handle-test.c131
-rw-r--r--src/lib/kadm5/unit-test/init-test.c26
-rw-r--r--src/lib/kadm5/unit-test/iter-test.c47
-rw-r--r--src/lib/kadm5/unit-test/lib.t367
-rw-r--r--src/lib/kadm5/unit-test/lock-test.c105
-rw-r--r--src/lib/kadm5/unit-test/randkey-test.c44
-rw-r--r--src/lib/kadm5/unit-test/site.exp2
-rw-r--r--src/lib/kadm5/unit-test/sizes-test.c21
-rw-r--r--src/lib/kdb/ChangeLog40
-rw-r--r--src/lib/kdb/Makefile.in21
-rw-r--r--src/lib/kdb/configure.in3
-rw-r--r--src/lib/kdb/kdb_cpw.c46
-rw-r--r--src/lib/kdb/kdb_dbm.c138
-rw-r--r--src/lib/kdb/kdb_xdr.c297
-rw-r--r--src/lib/krb5/keytab/file/ChangeLog5
-rw-r--r--src/lib/krb5/keytab/file/ktf_g_name.c18
-rw-r--r--src/lib/krb5/os/ChangeLog5
-rw-r--r--src/lib/krb5/os/ktdefname.c14
-rw-r--r--src/lib/rpc/ChangeLog20
-rw-r--r--src/lib/rpc/Makefile.in148
-rw-r--r--src/lib/rpc/Makefile.ov52
-rw-r--r--src/lib/rpc/auth.h197
-rw-r--r--src/lib/rpc/auth_any.c19
-rw-r--r--src/lib/rpc/auth_gssapi.c901
-rw-r--r--src/lib/rpc/auth_gssapi.h161
-rw-r--r--src/lib/rpc/auth_gssapi_misc.c390
-rw-r--r--src/lib/rpc/auth_none.c136
-rw-r--r--src/lib/rpc/auth_unix.c322
-rw-r--r--src/lib/rpc/auth_unix.h72
-rw-r--r--src/lib/rpc/authunix_prot.c66
-rw-r--r--src/lib/rpc/bindresvport.c79
-rw-r--r--src/lib/rpc/clnt.h335
-rw-r--r--src/lib/rpc/clnt_generic.c110
-rw-r--r--src/lib/rpc/clnt_perror.c306
-rw-r--r--src/lib/rpc/clnt_raw.c239
-rw-r--r--src/lib/rpc/clnt_simple.c112
-rw-r--r--src/lib/rpc/clnt_tcp.c476
-rw-r--r--src/lib/rpc/clnt_udp.c460
-rw-r--r--src/lib/rpc/configure.in41
-rw-r--r--src/lib/rpc/get_myaddress.c95
-rw-r--r--src/lib/rpc/getrpcent.c256
-rw-r--r--src/lib/rpc/getrpcport.c55
-rw-r--r--src/lib/rpc/netdb.h50
-rw-r--r--src/lib/rpc/pmap_clnt.c115
-rw-r--r--src/lib/rpc/pmap_clnt.h65
-rw-r--r--src/lib/rpc/pmap_getmaps.c88
-rw-r--r--src/lib/rpc/pmap_getport.c91
-rw-r--r--src/lib/rpc/pmap_prot.c57
-rw-r--r--src/lib/rpc/pmap_prot.h94
-rw-r--r--src/lib/rpc/pmap_prot2.c116
-rw-r--r--src/lib/rpc/pmap_rmt.c403
-rw-r--r--src/lib/rpc/pmap_rmt.h53
-rw-r--r--src/lib/rpc/rpc.h74
-rw-r--r--src/lib/rpc/rpc_callmsg.c195
-rw-r--r--src/lib/rpc/rpc_commondata.c41
-rw-r--r--src/lib/rpc/rpc_dtablesize.c60
-rw-r--r--src/lib/rpc/rpc_msg.h187
-rw-r--r--src/lib/rpc/rpc_prot.c287
-rw-r--r--src/lib/rpc/svc.c492
-rw-r--r--src/lib/rpc/svc.h298
-rw-r--r--src/lib/rpc/svc_auth.c119
-rw-r--r--src/lib/rpc/svc_auth.h61
-rw-r--r--src/lib/rpc/svc_auth_any.c22
-rw-r--r--src/lib/rpc/svc_auth_gssapi.c1181
-rw-r--r--src/lib/rpc/svc_auth_unix.c137
-rw-r--r--src/lib/rpc/svc_raw.c166
-rw-r--r--src/lib/rpc/svc_run.c72
-rw-r--r--src/lib/rpc/svc_simple.c143
-rw-r--r--src/lib/rpc/svc_tcp.c453
-rw-r--r--src/lib/rpc/svc_udp.c496
-rw-r--r--src/lib/rpc/types.hin90
-rw-r--r--src/lib/rpc/unit-test/Makefile97
-rw-r--r--src/lib/rpc/unit-test/client.c320
-rw-r--r--src/lib/rpc/unit-test/rpc_test.x30
-rw-r--r--src/lib/rpc/unit-test/server.c306
-rw-r--r--src/lib/rpc/unit-test/testsuite/Makefile24
-rw-r--r--src/lib/rpc/unit-test/testsuite/config/unix.exp79
-rw-r--r--src/lib/rpc/unit-test/testsuite/helpers.exp128
-rw-r--r--src/lib/rpc/unit-test/testsuite/rpc_test.0/expire.exp21
-rw-r--r--src/lib/rpc/unit-test/testsuite/rpc_test.0/fullrun.exp95
-rw-r--r--src/lib/rpc/unit-test/testsuite/rpc_test.0/gsserr.exp27
-rw-r--r--src/lib/rpc/unit-test/testsuite/rpc_test_setup.sh56
-rw-r--r--src/lib/rpc/xdr.c674
-rw-r--r--src/lib/rpc/xdr.h276
-rw-r--r--src/lib/rpc/xdr_alloc.c173
-rw-r--r--src/lib/rpc/xdr_array.c153
-rw-r--r--src/lib/rpc/xdr_float.c293
-rw-r--r--src/lib/rpc/xdr_mem.c188
-rw-r--r--src/lib/rpc/xdr_rec.c596
-rw-r--r--src/lib/rpc/xdr_reference.c132
-rw-r--r--src/lib/rpc/xdr_stdio.c189
-rw-r--r--src/tests/ChangeLog8
-rw-r--r--src/tests/Makefile.in2
-rw-r--r--src/tests/configure.in2
-rw-r--r--src/tests/dejagnu/config/ChangeLog6
-rw-r--r--src/tests/dejagnu/config/default.exp97
-rw-r--r--src/tests/dejagnu/krb-standalone/ChangeLog10
-rw-r--r--src/tests/dejagnu/krb-standalone/gssapi.exp26
-rw-r--r--src/tests/dejagnu/krb-standalone/gssftp.exp2
-rw-r--r--src/tests/gssapi/t_imp_name.c1
-rw-r--r--src/util/ChangeLog12
-rw-r--r--src/util/Makefile.in14
-rw-r--r--src/util/autoconf/ChangeLog9
-rw-r--r--src/util/autoconf/README.krb52
-rw-r--r--src/util/autoconf/autoconf.info324
-rw-r--r--src/util/autoconf/autoheader.sh1
-rw-r--r--src/util/autoconf/configure16
-rw-r--r--src/util/autoconf/standards.info2
-rw-r--r--src/util/configure.in11
-rw-r--r--src/util/db2/CHANGELOG123
-rw-r--r--src/util/db2/ChangeLog77
-rw-r--r--src/util/db2/Makefile.in12
-rw-r--r--src/util/db2/Makefile.inc10
-rw-r--r--src/util/db2/README41
-rw-r--r--src/util/db2/acconfig.h17
-rw-r--r--src/util/db2/btree/Makefile.inc7
-rw-r--r--src/util/db2/btree/bt_close.c182
-rw-r--r--src/util/db2/btree/bt_conv.c221
-rw-r--r--src/util/db2/btree/bt_debug.c372
-rw-r--r--src/util/db2/btree/bt_delete.c657
-rw-r--r--src/util/db2/btree/bt_get.c105
-rw-r--r--src/util/db2/btree/bt_open.c471
-rw-r--r--src/util/db2/btree/bt_overflow.c228
-rw-r--r--src/util/db2/btree/bt_page.c98
-rw-r--r--src/util/db2/btree/bt_put.c320
-rw-r--r--src/util/db2/btree/bt_search.c297
-rw-r--r--src/util/db2/btree/bt_seq.c490
-rw-r--r--src/util/db2/btree/bt_split.c827
-rw-r--r--src/util/db2/btree/bt_utils.c260
-rw-r--r--src/util/db2/btree/btree.h383
-rw-r--r--src/util/db2/btree/extern.h70
-rw-r--r--src/util/db2/clib/memmove.c138
-rw-r--r--src/util/db2/clib/mkstemp.c119
-rw-r--r--src/util/db2/clib/strerror.c67
-rw-r--r--src/util/db2/configure.in63
-rw-r--r--src/util/db2/db/Makefile.inc5
-rw-r--r--src/util/db2/db/db.c99
-rw-r--r--src/util/db2/docs/btree.3.ps366
-rw-r--r--src/util/db2/docs/dbopen.3.ps508
-rw-r--r--src/util/db2/docs/hash.3.ps292
-rw-r--r--src/util/db2/docs/hash.usenix.ps12209
-rw-r--r--src/util/db2/docs/libtp.usenix.ps12340
-rw-r--r--src/util/db2/docs/mpool.3.ps320
-rw-r--r--src/util/db2/docs/recno.3.ps341
-rw-r--r--src/util/db2/hash/Makefile.inc6
-rw-r--r--src/util/db2/hash/dbm.c297
-rw-r--r--src/util/db2/hash/extern.h76
-rw-r--r--src/util/db2/hash/hash.c1068
-rw-r--r--src/util/db2/hash/hash.c.patch109
-rw-r--r--src/util/db2/hash/hash.h196
-rw-r--r--src/util/db2/hash/hash_bigkey.c483
-rw-r--r--src/util/db2/hash/hash_debug.c106
-rw-r--r--src/util/db2/hash/hash_func.c196
-rw-r--r--src/util/db2/hash/hash_log2.c52
-rw-r--r--src/util/db2/hash/hash_page.c1380
-rw-r--r--src/util/db2/hash/hsearch.c107
-rw-r--r--src/util/db2/hash/page.h178
-rw-r--r--src/util/db2/hash/page.h.patch42
-rw-r--r--src/util/db2/hash/search.h51
-rw-r--r--src/util/db2/include/db-int.h208
-rw-r--r--src/util/db2/include/db-ndbm.h77
-rw-r--r--src/util/db2/include/db-queue.h245
-rw-r--r--src/util/db2/include/db.h170
-rw-r--r--src/util/db2/man/Makefile.inc7
-rw-r--r--src/util/db2/man/db.man.ps2295
-rw-r--r--src/util/db2/man/db_btree.3246
-rw-r--r--src/util/db2/man/db_hash.3138
-rw-r--r--src/util/db2/man/db_lock.3462
-rw-r--r--src/util/db2/man/db_log.3290
-rw-r--r--src/util/db2/man/db_mpool.3403
-rw-r--r--src/util/db2/man/db_open.3574
-rw-r--r--src/util/db2/man/db_recno.3268
-rw-r--r--src/util/db2/man/db_txn.3373
-rw-r--r--src/util/db2/man/spell.ok170
-rw-r--r--src/util/db2/mpool/Makefile.inc5
-rw-r--r--src/util/db2/mpool/README7
-rw-r--r--src/util/db2/mpool/mpool.c502
-rw-r--r--src/util/db2/mpool/mpool.h107
-rw-r--r--src/util/db2/obj/Makefile.in157
-rw-r--r--src/util/db2/recno/Makefile.inc6
-rw-r--r--src/util/db2/recno/extern.h54
-rw-r--r--src/util/db2/recno/rec_close.c186
-rw-r--r--src/util/db2/recno/rec_delete.c197
-rw-r--r--src/util/db2/recno/rec_get.c311
-rw-r--r--src/util/db2/recno/rec_open.c243
-rw-r--r--src/util/db2/recno/rec_put.c280
-rw-r--r--src/util/db2/recno/rec_search.c126
-rw-r--r--src/util/db2/recno/rec_seq.c131
-rw-r--r--src/util/db2/recno/rec_utils.c122
-rw-r--r--src/util/db2/recno/recno.h39
-rw-r--r--src/util/db2/test/Makefile23
-rw-r--r--src/util/db2/test/README74
-rw-r--r--src/util/db2/test/SEQ_TEST/data8
-rw-r--r--src/util/db2/test/SEQ_TEST/mbox399
-rw-r--r--src/util/db2/test/SEQ_TEST/t.c86
-rw-r--r--src/util/db2/test/btree.tests/main.c765
-rw-r--r--src/util/db2/test/dbtest.c753
-rw-r--r--src/util/db2/test/hash1.tests/Makefile43
-rw-r--r--src/util/db2/test/hash1.tests/driver2.c114
-rw-r--r--src/util/db2/test/hash1.tests/makedb.sh13
-rw-r--r--src/util/db2/test/hash1.tests/tcreat3.c105
-rw-r--r--src/util/db2/test/hash1.tests/tdel.c122
-rw-r--r--src/util/db2/test/hash1.tests/testit154
-rw-r--r--src/util/db2/test/hash1.tests/thash4.c131
-rw-r--r--src/util/db2/test/hash1.tests/tread2.c105
-rw-r--r--src/util/db2/test/hash1.tests/tseq.c88
-rw-r--r--src/util/db2/test/hash1.tests/tverify.c107
-rw-r--r--src/util/db2/test/hash2.tests/README72
-rw-r--r--src/util/db2/test/hash2.tests/bigtest.c76
-rw-r--r--src/util/db2/test/hash2.tests/passtest.c184
-rw-r--r--src/util/db2/test/hash2.tests/passwd/genpass.c23
-rw-r--r--src/util/db2/test/run.test717
-rw-r--r--src/util/dyn/ChangeLog13
-rw-r--r--src/util/dyn/Imakefile26
-rw-r--r--src/util/dyn/Makefile.in65
-rw-r--r--src/util/dyn/README32
-rw-r--r--src/util/dyn/TODO3
-rw-r--r--src/util/dyn/configure.in14
-rw-r--r--src/util/dyn/dyn.3m198
-rw-r--r--src/util/dyn/dyn_append.c26
-rw-r--r--src/util/dyn/dyn_initzero.c26
-rw-r--r--src/util/dyn/dyn_insert.c70
-rw-r--r--src/util/dyn/dyn_paranoid.c26
-rw-r--r--src/util/dyn/dyn_realloc.c88
-rw-r--r--src/util/et/ChangeLog4
-rw-r--r--src/util/et/et_c.awk31
651 files changed, 138835 insertions, 2676 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index fdfbd2e22d..3f10ce6afa 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,30 @@
+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
@@ -97,6 +124,15 @@ 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.
diff --git a/src/aclocal.m4 b/src/aclocal.m4
index 774178661f..7877c585d2 100644
--- a/src/aclocal.m4
+++ b/src/aclocal.m4
@@ -214,6 +214,9 @@ if test $withval = no; then
DEPKRB4_LIB=
KRB4_CRYPTO_LIB=
DEPKRB4_CRYPTO_LIB=
+ KDB4_LIB=
+ DEPKDB4_LIB=
+ KRB4_INCLUDES=
LDARGS=
krb5_cv_build_krb4_libs=no
krb5_cv_krb4_libdir=
@@ -226,6 +229,9 @@ else
DEPKRB4_LIB='$(TOPLIBD)/libkrb4.a'
KRB4_CRYPTO_LIB='-ldes425'
DEPKRB4_CRYPTO_LIB='$(TOPLIBD)/libdes425.a'
+ KDB4_LIB='-lkdb4'
+ DEPKDB4_LIB='$(TOPLIBD)/libkdb4.a'
+ KRB4_INCLUDES='-I$(SRCTOP)/include/kerberosIV'
LDARGS=
krb5_cv_build_krb4_libs=yes
krb5_cv_krb4_libdir=
@@ -236,11 +242,15 @@ else
DEPKRB4_LIB="$withval/lib/libkrb.a"
KRB4_CRYPTO_LIB='-ldes425'
DEPKRB4_CRYPTO_LIB='$(TOPLIBD)/libdes425.a'
+ KDB4_LIB="-lkdb"
+ DEPKDB4_LIB="$withval/lib/libkdb.a"
+ KRB4_INCLUDES="-I$withval/include"
LDARGS="-L$withval/lib"
krb5_cv_build_krb4_libs=no
krb5_cv_krb4_libdir="$withval/lib"
fi
fi
+AC_SUBST(KRB4_INCLUDES)
AC_SUBST(KRB4_LIB)
AC_SUBST(KRB4_CRYPTO_LIB)
AC_SUBST(DEPKRB4_LIB)
@@ -475,8 +485,8 @@ dnl V5_OUTPUT_MAKEFILE
dnl
define(V5_AC_OUTPUT_MAKEFILE,
[ifelse($1, , ac_v5_makefile_dirs=., ac_v5_makefile_dirs="$1")
+ifelse($2, , filelist="", filelist="$2")
dnl OPTIMIZE THIS FOR COMMON CASE!!
-filelist=""
for x in $ac_v5_makefile_dirs; do
filelist="$filelist $x/Makefile.tmp:$ac_prepend+$x/Makefile.in+$ac_postpend"
done
@@ -672,13 +682,37 @@ ADD_DEF(-Dvolatile=)
fi
])dnl
dnl
-dnl This rule tells KRB5_LIBRARIES to use the kadm library.
+dnl This rule tells KRB5_LIBRARIES to use the kadm5srv library.
dnl
-kadm_deplib=''
-kadm_lib=''
-define(USE_KADM_LIBRARY,[
-kadm_deplib="\[$](TOPLIBD)/libkadm.a"
-kadm_lib=-lkadm])
+kadmsrv_deplib=''
+kadmsrv_lib=''
+define(USE_KADMSRV_LIBRARY,[
+kadmsrv_deplib="\[$](TOPLIBD)/libkadm5srv.a"
+kadmsrv_lib=-lkadm5srv])
+dnl
+dnl This rule tells KRB5_LIBRARIES to use the kadm5clnt library.
+dnl
+kadmclnt_deplib=''
+kadmclnt_lib=''
+define(USE_KADMCLNT_LIBRARY,[
+kadmclnt_deplib="\[$](TOPLIBD)/libkadm5clnt.a"
+kadmclnt_lib=-lkadm5clnt])
+dnl
+dnl This rule tells KRB5_LIBRARIES to use the gssrpc library.
+dnl
+gssrpc_deplib=''
+gssrpc_lib=''
+define(USE_GSSRPC_LIBRARY,[
+gssrpc_deplib="\[$](TOPLIBD)/libgssrpc.a"
+gssrpc_lib=-lgssrpc])
+dnl
+dnl This rule tells KRB5_LIBRARIES to use the gssapi library.
+dnl
+gssapi_deplib=''
+gssapi_lib=''
+define(USE_GSSAPI_LIBRARY,[
+gssapi_deplib="\[$](TOPLIBD)/libgssapi_krb5.a"
+gssapi_lib=-lgssapi_krb5])
dnl
dnl This rule tells KRB5_LIBRARIES to use the krb5util library.
dnl
@@ -688,40 +722,20 @@ define(USE_KRB5UTIL_LIBRARY,[
kutil_deplib="\[$](TOPLIBD)/libkrb5util.a"
kutil_lib=-lkrb5util])
dnl
-dnl This rule tells KRB5_LIBRARIES to include the aname dbm library.
+dnl This rule tells KRB5_LIBRARIES to include the aname db library.
dnl
-kaname_deplib=''
-kaname_libs=''
define(USE_ANAME,[
-WITH_ANAME_DB
-kaname_libs="$dblibs"
-if test "$dbval" = "db"; then
- if test -n "$krb5_cv_shlib_version_libdb"; then
- kaname_deplib="\$(TOPLIBD)/libdb.$krb5_cv_shlibs_ext.$krb5_cv_shlib_version_libdb"
- else
- kaname_deplib="\$(TOPLIBD)/libdb.$krb5_cv_noshlibs_ext"
- fi
-fi
+USE_DB_LIBRARY
])dnl
dnl
-dnl This rule tells KRB5_LIBRARIES to include the kdb5 and dbm libraries.
+dnl This rule tells KRB5_LIBRARIES to include the kdb5 and db libraries.
dnl
kdb5_deplib=''
kdb5_lib=''
-kdbm_deplib=''
-kdbm_libs=''
define(USE_KDB5_LIBRARY,[
kdb5_deplib="\[$](TOPLIBD)/libkdb5.a"
kdb5_lib=-lkdb5
-WITH_KDB_DB
-kdbm_libs="$dblibs"
-if test "$dbval" = "db"; then
- if test -n "$krb5_cv_shlib_version_libdb"; then
- kdbm_deplib="\$(TOPLIBD)/libdb.$krb5_cv_shlibs_ext.$krb5_cv_shlib_version_libdb"
- else
- kdbm_deplib="\$(TOPLIBD)/libdb.$krb5_cv_noshlibs_ext"
- fi
-fi
+USE_DB_LIBRARY
])
dnl
dnl This rule tells KRB5_LIBRARIES to include the krb4 libraries.
@@ -742,18 +756,43 @@ ss_deplib="\[$](TOPLIBD)/libss.a"
ss_lib=-lss
])
dnl
+dnl This rule tells KRB5_LIBRARIES to include the dyn library.
+dnl
+dyn_deplib=''
+dyn_lib=''
+define(USE_DYN_LIBRARY,[
+dyn_deplib="\[$](TOPLIBD)/libdyn.a"
+dyn_lib=-ldyn
+])
+dnl
+dnl This rule tells KRB5_LIBRARIES to include the db library.
+dnl
+db_deplib=''
+db_lib=''
+define(USE_DB_LIBRARY,[
+db_deplib="\[$](TOPLIBD)/libdb.a"
+db_lib=-ldb
+])
+dnl
dnl This rule generates library lists for programs.
dnl
define(KRB5_LIBRARIES,[
-if test ${kdbm_deplib}x = x; then
-USE_ANAME
-fi
-DEPLIBS="\[$](DEPLOCAL_LIBRARIES) $kadm_deplib $kdb5_deplib $kutil_deplib \[$](TOPLIBD)/libkrb5.a $krb4_deplib $kdbm_deplib $kaname_deplib \[$](TOPLIBD)/libcrypto.a $ss_deplib \[$](TOPLIBD)/libcom_err.a"
-LIBS="\[$](LOCAL_LIBRARIES) $kadm_lib $kdb5_lib $kutil_lib $krb4_lib -lkrb5 $kdbm_libs $kaname_libs -lcrypto $ss_lib -lcom_err $LIBS"
-LDFLAGS="$LDFLAGS -L${BUILDTOP}/lib"
+dnl this is ugly, but it wouldn't be necessary if krb5 didn't abuse
+dnl configure so badly
+SRVDEPLIBS="\[$](DEPLOCAL_LIBRARIES) $kadmsrv_deplib $gssrpc_deplib $gssapi_deplib $kdb5_deplib $kutil_deplib \[$](TOPLIBD)/libkrb5.a $kdb4_deplib $krb4_deplib \[$](TOPLIBD)/libcrypto.a $ss_deplib $dyn_deplib $db_deplib \[$](TOPLIBD)/libcom_err.a"
+SRVLIBS="\[$](LOCAL_LIBRARIES) $kadmsrv_lib $gssrpc_lib $gssapi_lib $kdb5_lib $kdb4_lib $kutil_lib $krb4_lib -lkrb5 -lcrypto $ss_lib $dyn_lib $db_lib -lcom_err $LIBS"
+CLNTDEPLIBS="\[$](DEPLOCAL_LIBRARIES) $kadmclnt_deplib $gssrpc_deplib $gssapi_deplib $kdb5_deplib $kutil_deplib \[$](TOPLIBD)/libkrb5.a $kdb4_deplib $krb4_deplib \[$](TOPLIBD)/libcrypto.a $ss_deplib $dyn_deplib $db_deplib \[$](TOPLIBD)/libcom_err.a"
+CLNTLIBS="\[$](LOCAL_LIBRARIES) $kadmclnt_lib $gssrpc_lib $gssapi_lib $kdb5_lib $kdb4_lib $kutil_lib $krb4_lib -lkrb5 -lcrypto $ss_lib $dyn_lib $db_lib -lcom_err $LIBS"
+DEPLIBS="\[$](DEPLOCAL_LIBRARIES) $kadmclnt_deplib $kadmsrv_deplib $gssrpc_deplib $gssapi_deplib $kdb5_deplib $kutil_deplib \[$](TOPLIBD)/libkrb5.a $kdb4_deplib $krb4_deplib \[$](TOPLIBD)/libcrypto.a $ss_deplib $dyn_deplib $db_deplib \[$](TOPLIBD)/libcom_err.a"
+LIBS="\[$](LOCAL_LIBRARIES) $kadmclnt_lib $kadmsrv_lib $gssrpc_lib $gssapi_lib $kdb5_lib $kdb4_lib $kutil_lib $krb4_lib -lkrb5 -lcrypto $ss_lib $dyn_lib $db_lib -lcom_err $LIBS"
+LDFLAGS="$LDFLAGS -L\$(TOPLIBD)"
AC_SUBST(LDFLAGS)
AC_SUBST(LDARGS)
-AC_SUBST(DEPLIBS)])
+AC_SUBST(DEPLIBS)
+AC_SUBST(SRVDEPLIBS)
+AC_SUBST(SRVLIBS)
+AC_SUBST(CLNTDEPLIBS)
+AC_SUBST(CLNTLIBS)])
dnl
dnl This rule supports the generation of the shared library object files
dnl
@@ -773,7 +812,8 @@ dnl
dnl This rule adds the additional Makefile fragment necessary to actually
dnl create the shared library
dnl
-dnl V5_MAKE_SHARED_LIB(libname, version, libdir, dirname_relative_to_libdir)
+dnl V5_MAKE_SHARED_LIB(libname, version, libdir, dirname_relative_to_libdir,
+dnl lib_subdirs)
dnl
define(V5_MAKE_SHARED_LIB,[
if test "[$]krb5_cv_staticlibs_enabled" = yes
@@ -839,7 +879,7 @@ clean-unix::
$1.[$](SHEXT)$(VEXT): [$](LIBDONE) [$](DEPLIBS)
[$](BUILDTOP)/util/makeshlib [$]@ \
"[$](SHLIB_LIBDIRS)" \
- "[$](SHLIB_LIBS)" "[$](SHLIB_LDFLAGS)" "$2" [$](LIB_SUBDIRS)
+ "[$](SHLIB_LIBS)" "[$](SHLIB_LDFLAGS)" "$2" [$](LIB_SUBDIRS) $5
AC_POP_MAKEFILE()dnl
if test "$krb5_cv_shlibs_versioned_filenames" = "yes" ; then
LinkFile($1.[$](SHEXT),$1.[$](SHEXT).$2)
diff --git a/src/admin/create/ChangeLog b/src/admin/create/ChangeLog
index 9fd98714a7..611bdf10e2 100644
--- a/src/admin/create/ChangeLog
+++ b/src/admin/create/ChangeLog
@@ -1,3 +1,10 @@
+Tue May 7 23:04:17 1996 Marc Horowitz <marc@mit.edu>
+
+ * kdb5_create.c (add_principal): convert to used new krb5_dbe_*
+ tl_data functions.
+
+ * configure.in: use USE_KADMSRV_LIBRARY instead of
+ USE_KADM_LIBRARY.
Wed Dec 13 03:44:58 1995 Chris Provenzano (proven@mit.edu)
diff --git a/src/admin/create/configure.in b/src/admin/create/configure.in
index ef0252cf42..c884750277 100644
--- a/src/admin/create/configure.in
+++ b/src/admin/create/configure.in
@@ -1,7 +1,7 @@
AC_INIT(kdb5_create.c)
CONFIG_RULES
AC_PROG_INSTALL
-USE_KADM_LIBRARY
+USE_KADMSRV_LIBRARY
USE_KDB5_LIBRARY
KRB5_LIBRARIES
V5_USE_SHARED_LIB
diff --git a/src/admin/create/kdb5_create.c b/src/admin/create/kdb5_create.c
index 2d2adeb908..963d16f035 100644
--- a/src/admin/create/kdb5_create.c
+++ b/src/admin/create/kdb5_create.c
@@ -454,7 +454,7 @@ add_principal(context, princ, op, pblock)
krb5_error_code retval;
krb5_db_entry entry;
- krb5_tl_mod_princ mod_princ;
+ krb5_timestamp now;
struct iterate_args iargs;
int nentries = 1;
@@ -470,10 +470,11 @@ add_principal(context, princ, op, pblock)
if ((retval = krb5_copy_principal(context, princ, &entry.princ)))
goto error_out;
- mod_princ.mod_princ = &db_create_princ;
- if ((retval = krb5_timeofday(context, &mod_princ.mod_date)))
+ if ((retval = krb5_timeofday(context, &now)))
goto error_out;
- if ((retval = krb5_dbe_encode_mod_princ_data(context, &mod_princ, &entry)))
+
+ if ((retval = krb5_dbe_update_mod_princ_data(context, &entry,
+ now, &db_create_princ)))
goto error_out;
switch (op) {
diff --git a/src/admin/edit/ChangeLog b/src/admin/edit/ChangeLog
index 12eaab25f0..c01d269c15 100644
--- a/src/admin/edit/ChangeLog
+++ b/src/admin/edit/ChangeLog
@@ -17,6 +17,19 @@ Sat Jun 8 09:54:38 1996 Ezra Peisach <epeisach@kangaroo.mit.edu>
* dumpv4.c (handle_one_key): Remove the temporary --with-kdb4
support.
+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 May 2 22:16:01 1996 Ken Raeburn <raeburn@cygnus.com>
* ss_wrapper.c (main): Make sci_idx a global. This makes certain
diff --git a/src/admin/edit/configure.in b/src/admin/edit/configure.in
index 7567f34418..6fbf47008d 100644
--- a/src/admin/edit/configure.in
+++ b/src/admin/edit/configure.in
@@ -5,7 +5,7 @@ AC_PROG_YACC
AC_CONST
AC_HEADER_STDC
AC_CHECK_FUNCS(getcwd strstr)
-USE_KADM_LIBRARY
+USE_KADMSRV_LIBRARY
USE_KDB5_LIBRARY
USE_KRB4_LIBRARY
USE_SS_LIBRARY
diff --git a/src/admin/edit/cpw.c b/src/admin/edit/cpw.c
index 1afc293e92..663fc108ec 100644
--- a/src/admin/edit/cpw.c
+++ b/src/admin/edit/cpw.c
@@ -223,7 +223,7 @@ enter_pwd_key(cmdname, princ, ks_tuple, ks_tuple_count, entry)
ks_tuple = std_ks_tuple;
}
if ((retval = krb5_dbe_cpw(edit_context, &master_encblock, ks_tuple,
- ks_tuple_count, password, entry))) {
+ ks_tuple_count, password, 0, entry))) {
com_err(cmdname, retval, "while storing entry for '%s'\n", princ);
memset(password, 0, sizeof(password)); /* erase it */
krb5_dbe_free_contents(edit_context, entry);
diff --git a/src/admin/edit/dump.c b/src/admin/edit/dump.c
index 42118d555a..bbda74c9dc 100644
--- a/src/admin/edit/dump.c
+++ b/src/admin/edit/dump.c
@@ -328,7 +328,7 @@ dump_k5beta_iterator(ptr, entry)
krb5_error_code retval;
struct dump_args *arg;
char *name, *mod_name;
- krb5_tl_mod_princ *mprinc;
+ krb5_principal mod_princ;
krb5_tl_data *pwchg;
krb5_key_data *pkey, *akey, nullkey;
krb5_timestamp mod_date, last_pwd_change;
@@ -358,27 +358,24 @@ dump_k5beta_iterator(ptr, entry)
/*
* Deserialize the modifier record.
*/
- mprinc = (krb5_tl_mod_princ *) NULL;
mod_name = (char *) NULL;
+ mod_princ = NULL;
last_pwd_change = mod_date = 0;
pkey = akey = (krb5_key_data *) NULL;
- if (!(retval = krb5_dbe_decode_mod_princ_data(arg->kcontext,
+ if (!(retval = krb5_dbe_lookup_mod_princ_data(arg->kcontext,
entry,
- &mprinc))) {
- if (mprinc) {
- if (mprinc->mod_princ) {
- /*
- * Flatten the modifier name.
- */
- if ((retval = krb5_unparse_name(arg->kcontext,
- mprinc->mod_princ,
- &mod_name)))
- fprintf(stderr, mname_unp_err, arg->programname,
- error_message(retval));
- krb5_free_principal(arg->kcontext, mprinc->mod_princ);
- }
- mod_date = mprinc->mod_date;
- krb5_xfree(mprinc);
+ &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)
@@ -387,11 +384,13 @@ dump_k5beta_iterator(ptr, entry)
/*
* Find the last password change record and set it straight.
*/
- for (pwchg = entry->tl_data;
- (pwchg) && (pwchg->tl_data_type != KRB5_TL_LAST_PWD_CHANGE);
- pwchg = pwchg->tl_data_next);
- if (pwchg) {
- krb5_kdb_decode_int32(pwchg->tl_data_contents, last_pwd_change);
+ 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);
}
/*
@@ -823,7 +822,8 @@ find_record_end(f, fn, lineno)
putc(ch, stderr);
}
}
-
+
+#if 0
/*
* update_tl_data() - Generate the tl_data entries.
*/
@@ -908,7 +908,8 @@ update_tl_data(kcontext, dbentp, mod_name, mod_date, last_pwd_change)
return(kret);
}
-
+#endif
+
/*
* process_k5beta_record() - Handle a dump record in old format.
*
@@ -1129,11 +1130,15 @@ process_k5beta_record(fname, kcontext, filep, verbose, linenop)
if (!(kret = krb5_parse_name(kcontext,
mod_name,
&mod_princ))) {
- if (!(kret = update_tl_data(kcontext,
- &dbent,
- mod_princ,
- mod_date,
- last_pwd_change))) {
+ 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;
diff --git a/src/admin/edit/dumpv4.c b/src/admin/edit/dumpv4.c
index 7943e1bc2d..ef2eac6929 100644
--- a/src/admin/edit/dumpv4.c
+++ b/src/admin/edit/dumpv4.c
@@ -112,7 +112,8 @@ dump_v4_iterator(ptr, entry)
krb5_db_entry *entry;
{
struct dump_record *arg = (struct dump_record *) ptr;
- krb5_tl_mod_princ *mod_princ = NULL;
+ krb5_principal mod_princ;
+ krb5_timestamp mod_time;
krb5_error_code retval;
int i, max_kvno, ok_key;
@@ -152,12 +153,13 @@ dump_v4_iterator(ptr, entry)
strcpy(principal->instance, "*");
/* Now move to mod princ */
- if (retval = krb5_dbe_decode_mod_princ_data(edit_context,entry,&mod_princ)){
+ if (retval = krb5_dbe_lookup_mod_princ_data(edit_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(edit_context, mod_princ->mod_princ,
+ retval = krb5_524_conv_principal(edit_context, mod_princ,
principal->mod_name, principal->mod_instance,
principal->mod_realm);
if (retval) {
@@ -228,7 +230,7 @@ found_one:;
}
v4_print_time(arg->f, entry->expiration);
- v4_print_time(arg->f, mod_princ->mod_date);
+ v4_print_time(arg->f, mod_time);
fprintf(arg->f, " %s %s\n", principal->mod_name, principal->mod_instance);
return 0;
diff --git a/src/admin/edit/kdb5_edit.c b/src/admin/edit/kdb5_edit.c
index a3ac6fd065..0615e375d9 100644
--- a/src/admin/edit/kdb5_edit.c
+++ b/src/admin/edit/kdb5_edit.c
@@ -330,7 +330,7 @@ int create_db_entry(principal, newentry)
krb5_principal principal;
krb5_db_entry * newentry;
{
- krb5_tl_mod_princ mod_princ;
+ krb5_timestamp now;
int retval;
memset(newentry, 0, sizeof(krb5_db_entry));
@@ -345,16 +345,11 @@ int create_db_entry(principal, newentry)
&newentry->princ)))
return retval;
- if ((retval = krb5_timeofday(edit_context, &mod_princ.mod_date)))
+ if ((retval = krb5_timeofday(edit_context, &now)))
goto create_db_entry_error;
- if ((retval = krb5_copy_principal(edit_context, master_princ,
- &mod_princ.mod_princ)))
- goto create_db_entry_error;
-
- retval = krb5_dbe_encode_mod_princ_data(edit_context, &mod_princ, newentry);
- krb5_xfree(mod_princ.mod_princ->data);
-
+ retval = krb5_dbe_update_mod_princ_data(edit_context, newentry, now,
+ master_princ);
if (!retval)
return 0;
@@ -1314,7 +1309,7 @@ void modent(argc, argv)
char *argv[];
{
krb5_db_entry entry, oldentry;
- krb5_tl_mod_princ mod_princ;
+ krb5_timestamp now;
krb5_principal kprinc;
krb5_error_code retval;
krb5_boolean more;
@@ -1386,17 +1381,16 @@ void modent(argc, argv)
free(canon);
return;
}
- mod_princ.mod_princ = master_princ;
- if ((retval = krb5_timeofday(edit_context, &mod_princ.mod_date))) {
- com_err(argv[0], retval, "while fetching date");
+ if ((retval = krb5_timeofday(edit_context, &now))) {
+ com_err(argv[0], retval, "while getting current time");
krb5_free_principal(edit_context, entry.princ);
exit_status++;
free(canon);
return;
}
- if ((retval=krb5_dbe_encode_mod_princ_data(edit_context,
- &mod_princ,&entry))) {
- com_err(argv[0], retval, "while setting mod_prince and mod_date");
+ if ((retval=krb5_dbe_update_mod_princ_data(edit_context,
+ &entry, now, master_princ))) {
+ com_err(argv[0], retval, "while setting mod_princ_data");
krb5_free_principal(edit_context, entry.princ);
exit_status++;
free(canon);
diff --git a/src/admin/edit/loadv4.c b/src/admin/edit/loadv4.c
index 78b77e06bb..a1d37edc77 100644
--- a/src/admin/edit/loadv4.c
+++ b/src/admin/edit/loadv4.c
@@ -467,7 +467,8 @@ Principal *princ;
int nentries = 1;
des_cblock v4key;
char *name;
- krb5_tl_mod_princ mod_princ;
+ krb5_timestamp mod_time;
+ krb5_principal mod_princ;
krb5_keysalt keysalt;
/* don't convert local TGT if we created a TGT already.... */
@@ -518,7 +519,7 @@ Principal *princ;
free(name);
}
- if (retval = krb5_build_principal(context, &mod_princ.mod_princ,
+ if (retval = krb5_build_principal(context, &mod_princ,
strlen(realm),
realm, princ->mod_name,
princ->mod_instance[0] ? princ->mod_instance : 0,
@@ -526,7 +527,7 @@ Principal *princ;
krb5_free_principal(context, entry.princ);
return retval;
}
- mod_princ.mod_date = princ->mod_date;
+ mod_time = princ->mod_date;
entry.max_life = princ->max_life * 60 * 5;
entry.max_renewable_life = rblock.max_rlife;
@@ -552,7 +553,7 @@ Principal *princ;
retval = krb5_dbe_create_key_data(context, &entry);
if (retval) {
krb5_free_principal(context, entry.princ);
- krb5_free_principal(context, mod_princ.mod_princ);
+ krb5_free_principal(context, mod_princ);
return retval;
}
@@ -564,10 +565,11 @@ Principal *princ;
princ->key_version,
&entry.key_data[0]);
if (!retval)
- retval = krb5_dbe_encode_mod_princ_data(context, &mod_princ, &entry);
+ retval = krb5_dbe_update_mod_princ_data(context, &entry,
+ mod_time, mod_princ);
if (retval) {
krb5_db_free_principal(context, &entry, 1);
- krb5_free_principal(context, mod_princ.mod_princ);
+ krb5_free_principal(context, mod_princ);
return retval;
}
memset((char *)v4key, 0, sizeof(v4key));
@@ -586,7 +588,7 @@ Principal *princ;
}
krb5_db_free_principal(context, &entry, 1);
- krb5_free_principal(context, mod_princ.mod_princ);
+ krb5_free_principal(context, mod_princ);
return retval;
}
@@ -602,7 +604,8 @@ struct realm_info *pblock;
krb5_error_code retval;
krb5_keyblock *rkey;
int nentries = 1;
- krb5_tl_mod_princ mod_princ;
+ krb5_timestamp mod_time;
+ krb5_principal mod_princ;
memset((char *) &entry, 0, sizeof(entry));
if (retval = krb5_copy_principal(context, princ, &entry.princ))
@@ -611,23 +614,14 @@ struct realm_info *pblock;
entry.max_renewable_life = pblock->max_rlife;
entry.len = KRB5_KDB_V1_BASE_LENGTH;
entry.expiration = pblock->expiration;
- if (retval = krb5_copy_principal(context, &db_create_princ,
- &mod_princ.mod_princ)) {
- krb5_free_principal(context, entry.princ);
- return(retval);
- }
- if ((retval = krb5_timeofday(context, &mod_princ.mod_date)) ||
- (retval = krb5_copy_principal(context, &db_create_princ,
- &mod_princ.mod_princ))) {
- krb5_free_principal(context, mod_princ.mod_princ);
+ if ((retval = krb5_timeofday(context, &mod_time))) {
krb5_db_free_principal(context, &entry, 1);
return retval;
}
entry.attributes = pblock->flags;
if (retval = krb5_dbe_create_key_data(context, &entry)) {
- krb5_free_principal(context, mod_princ.mod_princ);
krb5_db_free_principal(context, &entry, 1);
return(retval);
}
@@ -639,7 +633,6 @@ struct realm_info *pblock;
&master_keyblock,
(krb5_keysalt *) NULL, 1,
&entry.key_data[0])) {
- krb5_free_principal(context, mod_princ.mod_princ);
krb5_db_free_principal(context, &entry, 1);
return retval;
}
@@ -647,7 +640,6 @@ struct realm_info *pblock;
case RANDOM_KEY:
if (retval = krb5_random_key(context, pblock->eblock, pblock->rseed,
&rkey)) {
- krb5_free_principal(context, mod_princ.mod_princ);
krb5_db_free_principal(context, &entry, 1);
return retval;
}
@@ -655,7 +647,6 @@ struct realm_info *pblock;
rkey,
(krb5_keysalt *) NULL, 1,
&entry.key_data[0])) {
- krb5_free_principal(context, mod_princ.mod_princ);
krb5_db_free_principal(context, &entry, 1);
return(retval);
}
@@ -667,11 +658,11 @@ struct realm_info *pblock;
break;
}
- retval = krb5_dbe_encode_mod_princ_data(context, &mod_princ, &entry);
+ 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);
- krb5_free_principal(context, mod_princ.mod_princ);
return retval;
}
diff --git a/src/admin/stash/ChangeLog b/src/admin/stash/ChangeLog
index e7b35b9a89..a2f6d89b44 100644
--- a/src/admin/stash/ChangeLog
+++ b/src/admin/stash/ChangeLog
@@ -1,3 +1,7 @@
+Sun May 12 01:16:49 1996 Marc Horowitz <marc@mit.edu>
+
+ * configure.in: USE_KADM_LIBRARY replaced by USE_KADMSRV_LIBRARY
+
Wed Sep 06 14:20:57 1995 Chris Provenzano (proven@mit.edu)
* kdb5_stash.c : s/keytype/enctype/g, s/KEYTYPE/ENCTYPE/g
diff --git a/src/admin/stash/configure.in b/src/admin/stash/configure.in
index 93fa3eff55..1cd10cdb58 100644
--- a/src/admin/stash/configure.in
+++ b/src/admin/stash/configure.in
@@ -1,7 +1,7 @@
AC_INIT(kdb5_stash.c)
CONFIG_RULES
AC_PROG_INSTALL
-USE_KADM_LIBRARY
+USE_KADMSRV_LIBRARY
USE_KDB5_LIBRARY
KRB5_LIBRARIES
V5_USE_SHARED_LIB
diff --git a/src/appl/gss-sample/ChangeLog b/src/appl/gss-sample/ChangeLog
index 100acd1104..d82e360ef2 100644
--- a/src/appl/gss-sample/ChangeLog
+++ b/src/appl/gss-sample/ChangeLog
@@ -4,6 +4,11 @@ Wed Jun 5 00:08:32 1996 Theodore Y. Ts'o <tytso@mit.edu>
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
diff --git a/src/appl/gss-sample/README b/src/appl/gss-sample/README
index a8d0afa7e2..52b1b2143e 100644
--- a/src/appl/gss-sample/README
+++ b/src/appl/gss-sample/README
@@ -41,26 +41,30 @@ interfaces.
The server's command line usage is
- gss-server [-port port] [-v2] service_name
+ gss-server [-port port] [-k keytab] service_name
where service_name is a GSS-API service name of the form
-"service@host". The server will accept TCP connections on port
-(default 4444) and establish contexts as service_name. The -v2 option
-means that the GSSAPI v2 calls should be used (and tested).
-
+"service@host" (or just "service", in which case the local host name
+is used). The server will accept TCP connections on port (default
+4444) and establish contexts as service_name. If you compile with
+GSS_KRB5 defined and link against the MIT Kerberos libraries, the -k
+option specifies a keytab to use instead of the default one.
The client's command line usage is
- gss-client [-port port] [-v2] [-d] host service_name msg
+ gss-client [-port port] [-d] 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, and msg is the
-message. The client connects to the TCP on <host:port> (default 4444)
-and performs the exchange. The "-d" option specifies delegation -
-a forwardable TGT will be sent to the server, which will put it in
-its credential cache (you must kinit -f for this to work).
-The -v2 option means that the GSSAPI v2 calls should be used (and
-tested).
+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 client connects to the TCP
+on <host:port> (default 4444) and performs a context
+establishment. The "-d" option specifies delegation - a forwardable
+TGT will be sent to the server, which will put it in its credential
+cache (you must kinit -f for this to work). The -v2 option means that
+the GSSAPI v2 calls should be used (and tested).
If you are using this sample application with OpenVision's Kerberos 5
GSS-API mechanism:
@@ -69,9 +73,10 @@ GSS-API mechanism:
-lisode -lcom_err.
2. 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".
+the default or specified 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:
@@ -85,3 +90,5 @@ This sample application uses the following GSS-API functions:
Barry Jaspan, bjaspan@security.ov.com
OpenVision Technologies, Inc.
+
+$Id$
diff --git a/src/appl/gss-sample/gss-client.c b/src/appl/gss-sample/gss-client.c
index ff1bfdda1b..fca0ef2315 100644
--- a/src/appl/gss-sample/gss-client.c
+++ b/src/appl/gss-sample/gss-client.c
@@ -20,6 +20,10 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
@@ -31,337 +35,16 @@
#include <sys/stat.h>
#include <fcntl.h>
-#include <gssapi/gssapi.h>
#include <gssapi/gssapi_generic.h>
-
-#ifdef USE_STRING_H
-#include <string.h>
-#else
-#include <strings.h>
-#endif
-
-int establish_context();
-int connect_to_server();
-int call_server();
-int client_establish_context();
-
-int send_token();
-int recv_token();
-void read_file();
-
-int deleg_flag;
-void display_status();
-
-extern FILE *display_file;
-
+#include "gss-misc.h"
void usage()
{
- fprintf(stderr, "Usage: gss-client [-port port] [-d] [-v2] host service \
+ fprintf(stderr, "Usage: gss-client [-port port] [-d] host service \
msg\n");
exit(1);
}
-int main(argc, argv)
- int argc;
- char **argv;
-{
- char *service_name, *server_host, *msg;
- u_short port = 4444;
- int v2 = 0;
- int use_file = 0;
-
- display_file = stdout;
- deleg_flag = 0;
-
- /* Parse arguments. */
- argc--; argv++;
- while (argc) {
- if (strcmp(*argv, "-port") == 0) {
- argc--; argv++;
- if (!argc) usage();
- port = atoi(*argv);
- } else if (strcmp(*argv, "-v2") == 0) {
- v2 = 1;
- } else if (strcmp(*argv, "-d") == 0) {
- deleg_flag = GSS_C_DELEG_FLAG;
- } else if (strcmp(*argv, "-f") == 0) {
- use_file = 1;
- } else
- break;
- argc--; argv++;
- }
- if (argc != 3)
- usage();
-
- server_host = *argv++;
- service_name = *argv++;
- msg = *argv++;
-
- if (call_server(server_host, port, v2, service_name, msg, use_file) < 0)
- exit(1);
-
- return 0;
-}
-
-/*
- * 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
- * msg (r) the message to have "signed"
- *
- * 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_seal, 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(host, port, dov2, service_name, msg, use_file)
- char *host;
- u_short port;
- int dov2;
- char *service_name;
- char *msg;
- int use_file;
-{
- gss_ctx_id_t context;
- gss_buffer_desc in_buf, out_buf, context_token;
- int s, state;
- 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;
-#ifdef GSSAPI_V2
- OM_uint32 context_flags;
- int is_open;
- gss_qop_t qop_state;
- gss_OID_set mech_names;
- gss_buffer_desc oid_name;
-#else /* GSSAPI_V2 */
- int context_flags;
-#endif /* GSSAPI_V2 */
-
- /* Open connection */
- if ((s = connect_to_server(host, port)) < 0)
- return -1;
-
- /* Establish context */
- if (client_establish_context(s, service_name, &context) < 0)
- return -1;
-
-#ifdef GSSAPI_V2
- if (dov2) {
- /*
- * Attempt to save and then restore the context.
- */
- 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;
- }
- maj_stat = gss_import_sec_context(&min_stat,
- &context_token,
- &context);
- if (maj_stat != GSS_S_COMPLETE) {
- display_status("importing context", maj_stat, min_stat);
- return -1;
- }
- (void) gss_release_buffer(&min_stat, &context_token);
- }
-#endif /* GSSAPI_V2 */
-
- /* Get context information */
- maj_stat = gss_inquire_context(&min_stat, context,
- &src_name, &targ_name, &lifetime,
- &mechanism, &context_flags,
- &is_local
-#ifdef GSSAPI_V2
- , &is_open
-#endif /* GSSAPI_V2 */
- );
- 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 context", 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 context", maj_stat, min_stat);
- return -1;
- }
- fprintf(stderr, "\"%s\" to \"%s\", lifetime %d, flags %x, %s",
- (char *) sname.value, (char *) tname.value, lifetime,
- context_flags,
- (is_local) ? "locally initiated" : "remotely initiated");
-#ifdef GSSAPI_V2
- fprintf(stderr, " %s", (is_open) ? "open" : "closed");
-#endif /* GSSAPI_V2 */
- fprintf(stderr, "\n");
-
- (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);
-
-#ifdef GSSAPI_V2
- if (dov2) {
- size_t i;
-
- 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;
- }
- fprintf(stderr, "Name type of source name is %s.\n",
- (char *) oid_name.value);
- (void) gss_release_buffer(&min_stat, &oid_name);
- (void) gss_release_oid(&min_stat, &name_type);
-
- /* 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;
- }
- fprintf(stderr, "Mechanism %s supports %d names\n",
- (char *) oid_name.value, mech_names->count);
- (void) gss_release_buffer(&min_stat, &oid_name);
- for (i=0; i<mech_names->count; i++) {
- gss_OID tmpoid;
- int is_present;
-
- 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;
- }
- fprintf(stderr, "%d: %s\n", i, (char *) oid_name.value);
-
- maj_stat = gss_str_to_oid(&min_stat,
- &oid_name,
- &tmpoid);
- if (maj_stat != GSS_S_COMPLETE) {
- display_status("converting string->oid", maj_stat, min_stat);
- return -1;
- }
-
- maj_stat = gss_test_oid_set_member(&min_stat,
- tmpoid,
- mech_names,
- &is_present);
- if (maj_stat != GSS_S_COMPLETE) {
- display_status("testing oid presence", maj_stat, min_stat);
- return -1;
- }
- if (!is_present) {
- fprintf(stderr, "%s is not present in list?\n",
- (char *) oid_name.value);
- }
- (void) gss_release_oid(&min_stat, &tmpoid);
- (void) gss_release_buffer(&min_stat, &oid_name);
- }
-
- (void) gss_release_oid_set(&min_stat, &mech_names);
- (void) gss_release_oid(&min_stat, &mechanism);
- }
-#endif /* GSSAPI_V2 */
-
- if (use_file) {
- read_file(msg, &in_buf);
- } else {
- /* Seal the message */
- in_buf.value = msg;
- in_buf.length = strlen(msg) + 1;
- }
-#ifdef GSSAPI_V2
- if (dov2)
- maj_stat = gss_wrap(&min_stat, context, 1, GSS_C_QOP_DEFAULT,
- &in_buf, &state, &out_buf);
- else
-#endif /* GSSAPI_V2 */
- maj_stat = gss_seal(&min_stat, context, 1, GSS_C_QOP_DEFAULT,
- &in_buf, &state, &out_buf);
- if (maj_stat != GSS_S_COMPLETE) {
- display_status("sealing message", maj_stat, min_stat);
- return -1;
- } else if (! state) {
- fprintf(stderr, "Warning! Message not encrypted.\n");
- }
-
- /* Send to server */
- if (send_token(s, &out_buf) < 0)
- return -1;
- (void) gss_release_buffer(&min_stat, &out_buf);
-
- /* Read signature block into out_buf */
- if (recv_token(s, &out_buf) < 0)
- return -1;
-
- /* Verify signature block */
-#ifdef GSSAPI_V2
- if (dov2)
- maj_stat = gss_verify_mic(&min_stat, context, &in_buf,
- &out_buf, &qop_state);
- else
-#endif /* GSSAPI_V2 */
- maj_stat = gss_verify(&min_stat, context, &in_buf, &out_buf, &state);
- if (maj_stat != GSS_S_COMPLETE) {
- display_status("verifying signature", maj_stat, min_stat);
- return -1;
- }
- (void) gss_release_buffer(&min_stat, &out_buf);
- if (use_file)
- free(in_buf.value);
-
- printf("Signature verified.\n");
-
- /* 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);
- return -1;
- }
- (void) gss_release_buffer(&min_stat, &out_buf);
-
- return 0;
-}
-
/*
* Function: connect_to_server
*
@@ -403,6 +86,7 @@ int connect_to_server(host, port)
}
if (connect(s, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
perror("connecting to server");
+ (void) close(s);
return -1;
}
return s;
@@ -419,6 +103,7 @@ int connect_to_server(host, port)
* s (r) an established TCP connection to the service
* service_name (r) the ASCII service name of the service
* context (w) the established GSS-API context
+ * ret_flags (w) the returned flags from init_sec_context
*
* Returns: 0 on success, -1 on failure
*
@@ -434,10 +119,13 @@ int connect_to_server(host, port)
* unsuccessful, the GSS-API error messages are displayed on stderr
* and -1 is returned.
*/
-int client_establish_context(s, service_name, gss_context)
+int client_establish_context(s, service_name, deleg_flag,
+ gss_context, ret_flags)
int s;
char *service_name;
+ OM_uint32 deleg_flag;
gss_ctx_id_t *gss_context;
+ OM_uint32 *ret_flags;
{
gss_buffer_desc send_tok, recv_tok, *token_ptr;
gss_name_t target_name;
@@ -489,7 +177,7 @@ int client_establish_context(s, service_name, gss_context)
token_ptr,
NULL, /* ignore mech type */
&send_tok,
- NULL, /* ignore ret_flags */
+ ret_flags,
NULL); /* ignore time_rec */
if (token_ptr != GSS_C_NO_BUFFER)
@@ -527,7 +215,6 @@ int client_establish_context(s, service_name, gss_context)
return 0;
}
-
void read_file(file_name, in_buf)
char *file_name;
gss_buffer_t in_buf;
@@ -566,3 +253,251 @@ void read_file(file_name, in_buf)
bytes_in, count);
}
+/*
+ * 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
+ * msg (r) the message to have "signed"
+ *
+ * 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_seal, 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(host, port, service_name, deleg_flag, msg, use_file)
+ char *host;
+ u_short port;
+ char *service_name;
+ OM_uint32 deleg_flag;
+ char *msg;
+ int use_file;
+{
+ 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;
+
+ /* Open connection */
+ if ((s = connect_to_server(host, port)) < 0)
+ return -1;
+
+ /* Establish context */
+ if (client_establish_context(s, service_name, deleg_flag, &context,
+ &ret_flags) < 0) {
+ (void) close(s);
+ return -1;
+ }
+
+ /* 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;
+ }
+ fprintf(stderr, "\"%.*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;
+ }
+ fprintf(stderr, "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;
+ }
+ fprintf(stderr, "Mechanism %.*s supports %d names\n",
+ (int) oid_name.length, (char *) oid_name.value,
+ 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;
+ }
+ fprintf(stderr, " %d: %.*s\n", 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) + 1;
+ }
+
+ maj_stat = gss_wrap(&min_stat, context, 1, GSS_C_QOP_DEFAULT,
+ &in_buf, &state, &out_buf);
+ if (maj_stat != GSS_S_COMPLETE) {
+ display_status("sealing message", maj_stat, min_stat);
+ (void) close(s);
+ (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
+ return -1;
+ } else if (! state) {
+ fprintf(stderr, "Warning! Message not encrypted.\n");
+ }
+
+ /* Send to server */
+ if (send_token(s, &out_buf) < 0) {
+ (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);
+
+ /* Read signature block into out_buf */
+ if (recv_token(s, &out_buf) < 0) {
+ (void) close(s);
+ (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
+ return -1;
+ }
+
+ /* 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;
+ }
+ (void) gss_release_buffer(&min_stat, &out_buf);
+
+ if (use_file)
+ free(in_buf.value);
+
+ printf("Signature verified.\n");
+
+ /* 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;
+}
+
+int main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *service_name, *server_host, *msg;
+ u_short port = 4444;
+ int use_file = 0;
+ OM_uint32 deleg_flag = 0;
+
+ display_file = stdout;
+
+ /* Parse arguments. */
+ argc--; argv++;
+ while (argc) {
+ if (strcmp(*argv, "-port") == 0) {
+ argc--; argv++;
+ if (!argc) usage();
+ port = atoi(*argv);
+ } else if (strcmp(*argv, "-d") == 0) {
+ deleg_flag = GSS_C_DELEG_FLAG;
+ } else if (strcmp(*argv, "-f") == 0) {
+ use_file = 1;
+ } else
+ break;
+ argc--; argv++;
+ }
+ if (argc != 3)
+ usage();
+
+ server_host = *argv++;
+ service_name = *argv++;
+ msg = *argv++;
+
+ if (call_server(server_host, port, service_name,
+ deleg_flag, msg, use_file) < 0)
+ exit(1);
+
+ return 0;
+}
+
diff --git a/src/appl/gss-sample/gss-misc.c b/src/appl/gss-sample/gss-misc.c
index 446aa3087c..67e898c1d6 100644
--- a/src/appl/gss-sample/gss-misc.c
+++ b/src/appl/gss-sample/gss-misc.c
@@ -20,16 +20,21 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
#include <stdio.h>
#include <sys/types.h>
#include <netinet/in.h>
+#include <errno.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <string.h>
-#include <gssapi/gssapi.h>
#include <gssapi/gssapi_generic.h>
+#include "gss-misc.h"
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
@@ -37,9 +42,48 @@
extern char *malloc();
#endif
-static void display_status_1();
+FILE *display_file;
+
+static void display_status_1
+ PROTOTYPE( (char *m, OM_uint32 code, int type) );
-FILE *display_file = NULL;
+static int write_all(int fildes, char *buf, unsigned int nbyte)
+{
+ int ret;
+ char *ptr;
+
+ for (ptr = buf; nbyte; ptr += ret, nbyte -= ret) {
+ ret = write(fildes, ptr, nbyte);
+ 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;
+
+ for (ptr = buf; nbyte; ptr += ret, nbyte -= ret) {
+ ret = read(fildes, ptr, nbyte);
+ if (ret < 0) {
+ if (errno == EINTR)
+ continue;
+ return(ret);
+ } else if (ret == 0) {
+ return(ptr-buf);
+ }
+ }
+
+ return(ptr-buf);
+}
/*
* Function: send_token
@@ -67,7 +111,7 @@ int send_token(s, tok)
len = htonl(tok->length);
- ret = write(s, (char *) &len, 4);
+ ret = write_all(s, (char *) &len, 4);
if (ret < 0) {
perror("sending token length");
return -1;
@@ -79,7 +123,7 @@ int send_token(s, tok)
return -1;
}
- ret = write(s, tok->value, tok->length);
+ ret = write_all(s, tok->value, tok->length);
if (ret < 0) {
perror("sending token data");
return -1;
@@ -120,9 +164,8 @@ int recv_token(s, tok)
gss_buffer_t tok;
{
int ret;
- int readsofar = 0;
- ret = read(s, (char *) &tok->length, 4);
+ ret = read_all(s, (char *) &tok->length, 4);
if (ret < 0) {
perror("reading token length");
return -1;
@@ -143,20 +186,45 @@ int recv_token(s, tok)
return -1;
}
- while (readsofar < tok->length) {
- ret = read(s, (char *) tok->value + readsofar,
- tok->length - readsofar);
- readsofar += ret;
- if (ret < 0) {
- perror("reading token data");
- free(tok->value);
- 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, 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
*
@@ -183,32 +251,37 @@ void display_status(msg, maj_stat, min_stat)
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;
+/*
+ * 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;
{
- OM_uint32 maj_stat, 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) {
- 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;
- }
+ 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)
@@ -228,24 +301,3 @@ void print_token(tok)
fprintf(display_file, "\n");
fflush(display_file);
}
-
-void display_buffer(buffer)
- gss_buffer_desc buffer;
-{
- char *namebuf;
-
- if (!display_file)
- return;
- 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';
- fprintf(display_file, "%s", namebuf);
- free(namebuf);
-}
-
-
-
diff --git a/src/appl/gss-sample/gss-misc.h b/src/appl/gss-sample/gss-misc.h
new file mode 100644
index 0000000000..bfdcad2f41
--- /dev/null
+++ b/src/appl/gss-sample/gss-misc.h
@@ -0,0 +1,46 @@
+/*
+ * 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
+ PROTOTYPE( (int s, gss_buffer_t tok) );
+int recv_token
+ PROTOTYPE( (int s, gss_buffer_t tok) );
+void display_status
+ PROTOTYPE( (char *msg, OM_uint32 maj_stat, OM_uint32 min_stat) );
+void display_ctx_flags
+ PROTOTYPE( (OM_uint32 flags) );
+void print_token
+ PROTOTYPE( (gss_buffer_t tok) );
+
+#endif
diff --git a/src/appl/gss-sample/gss-server.c b/src/appl/gss-sample/gss-server.c
index f685ab70fc..bd4e7fe906 100644
--- a/src/appl/gss-sample/gss-server.c
+++ b/src/appl/gss-sample/gss-server.c
@@ -20,6 +20,10 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
@@ -29,11 +33,9 @@
#endif
#include <stdlib.h>
#include <ctype.h>
-#include <sys/time.h>
-#include <time.h>
-#include <gssapi/gssapi.h>
#include <gssapi/gssapi_generic.h>
+#include "gss-misc.h"
#ifdef USE_STRING_H
#include <string.h>
@@ -41,292 +43,16 @@
#include <strings.h>
#endif
-int create_socket();
-
-int send_token();
-int recv_token();
-void display_status();
-int test_import_export_context();
-void print_token();
-
-int server_acquire_creds();
-int server_establish_context();
-int sign_server();
-
-extern FILE *display_file;
-FILE *log;
-
-int verbose = 0;
-
-void
usage()
{
- fprintf(stderr, "Usage: gss-server [-port port] [-v2] [-inetd] [-logfile file] service_name\n");
+ fprintf(stderr, "Usage: gss-server [-port port] [-verbose]\n");
+ fprintf(stderr, " [-inetd] [-logfile file] [service_name]\n");
exit(1);
}
-int
-main(argc, argv)
- int argc;
- char **argv;
-{
- char *service_name;
- u_short port = 4444;
- int s;
- int do_inetd = 0;
- int dov2 = 0;
- int once = 0;
-
- log = stdout;
- display_file = stdout;
- argc--; argv++;
- while (argc) {
- if (strcmp(*argv, "-port") == 0) {
- argc--; argv++;
- if (!argc) usage();
- port = atoi(*argv);
- } else if (strcmp(*argv, "-inetd") == 0) {
- do_inetd = 1;
- display_file = 0;
- } else if (strcmp(*argv, "-verbose") == 0) {
- verbose = 1;
- } else if (strcmp(*argv, "-v2") == 0) {
- dov2 = 1;
- } else if (strcmp(*argv, "-once") == 0) {
- once = 1;
- } else if (strcmp(*argv, "-logfile") == 0) {
- argc--; argv++;
- if (!argc) usage();
- log = fopen(*argv, "a");
- display_file = log;
- if (!log) {
- perror(*argv);
- exit(1);
- }
- } else
- break;
- argc--; argv++;
- }
- if (argc != 1)
- usage();
-
- service_name = *argv;
-
- if (do_inetd == 0) {
- if ((s = create_socket(port)) < 0)
- exit(1);
- } else {
- s = -1;
- close(1);
- close(2);
- }
-
- if (sign_server(s, service_name, dov2, once) < 0)
- exit(1);
-
- /*NOTREACHED*/
- 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.
- */
-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");
- return -1;
- }
- if (listen(s, 5) < 0) {
- perror("listening on socket");
- return -1;
- }
- return s;
-}
-
-/*
- * Function: sign_server
- *
- * Purpose: Performs the "sign" service.
- *
- * Arguments:
- *
- * s (r) a TCP socket on which to listen for connections.
- * If s is -1, then assume that we were started out of
- * inetd and use file descriptor 0.
- * service_name (r) the ASCII name of the GSS-API service to
- * establish a context as
- * dov2 (r) a boolean indicating whether we should use GSSAPI
- * V2 interfaces, if available.
- * once (r) a boolean indicating whether we should
- * only accept one connection, then exit.
- *
- * Returns: -1 on error
- *
- * Effects:
- *
- * sign_server acquires GSS-API credentials for service_name and then
- * loops forever accepting TCP connections on s, establishing a
- * context, and performing 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.
- */
-int sign_server(s, service_name, dov2, once)
- int s;
- char *service_name;
- int dov2;
- int once;
-{
- gss_cred_id_t server_creds;
- gss_buffer_desc client_name, xmit_buf, msg_buf;
- gss_ctx_id_t context;
- OM_uint32 maj_stat, min_stat;
- int i,s2;
- time_t now;
- char *cp;
-
- if (server_acquire_creds(service_name, &server_creds) < 0)
- return -1;
-
- while (1) {
- if (s >= 0) {
- /* Accept a TCP connection */
- if ((s2 = accept(s, NULL, 0)) < 0) {
- perror("accepting connection");
- exit(1);
- }
- } else
- s2 = 0;
-
- /* Establish a context with the client */
- if (server_establish_context(s2, server_creds, &context,
- &client_name) < 0)
- break;
-
- time(&now);
- fprintf(log, "Accepted connection: \"%s\" at %s",
- (char *) client_name.value, ctime(&now));
- (void) gss_release_buffer(&min_stat, &client_name);
-
- if (dov2) {
- for (i=0; i < 3; i++)
- if (test_import_export_context(&context))
- break;
- if (i < 3)
- break;
- }
-
- /* Receive the sealed message token */
- if (recv_token(s2, &xmit_buf) < 0)
- break;
-
- if (verbose && log) {
- fprintf(log, "Sealed message token:\n");
- print_token(xmit_buf);
- }
-
-#ifdef GSSAPI_V2
- if (dov2)
- maj_stat = gss_unwrap(&min_stat, context, &xmit_buf, &msg_buf,
- (int *) NULL, (gss_qop_t *) NULL);
- else
-#endif /* GSSAPI_V2 */
- /* Unseal the message token */
- maj_stat = gss_unseal(&min_stat, context, &xmit_buf,
- &msg_buf, NULL, NULL);
- if (maj_stat != GSS_S_COMPLETE) {
- display_status("unsealing message", maj_stat, min_stat);
- break;
- }
-
- (void) gss_release_buffer(&min_stat, &xmit_buf);
-
- fprintf(log, "Received message: ");
- cp = msg_buf.value;
- if (isprint(cp[0]) && isprint(cp[1]))
- fprintf(log, "\"%s\"\n", cp);
- else {
- printf("\n");
- print_token(msg_buf);
- }
-
- /* Produce a signature block for the message */
-#ifdef GSSAPI_V2
- if (dov2)
- maj_stat = gss_get_mic(&min_stat, context, GSS_C_QOP_DEFAULT,
- &msg_buf, &xmit_buf);
- else
-#endif /* GSSAPI_V2 */
- maj_stat = gss_sign(&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);
- break;
- }
-
- (void) gss_release_buffer(&min_stat, &msg_buf);
-
- /* Send the signature block to the client */
- if (send_token(s2, &xmit_buf) < 0)
- break;
-
- (void) gss_release_buffer(&min_stat, &xmit_buf);
-
- /* Delete context */
- maj_stat = gss_delete_sec_context(&min_stat, &context, &xmit_buf);
- if (maj_stat != GSS_S_COMPLETE) {
- display_status("deleting context", maj_stat, min_stat);
- break;
- }
-
- (void) gss_release_buffer(&min_stat, &xmit_buf);
-
- /* Close TCP connection */
- close(s2);
-
- fflush(log);
-
- if (s < 0 || once)
- break;
- }
+FILE *log;
- /*NOTREACHED*/
- (void) gss_release_cred(&min_stat, &server_creds);
- return -1;
-}
+int verbose = 0;
/*
* Function: server_acquire_creds
@@ -400,17 +126,17 @@ int server_acquire_creds(service_name, server_creds)
* in client_name and 0 is returned. If unsuccessful, an error
* message is displayed and -1 is returned.
*/
-int server_establish_context(s, server_creds, context, client_name)
+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;
- OM_uint32 ret_flags;
*context = GSS_C_NO_CONTEXT;
@@ -432,7 +158,7 @@ int server_establish_context(s, server_creds, context, client_name)
&client,
&doid,
&send_tok,
- &ret_flags,
+ ret_flags,
NULL, /* ignore time_rec */
NULL); /* ignore del_cred_handle */
@@ -441,8 +167,9 @@ int server_establish_context(s, server_creds, context, client_name)
(void) gss_release_buffer(&min_stat, &recv_tok);
return -1;
}
+
(void) gss_release_buffer(&min_stat, &recv_tok);
-
+
if (send_tok.length != 0) {
if (verbose && log) {
fprintf(log,
@@ -457,15 +184,18 @@ int server_establish_context(s, server_creds, context, client_name)
(void) gss_release_buffer(&min_stat, &send_tok);
}
- if (maj_stat == GSS_S_CONTINUE_NEEDED)
- if (log)
- fprintf(log, "continue needed...");
if (log) {
- fprintf(log, "\n");
+ if (maj_stat == GSS_S_CONTINUE_NEEDED)
+ fprintf(log, "\n");
+ else
+ fprintf(log, "continue needed...\n");
fflush(log);
}
} while (maj_stat == GSS_S_CONTINUE_NEEDED);
+ /* display the flags */
+ display_ctx_flags(*ret_flags);
+
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);
@@ -479,42 +209,232 @@ int server_establish_context(s, server_creds, context, client_name)
return 0;
}
-static float timeval_subtract(tv1, tv2)
- struct timeval *tv1, *tv2;
+/*
+ * 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.
+ */
+int create_socket(port)
+ u_short port;
{
- return ((tv1->tv_sec - tv2->tv_sec) +
- ((float) (tv1->tv_usec - tv2->tv_usec)) / 1000000);
+ 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;
}
-int test_import_export_context(context)
- gss_ctx_id_t *context;
+/*
+ * 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
+ *
+ * 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.
+ */
+int sign_server(s, server_creds)
+ int s;
+ gss_cred_id_t server_creds;
{
- OM_uint32 min_stat, maj_stat;
- gss_buffer_desc context_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",
- context_token.length, timeval_subtract(&tm2, &tm1));
- maj_stat = gss_import_sec_context(&min_stat, &context_token, context);
- if (maj_stat != GSS_S_COMPLETE) {
- display_status("importing context", maj_stat, min_stat);
- return 1;
- }
- 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;
+ 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;
+
+ /* Establish a context with the client */
+ if (server_establish_context(s, server_creds, &context,
+ &client_name, &ret_flags) < 0)
+ return(-1);
+
+ printf("Accepted connection: \"%.*s\"\n",
+ client_name.length, client_name.value);
+ (void) gss_release_buffer(&min_stat, &client_name);
+
+ /* Receive the sealed message token */
+ if (recv_token(s, &xmit_buf) < 0)
+ return(-1);
+
+ if (verbose && log) {
+ fprintf(log, "Sealed message token:\n");
+ print_token(&xmit_buf);
+ }
+
+ 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);
+ return(-1);
+ } else if (! conf_state) {
+ fprintf(stderr, "Warning! Message not encrypted.\n");
+ }
+
+ (void) gss_release_buffer(&min_stat, &xmit_buf);
+
+ fprintf(log, "Received message: ");
+ cp = msg_buf.value;
+ if (isprint(cp[0]) && isprint(cp[1]))
+ fprintf(log, "\"%s\"\n", cp);
+ else {
+ printf("\n");
+ print_token(&msg_buf);
+ }
+
+ /* 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);
+ }
+
+ (void) gss_release_buffer(&min_stat, &msg_buf);
+
+ /* Send the signature block to the client */
+ if (send_token(s, &xmit_buf) < 0)
+ return(-1);
+
+ (void) gss_release_buffer(&min_stat, &xmit_buf);
+
+ /* 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);
+ }
+
+ fflush(log);
+
+ 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 s;
+ int once = 0;
+ int do_inetd = 0;
+
+ log = stdout;
+ display_file = stdout;
+ argc--; argv++;
+ while (argc) {
+ if (strcmp(*argv, "-port") == 0) {
+ argc--; argv++;
+ if (!argc) usage();
+ port = atoi(*argv);
+ } 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, "-logfile") == 0) {
+ argc--; argv++;
+ if (!argc) usage();
+ 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();
+
+ 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);
+ close(0);
+ } else {
+ int stmp;
+
+ if (stmp = create_socket(port)) {
+ do {
+ /* Accept a TCP connection */
+ if ((s = accept(stmp, NULL, 0)) < 0) {
+ perror("accepting connection");
+ } else {
+ /* this return value is not checked, because there's
+ not really anything to do if it fails */
+ sign_server(s, server_creds);
+ }
+ } while (!once);
+ }
+
+ close(stmp);
+ }
+
+ (void) gss_release_cred(&min_stat, &server_creds);
+
+ /*NOTREACHED*/
+ (void) close(s);
+ return 0;
}
diff --git a/src/appl/gssftp/ftp/ChangeLog b/src/appl/gssftp/ftp/ChangeLog
index 0d480b2c6d..d73bf4c692 100644
--- a/src/appl/gssftp/ftp/ChangeLog
+++ b/src/appl/gssftp/ftp/ChangeLog
@@ -1,3 +1,8 @@
+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.
@@ -13,7 +18,7 @@ Thu Mar 28 19:26:53 1996 Marc Horowitz <marc@mit.edu>
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)
+ defined (in addition to the other tests)
* configure.in: Add AC_HEADER_STDARG
diff --git a/src/appl/gssftp/ftp/cmds.c b/src/appl/gssftp/ftp/cmds.c
index 396f317dd0..d0dc5dda66 100644
--- a/src/appl/gssftp/ftp/cmds.c
+++ b/src/appl/gssftp/ftp/cmds.c
@@ -1243,7 +1243,7 @@ lcd(argc, argv)
/*
* Delete a single file.
*/
-delete(argc, argv)
+delete_file(argc, argv)
int argc;
char *argv[];
{
diff --git a/src/appl/gssftp/ftp/cmdtab.c b/src/appl/gssftp/ftp/cmdtab.c
index 39d171d84f..f20660cac8 100644
--- a/src/appl/gssftp/ftp/cmdtab.c
+++ b/src/appl/gssftp/ftp/cmdtab.c
@@ -50,7 +50,7 @@ int setlevel(), setclear(), setsafe();
int setprivate();
#endif
int disconnect(), restart(), reget(), syst();
-int cd(), lcd(), delete(), mdelete(), user();
+int cd(), lcd(), delete_file(), mdelete(), user();
int ls(), mls(), get(), mget(), help(), append(), put(), mput();
int quit(), renamefile(), status();
int quote(), rmthelp(), shell(), site();
@@ -154,7 +154,7 @@ struct cmd cmdtab[] = {
{ "clear", clearhelp, 0, 1, 1, setclear },
{ "close", disconhelp, 0, 1, 1, disconnect },
{ "cr", crhelp, 0, 0, 0, setcr },
- { "delete", deletehelp, 0, 1, 1, delete },
+ { "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 },
diff --git a/src/appl/gssftp/ftpd/ChangeLog b/src/appl/gssftp/ftpd/ChangeLog
index 798b51dbd1..3f04d2cee7 100644
--- a/src/appl/gssftp/ftpd/ChangeLog
+++ b/src/appl/gssftp/ftpd/ChangeLog
@@ -1,3 +1,10 @@
+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
diff --git a/src/appl/gssftp/ftpd/ftpcmd.y b/src/appl/gssftp/ftpd/ftpcmd.y
index c891ab9139..c014f35b26 100644
--- a/src/appl/gssftp/ftpd/ftpcmd.y
+++ b/src/appl/gssftp/ftpd/ftpcmd.y
@@ -338,14 +338,14 @@ cmd: USER SP username CRLF
| STOR check_login SP pathname CRLF
= {
if ($2 && $4 != NULL)
- store((char *) $4, "w", 0);
+ store_file((char *) $4, "w", 0);
if ($4 != NULL)
free((char *) $4);
}
| APPE check_login SP pathname CRLF
= {
if ($2 && $4 != NULL)
- store((char *) $4, "a", 0);
+ store_file((char *) $4, "a", 0);
if ($4 != NULL)
free((char *) $4);
}
@@ -387,7 +387,7 @@ cmd: USER SP username CRLF
| DELE check_login SP pathname CRLF
= {
if ($2 && $4 != NULL)
- delete((char *) $4);
+ delete_file((char *) $4);
if ($4 != NULL)
free((char *) $4);
}
@@ -535,7 +535,7 @@ cmd: USER SP username CRLF
| STOU check_login SP pathname CRLF
= {
if ($2 && $4 != NULL)
- store((char *) $4, "w", 1);
+ store_file((char *) $4, "w", 1);
if ($4 != NULL)
free((char *) $4);
}
diff --git a/src/appl/gssftp/ftpd/ftpd.c b/src/appl/gssftp/ftpd/ftpd.c
index c260325f34..0d7044271b 100644
--- a/src/appl/gssftp/ftpd/ftpd.c
+++ b/src/appl/gssftp/ftpd/ftpd.c
@@ -923,7 +923,7 @@ done:
(*closefunc)(fin);
}
-store(name, mode, unique)
+store_file(name, mode, unique)
char *name, *mode;
int unique;
{
@@ -1549,7 +1549,7 @@ yyerror(s)
reply(500, "'%s': command not understood.", cbuf);
}
-delete(name)
+delete_file(name)
char *name;
{
struct stat st;
diff --git a/src/appl/telnet/libtelnet/ChangeLog b/src/appl/telnet/libtelnet/ChangeLog
index 1c131f1aef..7da90002ff 100644
--- a/src/appl/telnet/libtelnet/ChangeLog
+++ b/src/appl/telnet/libtelnet/ChangeLog
@@ -1,3 +1,16 @@
+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
@@ -15,7 +28,7 @@ Sat Apr 27 16:09:54 1996 Richard Basch <basch@lehman.com>
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>
+ krlogind forwarded credentials cache naming scheme - krb5cc_p<pid>
Thu Apr 11 21:45:21 1996 Richard Basch <basch@lehman.com>
diff --git a/src/appl/telnet/libtelnet/Makefile.in b/src/appl/telnet/libtelnet/Makefile.in
index 02d4e757b2..d3e9eb5a61 100644
--- a/src/appl/telnet/libtelnet/Makefile.in
+++ b/src/appl/telnet/libtelnet/Makefile.in
@@ -21,7 +21,7 @@
#
AUTH_DEF=-DAUTHENTICATION -DENCRYPTION -DDES_ENCRYPTION -DKRB5 -DFORWARD \
-UNO_LOGIN_F -DLOGIN_CAP_F -DLOGIN_PROGRAM=KRB5_PATH_LOGIN
-LOCALINCLUDES=-I.. -I$(srcdir)/..
+LOCALINCLUDES=-I.. -I$(srcdir)/.. @KRB4_INCLUDES@
CFLAGS = $(CCOPTS) $(AUTH_DEF) $(DEFS) $(LOCALINCLUDES)
LIBOBJS=@LIBOBJS@
diff --git a/src/appl/telnet/libtelnet/enc-proto.h b/src/appl/telnet/libtelnet/enc-proto.h
index 996a4f5d06..48f91430f5 100644
--- a/src/appl/telnet/libtelnet/enc-proto.h
+++ b/src/appl/telnet/libtelnet/enc-proto.h
@@ -117,10 +117,4 @@ int ofb64_reply P((unsigned char *, int));
void ofb64_session P((Session_Key *, int));
int ofb64_keyid P((int, unsigned char *, int *));
void ofb64_printsub P((unsigned char *, int, unsigned char *, int));
-
-int des_new_random_key P((Block));
-void des_set_random_generator_seed P((Block));
-void des_key_sched P((Block, Schedule));
-void des_ecb_encrypt P((Block, Block, Schedule, int));
-int des_string_to_key P((char *, Block));
#endif /* ENCRYPTION */
diff --git a/src/clients/kinit/ChangeLog b/src/clients/kinit/ChangeLog
index 75f9fa8529..7fa4f102bd 100644
--- a/src/clients/kinit/ChangeLog
+++ b/src/clients/kinit/ChangeLog
@@ -9,6 +9,11 @@ Sun Jul 7 15:21:58 1996 Ezra Peisach <epeisach@kangaroo.mit.edu>
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
diff --git a/src/clients/kinit/kinit.M b/src/clients/kinit/kinit.M
index 9d05b2d589..3108a0aad4 100644
--- a/src/clients/kinit/kinit.M
+++ b/src/clients/kinit/kinit.M
@@ -94,6 +94,11 @@ option is not used, the default cache is used. Any contents of the
cache are destroyed by
.IR kinit .
.PP
+The
+.B \-s
+option can be used to specify an alternate service name to use when
+getting initial tickets.
+.PP
The default credentials cache may vary between systems; however, if the
.B KRB5CCNAME
environment variable is set, its value is used to name the default
diff --git a/src/clients/kinit/kinit.c b/src/clients/kinit/kinit.c
index 555b1b8610..df8d449e48 100644
--- a/src/clients/kinit/kinit.c
+++ b/src/clients/kinit/kinit.c
@@ -60,6 +60,7 @@ main(argc, argv)
krb5_ccache ccache = NULL;
char *cache_name = NULL; /* -f option */
char *keytab_name = NULL; /* -t option */
+ char *service_name = NULL; /* -s option */
krb5_deltat lifetime = KRB5_DEFAULT_LIFE; /* -l option */
krb5_timestamp starttime = 0;
krb5_deltat rlife = 0;
@@ -90,7 +91,7 @@ main(argc, argv)
if (strrchr(argv[0], '/'))
argv[0] = strrchr(argv[0], '/')+1;
- while ((option = getopt(argc, argv, "r:Rfpl:s:c:kt:v")) != EOF) {
+ while ((option = getopt(argc, argv, "r:Rfpl:s:c:kt:vS:")) != EOF) {
switch (option) {
case 'r':
options |= KDC_OPT_RENEWABLE;
@@ -108,6 +109,9 @@ main(argc, argv)
/* validate the ticket */
options |= KDC_OPT_VALIDATE;
break;
+ case 'S':
+ service_name = optarg;
+ break;
case 'p':
options |= KDC_OPT_PROXIABLE;
break;
@@ -186,7 +190,7 @@ main(argc, argv)
}
if (errflg) {
- fprintf(stderr, "Usage: %s [-r time] [-R] [-s time] [-v] [-puf] [-l lifetime] [-c cachename] [-k] [-t keytab] [principal]\n", argv[0]);
+ fprintf(stderr, "Usage: %s [-r time] [-R] [-s time] [-v] [-puf] [-l lifetime] [-c cachename] [-k] [-t keytab] [-S target_service] [principal]\n", argv[0]);
exit(2);
}
@@ -250,17 +254,25 @@ main(argc, argv)
my_creds.client = me;
- if((code = krb5_build_principal_ext(kcontext, &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))) {
- com_err(argv[0], code, "while building server name");
- exit(1);
+ if (service_name == NULL) {
+ if((code = krb5_build_principal_ext(kcontext, &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))) {
+ com_err(argv[0], code, "while building server name");
+ exit(1);
+ }
+ } else {
+ if (code = krb5_parse_name(kcontext, service_name, &server)) {
+ com_err(argv[0], code, "while parsing service name %s",
+ service_name);
+ exit(1);
+ }
}
-
+
my_creds.server = server;
if (options & KDC_OPT_POSTDATED) {
diff --git a/src/config/ChangeLog b/src/config/ChangeLog
index 73323b9384..fec5211fd5 100644
--- a/src/config/ChangeLog
+++ b/src/config/ChangeLog
@@ -1,3 +1,8 @@
+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
diff --git a/src/config/pre.in b/src/config/pre.in
index d5f8342f05..78d94e17ae 100644
--- a/src/config/pre.in
+++ b/src/config/pre.in
@@ -38,6 +38,11 @@ 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_PROGRAM=@INSTALL_PROGRAM@ -s
INSTALL_DATA=@INSTALL_DATA@
diff --git a/src/configure.in b/src/configure.in
index 670a2c8d00..5885d1449f 100644
--- a/src/configure.in
+++ b/src/configure.in
@@ -257,7 +257,8 @@ dnl
WITH_ANAME_DB
WITH_KDB_DB
dnl
-CONFIG_DIRS(util include lib kdc admin kadmin $kadminv4 $krb524 slave clients appl tests config-files)
+CONFIG_DIRS(util include lib $krb524 kdc admin kadmin slave clients appl tests config-files)
+dnl $kadminv4 removed from the above
DO_SUBDIRS
-dnl dnl AC_OUTPUT(Makefile,[EXTRA_RULES])
+dnl AC_OUTPUT(Makefile,[EXTRA_RULES])
V5_AC_OUTPUT_MAKEFILE
diff --git a/src/include/ChangeLog b/src/include/ChangeLog
index cba08f35e6..8fa97791e6 100644
--- a/src/include/ChangeLog
+++ b/src/include/ChangeLog
@@ -89,6 +89,11 @@ Tue Apr 30 14:51:55 1996 <tytso@rsts-11.mit.edu>
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
diff --git a/src/include/k5-int.h b/src/include/k5-int.h
index e3d2057e2e..bcc6c5ac00 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -365,85 +365,7 @@ typedef unsigned char u_char;
#include "krb5.h"
#ifdef NEED_SOCKETS
-/*
- * Begin "k5-sockets.h"
- */
-#if defined (_MSDOS) || defined(_WIN32)
-
-#include <winsock.h>
-
-/* Some of our own infrastructure where the WinSock stuff was too hairy
- to dump into a clean Unix program... */
-
-#define SOCKET_INITIALIZE() win_socket_initialize()
-#define SOCKET_CLEANUP() WSACleanup()
-#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_EINTR WSAEINTR
-
-int win_socket_initialize();
-
-#else /* not _MSDOS */
-
-/* If this source file requires it, define struct sockaddr_in
- (and possibly other things related to network I/O). */
-
-#ifdef HAVE_MACSOCK_H /* Sockets stuff differs on Mac */
-#include "macsock.h" /* Macintosh sockets emulation library */
-
-/* Some of our own infrastructure where the WinSock stuff was too hairy
- to dump into a clean Unix program... */
-
-#define SOCKET_INITIALIZE() (WSAStartup(0x0101, (WSADATA *)0))
-#define SOCKET_CLEANUP() (WSACleanup())
-#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_EINTR WSAEINTR
-
-#else /* ! HAVE_MACSOCK_H */ /* Sockets stuff for Unix machines */
-
-#include <netinet/in.h> /* For struct sockaddr_in and in_addr */
-#include <arpa/inet.h> /* For inet_ntoa */
-#include <netdb.h> /* For struct hostent, gethostbyname, etc */
-#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 */
-
-/*
- * Compatability with WinSock calls on MS-Windows...
- */
-#define SOCKET unsigned int
-#define INVALID_SOCKET ((SOCKET)~0)
-#define closesocket close
-#define ioctlsocket ioctl
-#define SOCKET_ERROR (-1)
-
-/* 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_EINTR EINTR
-
-#endif /* HAVE_MACSOCK_H */
-
-#endif /* _MSDOS */
-
-/*
- * End "k5-sockets.h"
- */
+#include "port-sockets.h"
#endif
/* krb5/krb5.h includes many other .h files in the krb5 subdirectory.
diff --git a/src/include/krb5/ChangeLog b/src/include/krb5/ChangeLog
index adc0fabd5a..123349af26 100644
--- a/src/include/krb5/ChangeLog
+++ b/src/include/krb5/ChangeLog
@@ -1,3 +1,4 @@
+<<<<<<< ChangeLog
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
@@ -24,6 +25,12 @@ 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
diff --git a/src/include/krb5/adm.h b/src/include/krb5/adm.h
index 0202823502..b4ec50852c 100644
--- a/src/include/krb5/adm.h
+++ b/src/include/krb5/adm.h
@@ -197,6 +197,7 @@ typedef struct __krb5_realm_params {
char * realm_mkey_name;
char * realm_stash_file;
char * realm_kdc_ports;
+ char * realm_acl_file;
krb5_int32 realm_kadmind_port;
krb5_enctype realm_enctype;
krb5_deltat realm_max_life;
diff --git a/src/include/krb5/kdb.h b/src/include/krb5/kdb.h
index 7a8f5bb252..db7157f14f 100644
--- a/src/include/krb5/kdb.h
+++ b/src/include/krb5/kdb.h
@@ -111,18 +111,9 @@ typedef struct _krb5_db_entry_new {
#define KRB5_KDB_MAGIC_NUMBER 0xdbdbdbdb
#define KRB5_KDB_V1_BASE_LENGTH 38
-typedef struct tl_data_1 {
- krb5_timestamp last_pwd_change; /* Last time passwd changed */
-} krb5_tl_last_change;
-
#define KRB5_TL_LAST_PWD_CHANGE 0x0001
-
-typedef struct tl_data_2 {
- krb5_timestamp mod_date;
- krb5_principal mod_princ;
-} krb5_tl_mod_princ;
-
#define KRB5_TL_MOD_PRINC 0x0002
+#define KRB5_TL_KADM_DATA 0x0003
/*
* Determines the number of failed KDC requests before DISALLOW_ALL_TIX is set
@@ -263,22 +254,32 @@ krb5_error_code krb5_dbekd_decrypt_key_data
krb5_error_code krb5_dbe_create_key_data
KRB5_PROTOTYPE((krb5_context,
krb5_db_entry *));
-krb5_error_code krb5_dbe_encode_mod_princ_data
+krb5_error_code krb5_dbe_update_tl_data
KRB5_PROTOTYPE((krb5_context,
- krb5_tl_mod_princ *,
- krb5_db_entry *));
-krb5_error_code krb5_dbe_decode_mod_princ_data
+ krb5_db_entry *,
+ krb5_tl_data *));
+krb5_error_code krb5_dbe_lookup_tl_data
KRB5_PROTOTYPE((krb5_context,
- krb5_db_entry *,
- krb5_tl_mod_princ **));
-krb5_error_code krb5_dbe_encode_last_pwd_change
+ krb5_db_entry *,
+ krb5_tl_data *));
+krb5_error_code krb5_dbe_update_last_pwd_change
KRB5_PROTOTYPE((krb5_context,
- krb5_tl_last_change *,
- krb5_db_entry *));
-krb5_error_code krb5_dbe_decode_last_pwd_change
+ krb5_db_entry *,
+ krb5_timestamp));
+krb5_error_code krb5_dbe_lookup_last_pwd_change
+ KRB5_PROTOTYPE((krb5_context,
+ krb5_db_entry *,
+ krb5_timestamp *));
+krb5_error_code krb5_dbe_update_mod_princ_data
KRB5_PROTOTYPE((krb5_context,
- krb5_db_entry *,
- krb5_tl_last_change *));
+ krb5_db_entry *,
+ krb5_timestamp,
+ krb5_principal));
+krb5_error_code krb5_dbe_lookup_mod_princ_data
+ KRB5_PROTOTYPE((krb5_context,
+ krb5_db_entry *,
+ krb5_timestamp *,
+ krb5_principal *));
int krb5_encode_princ_dbmkey
KRB5_PROTOTYPE((krb5_context,
datum *,
@@ -322,11 +323,12 @@ struct __krb5_key_salt_tuple;
krb5_error_code krb5_dbe_cpw
KRB5_PROTOTYPE((krb5_context,
- krb5_encrypt_block *,
- struct __krb5_key_salt_tuple *,
- int,
- char *,
- krb5_db_entry *));
+ krb5_encrypt_block *,
+ struct __krb5_key_salt_tuple *,
+ int,
+ char *,
+ int,
+ krb5_db_entry *));
krb5_error_code krb5_dbe_apw
KRB5_PROTOTYPE((krb5_context,
krb5_encrypt_block *,
diff --git a/src/include/port-sockets.h b/src/include/port-sockets.h
new file mode 100644
index 0000000000..2c2fba906d
--- /dev/null
+++ b/src/include/port-sockets.h
@@ -0,0 +1,72 @@
+#ifdef _MSDOS
+
+#include <winsock.h>
+
+/* Some of our own infrastructure where the WinSock stuff was too hairy
+ to dump into a clean Unix program... */
+
+#define SOCKET_INITIALIZE() win_socket_initialize()
+#define SOCKET_CLEANUP() WSACleanup()
+#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_EINTR WSAEINTR
+
+int win_socket_initialize();
+
+#else /* not _MSDOS */
+
+/* If this source file requires it, define struct sockaddr_in
+ (and possibly other things related to network I/O). */
+
+#ifdef HAVE_MACSOCK_H /* Sockets stuff differs on Mac */
+#include "macsock.h" /* Macintosh sockets emulation library */
+
+/* Some of our own infrastructure where the WinSock stuff was too hairy
+ to dump into a clean Unix program... */
+
+#define SOCKET_INITIALIZE() (WSAStartup(0x0101, (WSADATA *)0))
+#define SOCKET_CLEANUP() (WSACleanup())
+#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_EINTR WSAEINTR
+
+#else /* ! HAVE_MACSOCK_H */ /* Sockets stuff for Unix machines */
+
+#include <netinet/in.h> /* For struct sockaddr_in and in_addr */
+#include <arpa/inet.h> /* For inet_ntoa */
+#include <netdb.h> /* For struct hostent, gethostbyname, etc */
+#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 */
+
+/*
+ * Compatability with WinSock calls on MS-Windows...
+ */
+#define SOCKET unsigned int
+#define INVALID_SOCKET ((SOCKET)~0)
+#define closesocket close
+#define ioctlsocket ioctl
+#define SOCKET_ERROR (-1)
+
+/* 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_EINTR EINTR
+
+#endif /* HAVE_MACSOCK_H */
+
+#endif /* _MSDOS */
diff --git a/src/kadmin/ChangeLog b/src/kadmin/ChangeLog
index 4dbf1ae4c6..5408cd3542 100644
--- a/src/kadmin/ChangeLog
+++ b/src/kadmin/ChangeLog
@@ -1,3 +1,13 @@
+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.
+
+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
+
Thu Aug 24 19:21:14 1995 Theodore Y. Ts'o <tytso@dcl>
* .Sanitize: Add ktutil directory
diff --git a/src/kadmin/Makefile.ov b/src/kadmin/Makefile.ov
new file mode 100644
index 0000000000..1b5cb8e395
--- /dev/null
+++ b/src/kadmin/Makefile.ov
@@ -0,0 +1,11 @@
+#
+# $Id$
+#
+
+TOP = .
+include $(TOP)/config.mk/template
+
+SUBDIRS = ../lib/kadm5 server create passwd import export v4server \
+ keytab cli testing dbutil
+
+expand SubdirTarget
diff --git a/src/kadmin/cli/ChangeLog b/src/kadmin/cli/ChangeLog
new file mode 100644
index 0000000000..a69639b86d
--- /dev/null
+++ b/src/kadmin/cli/ChangeLog
@@ -0,0 +1,28 @@
+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/src/kadmin/cli/Makefile.in b/src/kadmin/cli/Makefile.in
new file mode 100644
index 0000000000..c605dd81f6
--- /dev/null
+++ b/src/kadmin/cli/Makefile.in
@@ -0,0 +1,19 @@
+CFLAGS = $(CCOPTS) $(DEFS) $(LOCALINCLUDE)
+
+PROG = kadmin
+OBJS = kadmin.o kadmin_ct.o ss_wrapper.o getdate.o keytab.o
+
+all:: $(PROG).local $(PROG)
+
+$(PROG).local: $(OBJS) $(SRVDEPLIBS)
+ $(CC) $(LDFLAGS) $(LDARGS) -o $(PROG).local $(OBJS) $(SRVLIBS)
+
+$(PROG): $(OBJS) $(CLNTDEPLIBS)
+ $(CC) $(LDFLAGS) $(LDARGS) -o $(PROG) $(OBJS) $(CLNTLIBS)
+
+install::
+ $(INSTALL_PROGRAM) $(PROG).local ${DESTDIR}$(ADMIN_BINDIR)/$(PROG)
+ $(INSTALL_PROGRAM) $(PROG) ${DESTDIR}$(ADMIN_BINDIR)/$(PROG)
+
+clean::
+ $(RM) $(PROG).local $(PROG) $(OBJS)
diff --git a/src/kadmin/cli/Makefile.ov b/src/kadmin/cli/Makefile.ov
new file mode 100644
index 0000000000..5163bebb80
--- /dev/null
+++ b/src/kadmin/cli/Makefile.ov
@@ -0,0 +1,28 @@
+TOP = ..
+include $(TOP)/config.mk/template
+
+PROG = kadmin
+SRCS = kadmin.c kadmin_ct.c ss_wrapper.c getdate.c keytab.c
+OBJS = kadmin.o kadmin_ct.o ss_wrapper.o getdate.o keytab.o
+LIBS = $(LIBADMCLNT) $(LIBRPCLIB) $(LIBGSSAPI_KRB5) $(LIBKRB5_ALL) \
+ $(LIBSS) $(LIBDYN) $(LIBDB) $(NDBMLIB) $(BSDLIB) $(NETLIB)
+DEPENDS = kadmin_ct.c getdate.c
+
+expand NormalProgram
+
+PROG = kadmin.local
+LIBS = $(LIBADMSRV) $(LIBRPCLIB) $(LIBGSSAPI_KRB5) $(LIBKDB5) \
+ $(LIBKRB5_ALL) $(LIBSS) $(LIBDYN) $(LIBDB) $(NDBMLIB) \
+ $(BSDLIB) $(NETLIB) $(REGEXLIB)
+
+expand NormalProgram
+
+depend:: $(SRCS)
+clean:: ; -rm -f getdate.c y.tab.h kadmin_ct.c
+
+install::
+ $(INSTCMD) kadmin.1 $(INSTALL_MANDIR)/cat1/kadmin.1
+
+# needed until we run makedepend
+kadmin_ct.c: kadmin_ct.ct
+kadmin_ct.o: kadmin_ct.c
diff --git a/src/kadmin/cli/attic/Makefile b/src/kadmin/cli/attic/Makefile
new file mode 100644
index 0000000000..79e432fe4f
--- /dev/null
+++ b/src/kadmin/cli/attic/Makefile
@@ -0,0 +1,11 @@
+TOP = ../..
+include $(TOP)/config.mk/template
+
+SRCS = kadmin.c kadmin_ct.ct ss_wrapper.c getdate.y
+OBJS = kadmin.o kadmin_ct.o ss_wrapper.o getdate.o
+PROG = cli_secure_admin
+
+LIBS = $(LIBADMCLNT) $(LIBRPCLIB) $(LIBGSSAPI_KRB5) $(LIBKRB5_ALL) \
+ $(LIBSS) $(LIBDYN) $(LIBDB) $(NDBMLIB) $(BSDLIB) $(NETLIB)
+
+expand NormalProgram
diff --git a/src/kadmin/cli/attic/Makefile.in b/src/kadmin/cli/attic/Makefile.in
new file mode 100644
index 0000000000..160016af98
--- /dev/null
+++ b/src/kadmin/cli/attic/Makefile.in
@@ -0,0 +1,45 @@
+CFLAGS = $(CCOPTS) $(DEFS) $(LOCALINCLUDE) $(OVSECINC)
+OVSECROOT=/home/tlyu/ovsecure
+OVSECSTAGE=/afs/dev.mit.edu/reference/ovsecure/sunos/stage
+OVSECINC=-I$(OVSECROOT)/include -I$(OVSECSTAGE)/include
+OVSECLIB=-L$(OVSECSTAGE)/lib -lclient -lcommon -lrpclib -ldyn
+LDFLAGS = -g
+LIBOBJS=@LIBOBJS@
+ISODELIB=$(OVSECROOT)/lib/libisode.a
+COMERRLIB=$(OVSECROOT)/lib/libcom_err.a
+SSLIB=$(OVSECSTAGE)/lib/libss.a
+DBMLIB=$(OVSECROOT)/lib/libdb.a
+KDBLIB=$(OVSECROOT)/lib/libkdb5.a
+
+all::
+
+KLIB = $(OVSECROOT)/lib/libgssapi_krb5.a $(OVSECROOT)/lib/libkrb5.a $(OVSECROOT)/lib/libcrypto.a $(ISODELIB) $(SSLIB) $(COMERRLIB) $(DBMLIB)
+DEPKLIB = $(TOPLIBD)/libgssapi_krb5.a $(TOPLIBD)/libkrb5.a $(TOPLIBD)/libcrypto.a $(SSLIB) $(COMERRLIB) $(DBMLIB)
+
+SRCS =
+
+OBJS = kadmin.o kadmin_ct.o ss_wrapper.o getdate.o $(LIBOBJS)
+
+all:: kadmin
+kadmin.o:
+ $(CC) -c $(CCOPTS) $(OVSECINC) $(DEFS) kadmin.c
+getdate.c getdate.h: getdate.y
+ $(RM) getdate.c getdate.h y.tab.*
+ $(YACC) -d $(srcdir)/getdate.y
+ $(MV) y.tab.c getdate.c
+ $(MV) y.tab.h getdate.h
+
+kadmin: $(OBJS)
+ $(CC) -o kadmin $(CFLAGS) $(OBJS) $(OVSECLIB) $(KLIB) $(LIBS)
+
+# needed until we run makedepend
+kadmin_ct.c: kadmin_ct.ct
+
+kadmin_ct.o: kadmin_ct.c
+
+clean::
+ $(RM) kadmin $(OBJS) kadmin_ct.c getdate.c getdate.h y.tab.c y.tab.h
+
+# testing rule for building getdate
+getdate: getdate.c
+ $(CC) -o getdate $(CFLAGS) -DTEST getdate.c
diff --git a/src/kadmin/cli/attic/configure.in b/src/kadmin/cli/attic/configure.in
new file mode 100644
index 0000000000..8cca513167
--- /dev/null
+++ b/src/kadmin/cli/attic/configure.in
@@ -0,0 +1,15 @@
+AC_INIT(getdate.y)
+WITH_CCOPTS
+CONFIG_RULES
+AC_SET_BUILDTOP
+AC_PROG_INSTALL
+AC_PROG_YACC
+AC_HAVE_HEADERS(unistd.h sys/timeb.h alloca.h)
+AC_HAVE_FUNCS(ftime timezone)
+AC_CHECK_LIB(ndbm,main)
+AC_CHECK_LIB(dbm,main)
+AC_REPLACE_FUNCS([setenv memmove])
+KRB_INCLUDE
+ISODE_INCLUDE
+WITH_KRB5ROOT
+V5_AC_OUTPUT_MAKEFILE
diff --git a/src/kadmin/cli/attic/getdate.y b/src/kadmin/cli/attic/getdate.y
new file mode 100644
index 0000000000..6b03e73bb7
--- /dev/null
+++ b/src/kadmin/cli/attic/getdate.y
@@ -0,0 +1,1006 @@
+%{
+/*
+** 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
+
+/* 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>
+
+/* 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
+
+#if defined(HAVE_SYS_TIMEB_H)
+#include <sys/timeb.h>
+#else
+/*
+** We use the obsolete `struct timeb' as part of our interface!
+** Since the system doesn't have it, we define it here;
+** our callers must do likewise.
+*/
+struct 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(HAVE_SYS_TIMEB_H) */
+
+#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. */
+#if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (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 yylex ();
+static int yyerror ();
+
+#if !defined(lint) && !defined(SABER)
+static char RCS[] =
+ "$Header$";
+#endif /* !defined(lint) && !defined(SABER) */
+
+
+#define EPOCH 1970
+#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
+
+%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
+ ;
+
+item : time {
+ yyHaveTime++;
+ }
+ | zone {
+ yyHaveZone++;
+ }
+ | date {
+ yyHaveDate++;
+ }
+ | day {
+ yyHaveDay++;
+ }
+ | rel {
+ yyHaveRel++;
+ }
+ | number
+ ;
+
+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;
+ }
+ ;
+
+number : tUNUMBER {
+ if (yyHaveTime && yyHaveDate && !yyHaveRel)
+ yyYear = $1;
+ else {
+ if($1>10000) {
+ yyHaveDate++;
+ yyDay= ($1)%100;
+ yyMonth= ($1/100)%100;
+ yyYear = $1/10000;
+ }
+ else {
+ yyHaveTime++;
+ if ($1 < 100) {
+ yyHour = $1;
+ yyMinutes = 0;
+ }
+ else {
+ yyHour = $1 / 100;
+ yyMinutes = $1 % 100;
+ }
+ yySeconds = 0;
+ yyMeridian = MER24;
+ }
+ }
+ }
+ ;
+
+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 },
+ { 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 */
+#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 */
+ { "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 }
+};
+
+/* Military timezone table. */
+static TABLE const MilitaryTable[] = {
+ { "a", tZONE, HOUR( 1) },
+ { "b", tZONE, HOUR( 2) },
+ { "c", tZONE, HOUR( 3) },
+ { "d", tZONE, HOUR( 4) },
+ { "e", tZONE, HOUR( 5) },
+ { "f", tZONE, HOUR( 6) },
+ { "g", tZONE, HOUR( 7) },
+ { "h", tZONE, HOUR( 8) },
+ { "i", tZONE, HOUR( 9) },
+ { "k", tZONE, HOUR( 10) },
+ { "l", tZONE, HOUR( 11) },
+ { "m", tZONE, HOUR( 12) },
+ { "n", tZONE, HOUR(- 1) },
+ { "o", tZONE, HOUR(- 2) },
+ { "p", tZONE, HOUR(- 3) },
+ { "q", tZONE, HOUR(- 4) },
+ { "r", tZONE, HOUR(- 5) },
+ { "s", tZONE, HOUR(- 6) },
+ { "t", tZONE, HOUR(- 7) },
+ { "u", tZONE, HOUR(- 8) },
+ { "v", tZONE, HOUR(- 9) },
+ { "w", tZONE, HOUR(-10) },
+ { "x", tZONE, HOUR(-11) },
+ { "y", tZONE, HOUR(-12) },
+ { "z", tZONE, HOUR( 0) },
+ { 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 */
+}
+
+
+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 < 100)
+ Year += 1900;
+ DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
+ ? 29 : 28;
+ if (Year < EPOCH || Year > 1999
+ || 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);
+ 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;
+
+ if (RelMonth == 0)
+ return 0;
+ tm = localtime(&Start);
+ Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
+ Year = Month / 12;
+ Month = Month % 12 + 1;
+ return DSTcorrect(Start,
+ 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));
+}
+
+
+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(*p))
+ *p = tolower(*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;
+ }
+
+ /* Military timezones. */
+ if (buff[1] == '\0' && isalpha(*buff)) {
+ for (tp = MilitaryTable; 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(*yyInput))
+ yyInput++;
+
+ if (isdigit(c = *yyInput) || c == '-' || c == '+') {
+ if (c == '-' || c == '+') {
+ sign = c == '-' ? -1 : 1;
+ if (!isdigit(*++yyInput))
+ /* skip the '-' sign */
+ continue;
+ }
+ else
+ sign = 0;
+ for (yylval.Number = 0; isdigit(c = *yyInput++); )
+ yylval.Number = 10 * yylval.Number + c - '0';
+ yyInput--;
+ if (sign < 0)
+ yylval.Number = -yylval.Number;
+ return sign ? tSNUMBER : tUNUMBER;
+ }
+ if (isalpha(c)) {
+ for (p = buff; isalpha(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);
+}
+
+time_t
+get_date(p, now)
+ char *p;
+ struct timeb *now;
+{
+ struct tm *tm, gmt;
+ struct timeb ftz;
+ time_t Start;
+ time_t tod;
+
+ yyInput = p;
+ if (now == NULL) {
+ now = &ftz;
+ (void)time(&ftz.time);
+
+ 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;
+
+ if (yyparse()
+ || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
+ return -1;
+
+ 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;
+ }
+
+ Start += yyRelSeconds;
+ Start += RelativeMonth(Start, yyRelMonth);
+
+ 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 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/src/kadmin/cli/attic/kadmin.c b/src/kadmin/cli/attic/kadmin.c
new file mode 100644
index 0000000000..91d2a71e4d
--- /dev/null
+++ b/src/kadmin/cli/attic/kadmin.c
@@ -0,0 +1,958 @@
+/*
+ * 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. M.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/krb5.h>
+#include <krb5/los-proto.h>
+#include <krb5/ext-proto.h>
+#include <krb5/kdb.h>
+#include <ovsec_admin/admin.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <math.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <sys/timeb.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},
+{"requres_hwauth", 14, 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 }
+};
+
+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 */
+};
+
+char *getenv();
+struct passwd *getpwuid();
+int exit_status = 0;
+char *def_realm = NULL;
+
+void *ovsec_hndl = NULL;
+
+void usage()
+{
+ fprintf(stderr,
+ "usage: kadmin [-r realm] [-p principal] [-k keytab] [-q query]\n");
+ exit(1);
+}
+
+/* this is a wrapper to go around krb5_parse_principal so we can set
+ the default realm up properly */
+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, '@');
+ }
+ if (cp == NULL) {
+ strcat(fullname, "@");
+ strcat(fullname, def_realm);
+ }
+ retval = krb5_parse_name(fullname, principal);
+ free(fullname);
+ return retval;
+}
+
+char *kadmin_startup(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ char *princstr = NULL, *keytab = NULL, *query = NULL;
+ char *luser, *canon, *cp;
+ int optchar, freeprinc = 0;
+ struct passwd *pw;
+ ovsec_kadm_ret_t retval;
+ krb5_ccache cc;
+ krb5_principal princ;
+
+ while ((optchar = getopt(argc, argv, "r:p:k:q:")) != EOF) {
+ switch (optchar) {
+ case 'r':
+ def_realm = optarg;
+ break;
+ case 'p':
+ princstr = optarg;
+ break;
+ case 'k':
+ fprintf(stderr, "kadmin: -k not supported yet\n");
+ exit(1);
+ break;
+ case 'q':
+ query = optarg;
+ break;
+ default:
+ usage();
+ }
+ }
+ if (def_realm == NULL && krb5_get_default_realm(&def_realm)) {
+ if (freeprinc)
+ free(princstr);
+ fprintf(stderr, "kadmin: unable to get default realm\n");
+ exit(1);
+ }
+ if (princstr == NULL) {
+ if (!krb5_cc_default(&cc) && !krb5_cc_get_principal(cc, &princ)) {
+ char *realm = NULL;
+ if (krb5_unparse_name(princ, &canon)) {
+ fprintf(stderr,
+ "kadmin: unable to canonicalize principal\n");
+ krb5_free_principal(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, "kadmin: out of memory\n");
+ exit(1);
+ }
+ strcpy(princstr, canon);
+ strcat(princstr, "/admin");
+ if (realm) {
+ strcat(princstr, "@");
+ strcat(princstr, realm);
+ }
+ free(canon);
+ krb5_free_principal(princ);
+ freeprinc++;
+ } else if (luser = getenv("USER")) {
+ princstr = malloc(strlen(luser) + 7 /* "/admin@" */
+ + strlen(def_realm) + 1);
+ if (princstr == NULL) {
+ fprintf(stderr, "kadmin: out of memory\n");
+ exit(1);
+ }
+ strcpy(princstr, luser);
+ strcat(princstr, "/admin");
+ strcat(princstr, "@");
+ strcat(princstr, def_realm);
+ freeprinc++;
+ } else if (pw = getpwuid(getuid())) {
+ princstr = malloc(strlen(pw->pw_name) + 7 /* "/admin@" */
+ + strlen(def_realm) + 1);
+ if (princstr == NULL) {
+ fprintf(stderr, "kadmin: out of memory\n");
+ exit(1);
+ }
+ strcpy(princstr, pw->pw_name);
+ strcat(princstr, "/admin@");
+ strcat(princstr, def_realm);
+ freeprinc++;
+ } else {
+ fprintf(stderr, "kadmin: unable to figure out a principal name\n");
+ exit(1);
+ }
+ }
+ retval = ovsec_kadm_init_with_password(princstr, NULL,
+ OVSEC_KADM_ADMIN_SERVICE,
+ def_realm,
+ OVSEC_KADM_STRUCT_VERSION,
+ OVSEC_KADM_API_VERSION_1,
+ &ovsec_hndl);
+ if (freeprinc)
+ free(princstr);
+ if (retval) { /* assume kadm_init does init_ets() */
+ com_err("kadmin", retval, "while initializing kadmin interface");
+ exit(1);
+ }
+ return query;
+}
+
+int quit()
+{
+ ovsec_kadm_destroy(ovsec_hndl);
+ /* insert more random cleanup here */
+}
+
+void kadmin_delprinc(argc, argv)
+ int argc;
+ char *argv[];
+{
+ ovsec_kadm_ret_t retval;
+ krb5_principal princ;
+ char *canon;
+ char reply[5];
+
+ if (argc < 2 || argc > 3) {
+ fprintf(stderr, "delete_principal: wrong number of arguments\n");
+ return;
+ }
+ if (argc == 3 &&
+ (strlen(argv[1]) == 6 ? strcmp("-force", argv[1]) : 1)) {
+ fprintf(stderr, "delete_principal: bad arguments\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(princ, &canon);
+ if (retval) {
+ com_err("delete_principal", retval,
+ "while canonicalizing principal");
+ krb5_free_principal(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(princ);
+ return;
+ }
+ }
+ retval = ovsec_kadm_delete_principal(ovsec_hndl, princ);
+ krb5_free_principal(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_renprinc(argc, argv)
+ int argc;
+ char *argv[];
+{
+ krb5_principal oldprinc, newprinc;
+ char *oldcanon, *newcanon;
+ char reply[5];
+ ovsec_kadm_ret_t retval;
+
+ if (argc < 3 || argc > 4) {
+ fprintf(stderr, "rename_principal: wrong number of arguments\n");
+ return;
+ }
+ if (argc == 4 &&
+ (strlen(argv[1]) == 6 ? strcmp("-force", argv[1]) : 1)) {
+ fprintf(stderr, "rename_principal: bad arguments\n");
+ return;
+ }
+ retval = kadmin_parse_name(argv[argc - 2], &oldprinc);
+ if (retval) {
+ com_err("rename_principal", retval, "while parsing old principal");
+ return;
+ }
+ retval = kadmin_parse_name(argv[argc - 1], &newprinc);
+ if (retval) {
+ krb5_free_principal(oldprinc);
+ com_err("rename_principal", retval, "while parsing new principal");
+ return;
+ }
+ retval = krb5_unparse_name(oldprinc, &oldcanon);
+ if (retval) {
+ com_err("rename_principal", retval,
+ "while canonicalizing old principal");
+ krb5_free_principal(newprinc);
+ krb5_free_principal(oldprinc);
+ return;
+ }
+ retval = krb5_unparse_name(newprinc, &newcanon);
+ if (retval) {
+ com_err("rename_principal", retval,
+ "while canonicalizing new principal");
+ free(oldcanon);
+ krb5_free_principal(newprinc);
+ krb5_free_principal(oldprinc);
+ return;
+ }
+ if (argc == 3) {
+ printf("Are you sure you want to rename the principal \"%s\" to \"%s\"? (yes/no): ",
+ oldcanon, newcanon);
+ fgets(reply, sizeof (reply), stdin);
+ if (strcmp("yes\n", reply)) {
+ fprintf(stderr,
+ "rename_principal: \"%s\" NOT renamed to \"%s\".\n",
+ oldcanon, newcanon);
+ free(newcanon);
+ free(oldcanon);
+ krb5_free_principal(newprinc);
+ krb5_free_principal(oldprinc);
+ return;
+ }
+ }
+ retval = ovsec_kadm_rename_principal(ovsec_hndl, oldprinc, newprinc);
+ krb5_free_principal(oldprinc);
+ krb5_free_principal(newprinc);
+ if (retval) {
+ com_err("rename_principal", retval,
+ "while renaming \"%s\" to \"%s\".", oldcanon,
+ newcanon);
+ free(newcanon);
+ free(oldcanon);
+ return;
+ }
+ printf("Principal \"%s\" renamed to \"%s\".\nMake sure that you have removed \"%s\" from all ACLs before reusing.\n",
+ oldcanon, newcanon, newcanon);
+ return;
+}
+
+void kadmin_cpw(argc, argv)
+ int argc;
+ char *argv[];
+{
+ ovsec_kadm_ret_t retval;
+ static char newpw[1024];
+ static char prompt1[1024], prompt2[1024];
+ char *canon;
+ krb5_principal princ;
+
+ if (argc < 2 || argc > 4) {
+ fprintf(stderr, "change_password: too many arguments\n");
+ return;
+ }
+ retval = kadmin_parse_name(argv[argc - 1], &princ);
+ if (retval) {
+ com_err("change_password", retval, "while parsing principal name");
+ return;
+ }
+ retval = krb5_unparse_name(princ, &canon);
+ if (retval) {
+ com_err("change_password", retval, "while canonicalizing principal");
+ krb5_free_principal(princ);
+ return;
+ }
+ if ((argc == 4) && (strlen(argv[1]) == 3) && !strcmp("-pw", argv[1])) {
+ retval = ovsec_kadm_chpass_principal(ovsec_hndl, princ, argv[2]);
+ krb5_free_principal(princ);
+ if (retval) {
+ com_err("change_password", retval,
+ "while changing password for \"%s\".", canon);
+ free(canon);
+ return;
+ }
+ printf("Password for \"%s\" changed.\n", canon);
+ free(canon);
+ return;
+ } else if ((argc == 3) && (strlen(argv[1]) == 8) &&
+ !strcmp("-randkey", argv[1])) {
+ krb5_keyblock *newkey = NULL;
+ retval = ovsec_kadm_randkey_principal(ovsec_hndl, princ, &newkey);
+ krb5_free_principal(princ);
+ if (retval) {
+ com_err("change_password", retval,
+ "while randomizing key for \"%s\".", canon);
+ free(canon);
+ return;
+ }
+ memset(newkey->contents, 0, newkey->length);
+ printf("Key for \"%s\" randomized.\n", canon);
+ free(canon);
+ return;
+ } else if (argc == 2) {
+ int i = sizeof (newpw) - 1;
+
+ sprintf(prompt1, "Enter password for principal \"%.900s\": ",
+ argv[1]);
+ sprintf(prompt2,
+ "Re-enter password for principal \"%.900s\": ",
+ argv[1]);
+ retval = krb5_read_password(prompt1, prompt2,
+ newpw, &i);
+ if (retval) {
+ com_err("change_password", retval,
+ "while reading password for \"%s\".", canon);
+ free(canon);
+ krb5_free_principal(princ);
+ return;
+ }
+ retval = ovsec_kadm_chpass_principal(ovsec_hndl, princ, newpw);
+ krb5_free_principal(princ);
+ memset(newpw, 0, sizeof (newpw));
+ if (retval) {
+ com_err("change_password", retval,
+ "while changing password for \"%s\".", canon);
+ free(canon);
+ return;
+ }
+ printf("Password for \"%s\" changed.\n", canon);
+ free(canon);
+ return;
+ }
+ fprintf(stderr, "change_password: bad arguments\n");
+ free(canon);
+ krb5_free_principal(princ);
+ return;
+}
+
+int kadmin_parse_princ_args(argc, argv, oprinc, mask, pass, caller)
+ int argc;
+ char *argv[];
+ ovsec_kadm_principal_ent_t oprinc;
+ u_int32 *mask;
+ char **pass, *caller;
+{
+ int i, j;
+ struct timeb now;
+ krb5_error_code retval;
+
+ *mask = 0;
+ *pass = NULL;
+ ftime(&now);
+ for (i = 1; i < argc - 1; i++) {
+ if (strlen(argv[i]) == 7 &&
+ !strcmp("-expire", argv[i])) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ oprinc->princ_expire_time = get_date(argv[i], now);
+ *mask |= OVSEC_KADM_PRINC_EXPIRE_TIME;
+ continue;
+ }
+ }
+ if (strlen(argv[i]) == 9 &&
+ !strcmp("-pwexpire", argv[i])) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ oprinc->pw_expiration = get_date(argv[i], now);
+ *mask |= OVSEC_KADM_PW_EXPIRATION;
+ continue;
+ }
+ }
+ if (strlen(argv[i]) == 8 &&
+ !strcmp("-maxlife", argv[i])) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ oprinc->max_life = get_date(argv[i], now) - now.time;
+ *mask |= OVSEC_KADM_MAX_LIFE;
+ continue;
+ }
+ }
+ if (strlen(argv[i]) == 5 &&
+ !strcmp("-kvno", argv[i])) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ oprinc->kvno = atoi(argv[i]);
+ *mask |= OVSEC_KADM_KVNO;
+ continue;
+ }
+ }
+ if (strlen(argv[i]) == 8 &&
+ !strcmp("-policy", argv[i])) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ oprinc->policy = argv[i];
+ *mask |= OVSEC_KADM_POLICY;
+ continue;
+ }
+ }
+ if (strlen(argv[i]) == 12 &&
+ !strcmp("-clearpolicy", argv[i])) {
+ oprinc->policy = NULL;
+ *mask |= OVSEC_KADM_POLICY_CLR;
+ continue;
+ }
+ if (strlen(argv[i]) == 3 &&
+ !strcmp("-pw", argv[i])) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ *pass = argv[i];
+ 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 |= OVSEC_KADM_ATTRIBUTES;
+ break;
+ } else if (flags[j].set && argv[i][0] == '+' ||
+ !flags[j].set && argv[i][0] == '-') {
+ oprinc->attributes &= ~flags[j].theflag;
+ *mask |= OVSEC_KADM_ATTRIBUTES;
+ break;
+ } else {
+ return -1;
+ }
+ }
+ }
+ return -1;
+ }
+ if (i != argc - 1) {
+ fprintf(stderr, "%s: parser lost count!\n", caller);
+ return -1;
+ }
+ retval = kadmin_parse_name(argv[i], &oprinc->principal);
+ if (retval) {
+ com_err(caller, retval, "while parsing principal");
+ return -1;
+ }
+ return 0;
+}
+
+void kadmin_addprinc(argc, argv)
+ int argc;
+ char *argv[];
+{
+ ovsec_kadm_principal_ent_rec princ;
+ u_int32 mask;
+ char *pass, *canon;
+ krb5_error_code retval;
+ static char newpw[1024];
+ static char prompt1[1024], prompt2[1024];
+
+ princ.attributes = 0;
+ if (kadmin_parse_princ_args(argc, argv,
+ &princ, &mask, &pass, "add_principal")) {
+ fprintf(stderr, "add_principal: bad arguments\n");
+ return;
+ }
+ retval = krb5_unparse_name(princ.principal, &canon);
+ if (retval) {
+ com_err("add_principal",
+ retval, "while canonicalizing principal");
+ krb5_free_principal(princ.principal);
+ return;
+ }
+ if (pass == NULL) {
+ int i = sizeof (newpw) - 1;
+
+ sprintf(prompt1, "Enter password for principal \"%.900s\": ",
+ argv[1]);
+ sprintf(prompt2,
+ "Re-enter password for principal \"%.900s\": ",
+ argv[1]);
+ retval = krb5_read_password(prompt1, prompt2,
+ newpw, &i);
+ if (retval) {
+ com_err("add_principal", retval,
+ "while reading password for \"%s\".", canon);
+ free(canon);
+ krb5_free_principal(princ.principal);
+ return;
+ }
+ pass = newpw;
+ }
+ mask |= OVSEC_KADM_PRINCIPAL;
+ retval = ovsec_kadm_create_principal(ovsec_hndl, &princ, mask, pass);
+ krb5_free_principal(princ.principal);
+ if (retval) {
+ com_err("add_principal", retval, "while creating \"%s\".",
+ canon);
+ free(canon);
+ return;
+ }
+ printf("Principal \"%s\" created.\n", canon);
+ free(canon);
+}
+
+void kadmin_modprinc(argc, argv)
+ int argc;
+ char *argv[];
+{
+ ovsec_kadm_principal_ent_rec princ;
+ u_int32 mask;
+ krb5_error_code retval;
+ char *pass, *canon;
+
+ princ.attributes = 0;
+ if (kadmin_parse_princ_args(argc, argv,
+ &princ, &mask, &pass, "modify_principal")) {
+ fprintf(stderr, "modify_principal: bad arguments\n");
+ return;
+ }
+ retval = krb5_unparse_name(princ.principal, &canon);
+ if (retval) {
+ com_err("modify_principal", retval,
+ "while canonicalizing principal");
+ krb5_free_principal(princ.principal);
+ return;
+ }
+ retval = ovsec_kadm_modify_principal(ovsec_hndl, &princ, mask);
+ if (retval) {
+ com_err("modify_principal", retval, "while modifying \"%s\".",
+ argv[argc - 1]);
+ return;
+ }
+}
+
+void kadmin_getprinc(argc, argv)
+ int argc;
+ char *argv[];
+{
+ ovsec_kadm_principal_ent_t dprinc;
+ krb5_principal princ;
+ krb5_error_code retval;
+ char *canon, *modcanon;
+ int i;
+
+ if (argc < 2 || argc > 3) {
+ fprintf(stderr, "get_principal: wrong number of arguments\n");
+ return;
+ }
+ if (argc == 3 &&
+ (strlen(argv[1]) == 6 ? strcmp("-terse", argv[1]) : 1)) {
+ fprintf(stderr, "get_principal: bad arguments\n");
+ return;
+ }
+ retval = kadmin_parse_name(argv[argc - 1], &princ);
+ if (retval) {
+ com_err("get_principal", retval, "while parsing principal");
+ return;
+ }
+ retval = krb5_unparse_name(princ, &canon);
+ if (retval) {
+ com_err("get_principal", retval, "while canonicalizing principal");
+ krb5_free_principal(princ);
+ return;
+ }
+ retval = ovsec_kadm_get_principal(ovsec_hndl, princ, &dprinc);
+ krb5_free_principal(princ);
+ if (retval) {
+ com_err("get_principal", retval, "while retrieving \"%s\".", canon);
+ free(canon);
+ return;
+ }
+ retval = krb5_unparse_name(dprinc->mod_name, &modcanon);
+ if (retval) {
+ com_err("get_principal", retval, "while unparsing modname");
+ ovsec_kadm_free_principal_ent(ovsec_hndl, dprinc);
+ free(canon);
+ return;
+ }
+ if (argc == 2) {
+ printf("Principal: %s\n", canon);
+ printf("Expiration date: %d\n", dprinc->princ_expire_time);
+ printf("Last password change: %d\n", dprinc->last_pwd_change);
+ printf("Password expiration date: %d\n", dprinc->pw_expiration);
+ printf("Maximum life: %d\n", dprinc->max_life);
+ printf("Last modified: by %s\n\ton %d\n",
+ modcanon, dprinc->mod_date);
+ 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("Key version: %d\n", dprinc->kvno);
+ printf("Master key version: %d\n", dprinc->mkvno);
+ printf("Policy: %s\n", dprinc->policy);
+ } else {
+ printf("\"%s\"\t%d\t%d\t%d\t%d\t\"%s\"\t%d\t%d\t%d\t%d\t\"%s\"\n",
+ 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);
+ }
+ free(modcanon);
+ ovsec_kadm_free_principal_ent(ovsec_hndl, dprinc);
+ free(canon);
+}
+
+int kadmin_parse_policy_args(argc, argv, policy, mask, caller)
+ int argc;
+ char *argv[];
+ ovsec_kadm_policy_ent_t policy;
+ u_int32 *mask;
+ char *caller;
+{
+ int i;
+ struct timeb now;
+ krb5_error_code retval;
+
+ ftime(&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 {
+ policy->pw_max_life = get_date(argv[i], now) - now.time;
+ *mask |= OVSEC_KADM_PW_MAX_LIFE;
+ continue;
+ }
+ } else if (strlen(argv[i]) == 8 &&
+ !strcmp(argv[i], "-minlife")) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ policy->pw_min_life = get_date(argv[i], now) - now.time;
+ *mask |= OVSEC_KADM_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 |= OVSEC_KADM_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 |= OVSEC_KADM_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 |= OVSEC_KADM_PW_HISTORY_NUM;
+ continue;
+ }
+ } else
+ return -1;
+ }
+ if (i != argc -1) {
+ fprintf(stderr, "%s: parser lost count!\n", caller);
+ return -1;
+ } else
+ return 0;
+}
+
+void kadmin_addpol(argc, argv)
+ int argc;
+ char *argv[];
+{
+ krb5_error_code retval;
+ u_int32 mask;
+ ovsec_kadm_policy_ent_rec policy;
+
+ if (kadmin_parse_policy_args(argc, argv, &policy, &mask, "add_policy")) {
+ fprintf(stderr, "add_policy: bad arguments\n");
+ return;
+ } else {
+ policy.policy = argv[argc - 1];
+ mask |= OVSEC_KADM_POLICY;
+ retval = ovsec_kadm_create_policy(ovsec_hndl, &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;
+ u_int32 mask;
+ ovsec_kadm_policy_ent_rec policy;
+
+ if (kadmin_parse_policy_args(argc, argv, &policy, &mask,
+ "modify_policy")) {
+ fprintf(stderr, "modify_policy: bad arguments\n");
+ return;
+ } else {
+ policy.policy = argv[argc - 1];
+ retval = ovsec_kadm_modify_policy(ovsec_hndl, &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) {
+ fprintf(stderr, "delete_policy: wrong number of arguments\n");
+ return;
+ }
+ if (argc == 3 &&
+ (strlen(argv[1]) == 6 ? strcmp("-force", argv[1]) : 1)) {
+ fprintf(stderr, "delete_policy: bad arguments\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 = ovsec_kadm_delete_policy(ovsec_hndl, 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;
+ ovsec_kadm_policy_ent_t policy;
+
+ if (argc < 2 || argc > 3) {
+ fprintf(stderr, "get_policy: wrong number of arguments\n");
+ return;
+ }
+ if (argc == 3 &&
+ (strlen(argv[1]) == 6 ? strcmp("-terse", argv[1]) : 1)) {
+ fprintf(stderr, "get_policy: bad arguments\n");
+ return;
+ }
+ retval = ovsec_kadm_get_policy(ovsec_hndl, 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: %d\n", policy->pw_max_life);
+ printf("Minimum password life: %d\n", policy->pw_min_life);
+ printf("Minimum password length: %d\n", policy->pw_min_length);
+ printf("Minimum number of password character classes: %d\n",
+ policy->pw_min_classes);
+ printf("Number of old keys kept: %d\n", policy->pw_history_num);
+ printf("Reference count: %d\n", policy->policy_refcnt);
+ } else {
+ printf("\"%s\"\t%d\t%d\t%d\t%d\t%d\t%d\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);
+ }
+ ovsec_kadm_free_policy_ent(ovsec_hndl, policy);
+ return;
+}
+
+kadmin_getprivs(argc, argv)
+ int argc;
+ char *argv[];
+{
+ static char *privs[] = {"GET", "ADD", "MODIFY", "DELETE"};
+ krb5_error_code retval;
+ int i;
+ u_int32 plist;
+
+ if (argc != 1) {
+ fprintf(stderr, "get_privs: bad arguments\n");
+ return;
+ }
+ retval = ovsec_kadm_get_privs(ovsec_hndl, &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/src/kadmin/cli/attic/kadmin_ct.ct b/src/kadmin/cli/attic/kadmin_ct.ct
new file mode 100644
index 0000000000..f5a67ed530
--- /dev/null
+++ b/src/kadmin/cli/attic/kadmin_ct.ct
@@ -0,0 +1,67 @@
+# 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. M.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_prinicpal, addprinc, ank;
+
+request kadmin_delprinc, "Delete principal",
+ delete_principal, delprinc;
+
+request kadmin_modprinc, "Modify principal",
+ modify_principal, modprinc;
+
+request kadmin_renprinc, "Rename principal",
+ rename_principal, renprinc;
+
+request kadmin_cpw, "Change password",
+ change_password, cpw;
+
+request kadmin_getprinc, "Get principal",
+ get_principal, getprinc;
+
+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_getprivs, "Get privileges",
+ get_privs, getprivs;
+
+# 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/src/kadmin/cli/attic/memmove.c b/src/kadmin/cli/attic/memmove.c
new file mode 100644
index 0000000000..abc91e923e
--- /dev/null
+++ b/src/kadmin/cli/attic/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 USE_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/src/kadmin/cli/attic/setenv.c b/src/kadmin/cli/attic/setenv.c
new file mode 100644
index 0000000000..a2432c3d6d
--- /dev/null
+++ b/src/kadmin/cli/attic/setenv.c
@@ -0,0 +1,165 @@
+/*
+ * 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>
+
+#ifndef __P
+#define __P(x) ()
+#endif
+char *__findenv __P((const char *, int *));
+
+/*
+ * setenv --
+ * Set the value of the environmental variable "name" to be
+ * "value". If rewrite is set, replace any current value.
+ */
+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;
+ 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 (c = (char *)name; *c && *c != '='; ++c); /* no `=' in name */
+ if (!(environ[offset] = /* name + `=' + value */
+ malloc((size_t)((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)
+ 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;
+}
+
+/*
+ * getenv --
+ * Returns ptr to value associated with name, if any, else NULL.
+ */
+char *
+getenv(name)
+ const char *name;
+{
+ int offset;
+
+ return (__findenv(name, &offset));
+}
+
+/*
+ * __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 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/src/kadmin/cli/attic/ss_wrapper.c b/src/kadmin/cli/attic/ss_wrapper.c
new file mode 100644
index 0000000000..f7bbda5163
--- /dev/null
+++ b/src/kadmin/cli/attic/ss_wrapper.c
@@ -0,0 +1,56 @@
+/*
+ * 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. M.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/krb5.h>
+#include <ss/ss.h>
+#include <stdio.h>
+
+extern ss_request_table kadmin_cmds;
+extern int exit_status;
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char *request;
+ krb5_error_code retval;
+ int sci_idx, code = 0;
+
+ request = kadmin_startup(argc, argv);
+ sci_idx = ss_create_invocation("kadmin", "5.0", (char *) NULL,
+ &kadmin_cmds, &retval);
+ if (retval) {
+ ss_perror(sci_idx, retval, "creating invocation");
+ exit(1);
+ }
+ if (request) {
+ (void) ss_execute_line(sci_idx, request, &code);
+ if (code != 0) {
+ ss_perror(sci_idx, code, request);
+ exit_status++;
+ }
+ } else
+ ss_listen(sci_idx, &retval);
+ return quit() ? 1 : exit_status;
+}
diff --git a/src/kadmin/cli/configure.in b/src/kadmin/cli/configure.in
new file mode 100644
index 0000000000..713d7d2123
--- /dev/null
+++ b/src/kadmin/cli/configure.in
@@ -0,0 +1,20 @@
+AC_INIT(getdate.y)
+WITH_CCOPTS
+CONFIG_RULES
+AC_PROG_INSTALL
+AC_PROG_YACC
+AC_HAVE_HEADERS(unistd.h sys/timeb.h alloca.h)
+AC_HAVE_FUNCS(ftime timezone)
+AC_CHECK_LIB(ndbm,main)
+AC_CHECK_LIB(dbm,main)
+AC_REPLACE_FUNCS([setenv memmove strftime])
+KRB_INCLUDE
+USE_KADMCLNT_LIBRARY
+USE_GSSAPI_LIBRARY
+USE_KADMSRV_LIBRARY
+USE_GSSRPC_LIBRARY
+USE_DYN_LIBRARY
+USE_KDB5_LIBRARY
+USE_SS_LIBRARY
+KRB5_LIBRARIES
+V5_AC_OUTPUT_MAKEFILE
diff --git a/src/kadmin/cli/dump.c b/src/kadmin/cli/dump.c
new file mode 100644
index 0000000000..2c5e4e753b
--- /dev/null
+++ b/src/kadmin/cli/dump.c
@@ -0,0 +1,1485 @@
+/*
+ * admin/edit/dump.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. M.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. This file was originally written to be part
+ * of kdb5_edit but has now been adapted for kadmin.
+ */
+
+#include <stdio.h>
+#include <k5-int.h>
+#include <kadm5/admin.h>
+
+struct dump_args {
+ char *programname;
+ FILE *ofile;
+ krb5_context context;
+ int verbose;
+};
+
+/* External data */
+extern int exit_status;
+extern krb5_context context;
+extern void *handle;
+
+/* Strings */
+
+static const char k5beta5_dump_header[] = "kdb5_edit load_dump version 2.0\n";
+static const char k5_dump_header[] = "kdb5_edit load_dump version 3.0\n";
+static const char kadm5_dump_header[] = "kadm5 load_dump version 4.0\n";
+
+static const char null_mprinc_name[] = "kdb5_dump@MISSING";
+
+/* Message strings */
+static const char regex_err[] = "%s: regular expression error - %s\n";
+static const char regex_merr[] = "%s: regular expression match error - %s\n";
+static const char pname_unp_err[] = "%s: cannot unparse principal name (%s)\n";
+static const char mname_unp_err[] = "%s: cannot unparse modifier name (%s)\n";
+static const char nokeys_err[] = "%s: cannot find any standard key for %s\n";
+static const char sdump_tl_inc_err[] = "%s: tagged data list inconsistency for %s (counted %d, stored %d)\n";
+static const char ofopen_error[] = "%s: cannot open %s for writing (%s)\n";
+static const char oflock_error[] = "%s: cannot lock %s (%s)\n";
+static const char dumprec_err[] = "%s: error performing %s dump (%s)\n";
+static const char dumphdr_err[] = "%s: error dumping %s header (%s)\n";
+static const char trash_end_fmt[] = "%s(%d): ignoring trash at end of line: ";
+static const char read_name_string[] = "name string";
+static const char read_key_type[] = "key type";
+static const char read_key_data[] = "key data";
+static const char read_pr_data1[] = "first set of principal attributes";
+static const char read_mod_name[] = "modifier name";
+static const char read_pr_data2[] = "second set of principal attributes";
+static const char read_salt_data[] = "salt data";
+static const char read_akey_type[] = "alternate key type";
+static const char read_akey_data[] = "alternate key data";
+static const char read_asalt_type[] = "alternate salt type";
+static const char read_asalt_data[] = "alternate salt data";
+static const char read_exp_data[] = "expansion data";
+static const char store_err_fmt[] = "%s(%d): cannot store %s(%s)\n";
+static const char add_princ_fmt[] = "%s\n";
+static const char parse_err_fmt[] = "%s(%d): cannot parse %s (%s)\n";
+static const char read_err_fmt[] = "%s(%d): cannot read %s\n";
+static const char no_mem_fmt[] = "%s(%d): no memory for buffers\n";
+static const char rhead_err_fmt[] = "%s(%d): cannot match size tokens\n";
+static const char err_line_fmt[] = "%s: error processing line %d of %s\n";
+static const char head_bad_fmt[] = "%s: dump header bad in %s\n";
+static const char read_bytecnt[] = "record byte count";
+static const char read_encdata[] = "encoded data";
+static const char n_name_unp_fmt[] = "%s(%s): cannot unparse name\n";
+static const char n_dec_cont_fmt[] = "%s(%s): cannot decode contents\n";
+static const char read_nint_data[] = "principal static attributes";
+static const char read_tcontents[] = "tagged data contents";
+static const char read_ttypelen[] = "tagged data type and length";
+static const char read_kcontents[] = "key data contents";
+static const char read_ktypelen[] = "key data type and length";
+static const char read_econtents[] = "extra data contents";
+static const char k5beta5_fmt_name[] = "Kerberos version 5 old format";
+static const char k5beta6_fmt_name[] = "Kerberos version 5 beta 6 format";
+static const char lusage_err_fmt[] = "%s: usage is %s [%s] [%s] [%s] filename dbname\n";
+static const char no_name_mem_fmt[] = "%s: cannot get memory for temporary name\n";
+static const char ctx_err_fmt[] = "%s: cannot initialize Kerberos context\n";
+static const char stdin_name[] = "standard input";
+static const char restfail_fmt[] = "%s: %s restore failed\n";
+static const char close_err_fmt[] = "%s: cannot close database (%s)\n";
+static const char dbinit_err_fmt[] = "%s: cannot initialize database (%s)\n";
+static const char dbname_err_fmt[] = "%s: cannot set database name to %s (%s)\n";
+static const char dbdelerr_fmt[] = "%s: cannot delete bad database %s (%s)\n";
+static const char dbrenerr_fmt[] = "%s: cannot rename database %s to %s (%s)\n";
+static const char dbcreaterr_fmt[] = "%s: cannot create database %s (%s)\n";
+static const char dfile_err_fmt[] = "%s: cannot open %s (%s)\n";
+
+static const char oldoption[] = "-old";
+static const char verboseoption[] = "-verbose";
+static const char updateoption[] = "-update";
+static const char dump_tmptrail[] = "~";
+
+/* Can't use krb5_dbe_find_enctype because we have a */
+/* kadm5_principal_ent_t and not a krb5_db_entry */
+static krb5_error_code
+find_enctype(dbentp, enctype, salttype, kentp)
+ kadm5_principal_ent_rec *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 ((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);
+}
+
+
+/*
+ * dump_k5beta5_header() - Make a dump header that is recognizable by Kerberos
+ * Version 5 Beta 5 and previous releases.
+ */
+static krb5_error_code
+dump_k5beta5_header(arglist)
+ struct dump_args *arglist;
+{
+ /* The old header consists of the leading string */
+ fprintf(arglist->ofile, k5beta5_dump_header);
+ return(0);
+}
+
+
+/*
+ * dump_k5beta5_iterator() - Dump an entry in a format that is usable
+ * by Kerberos Version 5 Beta 5 and previous
+ * releases.
+ */
+static krb5_error_code
+dump_k5beta5_iterator(ptr, name, entry)
+ krb5_pointer ptr;
+ char *name;
+ kadm5_principal_ent_rec *entry;
+{
+ krb5_error_code retval;
+ struct dump_args *arg;
+ char *mod_name;
+ krb5_tl_data *pwchg;
+ krb5_key_data *pkey, *akey, nullkey;
+ int i;
+
+ /* Initialize */
+ arg = (struct dump_args *) ptr;
+ mod_name = (char *) NULL;
+ memset(&nullkey, 0, sizeof(nullkey));
+
+ /*
+ * Deserialize the modifier record.
+ */
+ mod_name = (char *) NULL;
+ pkey = akey = (krb5_key_data *) NULL;
+
+ /*
+ * Flatten the modifier name.
+ */
+ if ((retval = krb5_unparse_name(arg->context,
+ entry->mod_name,
+ &mod_name)))
+ fprintf(stderr, mname_unp_err, arg->programname,
+ error_message(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);
+ 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->princ_expire_time, entry->pw_expiration,
+ entry->last_pwd_change, entry->last_success, entry->last_failed,
+ entry->fail_auth_count, mod_name, entry->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);
+
+ return(0);
+}
+
+
+/*
+ * dump_k5beta6_header() - Output the k5beta6 dump header.
+ */
+static krb5_error_code
+dump_k5beta6_header(arglist)
+ struct dump_args *arglist;
+{
+ /* The k5beta6 header consists of the leading string */
+ fprintf(arglist->ofile, k5_dump_header);
+ return(0);
+}
+
+
+/*
+ * dump_k5beta6_iterator() - Output a dump record in k5beta6 format.
+ */
+static krb5_error_code
+dump_k5beta6_iterator(ptr, name, entry)
+ krb5_pointer ptr;
+ char *name;
+ kadm5_principal_ent_rec *entry;
+{
+ krb5_error_code retval = 0;
+ struct dump_args *arg;
+ krb5_tl_data *tlp, *etl;
+ krb5_key_data *kdata;
+ int counter, i, j;
+
+ /* Initialize */
+ arg = (struct dump_args *) ptr;
+
+ /*
+ * 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. Bracketed fields absence is indicated by a -1 in its
+ * place
+ */
+
+ /*
+ * Make sure that the tagged list is reasonably correct, and find
+ * E_DATA while we're at it.
+ */
+ counter = 0;
+ etl = NULL;
+ for (tlp = entry->tl_data; tlp; tlp = tlp->tl_data_next) {
+ if (tlp->tl_data_type == KRB5_TL_KADM5_E_DATA)
+ etl = tlp;
+ counter++;
+ }
+
+ if (counter == entry->n_tl_data) {
+ /* Pound out header */
+ fprintf(arg->ofile, "%d\t%d\t%d\t%d\t%d\t%s\t",
+ KRB5_KDB_V1_BASE_LENGTH + (etl ? etl->tl_data_length : 0),
+ strlen(name),
+ (int) entry->n_tl_data,
+ (int) entry->n_key_data,
+ etl ? etl->tl_data_length : 0,
+ 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->princ_expire_time,
+ 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) {
+ /* skip E_DATA since it is included later */
+ if (tlp->tl_data_type == KRB5_TL_KADM5_E_DATA)
+ continue;
+
+ 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 (etl && etl->tl_data_length)
+ for (i=0; i<etl->tl_data_length; i++)
+ fprintf(arg->ofile, "%02x", etl->tl_data_contents[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, (int) entry->n_tl_data);
+ retval = EINVAL;
+ }
+ return(retval);
+}
+
+
+/*
+ * usage is:
+ * dump_db [-old] [-verbose] [filename|- [principals...]]
+ */
+void dump_db(argc, argv)
+ int argc;
+ char **argv;
+{
+ FILE *f;
+ struct dump_args arglist;
+ int error;
+ char *programname;
+ char *ofile;
+ krb5_error_code kret;
+ krb5_error_code (*dump_iterator) PROTOTYPE((krb5_pointer,
+ char *,
+ kadm5_principal_ent_rec *));
+ krb5_error_code (*dump_header) PROTOTYPE((struct dump_args *));
+ const char * dump_name;
+ int aindex, num, i;
+ krb5_boolean locked;
+ char **princs;
+ kadm5_principal_ent_rec princ_ent;
+ krb5_principal princ;
+
+ /*
+ * Parse the arguments.
+ */
+ programname = argv[0];
+ if (strrchr(programname, (int) '/'))
+ programname = strrchr(argv[0], (int) '/') + 1;
+ ofile = (char *) NULL;
+ error = 0;
+ dump_iterator = dump_k5beta6_iterator;
+ dump_header = dump_k5beta6_header;
+ dump_name = k5beta6_fmt_name;
+ arglist.verbose = 0;
+
+ /*
+ * Parse the qualifiers.
+ */
+ for (aindex = 1; aindex < argc; aindex++) {
+ if (!strcmp(argv[aindex], oldoption)) {
+ dump_iterator = dump_k5beta5_iterator;
+ dump_header = dump_k5beta5_header;
+ dump_name = k5beta5_fmt_name;
+ }
+ else if (!strcmp(argv[aindex], verboseoption)) {
+ arglist.verbose++;
+ }
+ else
+ break;
+ }
+
+ if (aindex < argc) {
+ ofile = argv[aindex];
+ aindex++;
+ }
+
+ /* this works because of the way aindex and argc are used below */
+ if (aindex == argc) {
+ argv[aindex] = "*";
+ argc++;
+ }
+
+ locked = 0;
+ if (ofile) {
+ /*
+ * 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++;
+ goto cleanup;
+ }
+ if ((kret = krb5_lock_file(context,
+ fileno(f),
+ KRB5_LOCKMODE_EXCLUSIVE))) {
+ fprintf(stderr, oflock_error,
+ programname, ofile, error_message(kret));
+ exit_status++;
+ goto cleanup;
+ }
+ else
+ locked = 1;
+ } else {
+ f = stdout;
+ }
+
+ arglist.programname = programname;
+ arglist.ofile = f;
+ arglist.context = context;
+
+ if (kret = (*dump_header)(&arglist)) {
+ fprintf(stderr, dumphdr_err,
+ programname, dump_name, error_message(kret));
+ exit_status++;
+ goto cleanup;
+ }
+
+ while (aindex < argc) {
+ if (kret = kadm5_get_principals(handle, argv[aindex],
+ &princs, &num)) {
+ fprintf(stderr, "%s: error retrieving principals "
+ "matching %s: (%s)\n", programname,
+ argv[aindex], error_message(kret));
+ exit_status++;
+ goto cleanup;
+ }
+
+ for (i = 0; i < num; i++) {
+ if (kret = krb5_parse_name(context, princs[i],
+ &princ)) {
+ com_err(programname, kret,
+ "while parsing principal name");
+ exit_status++;
+ break;
+ }
+ if (kret = kadm5_get_principal(handle, princ,
+ &princ_ent,
+ KADM5_PRINCIPAL_NORMAL_MASK |
+ KADM5_KEY_DATA|KADM5_TL_DATA)){
+ com_err(programname, kret,
+ "while retrieving principal entry");
+ krb5_free_principal(context, princ);
+ exit_status++;
+ break;
+ }
+ if (kret = (*dump_iterator)(&arglist, princs[i], &princ_ent)) {
+ exit_status++;
+ krb5_free_principal(context, princ);
+ kadm5_free_principal_ent(handle, &princ_ent);
+ break;
+ }
+
+ krb5_free_principal(context, princ);
+ kadm5_free_principal_ent(handle, &princ_ent);
+ }
+
+ kadm5_free_name_list(handle, princs, num);
+ aindex++;
+ if (kret)
+ goto cleanup;
+ }
+
+cleanup:
+ if (ofile)
+ fclose(f);
+
+ if (locked)
+ (void) krb5_lock_file(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 = (char) 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
+/*
+ * process_k5beta5_record() - Handle a dump record in old format.
+ *
+ * Returns -1 for end of file, 0 for success and 1 for failure.
+ */
+static int
+process_k5beta5_record(fname, context, filep, verbose, linenop)
+ char *fname;
+ krb5_context context;
+ 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(context, &dbent) ||
+ krb5_dbe_create_key_data(context, &dbent)) {
+ krb5_db_free_principal(context, &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;
+ char *shortcopy = (krb5_octet *) malloc(shortlen);
+ char *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;
+ char *shortcopy = (krb5_octet *) malloc(shortlen);
+ char *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(context,
+ name,
+ &dbent.princ))) {
+ if (!(kret = krb5_parse_name(context,
+ mod_name,
+ &mod_princ))) {
+ if (!(kret =
+ krb5_dbe_update_mod_princ_data(context,
+ &dbent,
+ mod_date,
+ mod_princ)) &&
+ !(kret =
+ krb5_dbe_update_last_pwd_change(context,
+ &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(context,
+ &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(context, 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(context, &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_k5_record() - Handle a dump record in new format.
+ *
+ * Returns -1 for end of file, 0 for success and 1 for failure.
+ */
+static int
+process_k5_record(fname, context, filep, verbose, linenop)
+ char *fname;
+ krb5_context context;
+ 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(context, 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 */
+ 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(context,
+ &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(context, &dbentry, 1);
+ }
+ else {
+ if (nread == EOF)
+ retval = -1;
+ }
+ return(retval);
+}
+
+
+/*
+ * restore_k5beta5_compat() - Restore the database from a K5 Beta
+ * format dump file.
+ */
+static int
+restore_k5beta5_compat(programname, context, dumpfile, f, verbose)
+ const char *programname;
+ krb5_context context;
+ const char *dumpfile;
+ FILE *f;
+ int verbose;
+{
+ int error;
+ int lineno;
+ char buf[2*sizeof(k5beta5_dump_header)];
+
+ /*
+ * Get/check the header.
+ */
+ error = 0;
+ fgets(buf, sizeof(buf), f);
+ if (!strcmp(buf, k5beta5_dump_header)) {
+ lineno = 1;
+ /*
+ * Process the records.
+ */
+ while (!(error = process_k5beta5_record(dumpfile,
+ context,
+ f,
+ verbose,
+ &lineno)))
+ ;
+ if (error != -1)
+ fprintf(stderr, err_line_fmt, programname, lineno, dumpfile);
+ else
+ error = 0;
+
+ /*
+ * Close the input file.
+ */
+ if (f != stdin)
+ fclose(f);
+ }
+ else {
+ fprintf(stderr, head_bad_fmt, programname, dumpfile);
+ error++;
+ }
+ return(error);
+}
+
+
+/*
+ * restore_dump() - Restore the database from a standard dump file.
+ */
+static int
+restore_dump(programname, context, dumpfile, f, verbose)
+ const char *programname;
+ krb5_context context;
+ const char *dumpfile;
+ FILE *f;
+ int verbose;
+{
+ int error;
+ int lineno;
+ char buf[2*sizeof(k5_dump_header)];
+
+ /*
+ * Get/check the header.
+ */
+ error = 0;
+ fgets(buf, sizeof(buf), f);
+ if (!strcmp(buf, k5_dump_header)) {
+ lineno = 1;
+ /*
+ * Process the records.
+ */
+ while (!(error = process_k5_record(dumpfile,
+ context,
+ f,
+ verbose,
+ &lineno)))
+ ;
+ if (error != -1)
+ fprintf(stderr, err_line_fmt, programname, lineno, dumpfile);
+ else
+ error = 0;
+
+ /*
+ * Close the input file.
+ */
+ if (f != stdin)
+ fclose(f);
+ }
+ else {
+ fprintf(stderr, head_bad_fmt, programname, dumpfile);
+ error++;
+ }
+ return(error);
+}
+
+/*
+ * Usage is
+ * load_db [-old] [-verbose] [-update] filename dbname
+ */
+void
+load_db(argc, argv)
+ int argc;
+ char **argv;
+{
+ krb5_error_code kret;
+ krb5_context context;
+ FILE *f;
+ extern char *optarg;
+ extern int optind;
+ const char *programname;
+ const char *dumpfile;
+ char *dbname;
+ char *dbname_tmp;
+ int (*restore_function) PROTOTYPE((const char *,
+ krb5_context,
+ const char *,
+ FILE *,
+ int));
+ const char * restore_name;
+ int update, verbose;
+ int aindex;
+
+ /*
+ * Parse the arguments.
+ */
+ programname = argv[0];
+ if (strrchr(programname, (int) '/'))
+ programname = strrchr(argv[0], (int) '/') + 1;
+ dumpfile = (char *) NULL;
+ dbname = (char *) NULL;
+ restore_function = restore_dump;
+ restore_name = standard_fmt_name;
+ update = 0;
+ verbose = 0;
+ exit_status = 0;
+ dbname_tmp = (char *) NULL;
+ for (aindex = 1; aindex < argc; aindex++) {
+ if (!strcmp(argv[aindex], oldoption)) {
+ restore_function = restore_k5beta5_compat;
+ restore_name = k5beta5_fmt_name;
+ }
+ else if (!strcmp(argv[aindex], verboseoption)) {
+ verbose = 1;
+ }
+ else if (!strcmp(argv[aindex], updateoption)) {
+ update = 1;
+ }
+ else
+ break;
+ }
+ if ((argc - aindex) != 2) {
+ fprintf(stderr, lusage_err_fmt, argv[0], argv[0],
+ oldoption, verboseoption, updateoption);
+ exit_status++;
+ return;
+ }
+
+ dumpfile = argv[aindex];
+ dbname = argv[aindex+1];
+ 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(&context))) {
+ fprintf(stderr, ctx_err_fmt, programname);
+ free(dbname_tmp);
+ exit_status++;
+ return;
+ }
+ krb5_init_ets(context);
+
+ /*
+ * Open the dumpfile
+ */
+ if (dumpfile) {
+ if ((f = fopen(dumpfile, "r+"))) {
+ kret = krb5_lock_file(context, fileno(f), KRB5_LOCKMODE_SHARED);
+ }
+ }
+ else {
+ f = stdin;
+ }
+ if (f && !kret) {
+ /*
+ * Create the new database if not an update restoration.
+ */
+ if (update || !(kret = krb5_db_create(context, dbname_tmp))) {
+ /*
+ * Point ourselves at it.
+ */
+ if (!(kret = krb5_db_set_name(context,
+ (update) ? dbname : dbname_tmp))) {
+ /*
+ * Initialize the database.
+ */
+ if (!(kret = krb5_db_init(context))) {
+ if ((*restore_function)(programname,
+ context,
+ (dumpfile) ? dumpfile : stdin_name,
+ f,
+ verbose)) {
+ fprintf(stderr, restfail_fmt,
+ programname, restore_name);
+ exit_status++;
+ }
+ if ((kret = krb5_db_fini(context))) {
+ fprintf(stderr, close_err_fmt,
+ programname, error_message(kret));
+ exit_status++;
+ }
+ }
+ else {
+ fprintf(stderr, dbinit_err_fmt,
+ programname, error_message(kret));
+ exit_status++;
+ }
+ }
+ else {
+ fprintf(stderr, dbname_err_fmt,
+ programname,
+ (update) ? dbname : dbname_tmp, error_message(kret));
+ exit_status++;
+ }
+ /*
+ * If there was an error and this is not an update, then
+ * destroy the database.
+ */
+ if (!update) {
+ if (exit_status) {
+ if ((kret = kdb5_db_destroy(context, dbname))) {
+ fprintf(stderr, dbdelerr_fmt,
+ programname, dbname_tmp, error_message(kret));
+ exit_status++;
+ }
+ }
+ else {
+ if ((kret = krb5_db_rename(context,
+ dbname_tmp,
+ dbname))) {
+ fprintf(stderr, dbrenerr_fmt,
+ programname, dbname_tmp, dbname,
+ error_message(kret));
+ exit_status++;
+ }
+ }
+ }
+ }
+ else {
+ fprintf(stderr, dbcreaterr_fmt,
+ programname, dbname, error_message(kret));
+ exit_status++;
+ }
+ if (dumpfile) {
+ (void) krb5_lock_file(context, fileno(f), KRB5_LOCKMODE_UNLOCK);
+ fclose(f);
+ }
+ }
+ else {
+ fprintf(stderr, dfile_err_fmt, dumpfile, error_message(errno));
+ exit_status++;
+ }
+ free(dbname_tmp);
+ krb5_free_context(context);
+}
+#endif
diff --git a/src/kadmin/cli/getdate.y b/src/kadmin/cli/getdate.y
new file mode 100644
index 0000000000..975a819f5a
--- /dev/null
+++ b/src/kadmin/cli/getdate.y
@@ -0,0 +1,1009 @@
+%{
+/*
+** 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>
+
+/* 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
+
+#if defined(HAVE_SYS_TIMEB_H)
+#include <sys/timeb.h>
+#else
+/*
+** We use the obsolete `struct timeb' as part of our interface!
+** Since the system doesn't have it, we define it here;
+** our callers must do likewise.
+*/
+struct 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(HAVE_SYS_TIMEB_H) */
+
+#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. */
+#if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (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 yylex ();
+static int yyerror ();
+
+#if !defined(lint) && !defined(SABER)
+static char RCS[] =
+ "$Header$";
+#endif /* !defined(lint) && !defined(SABER) */
+
+
+#define EPOCH 1970
+#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
+
+%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
+ ;
+
+item : time {
+ yyHaveTime++;
+ }
+ | zone {
+ yyHaveZone++;
+ }
+ | date {
+ yyHaveDate++;
+ }
+ | day {
+ yyHaveDay++;
+ }
+ | rel {
+ yyHaveRel++;
+ }
+ | number
+ ;
+
+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;
+ }
+ ;
+
+number : tUNUMBER {
+ if (yyHaveTime && yyHaveDate && !yyHaveRel)
+ yyYear = $1;
+ else {
+ if($1>10000) {
+ yyHaveDate++;
+ yyDay= ($1)%100;
+ yyMonth= ($1/100)%100;
+ yyYear = $1/10000;
+ }
+ else {
+ yyHaveTime++;
+ if ($1 < 100) {
+ yyHour = $1;
+ yyMinutes = 0;
+ }
+ else {
+ yyHour = $1 / 100;
+ yyMinutes = $1 % 100;
+ }
+ yySeconds = 0;
+ yyMeridian = MER24;
+ }
+ }
+ }
+ ;
+
+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 },
+ { 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 }
+};
+
+/* Military timezone table. */
+static TABLE const MilitaryTable[] = {
+ { "a", tZONE, HOUR( 1) },
+ { "b", tZONE, HOUR( 2) },
+ { "c", tZONE, HOUR( 3) },
+ { "d", tZONE, HOUR( 4) },
+ { "e", tZONE, HOUR( 5) },
+ { "f", tZONE, HOUR( 6) },
+ { "g", tZONE, HOUR( 7) },
+ { "h", tZONE, HOUR( 8) },
+ { "i", tZONE, HOUR( 9) },
+ { "k", tZONE, HOUR( 10) },
+ { "l", tZONE, HOUR( 11) },
+ { "m", tZONE, HOUR( 12) },
+ { "n", tZONE, HOUR(- 1) },
+ { "o", tZONE, HOUR(- 2) },
+ { "p", tZONE, HOUR(- 3) },
+ { "q", tZONE, HOUR(- 4) },
+ { "r", tZONE, HOUR(- 5) },
+ { "s", tZONE, HOUR(- 6) },
+ { "t", tZONE, HOUR(- 7) },
+ { "u", tZONE, HOUR(- 8) },
+ { "v", tZONE, HOUR(- 9) },
+ { "w", tZONE, HOUR(-10) },
+ { "x", tZONE, HOUR(-11) },
+ { "y", tZONE, HOUR(-12) },
+ { "z", tZONE, HOUR( 0) },
+ { 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 */
+}
+
+
+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 < 100)
+ Year += 1900;
+ DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
+ ? 29 : 28;
+ if (Year < EPOCH || Year > 1999
+ || 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);
+ 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;
+
+ if (RelMonth == 0)
+ return 0;
+ tm = localtime(&Start);
+ Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
+ Year = Month / 12;
+ Month = Month % 12 + 1;
+ return DSTcorrect(Start,
+ 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));
+}
+
+
+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(*p))
+ *p = tolower(*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;
+ }
+
+ /* Military timezones. */
+ if (buff[1] == '\0' && isalpha(*buff)) {
+ for (tp = MilitaryTable; 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(*yyInput))
+ yyInput++;
+
+ if (isdigit(c = *yyInput) || c == '-' || c == '+') {
+ if (c == '-' || c == '+') {
+ sign = c == '-' ? -1 : 1;
+ if (!isdigit(*++yyInput))
+ /* skip the '-' sign */
+ continue;
+ }
+ else
+ sign = 0;
+ for (yylval.Number = 0; isdigit(c = *yyInput++); )
+ yylval.Number = 10 * yylval.Number + c - '0';
+ yyInput--;
+ if (sign < 0)
+ yylval.Number = -yylval.Number;
+ return sign ? tSNUMBER : tUNUMBER;
+ }
+ if (isalpha(c)) {
+ for (p = buff; isalpha(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);
+}
+
+time_t
+get_date(p, now)
+ char *p;
+ struct timeb *now;
+{
+ struct tm *tm, gmt;
+ struct timeb ftz;
+ time_t Start;
+ time_t tod;
+
+ yyInput = p;
+ if (now == NULL) {
+ now = &ftz;
+ (void)time(&ftz.time);
+
+ 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;
+
+ if (yyparse()
+ || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
+ return -1;
+
+ 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;
+ }
+
+ Start += yyRelSeconds;
+ Start += RelativeMonth(Start, yyRelMonth);
+
+ 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 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/src/kadmin/cli/kadmin.1 b/src/kadmin/cli/kadmin.1
new file mode 100644
index 0000000000..a8db58334a
--- /dev/null
+++ b/src/kadmin/cli/kadmin.1
@@ -0,0 +1,473 @@
+KADMIN(8) USER_COMMANDS KADMIN(8)
+
+NAME
+ kadmin - a command line interface to the Kerberos KADM5
+ administration system
+
+SYNOPSIS
+ kadmin [-r realm] [-p principal] [-q query] [clnt|local args]
+ clnt args: [-p principal] [[-c ccache]|[-k [-t keytab]]]
+ [-w] [-s admin_server[:port]]
+ local args: [-d dbname] [-e \"enc:salt ...\"] [-m]
+
+DESCRIPTION
+ kadmin is a command-line interface to the Kerberos KADM5
+ administration system. It provides for the maintainance of
+ Kerberos principals, KADM5 policies, and service key tables
+ (keytabs). It exists as both a remote client, using Kerberos
+ authentication and an encrypted RPC to operate securely from
+ anywhere on the network, and as a local client intended to run
+ directly on the KDC without Kerberos authentication. The
+ local version provides all of the functionality of the now
+ obsolete kdb5_edit(8) except for database dump and load, which
+ is now provided by the kdb5_util(8) utility.
+
+COMMAND LINE ARGUMENTS
+ If -r is specified, then kadmin will use the specified realm
+ as the default database realm rather than the default realm
+ for the local machine.
+
+ The -q option allows the passing of a request directly to
+ kadmin, which will then exit. This can be useful for writing
+ scripts.
+
+ The remote version authenticates to the KADM5 server using the
+ service kadmin/admin, and therefore needs a client Kerberos
+ principal name as which to authenticate. The -p, -c, and -k
+ are designed to work together to specify which principal as
+ which to authenticate and where the service ticket or
+ password/key for that principal should be obtained. If given
+ the -p option, kadmin will use the specified principal to
+ authenticate. Otherwise, if given -c option then the primary
+ principal name of the ccache is used. Otherwise, if given the
+ -k option, the principal name host/<hostname> is used.
+ Otherwise, kadmin will append "/admin" to the primary
+ principal name of the default ccache, the value of the USER
+ environment variable, or the username as obtained with
+ getpwuid, in order of preference.
+
+ Once kadmin knows the principal name as which to authenticate,
+ it needs to acquire a Kerberos service ticket for the KADM5
+ server. If the -c ccache argument is specified, the ccache
+ should contain a service ticket for the kadmin/admin service;
+ it can be acquired with the kinit(1) program. Otherwise,
+ kadmin requests a new service ticket from the KDC and stores
+ it in its own temporary ccache. If the -k keytab argument is
+ specified, the keytab is used to decrypt the KDC response;
+ otherwise, a password is required. By default, the user is
+ prompted for the password on the TTY. However, if given the
+ -w option, kadmin will use the password provided on the
+ command line instead of prompting for one on the TTY.
+ WARNING! Placing the password for a Kerberos principal with
+ administration access into a shell script is EXTREMELY
+ DANGEROUS and should only be done if you are highly sure that
+ the script will not fall into the wrong hands.
+
+ If given the -d argument, kadmin will use the specified
+ database name instead of the default defined in kdc.conf.
+ Note that specifying a different KDC database name also
+ specifies a different name for the KADM5 policy database and
+ lock file.
+
+ If given the -e argument, kadmin will use the specified list
+ of encryption and salt type tuples instead of the values
+ specified in kdc.conf. This is useful, for example, if you
+ want to create a single principal with a particular key/salt
+ type without affecting any other principals.
+
+ If given the -m argument, kadmin will prompt for the Kerberos
+ master password on the command line instead of attempting to
+ use the stash file.
+
+DATE FORMAT
+ Various commands in kadmin can take a variety of
+ date formats, specifying durations or absolute times.
+ Examples of valid formats are:
+
+ 1 month ago
+ 2 hours ago
+ 400000 seconds ago
+ last year
+ last Monday
+ yesterday
+ a fortnight ago
+ 3/31/92 10:00:07 PST
+ January 23, 1987 10:05pm
+ 22:00 GMT
+
+ 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" on a duration may
+ result in unexpected behaviour.
+
+COMMAND DESCRIPTIONS
+
+add_principal [options] _newprinc_
+ creates the principal _newprinc_, prompting twice for a
+ password. This command requires the "add" privilege. This
+ command has the aliases "addprinc", "ank".
+
+ OPTIONS
+ -salt _salttype_
+ uses the specified salt instead of the default V5 salt
+ for generating the key. Valid values for _salttype_
+ are:
+ full_name (aliases "v5_salt", "normal")
+ name_only
+ realm_only
+ no_salt (alias "v4_salt")
+
+ -expire _expdate_
+ expiration date of the principal
+
+ -pwexpire _pwexpdate_
+ password expiration date
+
+ -maxlife _maxlife_
+ maximum ticket life of the principal
+
+ -kvno _kvno_
+ explicity set the key version number. This is not
+ recommended.
+
+ -policy _policy_
+ policy used by this principal. If no policy is
+ supplied, the principal will default to having no
+ policy, and a warning message will be printed.
+
+ {-|+}allow_tgs_req
+ "-allow_tgs_req" specifies that a TGS request for a
+ ticket for a service ticket for this principal is not
+ permitted. This option is useless for most things.
+ "+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.
+
+ {-|+}allow_tix
+ "-allow_tix" 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.
+
+ {-|+}needchange
+ "+needchange" 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.
+
+ {-|+}password_changing_service
+ "+password_changing_service" sets a flag in the
+ attributes field marking this as a password change
+ service principal (useless for most things).
+ "-password_changing_service" clears the flag. This
+ flag intentionally has a long name. The default is
+ "-password_changing_service". In effect,
+ "+password_changing_service" sets the
+ KRB5_KDB_PWCHANGE_SERVICE flag on the principal in the
+ database.
+
+ -randpass
+ sets the key of the principal to a random value
+
+ -pw _password_
+ sets the key of the principal to the specified string
+ and does not prompt for a password. This is not
+ recommended.
+
+ EXAMPLE
+ kadmin: addprinc tlyu/deity
+ WARNING: no policy specified for "tlyu/deity@ATHENA.MIT.EDU";
+ defaulting to no policy.
+ Enter password for principal tlyu/deity@ATHENA.MIT.EDU:
+ Re-enter password for principal tlyu/deity@ATHENA.MIT.EDU:
+ Principal "tlyu/deity@ATHENA.MIT.EDU" created.
+ kadmin:
+
+ 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)
+
+delete_principal [-force] _principal_
+ deletes the specified principal from the database. This
+ command prompts for deletion, unless the "-force" option is
+ given. This command requires the "delete" privilege. Aliased
+ to "delprinc".
+
+ EXAMPLE
+ kadmin: delprinc mwm_user
+ Are you sure you want to delete the principal
+ "mwm_user@ATHENA.MIT.EDU"? (yes/no): yes
+ Principal "mwm_user@ATHENA.MIT.EDU" deleted.
+ Make sure that you have removed this principal from
+ all ACLs before reusing.
+ kadmin:
+
+ ERRORS
+ KADM5_AUTH_DELETE (reequires "delete" privilege)
+ KADM5_UNK_PRINC (principal does not exist)
+
+modify_principal [options] _principal_
+ modifies the specified principal, changing the fields as
+ specified. The options are as above for "add_principal",
+ except that password changing is forbidden by this command.
+ In addition, the option "-clearpolicy" will remove clear the
+ current policy of a principal. This command requires the
+ "modify" privilege. Aliased to "modprinc".
+
+ 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)
+
+rename_principal [-force] _old_ _new_
+ rename the principal _old_ to _new_. Prompts for
+ confirmation, unless the "-force" option is given. Requires
+ both the "add" and "delete" privileges. Aliased to
+ "renprinc".
+
+ EXAMPLE
+ kadmin: renprinc tlyutest test0
+ Are you sure you want to rename the principal
+ "tlyutest@ATHENA.MIT.EDU" to
+ "test0@ATHENA.MIT.EDU"? (yes/no): yes
+ Principal "tlyutest@ATHENA.MIT.EDU" renamed to
+ "test0@ATHENA.MIT.EDU".
+ Make sure that you have removed "tlyutest@ATHENA.MIT.EDU" from
+ all ACLs before reusing.
+ kadmin:
+
+ ERRORS
+ KADM5_AUTH_ADD (requires "add" privilege)
+ KADM5_AUTH_DELETE (requires "delete" privilege)
+ KADM5_UNK_PRINC (source principal does not exist)
+ KADM5_DUP (target principal already exists)
+
+change_password [options] _principal_
+ changes the password of _principal_. Prompts for a new
+ password if neither -randpass or -pw is specified. Requires
+ the "modify" privilege, or that the principal that is running
+ the program to be the same as the one changed. Aliased to
+ "cpw".
+
+ OPTIONS
+ -salt _salttype_
+ uses the specified salt instead of the default V5 salt
+ for generating the key. Options are the same as for
+ add_principal.
+
+ -randpass
+ sets the key of the principal to a random value
+
+ -pw _password_
+ set the password to the specified string. Not
+ recommended.
+
+ EXAMPLE
+ kadmin: cpw systest
+ Enter password for principal systest@ATHENA.MIT.EDU:
+ Re-enter password for principal systest@ATHENA.MIT.EDU:
+ Password for systest@ATHENA.MIT.EDU changed.
+ kadmin:
+
+ 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 istory)
+ KADM5_PASS_TOOSOON (current password minimum life not xpired)
+
+get_principal [-terse] _principal_
+ gets the attributes of _principal_. Requires the "get"
+ privilege, or that the principal that is running the the
+ program to be the same as the one being listed. With the
+ "-terse" option, outputs fields as a quoted tab-separated
+ strings. Alias "getprinc".
+
+ EXAMPLES
+ kadmin: getprinc tlyu/deity
+ Principal: tlyu/deity@ATHENA.MIT.EDU
+ Key version: 3
+ Maximum life: 1 day 00:00:00
+ Maximum renewable life: 7 days 00:00:00
+ Master key version: 1
+ Expires: Mon Jan 18 22:14:07 EDT 2038
+ Password expires: Mon Sep 19 14:40:00 EDT 1994
+ Password last changed: Mon Jan 31 02:06:40 EDT 1994
+ Last modified: by tlyu/admin@ATHENA.MIT.EDU
+ on Wed Jul 13 18:27:08 EDT 1994
+ Attributes: DISALLOW_FORWARDABLE, DISALLOW_PROXIABLE,
+ REQUIRES_HW_AUTH
+ Salt type: DEFAULT
+ kadmin: getprinc systest
+ systest@ATHENA.MIT.EDU 3 86400 604800 1
+ 785926535 753241234 785900000
+ tlyu/admin@ATHENA.MIT.EDU 786100034 0
+ 0
+ kadmin:
+
+ ERRORS
+ KADM5_AUTH_GET (requires the get privilege)
+ KADM5_UNK_PRINC (principal does not exist)
+
+get_principals [expression]
+ Retrieves all or some principal names. _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, the
+ expression "*" is assumed. If the expression does not contain
+ an "@" character, an "@" character followed by the local realm
+ is appended to the expression. Requires the "list" priviledge.
+ Alias "getprincs".
+
+ EXAMPLES
+ kadmin: getprincs test*
+ test3@SECURE-TEST.OV.COM
+ test2@SECURE-TEST.OV.COM
+ test1@SECURE-TEST.OV.COM
+ testuser@SECURE-TEST.OV.COM
+ kadmin:
+
+add_policy [options] _policy_
+ adds the named policy to the policy database. Requires the
+ "add" privilege. Aliased to "addpol".
+
+ OPTIONS
+ -maxlife _time_
+ sets the maximum lifetime of a password
+
+ -minlife _time_
+ sets the minimum lifetime of a password
+
+ -minlength _length_
+ sets the minimum length of a password
+
+ -minclasses _number_
+ sets the minimum number of character classes allowed
+ in a password
+
+ -history _number_
+ sets the number of past keys kept for a principal
+
+ ERRORS
+ KADM5_AUTH_ADD (requires the add privilege)
+ KADM5_DUP (policy already exists)
+
+delete_policy _policy_
+ deletes the named policy. Prompts for confirmation before
+ deletion. The command will fail if the policy is in use by
+ any principals. Requires the "delete" privilege. Alias
+ "delpol".
+
+ EXAMPLE
+ kadmin: del_policy guests
+ Are you sure you want to delete the policy "guests"?
+ (yes/no): yes
+ Policy "guests" deleted.
+ kadmin:
+
+ 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)
+
+modify_policy [options] _policy_
+ modifies the named policy. Options are as above for
+ "add_policy". Requires the "modify" privilege". Alias
+ "modpol".
+
+ ERRORS
+ KADM5_AUTH_MODIFY (requires the modify privilege)
+ KADM5_UNK_POLICY (policy does not exist)
+
+get_policy [-terse] _policy_
+ displays the values of the named policy. Requires the "get"
+ privilege. With the "-terse" flag, outputs the fields as
+ quoted strings separated by tabs. Alias "getpol".
+
+ 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:
+
+ ERRORS
+ KADM5_AUTH_GET (requires the get privilege)
+ KADM5_UNK_POLICY (policy does not exist)
+
+get_policies [expression]
+ Retrieves all or some policy names. _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, the
+ expression "*" is assumed. Requires the "list" priviledge.
+ Alias "getpols".
+
+ EXAMPLES
+ kadmin: getpols
+ test-pol
+ dict-only
+ once-a-min
+ test-pol-nopw
+ kadmin: getpols t*
+ test-pol
+ test-pol-nopw
+ kadmin:
+
+ktadd [-k keytab] [-q] [principal | -glob princ-exp] [...]
+ Adds principal or all principals matching princ-exp to a
+ keytab. princ-exp follows the same rules described for the
+ get_principals command. 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 -k
+ argument is not specified, the default keytab /etc/v5srvtab is
+ used. If the -q option is specified, less verbose status
+ information is displayed.
+
+ The -glob option requires the "list" privilege.
+
+ EXAMPLES
+ kadmin% ktadd -k /krb5/kadmind.keytab kadmin/admin kadmin/changepw
+ kadmin: Entry for principal kadmin/admin@ATHENA.MIT.EDU with
+ kvno 3, encryption type DES-CBC-CRC added to keytab
+ WRFILE:/krb5/kadmind.keytab.
+ kadmin: Entry for principal kadmin/changepw@ATHENA.MIT.EDU
+ with kvno 3, encryption type DES-CBC-CRC added to keytab
+ WRFILE:/krb5/kadmind.keytab.
+ kadmin:
+
+ktremove [-k keytab] [-q] principal [kvno|"all"|"old"]
+ Removes entries for the specified principal from a keytab. 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
+ -k argument is not specifeid, the default keytab /etc/v5srvtab
+ is used. If the -q is specified, less verbose status
+ information is displayed.
+
+ EXAMPLES
+ kadmin: ktremove -k /krb5/kadmind.keytab kadmin/admin
+ kadmin: Entry for principal kadmin/admin with kvno 3 removed
+ from keytab WRFILE:/krb5/kadmind.keytab.
+ kadmin:
+
+SEE ALSO
+ kerberos(1), kdb5_util(8)
+
+
diff --git a/src/kadmin/cli/kadmin.c b/src/kadmin/cli/kadmin.c
new file mode 100644
index 0000000000..e19383dd99
--- /dev/null
+++ b/src/kadmin/cli/kadmin.c
@@ -0,0 +1,1322 @@
+/*
+ * 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. M.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 <k5-int.h>
+#include <kadm5/admin.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>
+
+/* 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 }
+};
+
+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 */
+};
+
+char *getenv();
+struct passwd *getpwuid();
+int exit_status = 0;
+char *def_realm = NULL;
+char *whoami = NULL;
+time_t get_date();
+
+void *handle = NULL;
+krb5_context context;
+char *ccache_name = NULL;
+
+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: [-d dbname] [-e \"enc:salt ...\"] [-m]\n", whoami);
+ exit(1);
+}
+
+char *strdur(duration)
+ time_t duration;
+{
+ static char out[50];
+ int days, hours, minutes, seconds;
+
+ days = duration / (24 * 3600);
+ duration %= 24 * 3600;
+ hours = duration / 3600;
+ duration %= 3600;
+ minutes = duration / 60;
+ duration %= 60;
+ seconds = duration;
+ sprintf(out, "%d %s %02d:%02d:%02d", days, days == 1 ? "day" : "days",
+ hours, minutes, seconds);
+ return out;
+}
+
+char *strdate(when)
+ krb5_timestamp when;
+{
+ struct tm *tm;
+ static char out[30];
+
+ time_t lcltim = when;
+ tm = localtime(&lcltim);
+ strftime(out, 30, "%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 */
+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, '@');
+ }
+ 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 krb5_kt_ops krb5_ktf_writable_ops;
+ 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;
+
+ memset((char *) &params, 0, sizeof(params));
+
+ if (retval = krb5_init_context(&context)) {
+ com_err(whoami, retval, "while initializing krb5 library");
+ exit(1);
+ }
+ krb5_init_ets(context);
+
+ while ((optchar = getopt(argc, argv, "r:p:kq:w:d:s:m:c:t:e:")) != EOF) {
+ switch (optchar) {
+ 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':
+ params.dbname = optarg;
+ params.mask |= KADM5_CONFIG_DBNAME;
+ 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,
+ &params.keysalts,
+ &params.num_keysalts);
+ if (retval) {
+ com_err(whoami, retval, "while parsing keysalts %s", optarg);
+ exit(1);
+ }
+ params.mask |= KADM5_CONFIG_ENCTYPES;
+ 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;
+
+ /*
+ * 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 != NULL) {
+ 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);
+ }
+ }
+
+ /*
+ * Initialize the kadm5 connection. If we were given a ccache,
+ * use it. Otherwise, use/prompt for the password.
+ */
+ if (ccache_name)
+ retval = kadm5_init_with_creds(princstr, cc,
+ KADM5_ADMIN_SERVICE,
+ &params,
+ KADM5_STRUCT_VERSION,
+ KADM5_API_VERSION_2,
+ &handle);
+ else if (use_keytab)
+ retval = kadm5_init_with_skey(princstr, keytab_name,
+ KADM5_ADMIN_SERVICE,
+ &params,
+ KADM5_STRUCT_VERSION,
+ KADM5_API_VERSION_2,
+ &handle);
+ else
+ retval = kadm5_init_with_password(princstr, password,
+ KADM5_ADMIN_SERVICE,
+ &params,
+ KADM5_STRUCT_VERSION,
+ KADM5_API_VERSION_2,
+ &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 (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 */
+ if (retval = krb5_kt_register(context, &krb5_ktf_writable_ops)) {
+ com_err(whoami, retval,
+ "while registering writable key table functions");
+ exit(1);
+ }
+ {
+#define DEFAULT_KEYTAB "WRFILE:/etc/v5srvtab"
+ extern char *krb5_defkeyname;
+ krb5_defkeyname = DEFAULT_KEYTAB;
+ }
+
+ return query;
+}
+
+int quit()
+{
+ krb5_ccache cc;
+ int retval;
+
+ kadm5_destroy(handle);
+ if (ccache_name != NULL) {
+ fprintf(stderr,
+ "\n\a\a\aAdministration credentials NOT DESTROYED.\n");
+ }
+
+ /* insert more random cleanup here */
+}
+
+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_renprinc(argc, argv)
+ int argc;
+ char *argv[];
+{
+ krb5_principal oldprinc, newprinc;
+ char *oldcanon, *newcanon;
+ char reply[5];
+ kadm5_ret_t retval;
+
+ if (! (argc == 3 ||
+ (argc == 4 && !strcmp("-force", argv[1])))) {
+ fprintf(stderr, "usage: rename_principal [-force] old new\n");
+ return;
+ }
+ retval = kadmin_parse_name(argv[argc - 2], &oldprinc);
+ if (retval) {
+ com_err("rename_principal", retval, "while parsing old principal");
+ return;
+ }
+ retval = kadmin_parse_name(argv[argc - 1], &newprinc);
+ if (retval) {
+ krb5_free_principal(context, oldprinc);
+ com_err("rename_principal", retval, "while parsing new principal");
+ return;
+ }
+ retval = krb5_unparse_name(context, oldprinc, &oldcanon);
+ if (retval) {
+ com_err("rename_principal", retval,
+ "while canonicalizing old principal");
+ krb5_free_principal(context, newprinc);
+ krb5_free_principal(context, oldprinc);
+ return;
+ }
+ retval = krb5_unparse_name(context, newprinc, &newcanon);
+ if (retval) {
+ com_err("rename_principal", retval,
+ "while canonicalizing new principal");
+ free(oldcanon);
+ krb5_free_principal(context, newprinc);
+ krb5_free_principal(context, oldprinc);
+ return;
+ }
+ if (argc == 3) {
+ printf("Are you sure you want to rename the principal \"%s\" to \"%s\"? (yes/no): ",
+ oldcanon, newcanon);
+ fgets(reply, sizeof (reply), stdin);
+ if (strcmp("yes\n", reply)) {
+ fprintf(stderr,
+ "rename_principal: \"%s\" NOT renamed to \"%s\".\n",
+ oldcanon, newcanon);
+ free(newcanon);
+ free(oldcanon);
+ krb5_free_principal(context, newprinc);
+ krb5_free_principal(context, oldprinc);
+ return;
+ }
+ }
+ retval = kadm5_rename_principal(handle, oldprinc, newprinc);
+ krb5_free_principal(context, oldprinc);
+ krb5_free_principal(context, newprinc);
+ if (retval) {
+ com_err("rename_principal", retval,
+ "while renaming \"%s\" to \"%s\".", oldcanon,
+ newcanon);
+ free(newcanon);
+ free(oldcanon);
+ return;
+ }
+ printf("Principal \"%s\" renamed to \"%s\".\nMake sure that you have removed \"%s\" from all ACLs before reusing.\n",
+ oldcanon, newcanon, newcanon);
+ 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;
+ krb5_principal princ;
+
+ if (argc < 2) {
+ goto usage;
+ }
+
+ retval = kadmin_parse_name(argv[argc - 1], &princ);
+ if (retval) {
+ com_err("change_password", retval, "while parsing principal name");
+ return;
+ }
+ retval = krb5_unparse_name(context, princ, &canon);
+ if (retval) {
+ com_err("change_password", retval, "while canonicalizing principal");
+ krb5_free_principal(context, princ);
+ return;
+ }
+ if ((argc == 4) && (strlen(argv[1]) == 3) && !strcmp("-pw", argv[1])) {
+ retval = kadm5_chpass_principal(handle, princ, argv[2]);
+ krb5_free_principal(context, princ);
+ if (retval) {
+ com_err("change_password", retval,
+ "while changing password for \"%s\".", canon);
+ free(canon);
+ return;
+ }
+ printf("Password for \"%s\" changed.\n", canon);
+ free(canon);
+ return;
+ } else if ((argc == 3) && (strlen(argv[1]) == 8) &&
+ !strcmp("-randkey", argv[1])) {
+ 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);
+ return;
+ }
+ printf("Key for \"%s\" randomized.\n", canon);
+ free(canon);
+ return;
+ } else if (argc == 2) {
+ int i = sizeof (newpw) - 1;
+
+ sprintf(prompt1, "Enter password for principal \"%.900s\": ",
+ argv[1]);
+ sprintf(prompt2,
+ "Re-enter password for principal \"%.900s\": ",
+ argv[1]);
+ retval = krb5_read_password(context, prompt1, prompt2,
+ newpw, &i);
+ if (retval) {
+ com_err("change_password", retval,
+ "while reading password for \"%s\".", canon);
+ free(canon);
+ krb5_free_principal(context, princ);
+ return;
+ }
+ 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);
+ return;
+ }
+ printf("Password for \"%s\" changed.\n", canon);
+ free(canon);
+ return;
+ } else {
+ free(canon);
+ krb5_free_principal(context, princ);
+ usage:
+ fprintf(stderr,
+ "usage: change_password [-randpass] [-pw passowrd] "
+ "principal\n");
+ return;
+ }
+}
+
+int kadmin_parse_princ_args(argc, argv, oprinc, mask, pass, randkey, caller)
+ int argc;
+ char *argv[];
+ kadm5_principal_ent_t oprinc;
+ long *mask;
+ char **pass;
+ int *randkey;
+ char *caller;
+{
+ int i, j, attrib_set;
+ time_t date;
+ time_t now;
+ krb5_error_code retval;
+
+ *mask = 0;
+ *pass = NULL;
+ time(&now);
+ *randkey = 0;
+ for (i = 1; i < argc - 1; i++) {
+ attrib_set = 0;
+ if (strlen(argv[i]) == 7 &&
+ !strcmp("-expire", argv[i])) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ date = get_date(argv[i], NULL);
+ oprinc->princ_expire_time = date == (time_t)-1 ? 0 : 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], NULL);
+ oprinc->pw_expiration = date == (time_t)-1 ? 0 : date;
+ *mask |= KADM5_PW_EXPIRATION;
+ continue;
+ }
+ }
+ if (strlen(argv[i]) == 8 &&
+ !strcmp("-maxlife", argv[i])) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ oprinc->max_life = get_date(argv[i], NULL) - now;
+ *mask |= KADM5_MAX_LIFE;
+ 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;
+ }
+ 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) {
+ fprintf(stderr, "%s: parser lost count!\n", caller);
+ return -1;
+ }
+ retval = kadmin_parse_name(argv[i], &oprinc->principal);
+ if (retval) {
+ com_err(caller, retval, "while parsing principal");
+ return -1;
+ }
+ return 0;
+}
+
+void kadmin_addmodprinc_usage(func)
+ char *func;
+{
+ fprintf(stderr, "usage: %s [options] principal\n", func);
+ fprintf(stderr, "\toptions are:\n");
+ fprintf(stderr, "\t\t[-salt salttype] [-expire expdate] [-pwexpire pwexpdate]\n\t\t[-maxlife maxtixlife] [-kvno kvno] [-policy policy]\n\t\t[-randkey] [-pw password] [{+|-}attribute]\n");
+ fprintf(stderr, "\tattributes are:\n");
+ fprintf(stderr, "\t\tallow_tgs_req, allow_tix, needchange, password_changing_service\n");
+}
+
+void kadmin_addprinc(argc, argv)
+ int argc;
+ char *argv[];
+{
+ kadm5_principal_ent_rec princ;
+ long mask;
+ int randkey = 0;
+ char *pass, *canon;
+ krb5_error_code retval;
+ static char newpw[1024];
+ static char prompt1[1024], prompt2[1024];
+
+ princ.attributes = 0;
+ if (kadmin_parse_princ_args(argc, argv,
+ &princ, &mask, &pass, &randkey,
+ "add_principal")) {
+ kadmin_addmodprinc_usage("add_principal");
+ 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);
+ return;
+ }
+ if (randkey) { /* do special stuff if -randkey specified */
+ princ.attributes |= KRB5_KDB_DISALLOW_ALL_TIX; /* set notix */
+ mask |= KADM5_ATTRIBUTES;
+ pass = "dummy";
+ } else if (pass == NULL) {
+ int i = 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, &i);
+ if (retval) {
+ com_err("add_principal", retval,
+ "while reading password for \"%s\".", canon);
+ free(canon);
+ krb5_free_principal(context, princ.principal);
+ return;
+ }
+ pass = newpw;
+ }
+ mask |= KADM5_PRINCIPAL;
+ 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);
+ return;
+ }
+ if (randkey) { /* more special stuff for -randkey */
+ 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);
+ 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);
+ return;
+ }
+ }
+ krb5_free_principal(context, princ.principal);
+ printf("Principal \"%s\" created.\n", canon);
+ free(canon);
+}
+
+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;
+
+ if (argc < 2) {
+ kadmin_addmodprinc_usage("modify_principal");
+ return;
+ }
+
+ 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,
+ "modify_principal");
+ if (retval) {
+ kadmin_addmodprinc_usage("modify_principal");
+ free(canon);
+ return;
+ }
+ if (randkey) {
+ fprintf(stderr, "modify_principal: -randkey not allowed\n");
+ krb5_free_principal(context, princ.principal);
+ free(canon);
+ 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);
+ return;
+ }
+ printf("Principal \"%s\" modified.\n", canon);
+ 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;
+ }
+ 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", strdate(dprinc.princ_expire_time));
+ printf("Last password change: %s\n",
+ strdate(dprinc.last_pwd_change));
+ 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("Last modified: by %s\n\ton %s\n",
+ modcanon, strdate(dprinc.mod_date));
+ printf("Last successful authentication: %s\n",
+ strdate(dprinc.last_success));
+ printf("Last failed authentication: %s\n",
+ strdate(dprinc.last_failed));
+ 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.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 *exp, **names;
+ int i, count;
+
+ exp = NULL;
+ if (! (argc == 1 || (argc == 2 && (exp = argv[1])))) {
+ fprintf(stderr, "usage: get_principals [expression]\n");
+ return;
+ }
+ retval = kadm5_get_principals(handle, exp, &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);
+}
+
+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;
+ krb5_error_code retval;
+
+ 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], NULL);
+ policy->pw_max_life =
+ (date == (time_t)-1 ? 0 : 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], NULL);
+ policy->pw_min_life =
+ (date == (time_t)-1 ? 0 : 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;
+}
+
+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;
+
+ 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;
+
+ 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: %d\n", policy.pw_max_life);
+ printf("Minimum password life: %d\n", policy.pw_min_life);
+ printf("Minimum password length: %d\n", policy.pw_min_length);
+ printf("Minimum number of password character classes: %d\n",
+ policy.pw_min_classes);
+ printf("Number of old keys kept: %d\n", policy.pw_history_num);
+ printf("Reference count: %d\n", policy.policy_refcnt);
+ } else {
+ printf("\"%s\"\t%d\t%d\t%d\t%d\t%d\t%d\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 *exp, **names;
+ int i, count;
+
+ exp = NULL;
+ if (! (argc == 1 || (argc == 2 && (exp = argv[1])))) {
+ fprintf(stderr, "usage: get_policies [expression]\n");
+ return;
+ }
+ retval = kadm5_get_policies(handle, exp, &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);
+}
+
+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/src/kadmin/cli/kadmin_ct.ct b/src/kadmin/cli/kadmin_ct.ct
new file mode 100644
index 0000000000..d22229bf0c
--- /dev/null
+++ b/src/kadmin/cli/kadmin_ct.ct
@@ -0,0 +1,79 @@
+# 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. M.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_prinicpal, addprinc, ank;
+
+request kadmin_delprinc, "Delete principal",
+ delete_principal, delprinc;
+
+request kadmin_modprinc, "Modify principal",
+ modify_principal, modprinc;
+
+request kadmin_renprinc, "Rename principal",
+ rename_principal, renprinc;
+
+request kadmin_cpw, "Change password",
+ change_password, cpw;
+
+request kadmin_getprinc, "Get principal",
+ get_principal, getprinc;
+
+request kadmin_getprincs, "Get principals",
+ 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, "Get policies",
+ 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;
+
+# 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/src/kadmin/cli/keytab.c b/src/kadmin/cli/keytab.c
new file mode 100644
index 0000000000..4b51140b55
--- /dev/null
+++ b/src/kadmin/cli/keytab.c
@@ -0,0 +1,420 @@
+/*
+ * 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 <string.h>
+
+#include <krb5.h>
+#include <k5-int.h>
+#include <kadm5/admin.h>
+
+static int add_principal(void *handle, char *keytab_str, krb5_keytab keytab,
+ 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);
+
+extern char *krb5_defkeyname;
+extern char *whoami;
+extern krb5_context context;
+extern void *handle;
+static int quiet;
+
+void add_usage()
+{
+ fprintf(stderr, "Usage: ktadd [-k[eytab] keytab] [-q] [principal | -glob princ-exp] [...]\n");
+}
+
+void rem_usage()
+{
+ fprintf(stderr, "Usage: ktremove [-k[eytab] keytab] [-q] principal [kvno|\"all\"|\"old\"]\n");
+}
+
+int process_keytab(krb5_context context, char **keytab_str,
+ krb5_keytab *keytab)
+{
+ int code;
+
+ if (*keytab_str == NULL) {
+ if (! (*keytab_str = strdup(krb5_defkeyname))) {
+ com_err(whoami, ENOMEM, "while creating keytab name");
+ return 1;
+ }
+ code = krb5_kt_default(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(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 *princ_str, *keytab_str = NULL, **princs;
+ int code, num, i;
+
+ argc--; argv++;
+ 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
+ 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;
+ }
+
+ if (code = kadm5_get_principals(handle, *argv, &princs, &num)) {
+ com_err(whoami, code, "while expanding expression \"%s\".",
+ *argv);
+ argv++;
+ continue;
+ }
+
+ for (i = 0; i < num; i++)
+ (void) add_principal(handle, keytab_str, keytab,
+ princs[i]);
+ kadm5_free_name_list(handle, princs, num);
+ } else
+ (void) add_principal(handle, keytab_str, keytab, *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 *princ_str, *keytab_str = NULL;
+ int code;
+
+ argc--; argv++;
+ 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);
+}
+
+int add_principal(void *handle, char *keytab_str, krb5_keytab keytab,
+ char *princ_str)
+{
+ kadm5_principal_ent_rec princ_rec;
+ krb5_principal princ;
+ krb5_keytab_entry new_entry;
+ krb5_keyblock *keys;
+ int code, code2, mask, 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;
+ }
+
+ code = kadm5_randkey_principal(handle, 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(handle, 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(handle, &princ_rec);
+ goto cleanup;
+ }
+
+ if (!quiet)
+ printf("%s: Entry for principal %s with kvno %d, "
+ "encryption type %s added to keytab %s.\n",
+ whoami, princ_str, princ_rec.kvno,
+ etype_string(keys[i].enctype), keytab_str);
+ }
+
+ code = kadm5_free_principal_ent(handle, &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(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, kvno, did_something;
+
+ 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("%s: Entry for principal %s with kvno %d "
+ "removed from keytab %s.\n", whoami,
+ 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[12];
+
+ switch (enctype) {
+ case ENCTYPE_DES_CBC_CRC:
+ return "DES-CBC-CRC";
+ break;
+ case ENCTYPE_DES_CBC_MD4:
+ return "DES-CBC-MD4";
+ break;
+ case ENCTYPE_DES_CBC_MD5:
+ return "DES-CBC-MD5";
+ break;
+#if 0
+ case ENCTYPE_DES3_CBC_MD5:
+ return "DES3-CBC-MD5";
+ break;
+#endif
+ default:
+ sprintf(buf, "etype %d", enctype);
+ return buf;
+ break;
+ }
+}
diff --git a/src/kadmin/cli/memmove.c b/src/kadmin/cli/memmove.c
new file mode 100644
index 0000000000..abc91e923e
--- /dev/null
+++ b/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 USE_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/src/kadmin/cli/setenv.c b/src/kadmin/cli/setenv.c
new file mode 100644
index 0000000000..a2432c3d6d
--- /dev/null
+++ b/src/kadmin/cli/setenv.c
@@ -0,0 +1,165 @@
+/*
+ * 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>
+
+#ifndef __P
+#define __P(x) ()
+#endif
+char *__findenv __P((const char *, int *));
+
+/*
+ * setenv --
+ * Set the value of the environmental variable "name" to be
+ * "value". If rewrite is set, replace any current value.
+ */
+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;
+ 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 (c = (char *)name; *c && *c != '='; ++c); /* no `=' in name */
+ if (!(environ[offset] = /* name + `=' + value */
+ malloc((size_t)((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)
+ 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;
+}
+
+/*
+ * getenv --
+ * Returns ptr to value associated with name, if any, else NULL.
+ */
+char *
+getenv(name)
+ const char *name;
+{
+ int offset;
+
+ return (__findenv(name, &offset));
+}
+
+/*
+ * __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 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/src/kadmin/cli/ss_wrapper.c b/src/kadmin/cli/ss_wrapper.c
new file mode 100644
index 0000000000..89e94b36ba
--- /dev/null
+++ b/src/kadmin/cli/ss_wrapper.c
@@ -0,0 +1,61 @@
+/*
+ * 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. M.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>
+
+extern ss_request_table kadmin_cmds;
+extern int exit_status;
+extern char *kadmin_startup();
+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
+ ss_listen(sci_idx, &retval);
+ return quit() ? 1 : exit_status;
+}
diff --git a/src/kadmin/cli/strftime.c b/src/kadmin/cli/strftime.c
new file mode 100644
index 0000000000..484852a72d
--- /dev/null
+++ b/src/kadmin/cli/strftime.c
@@ -0,0 +1,469 @@
+/* strftime - custom formatting of date and/or time
+ Copyright (C) 1989, 1991, 1992 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Note: this version of strftime lacks locale support,
+ but it is standalone.
+
+ Performs `%' substitutions similar to those in printf. Except
+ where noted, substituted fields have a fixed size; numeric fields are
+ padded if necessary. Padding is with zeros by default; for fields
+ that display a single number, padding can be changed or inhibited by
+ following the `%' with one of the modifiers described below. Unknown
+ field specifiers are copied as normal characters. All other
+ characters are copied to the output without change.
+
+ Supports a superset of the ANSI C field specifiers.
+
+ Literal character fields:
+ % %
+ n newline
+ t tab
+
+ Numeric modifiers (a nonstandard extension):
+ - do not pad the field
+ _ pad the field with spaces
+
+ Time fields:
+ %H hour (00..23)
+ %I hour (01..12)
+ %k hour ( 0..23)
+ %l hour ( 1..12)
+ %M minute (00..59)
+ %p locale's AM or PM
+ %r time, 12-hour (hh:mm:ss [AP]M)
+ %R time, 24-hour (hh:mm)
+ %s time in seconds since 00:00:00, Jan 1, 1970 (a nonstandard extension)
+ %S second (00..61)
+ %T time, 24-hour (hh:mm:ss)
+ %X locale's time representation (%H:%M:%S)
+ %Z time zone (EDT), or nothing if no time zone is determinable
+
+ Date fields:
+ %a locale's abbreviated weekday name (Sun..Sat)
+ %A locale's full weekday name, variable length (Sunday..Saturday)
+ %b locale's abbreviated month name (Jan..Dec)
+ %B locale's full month name, variable length (January..December)
+ %c locale's date and time (Sat Nov 04 12:02:33 EST 1989)
+ %C century (00..99)
+ %d day of month (01..31)
+ %e day of month ( 1..31)
+ %D date (mm/dd/yy)
+ %h same as %b
+ %j day of year (001..366)
+ %m month (01..12)
+ %U week number of year with Sunday as first day of week (00..53)
+ %w day of week (0..6)
+ %W week number of year with Monday as first day of week (00..53)
+ %x locale's date representation (mm/dd/yy)
+ %y last two digits of year (00..99)
+ %Y year (1970...)
+
+ David MacKenzie <djm@gnu.ai.mit.edu> */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#if defined(TM_IN_SYS_TIME) || (!defined(HAVE_TM_ZONE) && !defined(HAVE_TZNAME))
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+
+#ifndef STDC_HEADERS
+time_t mktime ();
+#endif
+
+#if defined(HAVE_TZNAME)
+extern char *tzname[2];
+#endif
+
+/* Types of padding for numbers in date and time. */
+enum padding
+{
+ none, blank, zero
+};
+
+static char const* const days[] =
+{
+ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
+};
+
+static char const * const months[] =
+{
+ "January", "February", "March", "April", "May", "June",
+ "July", "August", "September", "October", "November", "December"
+};
+
+/* Add character C to STRING and increment LENGTH,
+ unless LENGTH would exceed MAX. */
+
+#define add_char(c) \
+ do \
+ { \
+ if (length + 1 <= max) \
+ string[length++] = (c); \
+ } \
+ while (0)
+
+/* Add a 2 digit number to STRING, padding if specified.
+ Return the number of characters added, up to MAX. */
+
+static int
+add_num2 (string, num, max, pad)
+ char *string;
+ int num;
+ int max;
+ enum padding pad;
+{
+ int top = num / 10;
+ int length = 0;
+
+ if (top == 0 && pad == blank)
+ add_char (' ');
+ else if (top != 0 || pad == zero)
+ add_char (top + '0');
+ add_char (num % 10 + '0');
+ return length;
+}
+
+/* Add a 3 digit number to STRING, padding if specified.
+ Return the number of characters added, up to MAX. */
+
+static int
+add_num3 (string, num, max, pad)
+ char *string;
+ int num;
+ int max;
+ enum padding pad;
+{
+ int top = num / 100;
+ int mid = (num - top * 100) / 10;
+ int length = 0;
+
+ if (top == 0 && pad == blank)
+ add_char (' ');
+ else if (top != 0 || pad == zero)
+ add_char (top + '0');
+ if (mid == 0 && top == 0 && pad == blank)
+ add_char (' ');
+ else if (mid != 0 || top != 0 || pad == zero)
+ add_char (mid + '0');
+ add_char (num % 10 + '0');
+ return length;
+}
+
+/* Like strncpy except return the number of characters copied. */
+
+static int
+add_str (to, from, max)
+ char *to;
+ const char *from;
+ int max;
+{
+ int i;
+
+ for (i = 0; from[i] && i <= max; ++i)
+ to[i] = from[i];
+ return i;
+}
+
+static int
+add_num_time_t (string, max, num)
+ char *string;
+ int max;
+ time_t num;
+{
+ /* This buffer is large enough to hold the character representation
+ (including the trailing NUL) of any unsigned decimal quantity
+ whose binary representation fits in 128 bits. */
+ char buf[40];
+ int length;
+
+ if (sizeof (num) > 16)
+ abort ();
+ sprintf (buf, "%lu", (unsigned long) num);
+ length = add_str (string, buf, max);
+ return length;
+}
+
+/* Return the week in the year of the time in TM, with the weeks
+ starting on Sundays. */
+
+static int
+sun_week (tm)
+ struct tm *tm;
+{
+ int dl;
+
+ /* Set `dl' to the day in the year of the last day of the week previous
+ to the one containing the day specified in TM. If the day specified
+ in TM is in the first week of the year, `dl' will be negative or 0.
+ Otherwise, calculate the number of complete weeks before our week
+ (dl / 7) and add any partial week at the start of the year (dl % 7). */
+ dl = tm->tm_yday - tm->tm_wday;
+ return dl <= 0 ? 0 : dl / 7 + (dl % 7 != 0);
+}
+
+/* Return the week in the year of the time in TM, with the weeks
+ starting on Mondays. */
+
+static int
+mon_week (tm)
+ struct tm *tm;
+{
+ int dl, wday;
+
+ if (tm->tm_wday == 0)
+ wday = 6;
+ else
+ wday = tm->tm_wday - 1;
+ dl = tm->tm_yday - wday;
+ return dl <= 0 ? 0 : dl / 7 + (dl % 7 != 0);
+}
+
+#if !defined(HAVE_TM_ZONE) && !defined(HAVE_TZNAME)
+char *
+zone_name (tp)
+ struct tm *tp;
+{
+ char *timezone ();
+ struct timeval tv;
+ struct timezone tz;
+
+ gettimeofday (&tv, &tz);
+ return timezone (tz.tz_minuteswest, tp->tm_isdst);
+}
+#endif
+
+/* Format the time given in TM according to FORMAT, and put the
+ results in STRING.
+ Return the number of characters (not including terminating null)
+ that were put into STRING, or 0 if the length would have
+ exceeded MAX. */
+
+size_t
+strftime (string, max, format, tm)
+ char *string;
+ size_t max;
+ const char *format;
+ const struct tm *tm;
+{
+ enum padding pad; /* Type of padding to apply. */
+ size_t length = 0; /* Characters put in STRING so far. */
+
+ for (; *format && length < max; ++format)
+ {
+ if (*format != '%')
+ add_char (*format);
+ else
+ {
+ ++format;
+ /* Modifiers: */
+ if (*format == '-')
+ {
+ pad = none;
+ ++format;
+ }
+ else if (*format == '_')
+ {
+ pad = blank;
+ ++format;
+ }
+ else
+ pad = zero;
+
+ switch (*format)
+ {
+ /* Literal character fields: */
+ case 0:
+ case '%':
+ add_char ('%');
+ break;
+ case 'n':
+ add_char ('\n');
+ break;
+ case 't':
+ add_char ('\t');
+ break;
+ default:
+ add_char (*format);
+ break;
+
+ /* Time fields: */
+ case 'H':
+ case 'k':
+ length +=
+ add_num2 (&string[length], tm->tm_hour, max - length,
+ *format == 'H' ? pad : blank);
+ break;
+ case 'I':
+ case 'l':
+ {
+ int hour12;
+
+ if (tm->tm_hour == 0)
+ hour12 = 12;
+ else if (tm->tm_hour > 12)
+ hour12 = tm->tm_hour - 12;
+ else
+ hour12 = tm->tm_hour;
+ length +=
+ add_num2 (&string[length], hour12, max - length,
+ *format == 'I' ? pad : blank);
+ }
+ break;
+ case 'M':
+ length +=
+ add_num2 (&string[length], tm->tm_min, max - length, pad);
+ break;
+ case 'p':
+ if (tm->tm_hour < 12)
+ add_char ('A');
+ else
+ add_char ('P');
+ add_char ('M');
+ break;
+ case 'r':
+ length +=
+ strftime (&string[length], max - length, "%I:%M:%S %p", tm);
+ break;
+ case 'R':
+ length +=
+ strftime (&string[length], max - length, "%H:%M", tm);
+ break;
+
+ case 's':
+ {
+ struct tm writable_tm;
+ writable_tm = *tm;
+ length += add_num_time_t (&string[length], max - length,
+ mktime (&writable_tm));
+ }
+ break;
+
+ case 'S':
+ length +=
+ add_num2 (&string[length], tm->tm_sec, max - length, pad);
+ break;
+ case 'T':
+ length +=
+ strftime (&string[length], max - length, "%H:%M:%S", tm);
+ break;
+ case 'X':
+ length +=
+ strftime (&string[length], max - length, "%H:%M:%S", tm);
+ break;
+ case 'Z':
+#ifdef HAVE_TM_ZONE
+ length += add_str (&string[length], tm->tm_zone, max - length);
+#else
+#ifdef HAVE_TZNAME
+ if (tm->tm_isdst && tzname[1] && *tzname[1])
+ length += add_str (&string[length], tzname[1], max - length);
+ else
+ length += add_str (&string[length], tzname[0], max - length);
+#else
+ length += add_str (&string[length], zone_name (tm), max - length);
+#endif
+#endif
+ break;
+
+ /* Date fields: */
+ case 'a':
+ add_char (days[tm->tm_wday][0]);
+ add_char (days[tm->tm_wday][1]);
+ add_char (days[tm->tm_wday][2]);
+ break;
+ case 'A':
+ length +=
+ add_str (&string[length], days[tm->tm_wday], max - length);
+ break;
+ case 'b':
+ case 'h':
+ add_char (months[tm->tm_mon][0]);
+ add_char (months[tm->tm_mon][1]);
+ add_char (months[tm->tm_mon][2]);
+ break;
+ case 'B':
+ length +=
+ add_str (&string[length], months[tm->tm_mon], max - length);
+ break;
+ case 'c':
+ length +=
+ strftime (&string[length], max - length,
+ "%a %b %d %H:%M:%S %Z %Y", tm);
+ break;
+ case 'C':
+ length +=
+ add_num2 (&string[length], (tm->tm_year + 1900) / 100,
+ max - length, pad);
+ break;
+ case 'd':
+ length +=
+ add_num2 (&string[length], tm->tm_mday, max - length, pad);
+ break;
+ case 'e':
+ length +=
+ add_num2 (&string[length], tm->tm_mday, max - length, blank);
+ break;
+ case 'D':
+ length +=
+ strftime (&string[length], max - length, "%m/%d/%y", tm);
+ break;
+ case 'j':
+ length +=
+ add_num3 (&string[length], tm->tm_yday + 1, max - length, pad);
+ break;
+ case 'm':
+ length +=
+ add_num2 (&string[length], tm->tm_mon + 1, max - length, pad);
+ break;
+ case 'U':
+ length +=
+ add_num2 (&string[length], sun_week (tm), max - length, pad);
+ break;
+ case 'w':
+ add_char (tm->tm_wday + '0');
+ break;
+ case 'W':
+ length +=
+ add_num2 (&string[length], mon_week (tm), max - length, pad);
+ break;
+ case 'x':
+ length +=
+ strftime (&string[length], max - length, "%m/%d/%y", tm);
+ break;
+ case 'y':
+ length +=
+ add_num2 (&string[length], tm->tm_year % 100,
+ max - length, pad);
+ break;
+ case 'Y':
+ add_char ((tm->tm_year + 1900) / 1000 + '0');
+ length +=
+ add_num3 (&string[length],
+ (1900 + tm->tm_year) % 1000, max - length, zero);
+ break;
+ }
+ }
+ }
+ add_char (0);
+ return length - 1;
+}
diff --git a/src/kadmin/config.mk/ChangeLog b/src/kadmin/config.mk/ChangeLog
new file mode 100644
index 0000000000..5dd46d71a1
--- /dev/null
+++ b/src/kadmin/config.mk/ChangeLog
@@ -0,0 +1,10 @@
+Fri Jul 12 14:39:28 1996 Marc Horowitz <marc@mit.edu>
+
+ * architecture: add uname test for NetBSD
+ * netbsd1.def: added
+
+Mon Jul 8 16:39:36 1996 Barry Jaspan <bjaspan@mit.edu>
+
+ * template, site.def, rules: Add SITEMAKEFILES to specify -f
+ Makefile.ov, add .ct default rule.
+
diff --git a/src/kadmin/config.mk/aix3.2.def b/src/kadmin/config.mk/aix3.2.def
new file mode 100644
index 0000000000..44fd07b1f6
--- /dev/null
+++ b/src/kadmin/config.mk/aix3.2.def
@@ -0,0 +1,40 @@
+export PS_ALL = ps auxww
+# Make sure there's no extra whitespace at the end of this line!
+export PS_PID = ps auxww
+# Make sure there is a blank space at the end of this line!
+export PS_TTY = ps -t
+export RSH_CMD = /usr/bin/rsh
+export INSTCMD = /usr/local/bin/ginstall -c
+export LEX = /usr/local/bin/flex
+export AWK_CMD = /usr/local/bin/gawk
+
+# needed for fd_set to be defined
+# Not convinced! Experimenting with disabling _BSD. - jik 3/21/95
+ifndef KRB5B4
+CFLAGS += -D_BSD
+endif
+CFLAGS += -D_ALL_SOURCE
+
+PCC_STRUCT_RETURN = -fpcc-struct-return
+D_NEEDS_RPCENT = -D_SUN
+
+D_NEEDS_GETUSERSHELL = -DNEEDS_GETUSERSHELL
+D_NEEDS_TREEWALK = -DNEEDS_TREEWALK
+D_SETEUID = -DNO_SETEUID -DSETEUID_INCLUDE='<sys/id.h>' \
+ -DSETEUIDPRE='setuidx(ID_REAL|ID_EFFECTIVE,' -DSETEUIDPOST=')'
+D_NO_SETENV = -DNO_SETENV
+D_REGEXP_TYPE = -DPOSIX_REGEXPS
+
+TERMCAPLIB = -ltermcap
+
+# extra libraries needed for login
+LOGINLIB = -ls -lcfg -lodm
+
+UTMP_FILE = /etc/utmp
+WTMP_FILE = /usr/adm/wtmp
+
+XINCDIR = /usr/lpp/X11/include
+XLIBDIR = /usr/lpp/X11/lib
+
+OMIT_DOC = true
+DONT_STRIP_NXLIBS = true
diff --git a/src/kadmin/config.mk/architecture b/src/kadmin/config.mk/architecture
new file mode 100644
index 0000000000..d976c27b2f
--- /dev/null
+++ b/src/kadmin/config.mk/architecture
@@ -0,0 +1,68 @@
+# $Id$
+
+# sample `uname -a` output:
+# SunOS dun-dun-n 4.1.3 3 sun4c
+# SunOS samosa 5.3 Generic_101318-31 sun4m sparc
+# HP-UX strange- A.09.01 A 9000/710 2005970723 two-user license
+# AIX krusty 2 3 000131533500
+
+# each section here should set ARCH_OS to a symbol specifically describing
+# the OS, and also set "relevant" capability symbols
+
+ifndef ARCH_OS
+__UNAME_A := $(shell uname -a)
+ifeq "$(strip $(filter SunOS 4.1.3, $(__UNAME_A)))" "SunOS 4.1.3"
+ export ARCH_OS := sunos4.1
+endif
+ifeq "$(strip $(filter SunOS 4.1.3C, $(__UNAME_A)))" "SunOS 4.1.3C"
+ export ARCH_OS := sunos4.1
+endif
+ifeq "$(strip $(filter SunOS 4.1.3_U1, $(__UNAME_A)))" "SunOS 4.1.3_U1"
+ export ARCH_OS := sunos4.1
+endif
+ifeq "$(strip $(filter SunOS 4.1.4, $(__UNAME_A)))" "SunOS 4.1.4"
+ export ARCH_OS := sunos4.1
+endif
+ifeq "$(strip $(filter SunOS 5.3, $(__UNAME_A)))" "SunOS 5.3"
+ export ARCH_OS := solaris2.3
+endif
+# For now, assume that Solaris 2.4 is the same as Solaris 2.3.
+ifeq "$(strip $(filter SunOS 5.4, $(__UNAME_A)))" "SunOS 5.4"
+ export ARCH_OS := solaris2.3
+endif
+ifeq "$(strip $(filter HP-UX A.09.01, $(__UNAME_A)))" "HP-UX A.09.01"
+ export ARCH_OS := hpux9.01
+endif
+ifeq "$(strip $(filter AIX 2, $(__UNAME_A)))" "AIX 2"
+ export ARCH_OS := aix3.2
+endif
+ifeq "$(strip $(filter sweet-and-sour-sauce, $(__UNAME_A)))" "sweet-and-sour-sauce"
+ export ARCH_OS := aix3.2
+ d:=$(shell echo "*** WARNING! Used hostname for architecture." 1>&2)
+endif
+ifeq "$(strip $(filter Linux, $(__UNAME_A)))" "Linux"
+ export ARCH_OS := linux
+endif
+ifeq "$(strip $(filter IRIX, $(__UNAME_A)))" "IRIX"
+ export ARCH_OS := irix5.2
+endif
+ifeq "$(strip $(filter NetBSD, $(__UNAME_A)))" "NetBSD NetBSD"
+ export ARCH_OS := netbsd1
+endif
+
+ifndef ARCH_OS
+ d:=$(shell echo "*** WARNING! Unknown architecture: $(__UNAME_A)" 1>&2)
+ export ARCH_OS := dummy
+ export ARCH_OS_UNKNOWN := dummy
+endif
+endif
+
+ifndef ARCH_OS_UNKNOWN
+ define IncludeArchFile
+ include $(CONFDIR)/$(ARCH_OS).def
+ endef
+else
+ define IncludeArchFile
+ endef
+endif
+
diff --git a/src/kadmin/config.mk/config b/src/kadmin/config.mk/config
new file mode 100644
index 0000000000..9bb800e849
--- /dev/null
+++ b/src/kadmin/config.mk/config
@@ -0,0 +1,141 @@
+# $Id$
+# $Source$
+
+#
+# local Programs
+#
+
+INSTHDRS = $(TOP)/scripts/inst-hdrs.sh
+COMPILE_ET = $(TOP)/../util/et/compile_et
+MK_CMDS = $(TOP)/../util/ss/mk_cmds
+SYM_RANDOMIZE = $(TOP)/intl/sym-randomize.pl
+
+#
+# Directories
+#
+
+STAGETOP= $(TOP)/..
+STAGE_BINDIR = $(STAGETOP)/bin
+STAGE_INCDIR = $(STAGETOP)/include
+STAGE_LIBDIR = $(STAGETOP)/lib
+
+INSTALLTOP= $(TOP)/..
+INSTALL_BINDIR = $(INSTALLTOP)/bin
+INSTALL_ETCDIR = $(INSTALLTOP)/etc
+INSTALL_INCDIR = $(INSTALLTOP)/include
+INSTALL_LIBDIR = $(INSTALLTOP)/lib
+INSTALL_CONFDIR = $(INSTALLTOP)/config
+INSTALL_PROTODIR = $(INSTALLTOP)/proto
+INSTALL_ADMINDIR = $(INSTALLTOP)/admin
+INSTALL_SERVERDIR = $(INSTALLTOP)/sbin
+INSTALL_INSTDIR = $(INSTALLTOP)/install
+INSTALL_DOCDIR = $(INSTALLTOP)/doc
+INSTALL_MANDIR = $(INSTALLTOP)/man
+INSTALL_SRCDIR = $(INSTALLTOP)/src
+
+#
+# libraries
+#
+
+# system
+LIBM = -lm
+
+# stage
+LIBADMCLNT := $(STAGE_LIBDIR)/libkadm5clnt.a
+LIBADMSRV := $(STAGE_LIBDIR)/libkadm5srv.a
+LIBRPCLIB := $(STAGE_LIBDIR)/libgssrpc.a
+LIBDYN := $(STAGE_LIBDIR)/libdyn.a
+LIBSS := $(STAGE_LIBDIR)/libss.a
+LIBOVSEC_UTIL := $(STAGE_LIBDIR)/libkadm5_util.a
+LIBFTPSEC := $(STAGE_LIBDIR)/libftpsec.a
+
+# install
+LIBGSSAPI_KRB5 := $(INSTALL_LIBDIR)/libgssapi_krb5.a
+LIBGSSAPI_KRB5_DX := $(INSTALL_LIBDIR)/libgssapi_krb5_dx.a
+LIBGSSAPI_KRB5_WX := $(INSTALL_LIBDIR)/libgssapi_krb5_wx.a
+LIBGSSAPI_KRB5_NX := $(INSTALL_LIBDIR)/libgssapi_krb5_nx.a
+LIBGSSAPI_TRUST := $(INSTALL_LIBDIR)/libgssapi_trust.a
+LIBDB := $(INSTALL_LIBDIR)/libdb.a
+LIBKRB5 := $(INSTALL_LIBDIR)/libkrb5.a
+LIBKDB5 := $(INSTALL_LIBDIR)/libkdb5.a
+LIBCRYPTO := $(INSTALL_LIBDIR)/libcrypto.a
+ifndef KRB5B4
+LIBISODE := $(INSTALL_LIBDIR)/libisode.a
+endif
+LIBCOM_ERR := $(INSTALL_LIBDIR)/libcom_err.a
+LIBKRB5_ALL := $(LIBKRB5) $(LIBCRYPTO) $(LIBISODE) $(LIBCOM_ERR)
+LIBKRB := $(INSTALL_LIBDIR)/libkrb4.a
+LIBKDB := $(INSTALL_LIBDIR)/libkdb.a
+LIBKADM := $(INSTALL_LIBDIR)/libkadm.a
+LIBKRB425 := $(INSTALL_LIBDIR)/libkrb425.a
+LIBDES425 := $(INSTALL_LIBDIR)/libdes425.a
+
+# X libraries. XXX this uses -L! but perhaps it doesn't matter, see
+# [secure-build/2649]
+XLIB = -L$(XLIBDIR) -lXext -lX11
+
+#
+# library name mangling for export
+#
+
+ADMIN_INTERFACE_SYMBOL_FILES := $(TOP)/intl/adm-export-symbols \
+ $(TOP)/intl/misc-export-symbols
+OTHER_INTERFACE_SYMBOL_FILES := $(TOP)/intl/gss-export-symbols
+
+ADMIN_CRYPTO_LIBS := $(LIBADMCLNT) $(LIBADMSRV) $(LIBRPCLIB) \
+ $(LIBGSSAPI_KRB5) $(LIBKRB5) $(LIBKDB5) $(LIBCRYPTO) \
+ $(LIBISODE) $(LIBKRB) $(LIBKDB) $(LIBDES425)
+OTHER_CRYPTO_LIBS := $(LIBGSSAPI_KRB5_DX) $(LIBGSSAPI_KRB5_WX) \
+ $(LIBGSSAPI_KRB5_NX)
+
+#
+# compiler/linker flags
+#
+
+CFLAGS := $(CFLAGS) -I$(INSTALL_INCDIR)
+
+#
+# Variables for testing
+#
+# These are all exported because lots of test scripts (/bin/sh, perl,
+# tcl) use them.
+#
+
+export TESTDIR = $(TOP)/testing
+export COMPARE_DUMP = $(TESTDIR)/scripts/compare_dump.pl
+export FIX_CONF_FILES = $(TESTDIR)/scripts/fixup-conf-files.pl
+export INITDB = $(TESTDIR)/scripts/init_db
+export MAKE_KEYTAB = $(TESTDIR)/scripts/make-host-keytab.pl
+export LOCAL_MAKE_KEYTAB= $(TESTDIR)/scripts/make-host-keytab.pl
+export RESTORE_FILES = $(TESTDIR)/scripts/restore_files.sh
+export SAVE_FILES = $(TESTDIR)/scripts/save_files.sh
+export SIMPLE_DUMP = $(TESTDIR)/scripts/simple_dump.pl
+export TCLUTIL = $(TESTDIR)/tcl/util.t
+export BSDDB_DUMP = $(TESTDIR)/util/bsddb_dump
+export CLNTTCL = $(TESTDIR)/util/ovsec_kadm_clnt_tcl
+export SRVTCL = $(TESTDIR)/util/ovsec_kadm_srv_tcl
+export QUALNAME = $(TOP)/inst-scripts/qualname
+
+export START_SERVERS = $(TESTDIR)/scripts/start_servers $(TEST_SERVER)
+export START_SERVERS_LOCAL = $(TESTDIR)/scripts/start_servers_local
+
+export STOP_SERVERS = $(TESTDIR)/scripts/stop_servers $(TEST_SERVER)
+export STOP_SERVERS_LOCAL = $(TESTDIR)/scripts/stop_servers_local
+
+export KRB5_CONFIG = /krb5/krb5.conf
+export KRB5_KDC_PROFILE = /krb5/kdc.conf
+export KRB5_KTNAME = /krb5/ovsec_adm.srvtab
+
+ifdef TEST_SERVER
+MAKE_KEYTAB += -server $(TEST_SERVER)
+ifdef TEST_PATH
+MAKE_KEYTAB += -top $(TEST_PATH)
+START_SERVERS += $(TEST_PATH)
+STOP_SERVERS += $(TEST_PATH)
+endif
+endif
+
+export VERBOSE_TEST DEJALFLAGS
+
+# We're running low on disk space, so strip installed binaries
+STRIP_INSTALLED = true
diff --git a/src/kadmin/config.mk/hpux9.01.def b/src/kadmin/config.mk/hpux9.01.def
new file mode 100644
index 0000000000..17da13c525
--- /dev/null
+++ b/src/kadmin/config.mk/hpux9.01.def
@@ -0,0 +1,32 @@
+export ARCH_SKIP_RANLIB := 1
+export INSTCMD = ginstall -c
+export PS_ALL = ps -ef
+# Make sure there's no extra whitespace at the end of this line!
+export PS_PID = ps -fp
+# Make sure there is a blank space at the end of this line!
+export PS_TTY = ps -t
+export STATIC_LINK_GUI := 1
+export RSH_CMD = /usr/bin/remsh
+
+PCC_STRUCT_RETURN = -fpcc-struct-return
+# this must always be at the end.
+REGEXLIB = -lc -lPW
+TERMCAPLIB = -ltermcap
+
+XINCDIR = /usr/include/X11R5
+XLIBDIR = /usr/lib/X11R5
+NDBMLIB := /usr/lib/libndbm.a
+ARCH_CFLAGS = -mpa-risc-1-0
+
+CFLAGS := $(ARCH_CFLAGS) $(CFLAGS)
+
+UTMP_FILE = /etc/utmp
+WTMP_FILE = /etc/wtmp
+
+D_RANDOM = -Dsrandom=srand48 -Drandom=lrand48
+D_SETEUID = -DNO_SETEUID \
+ -DSETEUIDPRE='setresuid(-1,' -DSETEUIDPOST=',-1)'
+D_FATALINLIBS = -Dfatal=ftpd_fatal
+D_NO_SETENV = -DNO_SETENV
+D_REGEXP_TYPE = -DPOSIX_REGEXPS
+
diff --git a/src/kadmin/config.mk/irix5.2.def b/src/kadmin/config.mk/irix5.2.def
new file mode 100644
index 0000000000..053d9328e2
--- /dev/null
+++ b/src/kadmin/config.mk/irix5.2.def
@@ -0,0 +1,22 @@
+export PS_ALL = /usr/bin/ps -ef
+# Make sure there's no extra whitespace at the end of this line!
+export PS_PID = /usr/bin/ps -fp
+# Make sure there is a blank space at the end of this line!
+export PS_TTY = /usr/bin/ps -t
+
+RANLIB = /bin/true
+D_NO_SETENV = -DNO_SETENV
+D_HAVE_SYSLOG_H = -DHAVE_SYSLOG_H
+D_HAVE_STDARG_H = -DHAVE_STDARG_H
+D_HAVE_SYSLOG = -DHAVE_SYSLOG
+D_HAVE_VSPRINTF = -DHAVE_VSPRINTF
+D_HAVE_OPENLOG = -DHAVE_OPENLOG
+D_HAVE_CLOSELOG = -DHAVE_CLOSELOG
+D_HAVE_STRFTIME = -DHAVE_STRFTIME
+
+# libgen.a is for regcmp and regex, used in /usr/lib/libXm.a; this is
+# a different set of regexp routines than used by svr_iters.c
+XM_LIB = /usr/lib/libXm.a /usr/lib/libgen.a
+XT_LIB = /usr/lib/libXt.a
+X_LIB = /usr/lib/libX11.so
+
diff --git a/src/kadmin/config.mk/linux.def b/src/kadmin/config.mk/linux.def
new file mode 100644
index 0000000000..69a0c62877
--- /dev/null
+++ b/src/kadmin/config.mk/linux.def
@@ -0,0 +1,23 @@
+export PS_ALL = ps auxww
+# Make sure there's no extra whitespace at the end of this line!
+export PS_PID = ps auxww
+export RSH_CMD = /usr/bin/rsh
+
+XINCDIR = /usr/include
+XLIBDIR = /usr/lib
+
+NDBMLIB = -ldbm
+
+PERL = /usr/bin/perl
+LEX_LIB = -lfl
+
+OMIT_GUI = true
+OMIT_XM_KPASSWD = true
+OMIT_DOC = true
+
+UTMP_FILE = /etc/utmp
+WTMP_FILE = /var/adm/wtmp
+
+LIBTCL = -ltcl
+
+TERMCAPLIB = -ltermcap
diff --git a/src/kadmin/config.mk/netbsd1.def b/src/kadmin/config.mk/netbsd1.def
new file mode 100644
index 0000000000..2b6090355d
--- /dev/null
+++ b/src/kadmin/config.mk/netbsd1.def
@@ -0,0 +1,22 @@
+export PS_ALL = ps auxww
+# Make sure there's no extra whitespace at the end of this line!
+export PS_PID = ps auxww
+# Make sure there's no extra whitespace at the end of this line!
+export PS_TTY = ps -t
+export RSH_CMD = /usr/bin/rsh
+
+PCC_STRUCT_RETURN =
+TERMCAPLIB = -ltermcap
+
+XINCDIR = /usr/X11/include
+XLIBDIR = /usr/X11/lib
+
+UTMP_FILE = /etc/utmp
+WTMP_FILE = /usr/adm/wtmp
+
+D_NO_SETENV = -DNO_SETENV
+
+SHLIBCFLAGS := -fpic
+SHLIBLDFLAGS := -assert pure-text
+SHLIBEXT := so
+SHLIBSEP := .
diff --git a/src/kadmin/config.mk/rules b/src/kadmin/config.mk/rules
new file mode 100644
index 0000000000..35b647bdab
--- /dev/null
+++ b/src/kadmin/config.mk/rules
@@ -0,0 +1,538 @@
+#
+# $Id$
+# $Source$
+#
+
+#
+# DefaultRules --- clean, depend, all, stage, includes, and
+# install.
+#
+
+define DefaultRules
+clean::
+ $(CLEAN) core *.o *~ *.bak #* y.output
+
+depend::
+
+all::
+
+includes::
+
+stage::
+
+install::
+
+unit-test::
+
+traverse::
+
+endef
+
+
+#
+# SubdirTarget
+#
+# SUBDIRS = subdirs to work in
+#
+define SubdirTarget
+__SUBDIR_TARGET := clean
+expand _DoSubdir
+
+__SUBDIR_TARGET := depend
+expand _DoSubdir
+
+__SUBDIR_TARGET := all
+expand _DoSubdir
+
+__SUBDIR_TARGET := includes
+expand _DoSubdir
+
+__SUBDIR_TARGET := stage
+expand _DoSubdir
+
+__SUBDIR_TARGET := install
+expand _DoSubdir
+
+__SUBDIR_TARGET := unit-test
+expand _DoSubdir
+
+__SUBDIR_TARGET := traverse
+expand _DoSubdir
+
+ALL_SUBDIRS_TARGET := everything
+expand AllTargetsTarget
+endef
+
+#
+# Makes the target $(ALL_SUBDIRS_TARGET) perform the targets includes
+# depend stage all install in $(SUBDIRS).
+#
+define AllTargetsTarget
+$(ALL_SUBDIRS_TARGET)::
+ @cwd=`pwd`; \
+ for d in $(SUBDIRS); do \
+ echo "--- Making includes depend stage all install in $(CUR_DIR)/$$$$d"; \
+ cd $$$$d && \
+ $(MAKE) includes depend CUR_DIR=$(CUR_DIR)/$$$$d; \
+ $(MAKE) stage all install CUR_DIR=$(CUR_DIR)/$$$$d; \
+ cd $$$$cwd; \
+ done
+
+endef
+
+define _DoSubdir
+# $(__SUBDIR_TARGET)::
+# @echo "--- SKIPPING $(__SUBDIR_TARGET) in $(SUBDIRS)"
+$(__SUBDIR_TARGET)::
+ @cwd=`pwd`; \
+ for d in $(SUBDIRS); do \
+ echo "--- Making $(__SUBDIR_TARGET) in $(CUR_DIR)/$$$$d"; \
+ cd $$$$d && \
+ $(MAKE) $(SITEMAKEFLAGS) $(__SUBDIR_TARGET) CUR_DIR=$(CUR_DIR)/$$$$d; \
+ cd $$$$cwd; \
+ done
+endef
+
+#
+# Program -- compile prog, adds all and clean targets
+#
+# PROG program name
+# OBJS object files
+# DEPS additional dependencies (e.g.: libraries)
+# LIBS libraries
+# LDFLAGS arguments for link stage
+# PUREFLAGS arguments for purify
+# PURELIBS extra libraries to link in when using purify
+#
+define Program
+all:: $(PROG)
+
+$(PROG): $(OBJS) $(DEPS) $(filter-out -L% -l%, $(LIBS))
+ifdef BUILD_IN_TMP
+ rm -f /tmp/$(PROG).$(__PID__)
+ $(CC) $(LDFLAGS) -o /tmp/$(PROG).$(__PID__) $(OBJS) $(LIBS) $(STD_LIBS)
+ mv /tmp/$(PROG).$(__PID__) $(PROG)
+else
+ $(CC) $(LDFLAGS) -o $(PROG) $(OBJS) $(LIBS) $(STD_LIBS)
+endif
+
+clean::
+ $(CLEAN) $(PROG)
+
+proof:: $(PROG).tc
+
+$(PROG).tc: $(OBJS) $(DEPS) $(filter-out -L% -l%, $(LIBS))
+ifdef BUILD_IN_TMP
+ rm -f /tmp/$(PROG).tc.$(__PID__)
+ $(PROOF) $(CC) $(LDFLAGS) -o /tmp/$(PROG).tc.$(__PID__) $(OBJS) \
+ $(LIBS) $(STD_LIBS)
+ mv /tmp/$(PROG).tc.$(__PID__) $(PROG).tc
+else
+ $(PROOF) $(CC) $(LDFLAGS) -o $(PROG).tc $(OBJS) $(LIBS) $(STD_LIBS)
+endif
+
+clean::
+ $(CLEAN) $(PROG).tc $(PROG).tc.*
+
+pure:: $(PROG).pure
+
+$(PROG).pure: $(OBJS) $(DEPS) $(filter-out -L% -l%, $(LIBS))
+ifdef BUILD_IN_TMP
+ rm -f /tmp/$(PROG).pure.$(__PID__)
+ $(PURIFY) $(PUREFLAGS) \
+ $(CC) $(LDFLAGS) -o /tmp/$(PROG).pure.$(__PID__) $(OBJS) \
+ $(LIBS) $(STD_LIBS) $(PURELIBS)
+ mv /tmp/$(PROG).pure.$(__PID__) $(PROG).pure
+else
+ $(PURIFY) $(PUREFLAGS) $(CC) $(LDFLAGS) -o $(PROG).pure $(OBJS) $(LIBS) $(STD_LIBS) $(PURELIBS)
+endif
+
+clean::
+ $(CLEAN) $(PROG).pure $(PROG).pure.pure_*
+
+quant:: $(PROG).quant
+
+$(PROG).quant: $(OBJS) $(DEPS) $(filter-out -L% -l%, $(LIBS))
+ifdef BUILD_IN_TMP
+ rm -f /tmp/$(PROG).quant.$(__PID__)
+ $(QUANTIFY) $(QUANTFLAGS) \
+ $(CC) $(LDFLAGS) -o /tmp/$(PROG).quant.$(__PID__) $(OBJS) \
+ $(LIBS) $(STD_LIBS) $(QUANTLIBS)
+ mv /tmp/$(PROG).quant.$(__PID__) $(PROG).quant
+else
+ $(QUANTIFY) $(QUANTFLAGS) $(CC) $(LDFLAGS) -o $(PROG).quant $(OBJS) $(LIBS) $(STD_LIBS) $(QUANTLIBS)
+endif
+
+clean::
+ $(CLEAN) $(PROG).quant $(PROG).quant.quant.*.qv
+endef
+
+#
+# InstallProgram -- build program, install in INSTALL_BINDIR, adds
+# install target
+#
+define InstallProgram
+__INST_DIR := $(INSTALL_BINDIR)
+expand Program
+expand InstallExecutable
+endef
+
+#
+# InstallUtil -- build program, install in INSTALL_ETCDIR, adds
+# install target
+#
+define InstallUtil
+__INST_DIR := $(INSTALL_ETCDIR)
+expand Program
+expand InstallExecutable
+endef
+
+#
+# InstallAdmin -- build program, install in INSTALL_ADMINDIR, adds
+# install target
+#
+define InstallAdmin
+__INST_DIR := $(INSTALL_ADMINDIR)
+expand Program
+expand InstallExecutable
+endef
+
+#
+# InstallServer -- build program, install in INSTALL_SERVERDIR, adds
+# install target
+#
+define InstallServer
+__INST_DIR := $(INSTALL_SERVERDIR)
+expand Program
+expand InstallExecutable
+endef
+
+#
+# InstallExecuteable(bin, as, dir)
+#
+define InstallExecutable
+ifndef INST_NAME
+install:: $(PROG)
+ rm -f $(__INST_DIR)/$(PROG)
+ $(INSTCMD) $(INST_PROG_FLAGS) $(PROG) $(__INST_DIR)/$(PROG)
+else
+install:: $(PROG)
+ rm -f $(__INST_DIR)/$(INST_NAME)
+ $(INSTCMD) $(INST_PROG_FLAGS) $(PROG) $(__INST_DIR)/$(INST_NAME)
+endif
+endef
+
+#
+# Library -- create library from object files and ranlib it, adds all
+# and clean targets
+#
+# LIB name of library (e.g. libfoo.a)
+# OBJS object files in library
+#
+define Library
+all:: $(LIB)
+
+$(LIB): $(OBJS) $(OTHER_OBJS)
+ $(RM) -f $(LIB)
+ $(AR) $(ARFLAGS) $(LIB) $(OBJS)
+ifndef ARCH_SKIP_RANLIB
+ $(RANLIB) $(LIB)
+endif
+
+clean::
+ $(CLEAN) $(LIB)
+endef
+
+#
+# SharedLibrary -- create shared library from object files, adds all
+# and clean targets
+#
+# LIB basename of library (e.g. libfoo)
+# (this will be basenamified, anyway)
+# OBJS object files in library
+# VERSION version of shared library
+#
+define SharedLibrary
+ifdef DO_SHARED_LIBRARIES
+ifdef SHLIBLDFLAGS
+ifdef SHLIBSEP
+__LIB := $(basename $(LIB)).$(SHLIBEXT)$(SHLIBSEP)$(VERSION)
+else
+__LIB := $(basename $(LIB)).$(SHLIBEXT)
+endif
+__LIBNV := $(basename $(LIB)).$(SHLIBEXT)
+expand SharedLibrary_1
+endif
+endif
+endef
+
+define SharedLibrary_1
+ifdef DO_SHARED_LIBRARIES
+all:: $(__LIB)
+
+$(__LIB): $(OBJS) $(OTHER_OBJS)
+ $(RM) -f $(__LIB) $(__LIBNV)
+ $(LD) -o $(__LIB) $(SHLIBLDFLAGS) $(OBJS)
+ $(LNSOFT) $(__LIB) $(__LIBNV)
+clean::
+ $(CLEAN) $(__LIB) $(__LIBNV)
+endif
+endef
+
+#
+# StageLibrary -- build library, install in STAGE_LIBDIR, adds stage target
+#
+define StageLibrary
+expand Library
+
+stage:: $(STAGE_LIBDIR)/$(LIB)
+
+$(STAGE_LIBDIR)/$(LIB): $(LIB)
+ $(INSTCMD) $(LIB) $(STAGE_LIBDIR)/$(LIB)
+ifndef ARCH_SKIP_RANLIB
+ $(RANLIB) $(STAGE_LIBDIR)/$(LIB)
+endif
+endef
+
+#
+# StageSharedLibrary -- build library, install in STAGE_LIBDIR, adds
+# stage target
+#
+define StageSharedLibrary
+ifdef DO_SHARED_LIBRARIES
+expand SharedLibrary
+expand StageSharedLibrary_1
+endif
+endef
+
+define StageSharedLibrary_1
+ifdef DO_SHARED_LIBRARIES
+ifdef __LIB
+stage:: $(STAGE_LIBDIR)/$(__LIB)
+
+$(STAGE_LIBDIR)/$(__LIB): $(__LIB)
+ $(INSTCMD) $(__LIB) $(STAGE_LIBDIR)/$(__LIB)
+endif
+endif
+endef
+
+#
+# InstallLibrary -- build library, install in INSTALL_LIBDIR,
+# adds install target
+#
+define InstallLibrary
+expand Library
+
+install:: $(INSTALL_LIBDIR)/$(LIB)
+
+$(INSTALL_LIBDIR)/$(LIB): $(LIB)
+ $(INSTCMD) $(LIB) $(INSTALL_LIBDIR)/$(LIB)
+ifndef ARCH_SKIP_RANLIB
+ $(RANLIB) $(INSTALL_LIBDIR)/$(LIB)
+endif
+endef
+
+#
+# InstallSharedLibrary -- build library, install in INSTALL_LIBDIR,
+# adds install target
+#
+define InstallSharedLibrary
+ifdef DO_SHARED_LIBRARIES
+expand SharedLibrary
+expand InstallSharedLibrary_1
+endif
+endef
+
+define InstallSharedLibrary_1
+ifdef DO_SHARED_LIBRARIES
+ifdef __LIB
+install:: $(INSTALL_LIBDIR)/$(__LIB)
+
+$(INSTALL_LIBDIR)/$(__LIB): $(__LIB)
+ $(INSTCMD) $(__LIB) $(INSTALL_LIBDIR)/$(__LIB)
+endif
+endif
+endef
+
+#
+# StageFiles(files, dir)
+#
+define StageFiles
+stage:: $(FILES)
+ $(INSTCMD) $(FILES) $(DIR)
+endef
+
+#
+# StageIncludes -- copy include files to staging area, adds includes
+# and stage target
+#
+# HDRS header files to copy
+# HDRS_DIR subdir of STAGE_INCDIR to copy to
+#
+define StageIncludes
+includes:: $(HDRS)
+ $(INSTHDRS) $(STAGE_INCDIR)/$(HDRS_DIR) $(HDRS)
+
+stage:: $(HDRS)
+ $(INSTHDRS) $(STAGE_INCDIR)/$(HDRS_DIR) $(HDRS)
+endef
+
+#
+# InstallIncludes -- copy include files to staging area, adds includes
+# and install target
+#
+# HDRS header files to copy
+# HDRS_DIR subdir of INSTALL_INCDIR to copy to
+#
+define InstallIncludes
+includes:: $(HDRS)
+ $(INSTHDRS) $(INSTALL_INCDIR)/$(HDRS_DIR) $(HDRS)
+
+install:: $(HDRS)
+ $(INSTHDRS) $(INSTALL_INCDIR)/$(HDRS_DIR) $(HDRS)
+endef
+
+#
+# Depend -- run makedepend
+#
+# SRCS source files to generate dependencies for
+# DEPENDS dependencies for "make depend"
+# ETABLES error tables whose .c and .h files are implicitly
+# dependencies of make depend
+#
+define Depend
+depend:: $(DEPENDS) $(addsuffix .c,$(basename $(ETABLES))) $(addsuffix .h,$(basename $(ETABLES)))
+
+ifeq (,$(findstring -a,$(__MDFLAGS)))
+ @rm -f Makefile.depend; touch Makefile.depend
+endif
+ $(MAKEDEPEND) $(__MDFLAGS) $(MDFLAGS) -fMakefile.depend -- $(CFLAGS) -- $(SRCS)
+
+clean::
+ $(CLEAN) Makefile.depend
+
+ifeq (,$(findstring -a,$(__MDFLAGS)))
+__MDFLAGS += -a
+endif
+endef
+
+#
+# NormalProgram -- everything for a single program
+#
+# PROG = program name
+# SRCS = list of .c sources
+# HDRS = list of .h sources
+# OBJS = list of .o files to depend and link against
+# STAGELIBS = foo.a within the stage area tree to link against
+# INSTALLLIBS = foo.a within the install area tree to link against
+# LIBS = system libraries to link against
+#
+# STAGELIBS And INSTALLLIBS are added to the dependencies for PROG.
+#
+define NormalProgram
+expand SaveStuff
+LIBS := $(addprefix $(STAGE_LIBDIR)/,$(STAGELIBS)) \
+ $(addprefix $(INSTALL_LIBDIR)/,$(INSTALLLIBS)) \
+ $(LIBS)
+DEPS := $(addprefix $(STAGE_LIBDIR)/,$(STAGELIBS)) \
+ $(addprefix $(INSTALL_LIBDIR)/,$(INSTALLLIBS)) \
+ $(DEPS)
+
+clean::
+ $(CLEAN) $(OBJS)
+
+expand InstallProgram
+expand Depend
+expand RestoreStuff
+endef
+
+define NormalLibrary
+expand Library
+
+clean::
+ $(CLEAN) $(OBJS)
+
+expand Depend
+endef
+
+#
+# ErrorTables -- compile an error table with compile_et
+#
+# ETABLES list of .et files
+# CFLAGS for saber target
+#
+#
+define ErrorTables
+__ETABLE_HS := $(addsuffix .h,$(basename $(ETABLES)))
+__ETABLE_CS := $(addsuffix .c,$(basename $(ETABLES)))
+expand ErrorTables_1
+endef
+
+define ErrorTables_1
+
+saber::
+ #load $(CFLAGS) $(__ETABLE_CS)
+
+clean::
+ $(CLEAN) $(__ETABLE_HS) $(__ETABLE_CS)
+endef
+
+#
+# StageErrorTables -- copy generated include file into staging area.
+#
+# ETABLES list of .et file
+# HDRS_DIR subdir of STAGE_INCDIR to copy to
+#
+define StageErrorTables
+expand ErrorTables
+expand StageErrorTables_1
+endef
+
+define StageErrorTables_1
+includes:: $(__ETABLE_HS)
+ $(INSTHDRS) $(STAGE_INCDIR)/$(HDRS_DIR) $(__ETABLE_HS)
+
+stage:: $(__ETABLE_HS)
+ $(INSTHDRS) $(STAGE_INCDIR)/$(HDRS_DIR) $(__ETABLE_HS)
+endef
+
+define SaveStuff
+__LIBS := $(LIBS)
+__DEPS := $(DEPS)
+endef
+
+define RestoreStuff
+LIBS := $(__LIBS)
+DEPS := $(__DEPS)
+endef
+
+#
+# XDR -- generate .c and .h from .x
+#
+# XDRS list of .x files
+#
+define XDR
+__XDR_HS := $(addsuffix .h,$(basename $(XDRS)))
+__XDR_CS := $(addsuffix .c,$(basename $(XDRS)))
+expand XDR_1
+endef
+
+define XDR_1
+saber::
+ #load $(CFLAGS) $(__XDR_CS)
+
+clean::
+ $(CLEAN) $(__XDR_HS) $(__XDR_CS)
+endef
+
+
+
+#
+# Saber -- load files into saber
+#
+# SRCS list of .c files
+#
+define Saber
+saber::
+ #load $(CFLAGS) $(SRCS)
+endef
diff --git a/src/kadmin/config.mk/site.def b/src/kadmin/config.mk/site.def
new file mode 100644
index 0000000000..be7fe9e25b
--- /dev/null
+++ b/src/kadmin/config.mk/site.def
@@ -0,0 +1,52 @@
+# $Id$
+
+# XXXX this file will probably have lots of ARCH_OS defines in it.
+
+#
+# Misc settings
+#
+
+#
+# site-specific compiler/linker flags
+#
+
+CFLAGS := $(CFLAGS) -I$(TOP)/../../src/include \
+ -I$(TOP)/../../src/include/krb5 \
+ -I$(TOP)/../include \
+ -I$(TOP)/../include/krb5 \
+ $(PCC_STRUCT_RETURN) -g
+
+SITEMAKEFLAGS := -f Makefile.ov
+
+#
+# Packages whose locations we need to know
+#
+
+ifeq ($(shell ls -d /.afs/gza.com/product/secure 2>/dev/null),/.afs/gza.com/product/secure)
+AFS_ROOT=/.afs
+else
+AFS_ROOT=/afs
+endif
+
+PERL = /afs/athena/contrib/perl/p
+# /afs/sipb/project/tcl/lib/libtcl.a
+LIBTCL = /mit/gnu/lib/libtcl.a
+# /afs/sipb/project/tcl/include
+TCLINC = /mit/gnu/include
+
+#
+# Default locations
+#
+
+YACC = bison -y
+
+#
+# I'm not really sure where this should go, but it is often useful to
+# be able to set up a test environment from anywhere in the build
+# tree.
+#
+start-servers:
+ $(START_SERVERS)
+
+stop-servers:
+ $(STOP_SERVERS)
diff --git a/src/kadmin/config.mk/solaris2.3.def b/src/kadmin/config.mk/solaris2.3.def
new file mode 100644
index 0000000000..d18e0e1640
--- /dev/null
+++ b/src/kadmin/config.mk/solaris2.3.def
@@ -0,0 +1,39 @@
+export PS_ALL = /usr/bin/ps -ef
+# Make sure there's no extra whitespace at the end of this line!
+export PS_PID = /usr/bin/ps -fp
+# Make sure there is a blank space at the end of this line!
+export PS_TTY = /usr/bin/ps -t
+export RSH_CMD = /usr/ucb/rsh
+export INSTCMD = /usr/ucb/install
+export PATH := $(PATH):/usr/ucb:/usr/ccs/bin
+
+PCC_STRUCT_RETURN = -fpcc-struct-return
+D_NEEDS_RPCENT = -DNEEDS_RPCENT
+D_SYSV = -DSYSV
+D_POSIX = -DPOSIX
+D_NO_SETENV = -DNO_SETENV
+D_POSIX_SIGNALS = -DPOSIX_SIGNALS
+D_RANDOM = -Dsrandom=srand48 -Drandom=lrand48
+D_REGEXP_TYPE = -DSOLARIS_REGEXPS
+NETLIB = -lsocket -lnsl
+#BSDLIB = /usr/ucblib/libucb.a
+TERMCAPLIB = -lcurses -ltermcap
+REGEXLIB = -lgen
+LOGINLIB = -lcmd
+
+XINCDIR = /usr/openwin/include
+XLIBDIR = /usr/openwin/lib
+RANLIB = /bin/true
+
+OMIT_GUI = true
+
+# These are used by admin/v4server/Makefile. They are determined
+# automatically by the krb5 beta 4 auto-configure, but we're not using
+# that right now.
+WAIT_USES_INT = true
+OPEN_NEEDS_FCNTL = true
+
+UTMP_FILE = /var/adm/utmp
+WTMP_FILE = /var/adm/wtmp
+UTMPX_FILE = /var/adm/utmpx
+WTMPX_FILE = /var/adm/wtmpx
diff --git a/src/kadmin/config.mk/sunos4.1.def b/src/kadmin/config.mk/sunos4.1.def
new file mode 100644
index 0000000000..942615511f
--- /dev/null
+++ b/src/kadmin/config.mk/sunos4.1.def
@@ -0,0 +1,22 @@
+export PS_ALL = ps auxww
+# Make sure there's no extra whitespace at the end of this line!
+export PS_PID = ps auxww
+# Make sure there's no extra whitespace at the end of this line!
+export PS_TTY = ps -t
+export RSH_CMD = /usr/ucb/rsh
+
+PCC_STRUCT_RETURN = -fpcc-struct-return
+TERMCAPLIB = -ltermcap
+
+XINCDIR = /usr/openwin/include
+XLIBDIR = /usr/openwin/lib
+
+UTMP_FILE = /etc/utmp
+WTMP_FILE = /usr/adm/wtmp
+
+D_NO_SETENV = -DNO_SETENV
+
+SHLIBCFLAGS := -fpic
+SHLIBLDFLAGS := -assert pure-text
+SHLIBEXT := so
+SHLIBSEP := .
diff --git a/src/kadmin/config.mk/template b/src/kadmin/config.mk/template
new file mode 100644
index 0000000000..caf3a2d9d2
--- /dev/null
+++ b/src/kadmin/config.mk/template
@@ -0,0 +1,142 @@
+# $Id$
+# $Source$
+
+export TOP
+
+KRB5B4 = true
+CONFDIR = $(TOP)/config.mk
+
+ifndef CUR_DIR
+CUR_DIR = .
+endif
+
+#
+# get the os name
+#
+
+include $(CONFDIR)/architecture
+
+#
+# Programs
+#
+IMAKE = imake
+# The purpose of this variable setting is to prevent -w from being
+# passed down via environment variables into sub-makes that use SunOS
+# Make rather than GNU make.
+ifndef MAKE_PRINT_DIRECTORY
+MAKE := $(MAKE) --no-print-directory MAKEFLAGS=$(MAKEFLAGS) MFLAGS=$(MFLAGS)
+endif
+CC = gcc
+AR = ar
+RANLIB = ranlib
+LD = ld
+RM = rm
+CLEAN = rm -f
+MV = mv
+LN = ln
+LNSOFT = $(LN) -s
+MAKEDEPEND = makedepend
+RPCGEN = rpcgen
+PERL = /usr/local/bin/perl
+DUMPPERL = /usr/local/bin/perl.static
+UNDUMP = undump
+YACC = $(TOP)/scripts/newyacc.sh
+GENPROT = $(TOP)/scripts/genproto.sh
+INSTCMD = install -c
+export INSTCMD
+PURIFY = purify
+PROOF = proof
+QUANTIFY = quantify
+LEX_LIB = -ll
+PERL = /usr/local/bin/perl
+OBJDUMP = /usr/local/bin/gobjdump
+OBJCOPY = /usr/local/bin/gobjcopy
+
+# 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 "*-*-*".
+
+DEJAFLAGS := $(DEJALFLAGS) $(CLFLAGS) --debug --host \
+ unknown-$(shell uname -m)-$(shell uname -s)$(shell uname -r)
+ifdef VERBOSE_TEST
+DEJAFLAGS += --verbose
+endif
+
+RUNTEST := runtest $(DEJAFLAGS)
+
+#
+# Flags. Since this is the initial setting, don't preserve current
+# values; otherwise, recursive makes will get the sum of everything.
+#
+YFLAGS = -d
+ARFLAGS = cru
+CFLAGS := $(CLFLAGS)
+LDFLAGS := $(CLFLAGS)
+
+#
+# The default target is "all". Put this before any includes, in case
+# the includes define new targets. Or perhaps they should be allowed
+# to define a new default target...
+#
+all::
+
+#
+# Get a unique number for files built in /tmp
+#
+__PID__ := $(shell echo $$$$)
+
+include $(CONFDIR)/config
+
+include $(CONFDIR)/rules
+
+expand IncludeArchFile
+
+include $(CONFDIR)/site.def
+
+ifdef STRIP_INSTALLED
+INST_PROG_FLAGS = -s
+endif
+
+# avoid makefiles from failing on default rules
+expand DefaultRules
+
+# include dependencies
+ifeq ($(shell [ -r Makefile.depend ] && echo yes),yes)
+include Makefile.depend
+endif
+
+# disable RCS frobbing
+% :: RCS/%,v
+
+# fix lex rule
+.l.c:
+ $(RM) -f $@
+ $(LEX) $(LFLAGS) -t $< > $@
+
+# error table rule
+.SUFFIXES: .et
+.et.c:
+ $(COMPILE_ET) $<
+.et.h:
+ $(COMPILE_ET) $<
+
+# rpcgen rule
+.SUFFIXES: .x
+.x.c:
+ $(RPCGEN) -o $@ -c $<
+.x.h:
+ $(RPCGEN) -o $@ -h $<
+
+# command table rule
+.SUFFIXES: .ct
+.ct.c:
+ $(MK_CMDS) $<
+.ct.h:
+ $(MK_CMDS) $<
+
+CMD="echo 'You must specify CMD to use the 'execute' rule.'; exit 1"
+
+execute:
+ @eval $(CMD)
diff --git a/src/kadmin/configure.in b/src/kadmin/configure.in
index 12d4f04ef2..959626b36d 100644
--- a/src/kadmin/configure.in
+++ b/src/kadmin/configure.in
@@ -1,5 +1,6 @@
AC_INIT(configure.in)
CONFIG_RULES
-CONFIG_DIRS(kpasswd v5server v5client ktutil)
+dnl CONFIG_DIRS(kpasswd v5server v5client)
+CONFIG_DIRS(create export import keytab cli dbutil passwd ktutil server v4server)
DO_SUBDIRS
V5_AC_OUTPUT_MAKEFILE
diff --git a/src/kadmin/create/ChangeLog b/src/kadmin/create/ChangeLog
new file mode 100644
index 0000000000..0c724422d8
--- /dev/null
+++ b/src/kadmin/create/ChangeLog
@@ -0,0 +1,9 @@
+Fri Jul 12 14:43:56 1996 Marc Horowitz <marc@mit.edu>
+
+ * configure.in (USE_GSSAPI_LIBRARY): shared libraries require that
+ all symbols be resolved, even if they are not used by the
+ executeable. Thus, create needs to link against gssapi
+
+Wed Jul 10 01:24:29 1996 Marc Horowitz <marc@mit.edu>
+
+ * Makefile.in, configure.in: added autoconf support
diff --git a/src/kadmin/create/Makefile.in b/src/kadmin/create/Makefile.in
new file mode 100644
index 0000000000..547bd39c6b
--- /dev/null
+++ b/src/kadmin/create/Makefile.in
@@ -0,0 +1,15 @@
+CFLAGS = $(CCOPTS) $(DEFS) $(LOCALINCLUDE)
+
+PROG = kdb5_create
+OBJS = kdb5_create.o kadm5_create.o string_table.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/src/kadmin/create/Makefile.ov b/src/kadmin/create/Makefile.ov
new file mode 100644
index 0000000000..cdec414b73
--- /dev/null
+++ b/src/kadmin/create/Makefile.ov
@@ -0,0 +1,12 @@
+TOP = ..
+include $(TOP)/config.mk/template
+
+PROG = kadmin_create
+SRCS = kdb5_create.c kadm5_create.c string_table.c
+OBJS = kdb5_create.o kadm5_create.o string_table.o
+
+LIBS = $(LIBADMSRV) $(LIBRPCLIB) $(LIBKDB5) $(LIBKRB5_ALL) \
+ $(LIBDYN) $(NDBMLIB) $(LIBDB) $(BSDLIB) $(NETLIB)
+
+expand InstallAdmin
+expand Depend
diff --git a/src/kadmin/create/attic/Makefile.in b/src/kadmin/create/attic/Makefile.in
new file mode 100644
index 0000000000..f7bd9ca381
--- /dev/null
+++ b/src/kadmin/create/attic/Makefile.in
@@ -0,0 +1,20 @@
+CFLAGS = $(CCOPTS) $(DEFS) $(LOCALINCLUDE)
+
+all::
+
+SRCS = $(srcdir)/ovsec_adm_create.c \
+ $(srcdir)/string_table.c
+
+OBJS = ovsec_adm_create.o \
+ string_table.o
+
+all:: ovsec_adm_create
+
+ovsec_adm_create: $(OBJS) $(DEPLIBS)
+ $(LD) $(LDFLAGS) $(LDARGS) -o ovsec_adm_create $(OBJS) $(LIBS)
+
+install::
+ $(INSTALL_PROGRAM) ./ovsec_adm_create ${DESTDIR}$(SERVER_BINDIR)/kadmind5
+
+clean::
+ $(RM) ovsec_adm_create
diff --git a/src/kadmin/create/attic/configure.in b/src/kadmin/create/attic/configure.in
new file mode 100644
index 0000000000..67b8f7c52b
--- /dev/null
+++ b/src/kadmin/create/attic/configure.in
@@ -0,0 +1,12 @@
+AC_INIT(ovsec_adm_create.c)
+CONFIG_RULES
+AC_PROG_INSTALL
+USE_KADMSRV_LIBRARY
+USE_GSSRPC_LIBRARY
+USE_GSSAPI_LIBRARY
+USE_KDB5_LIBRARY
+USE_DYN_LIBRARY
+USE_DB_LIBRARY
+KRB5_LIBRARIES
+V5_USE_SHARED_LIB
+V5_AC_OUTPUT_MAKEFILE
diff --git a/src/kadmin/create/attic/make_extern b/src/kadmin/create/attic/make_extern
new file mode 100644
index 0000000000..5432edf66a
--- /dev/null
+++ b/src/kadmin/create/attic/make_extern
@@ -0,0 +1,16 @@
+#!/bin/csh
+
+echo '/*'
+echo ' * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.'
+echo ' * '
+echo ' * $Header$'
+echo ' *'
+echo ' */'
+echo ' '
+echo '#ifndef _OVSEC_ADM_STRINGS_'
+echo ' '
+
+cat $1 | grep -v rcsid | grep ^char | awk '{printf "extern %s %s;\n",$1,$2}'
+
+echo ' '
+echo '#endif /* _OVSEC_ADM_STRINGS_ */'
diff --git a/src/kadmin/create/attic/ovsec_adm_create.c b/src/kadmin/create/attic/ovsec_adm_create.c
new file mode 100644
index 0000000000..90be0c406c
--- /dev/null
+++ b/src/kadmin/create/attic/ovsec_adm_create.c
@@ -0,0 +1,663 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Id$
+ * $Source$
+ *
+ * $Log$
+ * Revision 1.23 1996/07/22 20:24:35 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.22.4.1 1996/07/18 03:01:22 marc
+ * merged in changes from OV_9510_BP to OV_9510_FINAL1
+ *
+ * Revision 1.22.2.1 1996/06/20 21:44:55 marc
+ * File added to the repository on a branch
+ *
+ * Revision 1.22 1996/06/19 15:09:32 bjaspan
+ * changes to work in mit tree
+ *
+ * Revision 1.21 1995/11/07 23:27:28 grier
+ * Add stdlib.h
+ * Add string.h
+ *
+ * Revision 1.20 1995/08/13 16:41:11 jik
+ * Fix a nonsensical comment about the iterator() function. See PR
+ * secure-admin/470.
+ *
+ * Revision 1.19 1995/07/02 19:55:13 jik
+ * Key version numbers should start out at 1, not 0.
+ * Should get the master key version number from the master_db entry in
+ * server_kdb.c, rather than assuming that the master key version number
+ * is 0.
+ *
+ * Revision 1.18 1995/03/14 16:58:50 jik
+ * Use krb5_xfree instead of xfree if KRB5B4 is defined.
+ *
+ * Revision 1.17 1994/03/11 19:37:34 bjaspan
+ * [secure-admin/1593: ovsec_adm_create non-error messages go to stderr]
+ * [secure-releng/1608: audit secure-admin/1593: ovsec_adm_create non-error messages go to stderr]
+ *
+ * Sandbox:
+ *
+ * Normal messages should be printed to stdout rather than displayed
+ * using com_err, which will cause then to go to stderr.
+ *
+ * Revision 1.17 1994/03/09 22:21:33 jik
+ * Normal messages should be printed to stdout rather than displayed
+ * using com_err, which will cause then to go to stderr.
+ *
+ * Revision 1.16 1993/12/21 20:26:34 marc
+ * create new principals with policy NULL, not ""
+ *
+ * Revision 1.15 1993/12/14 22:51:35 marc
+ * missing * in call to krb5_random_key
+ *
+ * Revision 1.14 1993/11/27 20:42:32 bjaspan
+ * fix secure/621: coredumps with default realm
+ *
+ * Revision 1.13 1993/11/19 20:03:51 shanzer
+ * osa_adb_open_T takes a file name argument.
+ *
+ * Revision 1.12 1993/11/10 21:30:24 bjaspan
+ * move init code to main, accept -m
+ *
+ * Revision 1.11 1993/11/10 04:33:35 bjaspan
+ * rewrote adding principals to kdb, and set lifetimes
+ *
+ * Revision 1.10 1993/11/06 00:08:44 bjaspan
+ * use new OVSEC_KADM_* names, use correct realm
+ *
+ * Revision 1.9 1993/11/05 05:05:35 bjaspan
+ * added -r realm argument
+ *
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include "string_table.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ovsec_admin/adb.h>
+#include <ovsec_admin/admin.h>
+
+#include <krb5.h>
+#include <krb5/kdb.h>
+
+int add_admin_princ(void *handle, krb5_context context,
+ char *name, char *realm, int attrs, int lifetime);
+
+#define ERR 1
+#define OK 0
+
+#define ADMIN_LIFETIME 60*60*3 /* 3 hours */
+#define CHANGEPW_LIFETIME 60*5 /* 5 minutes */
+
+char *whoami;
+
+extern krb5_encrypt_block master_encblock;
+extern krb5_keyblock master_keyblock;
+extern krb5_db_entry master_db;
+
+/*
+ * Function: main
+ *
+ * Purpose: create admin principals, create and populate admin dbs
+ *
+ * Arguments:
+ *
+ * input none
+ * <return value> exit status 1 for error 0 for success
+ *
+ * Requires:
+ *
+ *
+ * Effects:
+ *
+ *
+ * Modifies:
+ *
+ */
+
+void usage()
+{
+ fprintf(stderr, "%s\n", str_PROG_CREATE_USAGE);
+ exit(1);
+}
+
+void main(int argc, char **argv)
+{
+ char *realm = NULL;
+ int freerealm = 0;
+ int retval, from_keyboard = 0;
+ krb5_principal creator = NULL;
+ void *handle;
+ krb5_context context;
+
+ whoami = str_PROG_NAME_CREATE;
+
+ argc--; argv++;
+ while (argc) {
+ if (strcmp(*argv, "-r") == 0) {
+ argc--; argv++;
+ if (!argc)
+ usage();
+ realm = *argv;
+ } else if (strcmp(*argv, "-m") == 0) {
+ from_keyboard = 1;
+ } else
+ break;
+ argc--; argv++;
+ }
+
+ if (argc != 0)
+ usage();
+
+ if (retval = krb5_init_context(&context))
+ exit(ERR);
+
+ if (realm == NULL) {
+ if ((retval = krb5_get_default_realm(context, &realm)) != 0)
+ exit(retval);
+ freerealm = 1;
+ }
+
+ if ((retval = ovsec_kadm_init(whoami, from_keyboard?"non-null":NULL,
+ NULL, realm,
+ OVSEC_KADM_STRUCT_VERSION,
+ OVSEC_KADM_API_VERSION_1,
+ &handle))) {
+ com_err(whoami, retval, str_INITING_KCONTEXT);
+
+ krb5_free_context(context);
+ exit(ERR);
+ }
+
+ retval = add_admin_princs(handle, context, realm);
+
+ ovsec_kadm_destroy(handle);
+ krb5_free_context(context);
+
+ if (retval)
+ exit(retval);
+
+ exit(0);
+}
+
+/*
+ * 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
+ */
+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 OVSEC_KADM_ADMIN_SERVICE,
+ * OVSEC_KADM_CHANGEPW_SERVICE, and OVSEC_KADM_HIST_PRINCIPAL. 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.
+ */
+int add_admin_princs(void *handle, krb5_context context, char *realm)
+{
+ krb5_error_code ret = 0;
+
+ if ((ret = add_admin_princ(handle, context,
+ OVSEC_KADM_ADMIN_SERVICE, realm,
+ KRB5_KDB_DISALLOW_TGT_BASED,
+ ADMIN_LIFETIME)))
+ goto clean_and_exit;
+
+ if ((ret = add_admin_princ(handle, context,
+ OVSEC_KADM_CHANGEPW_SERVICE, realm,
+ KRB5_KDB_DISALLOW_TGT_BASED |
+ KRB5_KDB_PWCHANGE_SERVICE,
+ CHANGEPW_LIFETIME)))
+ goto clean_and_exit;
+
+#if 0
+ /* this is now done inside kdb_init_hist in the admin server */
+
+ if ((ret = add_admin_princ(handle, context,
+ OVSEC_KADM_HIST_PRINCIPAL, realm,
+ KRB5_KDB_DISALLOW_ALL_TIX,
+ 0)))
+ goto clean_and_exit;
+#endif
+
+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;
+ int nprincs;
+ krb5_error_code ret;
+ ovsec_kadm_principal_ent_rec ent;
+
+ memset(&ent, 0, sizeof(ent));
+
+ fullname = build_name_with_realm(name, realm);
+ if (ret = krb5_parse_name(context, fullname, &ent.principal)) {
+ com_err(whoami, ret, str_PARSE_NAME);
+ return(ERR);
+ }
+ ent.max_life = lifetime;
+ ent.attributes = attrs;
+
+ if (ret = ovsec_kadm_create_principal(handle, &ent,
+ (OVSEC_KADM_PRINCIPAL |
+ OVSEC_KADM_MAX_LIFE |
+ OVSEC_KADM_ATTRIBUTES),
+ "to-be-random")) {
+ if (ret == OVSEC_KADM_DUP)
+ ret = ovsec_kadm_modify_principal(handle, &ent,
+ (OVSEC_KADM_PRINCIPAL |
+ OVSEC_KADM_MAX_LIFE |
+ OVSEC_KADM_ATTRIBUTES));
+
+ if (ret) {
+ com_err(whoami, ret, str_PUT_PRINC, fullname);
+ krb5_free_principal(context, ent.principal);
+ free(fullname);
+ return ERR;
+ }
+ }
+
+ ret = ovsec_kadm_randkey_principal(handle, ent.principal, NULL);
+
+ krb5_free_principal(context, ent.principal);
+ free(fullname);
+
+ if (ret) {
+ com_err(whoami, ret, str_RANDOM_KEY, fullname);
+ return ERR;
+ }
+
+ return OK;
+}
+
+#if 0
+/*
+ * Function: main
+ *
+ * Purpose: Return "garbage" if the caller asks for it.
+ *
+ * Arguments:
+ *
+ * input (input) A null-terminated string,
+ * or NULL.
+ * delay (input/output) The number of seconds the
+ * function should delay before returning.
+ * <return value> (output) A string.
+ *
+ * Requires:
+ *
+ * "input" must either be NULL or point to an address in the
+ * program's address space. "delay" must point to an address in
+ * the program's address space.
+ *
+ * Effects:
+ *
+ * The function first sleeps for approximately the number of
+ * seconds specified in "delay".
+ *
+ * Then, if "input" is non-NULL and points to a null-terminated
+ * string which is equal to "garbage", the function sets "delay"
+ * to 42 and returns a string allocated with malloc(3) containing
+ * "more-garbage".
+ *
+ * If "input" is NULL or does not contain "garbage", the function
+ * returns NULL without modifying "delay".
+ *
+ * If "<return value>" is non-NULL, the caller should deallocate
+ * the string in it (with free(3)) when it is no longer needed.
+ *
+ * Modifies:
+ *
+ * May allocate a new block of memory in the malloc(3) arena.
+ * May change the value in the memory location pointed to by
+ * "delay".
+ */
+
+krb5_error_code add_random_princ(princ_str, princ, attrs, lifetime,
+ creator, rseed)
+ char *princ_str;
+ krb5_principal princ, creator;
+ krb5_flags attrs;
+ int lifetime;
+ krb5_pointer *rseed;
+{
+ krb5_db_entry entry;
+ krb5_error_code ret;
+ krb5_encrypted_keyblock ekey;
+ krb5_keyblock *rkey;
+ int nentries = 1;
+
+ memset((char *) &entry, 0, sizeof(entry));
+ entry.principal = princ;
+ entry.kvno = 1;
+ entry.max_life = KRB5_KDB_MAX_LIFE;
+ entry.max_renewable_life = 0;
+ entry.mkvno = master_db.mkvno;
+ entry.expiration = KRB5_KDB_EXPIRATION;
+ entry.mod_name = creator;
+ if (lifetime != 0)
+ entry.max_life = lifetime;
+
+ if (ret = krb5_timeofday(&entry.mod_date))
+ return(ret);
+
+ entry.attributes = attrs;
+
+ ret = krb5_random_key(&master_encblock, *rseed, &rkey);
+ if (ret != 0) {
+ com_err(whoami, ret, str_RANDOM_KEY, princ_str);
+ return (ERR);
+ }
+
+
+ ret = krb5_kdb_encrypt_key(&master_encblock, rkey, &ekey);
+ krb5_free_keyblock(rkey);
+ if (ret != 0) {
+ com_err(whoami, ret, str_ENCRYPT_KEY, princ_str);
+ return (ERR);
+ }
+
+ entry.key = ekey;
+ entry.salt_type = KRB5_KDB_SALTTYPE_NORMAL;
+ entry.salt_length = 0;
+ entry.salt = 0;
+
+ ret = krb5_db_put_principal(&entry, &nentries);
+ if (ret != 0)
+ com_err(whoami, ret, str_PUT_PRINC, princ_str);
+#ifdef KRB5B4
+ krb5_xfree(ekey.contents);
+#else
+ xfree(ekey.contents);
+#endif
+
+ if (ret) return(ERR);
+
+ printf(str_CREATED_PRINC, whoami, princ_str);
+
+ return(OK);
+}
+
+/*
+ * Function: create_admin_policy_db
+ *
+ * Purpose: Return "garbage" if the caller asks for it.
+ *
+ * Arguments:
+ *
+ * input (input) A null-terminated string,
+ * or NULL.
+ * delay (input/output) The number of seconds the
+ * function should delay before returning.
+ * <return value> (output) A string.
+ *
+ * Requires:
+ *
+ * "input" must either be NULL or point to an address in the
+ * program's address space. "delay" must point to an address in
+ * the program's address space.
+ *
+ * Effects:
+ *
+ * The function first sleeps for approximately the number of
+ * seconds specified in "delay".
+ *
+ * Then, if "input" is non-NULL and points to a null-terminated
+ * string which is equal to "garbage", the function sets "delay"
+ * to 42 and returns a string allocated with malloc(3) containing
+ * "more-garbage".
+ *
+ * If "input" is NULL or does not contain "garbage", the function
+ * returns NULL without modifying "delay".
+ *
+ * If "<return value>" is non-NULL, the caller should deallocate
+ * the string in it (with free(3)) when it is no longer needed.
+ *
+ * Modifies:
+ *
+ * May allocate a new block of memory in the malloc(3) arena.
+ * May change the value in the memory location pointed to by
+ * "delay".
+ */
+
+int create_admin_policy_db()
+{
+ /* We don't have a create/destroy routine, so opening the db and
+ closing it will have to do. */
+ osa_adb_policy_t policy_db = NULL;
+ osa_adb_ret_t ret;
+
+ ret = osa_adb_open_policy(&policy_db, POLICY_DB);
+ if (ret != OSA_ADB_OK) {
+ com_err (whoami, ret, str_CREATING_POLICY_DB);
+ return(-1);
+ }
+
+ /* Should create sample policies here */
+
+ ret = osa_adb_close_policy(policy_db);
+ if (ret != OSA_ADB_OK) {
+ com_err (whoami, ret, str_CLOSING_POLICY_DB);
+ return(-1);
+ }
+
+ printf(str_CREATED_POLICY_DB, whoami);
+
+ return(OK);
+}
+
+/*
+
+ * Function: iterator(ptr, entry)
+ *
+ * Purpose:
+ *
+ * Creates an entry in the Admin database corresponding to the
+ * specified entry in the Kerberos database.
+ *
+ * Arguments:
+ *
+ * ptr (input) Actually of type osa_adb_princ_t,
+ * represents the Admin database in which to
+ * create the principal.
+ * entry (input) The entry in the Kerberos database for
+ * which to create an entry in the Admin
+ * database.
+ *
+ * Requires:
+ *
+ * "ptr" represents a valid, open Admin principal database.
+ * "entry" represents a valid, decoded Kerberos database
+ * principal entry.
+ *
+ * Effects:
+ *
+ * Modifies the Admin principal database by creating a principal
+ * in the database with the same name as "entry" and no other
+ * information.
+ *
+ * Modifies:
+ *
+ * Does not modify any global memory. Modifies the Admin
+ * principal database whose handle is passed into it.
+ */
+
+krb5_error_code
+iterator(ptr, entry)
+krb5_pointer ptr;
+krb5_db_entry *entry;
+{
+ osa_adb_ret_t retval;
+ krb5_error_code retval2;
+ char *princ_str = NULL;
+ osa_princ_ent_rec osa_princ;
+
+ /* Zero the whole struct, and fill in the princ name */
+ memset(&osa_princ, 0, sizeof(osa_princ_ent_rec));
+
+ osa_princ.name = entry->principal;
+ osa_princ.policy = NULL;
+
+ retval = osa_adb_create_princ((osa_adb_princ_t) ptr, &osa_princ);
+ if (retval != OSA_ADB_OK) {
+ if (retval2 = krb5_unparse_name(entry->principal, &princ_str)) {
+ com_err(whoami, retval2, str_UNPARSE_PRINC);
+ }
+ com_err(whoami, retval, str_CREATING_PRINC_ENTRY,
+ (princ_str ? princ_str : str_A_PRINC));
+ if (princ_str) free(princ_str);
+ }
+ return (0);
+}
+
+/*
+ * Function: create_and_populate_admin_princ_db
+ *
+ * Purpose: Return "garbage" if the caller asks for it.
+ *
+ * Arguments:
+ *
+ * input (input) A null-terminated string,
+ * or NULL.
+ * delay (input/output) The number of seconds the
+ * function should delay before returning.
+ * <return value> (output) A string.
+ *
+ * Requires:
+ *
+ * "input" must either be NULL or point to an address in the
+ * program's address space. "delay" must point to an address in
+ * the program's address space.
+ *
+ * Effects:
+ *
+ * The function first sleeps for approximately the number of
+ * seconds specified in "delay".
+ *
+ * Then, if "input" is non-NULL and points to a null-terminated
+ * string which is equal to "garbage", the function sets "delay"
+ * to 42 and returns a string allocated with malloc(3) containing
+ * "more-garbage".
+ *
+ * If "input" is NULL or does not contain "garbage", the function
+ * returns NULL without modifying "delay".
+ *
+ * If "<return value>" is non-NULL, the caller should deallocate
+ * the string in it (with free(3)) when it is no longer needed.
+ *
+ * Modifies:
+ *
+ * May allocate a new block of memory in the malloc(3) arena.
+ * May change the value in the memory location pointed to by
+ * "delay".
+ */
+
+int create_and_populate_admin_princ_db()
+{
+ osa_adb_princ_t princ_db = NULL;
+ osa_adb_ret_t ret;
+
+ /* We don't have a create/destroy routine, so opening the db and
+ closing it will have to do. */
+
+ ret = osa_adb_open_princ(&princ_db, PRINCIPAL_DB);
+ if (ret != OSA_ADB_OK) {
+ com_err (whoami, ret, str_CREATING_PRINC_DB);
+ return(-1);
+ }
+
+ printf(str_CREATED_PRINC_DB, whoami);
+
+ (void) krb5_db_iterate(iterator, princ_db);
+
+ ret = osa_adb_close_princ(princ_db);
+ if (ret != OSA_ADB_OK) {
+ com_err (whoami, ret, str_CLOSING_PRINC_DB);
+ return(-1);
+ }
+
+
+ return(OK);
+}
+
+#endif
diff --git a/src/kadmin/create/configure.in b/src/kadmin/create/configure.in
new file mode 100644
index 0000000000..4030342632
--- /dev/null
+++ b/src/kadmin/create/configure.in
@@ -0,0 +1,11 @@
+AC_INIT(kdb5_create.c)
+CONFIG_RULES
+AC_PROG_INSTALL
+USE_KADMSRV_LIBRARY
+USE_GSSRPC_LIBRARY
+USE_GSSAPI_LIBRARY
+USE_DYN_LIBRARY
+USE_KDB5_LIBRARY
+KRB5_LIBRARIES
+V5_USE_SHARED_LIB
+V5_AC_OUTPUT_MAKEFILE
diff --git a/src/kadmin/create/kadm5_create.c b/src/kadmin/create/kadm5_create.c
new file mode 100644
index 0000000000..33b30ec9c1
--- /dev/null
+++ b/src/kadmin/create/kadm5_create.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Id$
+ * $Source$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include "string_table.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <kadm5/adb.h>
+#include <kadm5/admin.h>
+
+#include <krb5.h>
+#include <krb5/kdb.h>
+
+int add_admin_princ(void *handle, krb5_context context,
+ char *name, char *realm, int attrs, int lifetime);
+
+#define ERR 1
+#define OK 0
+
+#define ADMIN_LIFETIME 60*60*3 /* 3 hours */
+#define CHANGEPW_LIFETIME 60*5 /* 5 minutes */
+
+extern char *whoami;
+
+extern krb5_encrypt_block master_encblock;
+extern krb5_keyblock master_keyblock;
+extern krb5_db_entry master_db;
+
+/*
+ * 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.
+ */
+void kadm5_create(kadm5_config_params *params)
+{
+ int retval;
+ void *handle;
+ krb5_context context;
+ FILE *f;
+
+
+ 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, params)) {
+ com_err(whoami, retval, str_INITING_KCONTEXT);
+ exit(1);
+ }
+
+ if (retval = osa_adb_create_policy_db(params)) {
+ com_err(whoami, retval, str_CREATING_POLICY_DB);
+ exit(1);
+ }
+
+ if ((retval = kadm5_init(whoami, NULL, NULL, params,
+ KADM5_STRUCT_VERSION,
+ KADM5_API_VERSION_2,
+ &handle))) {
+ com_err(whoami, retval, str_INITING_KCONTEXT);
+
+ krb5_free_context(context);
+ exit(ERR);
+ }
+
+ retval = add_admin_princs(handle, context, params->realm);
+
+ kadm5_destroy(handle);
+ krb5_free_context(context);
+
+ if (retval)
+ exit(retval);
+
+ exit(0);
+}
+
+/*
+ * 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
+ */
+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.
+ */
+int add_admin_princs(void *handle, krb5_context context, char *realm)
+{
+ krb5_error_code ret = 0;
+
+ 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;
+ int nprincs;
+ krb5_error_code ret;
+ kadm5_principal_ent_rec ent;
+
+ memset(&ent, 0, sizeof(ent));
+
+ fullname = build_name_with_realm(name, realm);
+ if (ret = krb5_parse_name(context, fullname, &ent.principal)) {
+ com_err(whoami, ret, str_PARSE_NAME);
+ return(ERR);
+ }
+ ent.max_life = lifetime;
+ ent.attributes = attrs;
+
+ if (ret = kadm5_create_principal(handle, &ent,
+ (KADM5_PRINCIPAL |
+ KADM5_MAX_LIFE |
+ KADM5_ATTRIBUTES),
+ "to-be-random")) {
+ if (ret == KADM5_DUP)
+ ret = kadm5_modify_principal(handle, &ent,
+ (KADM5_PRINCIPAL |
+ KADM5_MAX_LIFE |
+ KADM5_ATTRIBUTES));
+
+ if (ret) {
+ com_err(whoami, ret, str_PUT_PRINC, fullname);
+ krb5_free_principal(context, ent.principal);
+ free(fullname);
+ return ERR;
+ }
+ }
+
+ ret = kadm5_randkey_principal(handle, ent.principal, NULL, NULL);
+
+ krb5_free_principal(context, ent.principal);
+ free(fullname);
+
+ if (ret) {
+ com_err(whoami, ret, str_RANDOM_KEY, fullname);
+ return ERR;
+ }
+
+ return OK;
+}
diff --git a/src/kadmin/create/kdb5_create.c b/src/kadmin/create/kdb5_create.c
new file mode 100644
index 0000000000..8b167b6b93
--- /dev/null
+++ b/src/kadmin/create/kdb5_create.c
@@ -0,0 +1,536 @@
+/*
+ * admin/create/kdb5_create.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. M.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.
+ */
+
+#include <stdio.h>
+#include <k5-int.h>
+#include <kadm5/admin.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_encrypt_block *eblock;
+ krb5_pointer rseed;
+ 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_encrypt_block *) NULL,
+ (krb5_pointer) NULL,
+ 1,
+ &def_kslist
+};
+
+struct iterate_args {
+ krb5_context ctx;
+ struct realm_info *rblock;
+ krb5_db_entry *dbentp;
+};
+
+static krb5_error_code add_principal
+ PROTOTYPE((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
+ */
+
+static void
+usage(who, status)
+char *who;
+int status;
+{
+ fprintf(stderr, "usage: %s [-d dbpathname] [-r realmname] [-k enctype]\n\
+\t[-M mkeyname]\n",
+ who);
+ exit(status);
+}
+
+krb5_keyblock master_keyblock;
+krb5_principal master_princ;
+krb5_encrypt_block master_encblock;
+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 */
+};
+
+char *mkey_password = 0;
+char *whoami;
+
+void
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ extern char *optarg;
+ int optchar;
+
+ krb5_error_code retval;
+ char *dbname = (char *) NULL;
+ char *realm = 0;
+ char *mkey_name = 0;
+ char *mkey_fullname;
+ char *defrealm;
+ char *pw_str = 0;
+ char *keyfile = 0;
+ int pw_size = 0;
+ int enctypedone = 0;
+ int do_stash = 0;
+ krb5_data pwd;
+ krb5_context context;
+ krb5_realm_params *rparams;
+ kadm5_config_params kadm5_params;
+
+ memset(&kadm5_params, 0, sizeof(kadm5_params));
+
+ krb5_init_context(&context);
+ krb5_init_ets(context);
+
+ if (strrchr(argv[0], '/'))
+ argv[0] = strrchr(argv[0], '/')+1;
+ whoami = argv[0];
+
+ kadm5_params.mask |= KADM5_CONFIG_MKEY_FROM_KBD;
+ kadm5_params.mkey_from_kbd = 1;
+
+ while ((optchar = getopt(argc, argv, "d:r:k:M:e:P:sf:")) != EOF) {
+ switch(optchar) {
+ case 'd': /* set db name */
+ kadm5_params.dbname = dbname = optarg;
+ kadm5_params.mask |= KADM5_CONFIG_DBNAME;
+ break;
+ case 'r':
+ kadm5_params.realm = realm = optarg;
+ kadm5_params.mask |= KADM5_CONFIG_REALM;
+ break;
+ case 'k':
+ if (!krb5_string_to_enctype(optarg, &master_keyblock.enctype)){
+ enctypedone++;
+ kadm5_params.enctype = master_keyblock.enctype;
+ kadm5_params.mask |= KADM5_CONFIG_ENCTYPE;
+ }
+ else
+ com_err(argv[0], 0, "%s is an invalid enctype", optarg);
+ break;
+ case 's':
+ do_stash++;
+ kadm5_params.mkey_from_kbd = 0;
+ break;
+ case 'f':
+ kadm5_params.stash_file = keyfile = optarg;
+ kadm5_params.mask |= KADM5_CONFIG_STASH_FILE;
+ break;
+ case 'M': /* master key name in DB */
+ kadm5_params.mkey_name = mkey_name = optarg;
+ kadm5_params.mask |= KADM5_CONFIG_MKEY_NAME;
+ break;
+ case 'P': /* Only used for testing!!! */
+ mkey_password = optarg;
+ break;
+ case '?':
+ default:
+ usage(argv[0], 1);
+ /*NOTREACHED*/
+ }
+ }
+
+ /*
+ * Attempt to read the KDC profile. If we do, then read appropriate values
+ * from it and augment values supplied on the command line.
+ */
+ if (!(retval = krb5_read_realm_params(context,
+ realm,
+ (char *) NULL,
+ (char *) NULL,
+ &rparams))) {
+ /* Get the value for the database */
+ if (rparams->realm_dbname && !dbname)
+ dbname = strdup(rparams->realm_dbname);
+
+ /* Get the value for the master key name */
+ if (rparams->realm_mkey_name && !mkey_name)
+ mkey_name = strdup(rparams->realm_mkey_name);
+
+ /* Get the value for the master key type */
+ if (rparams->realm_enctype_valid && !enctypedone) {
+ master_keyblock.enctype = rparams->realm_enctype;
+ enctypedone++;
+ }
+
+ /* Get the value for maximum ticket lifetime. */
+ if (rparams->realm_max_life_valid)
+ rblock.max_life = rparams->realm_max_life;
+
+ /* Get the value for maximum renewable ticket lifetime. */
+ if (rparams->realm_max_rlife_valid)
+ rblock.max_rlife = rparams->realm_max_rlife;
+
+ /* Get the value for the default principal expiration */
+ if (rparams->realm_expiration_valid)
+ rblock.expiration = rparams->realm_expiration;
+
+ /* Get the value for the default principal flags */
+ if (rparams->realm_flags_valid)
+ rblock.flags = rparams->realm_flags;
+
+ /* Get the value of the supported key/salt pairs */
+ if (rparams->realm_num_keysalts) {
+ rblock.nkslist = rparams->realm_num_keysalts;
+ rblock.kslist = rparams->realm_keysalts;
+ rparams->realm_num_keysalts = 0;
+ rparams->realm_keysalts = (krb5_key_salt_tuple *) NULL;
+ }
+
+ /* Get the value for the stash file */
+ if (rparams->realm_stash_file && !keyfile)
+ keyfile = strdup(rparams->realm_stash_file);
+
+ krb5_free_realm_params(context, rparams);
+ }
+
+ if (!dbname)
+ dbname = DEFAULT_KDB_FILE;
+
+ if (!enctypedone)
+ master_keyblock.enctype = DEFAULT_KDC_ENCTYPE;
+
+ if (!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(1);
+ }
+
+ krb5_use_enctype(context, &master_encblock, master_keyblock.enctype);
+
+ retval = krb5_db_set_name(context, dbname);
+ if (!retval) retval = EEXIST;
+
+ if (retval == EEXIST || retval == EACCES || retval == EPERM) {
+ /* it exists ! */
+ com_err(argv[0], 0, "The database '%s' appears to already exist",
+ dbname);
+ exit(1);
+ }
+ if (!realm) {
+ if ((retval = krb5_get_default_realm(context, &defrealm))) {
+ com_err(argv[0], retval, "while retrieving default realm name");
+ exit(1);
+ }
+ realm = defrealm;
+ }
+
+ /* assemble & parse the master key name */
+
+ if ((retval = krb5_db_setup_mkey_name(context, mkey_name, realm,
+ &mkey_fullname, &master_princ))) {
+ com_err(argv[0], retval, "while setting up master key name");
+ exit(1);
+ }
+
+ 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 (!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(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(1);
+ }
+ mkey_password = pw_str;
+ }
+
+ pwd.data = mkey_password;
+ pwd.length = strlen(mkey_password);
+ retval = krb5_principal2salt(context, master_princ, &master_salt);
+ if (retval) {
+ com_err(argv[0], retval, "while calculated master key salt");
+ exit(1);
+ }
+ if (retval = krb5_string_to_key(context, &master_encblock,
+ &master_keyblock, &pwd, &master_salt)) {
+ com_err(argv[0], retval, "while transforming master key from password");
+ exit(1);
+ }
+
+ if ((retval = krb5_process_key(context, &master_encblock,
+ &master_keyblock))) {
+ com_err(argv[0], retval, "while processing master key");
+ exit(1);
+ }
+
+ rblock.eblock = &master_encblock;
+ if ((retval = krb5_init_random_key(context, &master_encblock,
+ &master_keyblock, &rblock.rseed))) {
+ com_err(argv[0], retval, "while initializing random key generator");
+ (void) krb5_finish_key(context, &master_encblock);
+ exit(1);
+ }
+ if ((retval = krb5_db_create(context, dbname))) {
+ (void) krb5_finish_key(context, &master_encblock);
+ (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed);
+ com_err(argv[0], retval, "while creating database '%s'",
+ dbname);
+ exit(1);
+ }
+ if ((retval = krb5_db_set_name(context, dbname))) {
+ (void) krb5_finish_key(context, &master_encblock);
+ (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed);
+ com_err(argv[0], retval, "while setting active database to '%s'",
+ dbname);
+ exit(1);
+ }
+ if ((retval = krb5_db_init(context))) {
+ (void) krb5_finish_key(context, &master_encblock);
+ (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed);
+ com_err(argv[0], retval, "while initializing the database '%s'",
+ dbname);
+ exit(1);
+ }
+
+ if ((retval = add_principal(context, master_princ, MASTER_KEY, &rblock)) ||
+ (retval = add_principal(context, &tgt_princ, TGT_KEY, &rblock))) {
+ (void) krb5_db_fini(context);
+ (void) krb5_finish_key(context, &master_encblock);
+ (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed);
+ com_err(argv[0], retval, "while adding entries to the database");
+ exit(1);
+ }
+ if (do_stash &&
+ ((retval = krb5_db_store_mkey(context, keyfile, master_princ,
+ &master_keyblock)))) {
+ com_err(argv[0], errno, "while storing key");
+ printf("Warning: couldn't stash master key.\n");
+ }
+ /* clean up */
+ (void) krb5_db_fini(context);
+ (void) krb5_finish_key(context, &master_encblock);
+ (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed);
+ 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);
+
+ kadm5_create(&kadm5_params);
+
+ exit(0);
+
+}
+
+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 random_keyblock, *key;
+ krb5_int32 ind;
+ krb5_encrypt_block random_encblock;
+ krb5_pointer rseed;
+ 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.
+ */
+ krb5_use_enctype(context, &random_encblock, ksent->ks_enctype);
+ pwd.data = mkey_password;
+ pwd.length = strlen(mkey_password);
+ if (kret = krb5_string_to_key(context, &random_encblock, &random_keyblock,
+ &pwd, &master_salt))
+ return kret;
+ if ((kret = krb5_init_random_key(context, &random_encblock,
+ &random_keyblock, &rseed)))
+ return kret;
+
+ if (!(kret = krb5_dbe_create_key_data(iargs->ctx, iargs->dbentp))) {
+ ind = iargs->dbentp->n_key_data-1;
+ if (!(kret = krb5_random_key(context,
+ &random_encblock, rseed,
+ &key))) {
+ kret = krb5_dbekd_encrypt_key_data(context,
+ iargs->rblock->eblock,
+ key,
+ NULL,
+ 1,
+ &iargs->dbentp->key_data[ind]);
+ krb5_free_keyblock(context, key);
+ }
+ }
+ memset((char *)random_keyblock.contents, 0, random_keyblock.length);
+ free(random_keyblock.contents);
+ (void) krb5_finish_random_key(context, &random_encblock, &rseed);
+ 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->eblock,
+ &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_dbe_free_contents(context, &entry);
+ return retval;
+}
diff --git a/src/kadmin/create/string_table.c b/src/kadmin/create/string_table.c
new file mode 100644
index 0000000000..b9f86a3634
--- /dev/null
+++ b/src/kadmin/create/string_table.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Header$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+/* String table of messages for kadm5_create */
+
+char *str_INITING_KCONTEXT = "while initializing the kerberos context";
+
+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 calling 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/src/kadmin/create/string_table.h b/src/kadmin/create/string_table.h
new file mode 100644
index 0000000000..e8cb45367c
--- /dev/null
+++ b/src/kadmin/create/string_table.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Header$
+ *
+ */
+
+#ifndef _OVSEC_ADM_STRINGS_
+
+extern char *str_INITING_KCONTEXT;
+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/src/kadmin/dbutil/ChangeLog b/src/kadmin/dbutil/ChangeLog
new file mode 100644
index 0000000000..7719cc749b
--- /dev/null
+++ b/src/kadmin/dbutil/ChangeLog
@@ -0,0 +1,440 @@
+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/src/kadmin/dbutil/Makefile.in b/src/kadmin/dbutil/Makefile.in
new file mode 100644
index 0000000000..b5bba09d99
--- /dev/null
+++ b/src/kadmin/dbutil/Makefile.in
@@ -0,0 +1,18 @@
+CFLAGS = $(CCOPTS) $(DEFS) -DKDB4_DISABLE $(LOCALINCLUDE) @KRB4_INCLUDES@
+
+PROG = kdb5_util
+OBJS = kdb5_create.o kadm5_create.o string_table.o
+OBJS = kdb5_util.o kdb5_util_ct.o dump.o dumpv4.o loadv4.o ss_wrapper.o \
+ kdb5_create.o kadm5_create.o string_table.o kdb5_stash.o \
+ kdb5_destroy.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/src/kadmin/dbutil/Makefile.ov b/src/kadmin/dbutil/Makefile.ov
new file mode 100644
index 0000000000..f762282f25
--- /dev/null
+++ b/src/kadmin/dbutil/Makefile.ov
@@ -0,0 +1,19 @@
+TOP = ..
+include $(TOP)/config.mk/template
+
+CFLAGS += -I$(TOP)/../include/kerberosIV
+
+PROG = kdb5_util
+SRCS = kdb5_util.c kdb5_util_ct.c dump.c ss_wrapper.c dumpv4.c loadv4.c \
+ kdb5_create.c kadm5_create.c string_table.c kdb5_stash.c \
+ kdb5_destroy.c
+OBJS = kdb5_util.o kdb5_util_ct.o dump.o dumpv4.o loadv4.o ss_wrapper.o \
+ kdb5_create.o kadm5_create.o string_table.o kdb5_stash.o \
+ kdb5_destroy.o
+ETABLES = kdb5_util_ct.ct
+
+LIBS = $(LIBADMSRV) $(LIBKDB5) $(LIBKRB5_ALL) $(LIBRPCLIB) $(LIBDYN) \
+ $(LIBSS) $(LIBDB)
+
+expand NormalProgram
+expand ErrorTables
diff --git a/src/kadmin/dbutil/configure.in b/src/kadmin/dbutil/configure.in
new file mode 100644
index 0000000000..c9234524ef
--- /dev/null
+++ b/src/kadmin/dbutil/configure.in
@@ -0,0 +1,13 @@
+AC_INIT(kdb5_create.c)
+CONFIG_RULES
+WITH_KRB4
+AC_PROG_INSTALL
+USE_KADMSRV_LIBRARY
+USE_GSSRPC_LIBRARY
+USE_KDB5_LIBRARY
+USE_DYN_LIBRARY
+USE_SS_LIBRARY
+USE_KRB4_LIBRARY
+KRB5_LIBRARIES
+V5_USE_SHARED_LIB
+V5_AC_OUTPUT_MAKEFILE
diff --git a/src/kadmin/dbutil/dump.c b/src/kadmin/dbutil/dump.c
new file mode 100644
index 0000000000..8bd54ca4dd
--- /dev/null
+++ b/src/kadmin/dbutil/dump.c
@@ -0,0 +1,1957 @@
+/*
+ * admin/edit/dump.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. M.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/adb.h>
+#include <com_err.h>
+#include "kdb5_util.h"
+#if HAVE_REGEX_H
+#include <regex.h>
+#endif /* HAVE_REGEX_H */
+
+/*
+ * 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 PROTOTYPE((krb5_pointer,
+ krb5_db_entry *));
+static krb5_error_code dump_k5beta6_iterator PROTOTYPE((krb5_pointer,
+ krb5_db_entry *));
+static krb5_error_code dump_k5beta7_princ PROTOTYPE((krb5_pointer,
+ krb5_db_entry *));
+static void dump_k5beta7_policy PROTOTYPE((void *, osa_policy_ent_t));
+
+typedef krb5_error_code (*dump_func)PROTOTYPE((krb5_pointer,
+ krb5_db_entry *));
+
+static int process_k5beta_record PROTOTYPE((char *, krb5_context,
+ FILE *, int, int *, void *));
+static int process_k5beta6_record PROTOTYPE((char *, krb5_context,
+ FILE *, int, int *, void *));
+static int process_k5beta7_record PROTOTYPE((char *, krb5_context,
+ FILE *, int, int *, void *));
+typedef krb5_error_code (*load_func)PROTOTYPE((char *, krb5_context,
+ FILE *, int, int *, void *));
+
+typedef struct _dump_version {
+ char *name;
+ char *header;
+ 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",
+ 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",
+ dump_k5beta6_iterator,
+ NULL,
+ process_k5beta6_record,
+};
+dump_version beta7_version = {
+ "Kerberos version 5",
+ "kdb5_util load_dump version 4\n",
+ dump_k5beta7_princ,
+ 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 */
+
+static const char k5beta_dump_header[] = "kdb5_edit load_dump version 2.0\n";
+static const char k5beta6_dump_header[] = "kdb5_edit load_dump version 3.0\n";
+static const char k5beta7_dump_header[] = "kdb5_edit load_dump version 4\n";
+
+static const char null_mprinc_name[] = "kdb5_dump@MISSING";
+
+/* Message strings */
+static const char regex_err[] = "%s: regular expression error - %s\n";
+static const char regex_merr[] = "%s: regular expression match error - %s\n";
+static const char pname_unp_err[] = "%s: cannot unparse principal name (%s)\n";
+static const char mname_unp_err[] = "%s: cannot unparse modifier name (%s)\n";
+static const char nokeys_err[] = "%s: cannot find any standard key for %s\n";
+static const char sdump_tl_inc_err[] = "%s: tagged data list inconsistency for %s (counted %d, stored %d)\n";
+static const char stand_fmt_name[] = "Kerberos version 5";
+static const char old_fmt_name[] = "Kerberos version 5 old format";
+static const char b6_fmt_name[] = "Kerberos version 5 beta 6 format";
+static const char ofopen_error[] = "%s: cannot open %s for writing (%s)\n";
+static const char oflock_error[] = "%s: cannot lock %s (%s)\n";
+static const char dumprec_err[] = "%s: error performing %s dump (%s)\n";
+static const char dumphdr_err[] = "%s: error dumping %s header (%s)\n";
+static const char trash_end_fmt[] = "%s(%d): ignoring trash at end of line: ";
+static const char read_name_string[] = "name string";
+static const char read_key_type[] = "key type";
+static const char read_key_data[] = "key data";
+static const char read_pr_data1[] = "first set of principal attributes";
+static const char read_mod_name[] = "modifier name";
+static const char read_pr_data2[] = "second set of principal attributes";
+static const char read_salt_data[] = "salt data";
+static const char read_akey_type[] = "alternate key type";
+static const char read_akey_data[] = "alternate key data";
+static const char read_asalt_type[] = "alternate salt type";
+static const char read_asalt_data[] = "alternate salt data";
+static const char read_exp_data[] = "expansion data";
+static const char store_err_fmt[] = "%s(%d): cannot store %s(%s)\n";
+static const char add_princ_fmt[] = "%s\n";
+static const char parse_err_fmt[] = "%s(%d): cannot parse %s (%s)\n";
+static const char read_err_fmt[] = "%s(%d): cannot read %s\n";
+static const char no_mem_fmt[] = "%s(%d): no memory for buffers\n";
+static const char rhead_err_fmt[] = "%s(%d): cannot match size tokens\n";
+static const char err_line_fmt[] = "%s: error processing line %d of %s\n";
+static const char head_bad_fmt[] = "%s: dump header bad in %s\n";
+static const char read_bytecnt[] = "record byte count";
+static const char read_encdata[] = "encoded data";
+static const char n_name_unp_fmt[] = "%s(%s): cannot unparse name\n";
+static const char n_dec_cont_fmt[] = "%s(%s): cannot decode contents\n";
+static const char read_nint_data[] = "principal static attributes";
+static const char read_tcontents[] = "tagged data contents";
+static const char read_ttypelen[] = "tagged data type and length";
+static const char read_kcontents[] = "key data contents";
+static const char read_ktypelen[] = "key data type and length";
+static const char read_econtents[] = "extra data contents";
+static const char k5beta_fmt_name[] = "Kerberos version 5 old format";
+static const char standard_fmt_name[] = "Kerberos version 5 format";
+static const char lusage_err_fmt[] = "%s: usage is %s [%s] [%s] [%s] filename dbname [admin_dbname]\n";
+static const char no_name_mem_fmt[] = "%s: cannot get memory for temporary name\n";
+static const char ctx_err_fmt[] = "%s: cannot initialize Kerberos context\n";
+static const char stdin_name[] = "standard input";
+static const char restfail_fmt[] = "%s: %s restore failed\n";
+static const char close_err_fmt[] = "%s: cannot close database (%s)\n";
+static const char dbinit_err_fmt[] = "%s: cannot initialize database (%s)\n";
+static const char dbname_err_fmt[] = "%s: cannot set database name to %s (%s)\n";
+static const char dbdelerr_fmt[] = "%s: cannot delete bad database %s (%s)\n";
+static const char dbrenerr_fmt[] = "%s: cannot rename database %s to %s (%s)\n";
+static const char dbcreaterr_fmt[] = "%s: cannot create database %s (%s)\n";
+static const char dfile_err_fmt[] = "%s: cannot open %s (%s)\n";
+
+static const char oldoption[] = "-old";
+static const char b6option[] = "-b6";
+static const char verboseoption[] = "-verbose";
+static const char updateoption[] = "-update";
+static const char dump_tmptrail[] = "~";
+
+/*
+ * 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.
+ */
+ if (match_error = regcomp(&match_exp,
+ arglist->names[i],
+ REG_EXTENDED)) {
+ 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.
+ */
+ if (match_error = regexec(&match_exp, name, 1, &match_match, 0)) {
+ 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,
+ &regexp_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 ((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);
+}
+
+/*
+ * 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);
+}
+
+/*
+ * 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_tl_data *pwchg;
+ 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);
+ }
+ /*
+ * 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;
+{
+ krb5_error_code retval;
+ struct dump_args *arg;
+ char *name;
+ krb5_tl_data *tlp;
+ krb5_key_data *kdata;
+ int counter, 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);
+ }
+ /*
+ * 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. Bracketed fields absence is indicated by a -1 in its
+ * place
+ */
+
+ /*
+ * Make sure that the tagged list is reasonably correct.
+ */
+ counter = 0;
+ for (tlp = entry->tl_data; tlp; tlp = tlp->tl_data_next)
+ counter++;
+ if (counter == 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),
+ (int) entry->n_tl_data,
+ (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) {
+ 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, (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;
+{
+ 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(ptr, entry);
+ arg->nnames = tmp_nnames;
+ }
+
+ free(name);
+ return retval;
+}
+
+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);
+}
+
+/*
+ * usage is:
+ * dump_db [-old] [-b6] [-verbose] [filename [principals...]]
+ */
+void
+dump_db(argc, argv)
+ int argc;
+ char **argv;
+{
+ FILE *f;
+ struct dump_args arglist;
+ int error;
+ char *programname;
+ char *ofile;
+ krb5_error_code kret;
+ dump_version *dump;
+ int aindex;
+ krb5_boolean locked;
+ extern osa_adb_policy_t policy_db;
+
+ /*
+ * Parse the arguments.
+ */
+ programname = argv[0];
+ if (strrchr(programname, (int) '/'))
+ programname = strrchr(argv[0], (int) '/') + 1;
+ ofile = (char *) NULL;
+ error = 0;
+ dump = &beta7_version;
+ arglist.verbose = 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], verboseoption))
+ arglist.verbose++;
+ 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;
+ }
+ }
+
+ /*
+ * Attempt to open the database. The policy database only has to
+ * be opened if we try a dump that uses it.
+ */
+ if (!dbactive || (dump->dump_policy != NULL && policy_db == NULL)) {
+ com_err(argv[0], 0, Err_no_database);
+ exit_status++;
+ return;
+ }
+
+ kret = 0;
+ locked = 0;
+ if (ofile && strcmp(ofile, "-")) {
+ /*
+ * 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++;
+ }
+ 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 ((kret = krb5_db_iterate(util_context,
+ dump->dump_princ,
+ (krb5_pointer) &arglist))) {
+ fprintf(stderr, dumprec_err,
+ programname, dump->name, error_message(kret));
+ exit_status++;
+ }
+ if (dump->dump_policy &&
+ (kret = osa_adb_iter_policy(policy_db, dump->dump_policy,
+ &arglist))) {
+ fprintf(stderr, dumprec_err, programname, dump->name,
+ error_message(kret));
+ exit_status++;
+ }
+ if (ofile && !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 = (char) 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, pol_db)
+ char *fname;
+ krb5_context kcontext;
+ FILE *filep;
+ int verbose;
+ int *linenop;
+ void *pol_db;
+{
+ 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;
+ char *shortcopy = (krb5_octet *) malloc(shortlen);
+ char *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;
+ char *shortcopy = (krb5_octet *) malloc(shortlen);
+ char *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, pol_db)
+ char *fname;
+ krb5_context kcontext;
+ FILE *filep;
+ int verbose;
+ int *linenop;
+ void *pol_db;
+{
+ 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 */
+ 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);
+}
+
+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 = osa_adb_create_policy(pol_db, &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 krb5b6 format.
+ *
+ * Returns -1 for end of file, 0 for success and 1 for failure.
+ */
+static int
+process_k5beta7_record(fname, kcontext, filep, verbose, linenop, pol_db)
+ char *fname;
+ krb5_context kcontext;
+ FILE *filep;
+ int verbose;
+ int *linenop;
+ void *pol_db;
+{
+ 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, pol_db);
+ else if (strcmp(rectype, "policy") == 0)
+ process_k5beta7_policy(fname, kcontext, filep, verbose,
+ linenop, pol_db);
+ 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, pol_db)
+ char *programname;
+ krb5_context kcontext;
+ char *dumpfile;
+ FILE *f;
+ int verbose;
+ dump_version *dump;
+ osa_adb_policy_t pol_db;
+{
+ int error;
+ int lineno;
+
+ error = 0;
+ lineno = 1;
+
+ /*
+ * Process the records.
+ */
+ while (!(error = (*dump->load_record)(dumpfile,
+ kcontext,
+ f,
+ verbose,
+ &lineno,
+ pol_db)))
+ ;
+ if (error != -1)
+ fprintf(stderr, err_line_fmt, programname, lineno, dumpfile);
+ else
+ error = 0;
+
+ return(error);
+}
+
+/*
+ * Usage is
+ * load_db [-old] [-verbose] [-update] filename dbname
+ */
+void
+load_db(argc, argv)
+ int argc;
+ char **argv;
+{
+ kadm5_config_params newparams;
+ osa_adb_policy_t pol_db;
+ krb5_error_code kret;
+ krb5_context kcontext;
+ FILE *f;
+ extern char *optarg;
+ extern int optind;
+ char *programname;
+ char *dumpfile;
+ char *dbname, *adbname;
+ char *dbname_tmp, *adbname_real;
+ char buf[BUFSIZ];
+ dump_version *load;
+ int update, verbose;
+ int aindex;
+
+ /*
+ * Parse the arguments.
+ */
+ programname = argv[0];
+ if (strrchr(programname, (int) '/'))
+ programname = strrchr(argv[0], (int) '/') + 1;
+ dumpfile = (char *) NULL;
+ dbname = (char *) NULL;
+ load = NULL;
+ update = 0;
+ verbose = 0;
+ 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], verboseoption))
+ verbose = 1;
+ else if (!strcmp(argv[aindex], updateoption))
+ update = 1;
+ else
+ break;
+ }
+ if ((argc - aindex) != 2 && (argc - aindex) != 3) {
+ fprintf(stderr, lusage_err_fmt, argv[0], argv[0],
+ oldoption, verboseoption, updateoption);
+ exit_status++;
+ return;
+ }
+
+ dumpfile = argv[aindex];
+ dbname = argv[aindex+1];
+ adbname = argv[aindex+2];
+ 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;
+ }
+ krb5_init_ets(kcontext);
+
+ /*
+ * 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) {
+ if (strcmp(buf, 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 {
+ fprintf(stderr, head_bad_fmt, programname, dumpfile);
+ exit_status++;
+ if (dumpfile) fclose(f);
+ return;
+ }
+
+ if (load != &beta7_version && adbname != NULL) {
+ fprintf(stderr, lusage_err_fmt, argv[0], argv[0],
+ oldoption, verboseoption, updateoption);
+ exit_status++;
+ return;
+ }
+ }
+
+ /*
+ * Cons up config params for new policy database. Use adbname is
+ * specified, otherwise let the policy dbname key off the dbname.
+ * However, after the name is retrieved, change the actual file
+ * name to a temp name that we'll rename later (but use the
+ * correct lock file).
+ */
+ newparams = global_params;
+ newparams.mask &= ~(KADM5_CONFIG_ADBNAME | KADM5_CONFIG_ADB_LOCKFILE);
+ newparams.dbname = dbname;
+ newparams.mask |= KADM5_CONFIG_DBNAME;
+ if (adbname) {
+ newparams.admin_dbname = adbname;
+ newparams.mask |= KADM5_CONFIG_ADBNAME;
+ }
+ if (kret = kadm5_get_config_params(kcontext, NULL, NULL, &newparams,
+ &newparams)) {
+ fprintf(stderr, "%s while retrieiving configuration "
+ "parameters.\n", error_message(kret));
+ if (dumpfile) fclose(f);
+ exit_status++;
+ return;
+ }
+ adbname_real = newparams.admin_dbname;
+ newparams.admin_dbname = (char *) malloc(strlen(adbname_real) +
+ strlen(dump_tmptrail) + 1);
+ strcpy(newparams.admin_dbname, adbname_real);
+ strcat(newparams.admin_dbname, dump_tmptrail);
+
+ /*
+ * Create the new database if not an update restoration. Always
+ * create the policy db, even if we are not loading a dump file
+ * with policy info, because they may be loading an old dump
+ * intending to use it with the new kadm5 system (ie: using load
+ * as create).
+ */
+ if (!update && (kret = krb5_db_create(kcontext, dbname_tmp))) {
+ fprintf(stderr, dbcreaterr_fmt,
+ programname, dbname, error_message(kret));
+ exit_status++;
+ kadm5_free_config_params(kcontext, &newparams);
+ if (dumpfile) fclose(f);
+ return;
+ }
+ if (!update && (kret = osa_adb_create_policy_db(&newparams))) {
+ fprintf(stderr, "%s: %s while creating policy database\n",
+ programname, error_message(kret));
+ kadm5_free_config_params(kcontext, &newparams);
+ if (dumpfile) fclose(f);
+ return;
+ }
+
+ /*
+ * Point ourselves at the new databases.
+ */
+ if (kret = krb5_db_set_name(kcontext,
+ (update) ? dbname : dbname_tmp)) {
+ fprintf(stderr, dbname_err_fmt,
+ programname,
+ (update) ? dbname : dbname_tmp, error_message(kret));
+ exit_status++;
+ goto error;
+ }
+ if (kret = osa_adb_open_policy(&pol_db, &newparams)) {
+ fprintf(stderr, "%s: %s while opening policy database\n",
+ programname, error_message(kret));
+ exit_status++;
+ goto error;
+ }
+
+ /*
+ * Initialize the database.
+ */
+ if (kret = krb5_db_init(kcontext)) {
+ fprintf(stderr, dbinit_err_fmt,
+ programname, error_message(kret));
+ exit_status++;
+ goto error;
+ }
+
+ if (restore_dump(programname, kcontext, (dumpfile) ? dumpfile : stdin_name,
+ f, verbose, load, pol_db)) {
+ fprintf(stderr, restfail_fmt,
+ programname, load->name);
+ exit_status++;
+ }
+
+ if ((kret = krb5_db_fini(kcontext)) ||
+ (kret = osa_adb_close_policy(pol_db))) {
+ fprintf(stderr, close_err_fmt,
+ programname, error_message(kret));
+ exit_status++;
+ }
+
+error:
+ /*
+ * If there was an error and this is not an update, then
+ * destroy the database.
+ */
+ if (!update) {
+ if (exit_status) {
+ if ((kret = kdb5_db_destroy(kcontext, dbname))) {
+ fprintf(stderr, dbdelerr_fmt,
+ programname, dbname_tmp, error_message(kret));
+ exit_status++;
+ }
+ }
+ else {
+ if ((kret = krb5_db_rename(kcontext,
+ dbname_tmp,
+ dbname))) {
+ fprintf(stderr, dbrenerr_fmt,
+ programname, dbname_tmp, dbname,
+ error_message(kret));
+ exit_status++;
+ }
+
+ if (kret = osa_adb_get_lock(pol_db, OSA_ADB_PERMANENT)) {
+ fprintf(stderr,
+ "%s: %s while getting permanent lock\n",
+ programname, error_message(kret));
+ exit_status++;
+ } else if (rename(newparams.admin_dbname,
+ adbname_real) < 0) {
+ fprintf(stderr, "%s: %s while renaming %s to %s\n",
+ programname, error_message(kret),
+ newparams.admin_dbname, adbname_real);
+ exit_status++;
+ } else if (kret = osa_adb_release_lock(pol_db)) {
+ fprintf(stderr, "%s: %s while unlocking %s\n",
+ programname, error_message(kret),
+ adbname_real);
+ exit_status++;
+ }
+ }
+ }
+
+ if (dumpfile) {
+ (void) krb5_lock_file(kcontext, fileno(f), KRB5_LOCKMODE_UNLOCK);
+ fclose(f);
+ }
+
+ free(newparams.admin_dbname);
+ newparams.admin_dbname = adbname_real;
+ kadm5_free_config_params(kcontext, &newparams);
+ free(dbname_tmp);
+ krb5_free_context(kcontext);
+}
diff --git a/src/kadmin/dbutil/dumpv4.c b/src/kadmin/dbutil/dumpv4.c
new file mode 100644
index 0000000000..a51626db34
--- /dev/null
+++ b/src/kadmin/dbutil/dumpv4.c
@@ -0,0 +1,411 @@
+/*
+ * 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. M.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.
+ */
+
+#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>
+
+#include <stdio.h>
+#include "kdb5_util.h"
+
+struct dump_record {
+ char *comerr_name;
+ FILE *f;
+ krb5_encrypt_block *v5master;
+ C_Block v4_master_key;
+ Key_schedule v4_master_key_schedule;
+ long master_key_version;
+ char *realm;
+};
+
+extern krb5_encrypt_block master_encblock;
+extern krb5_keyblock master_keyblock;
+extern krb5_principal master_princ;
+extern krb5_boolean dbactive;
+extern int exit_status;
+extern krb5_context util_context;
+
+void update_ok_file();
+
+#define ANAME_SZ 40
+#define INST_SZ 40
+
+static char *v4_mkeyfile = "/.k";
+
+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;
+}
+
+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);
+}
+
+
+
+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 ((principal->max_life = entry->max_life / (60 * 5)) > 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->v5master, &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);
+ }
+
+ 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;
+{
+ FILE *f;
+ struct dump_record arg;
+
+ if (argc > 2) {
+ com_err(argv[0], 0, "Usage: %s filename", argv[0]);
+ exit_status++;
+ return;
+ }
+ if (!dbactive) {
+ com_err(argv[0], 0, Err_no_database);
+ exit_status++;
+ return;
+ }
+ if (argc == 2) {
+ /*
+ * 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(argv[1]);
+ if (!(f = fopen(argv[1], "w"))) {
+ com_err(argv[0], errno,
+ "While opening file %s for writing", argv[1]);
+ 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 i;
+
+ /* 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 (i=0; i<8; i++) {
+ fprintf(f, "%02x", ((unsigned char*)v4key)[i]);
+ if (i == 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 (argv[1])
+ update_ok_file(argv[1]);
+}
+
+int handle_keys(arg)
+ struct dump_record *arg;
+{
+ krb5_error_code retval;
+ char *defrealm;
+ char *mkey_name = 0;
+ char *mkey_fullname;
+ krb5_principal 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, &master_princ)) {
+ com_err(arg->comerr_name, retval, "while setting up master key name");
+ exit(1);
+ }
+
+ krb5_use_enctype(util_context, &master_encblock, DEFAULT_KDC_ENCTYPE);
+ if (retval = krb5_db_fetch_mkey(util_context, master_princ,
+ &master_encblock, 0,
+ 0, (char *) NULL, 0, &master_keyblock)) {
+ com_err(arg->comerr_name, retval, "while reading master key");
+ exit(1);
+ }
+ if (retval = krb5_process_key(util_context, &master_encblock,
+ &master_keyblock)) {
+ com_err(arg->comerr_name, retval, "while processing master key");
+ exit(1);
+ }
+ arg->v5master = &master_encblock;
+ return(0);
+}
+
+handle_one_key(arg, v5master, v5key, v4key)
+ struct dump_record *arg;
+ krb5_encrypt_block *v5master;
+ krb5_key_data *v5key;
+ des_cblock v4key;
+{
+ krb5_error_code retval;
+
+ krb5_keyblock v4v5key;
+ krb5_keyblock v5plainkey;
+ /* v4key is the actual v4 key from the file. */
+
+ if (retval = krb5_dbekd_decrypt_key_data(util_context, v5master, v5key,
+ &v5plainkey, NULL))
+ return retval;
+
+ /* v4v5key.contents = (krb5_octet *)v4key; */
+ /* v4v5key.enctype = ENCTYPE_DES; */
+ /* v4v5key.length = sizeof(v4key); */
+
+ 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/src/kadmin/dbutil/kadm5_create.c b/src/kadmin/dbutil/kadm5_create.c
new file mode 100644
index 0000000000..d31ce33192
--- /dev/null
+++ b/src/kadmin/dbutil/kadm5_create.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Id$
+ * $Source$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include "string_table.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <kadm5/adb.h>
+#include <kadm5/admin.h>
+
+#include <krb5.h>
+#include <krb5/kdb.h>
+
+int add_admin_princ(void *handle, krb5_context context,
+ char *name, char *realm, int attrs, int lifetime);
+
+#define ERR 1
+#define OK 0
+
+#define ADMIN_LIFETIME 60*60*3 /* 3 hours */
+#define CHANGEPW_LIFETIME 60*5 /* 5 minutes */
+
+extern char *whoami;
+
+extern krb5_encrypt_block master_encblock;
+extern krb5_keyblock master_keyblock;
+extern krb5_db_entry master_db;
+
+/*
+ * 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;
+ void *handle;
+ krb5_context context;
+ FILE *f;
+
+
+ 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, params)) {
+ com_err(whoami, retval, str_INITING_KCONTEXT);
+ return 1;
+ }
+
+ if (retval = osa_adb_create_policy_db(params)) {
+ com_err(whoami, retval, str_CREATING_POLICY_DB);
+ return 1;
+ }
+
+ if ((retval = kadm5_init(whoami, NULL, NULL, params,
+ KADM5_STRUCT_VERSION,
+ KADM5_API_VERSION_2,
+ &handle))) {
+ com_err(whoami, retval, str_INITING_KCONTEXT);
+
+ krb5_free_context(context);
+ exit(ERR);
+ }
+
+ retval = add_admin_princs(handle, context, params->realm);
+
+ kadm5_destroy(handle);
+ krb5_free_context(context);
+
+ if (retval)
+ exit(retval);
+
+ return 0;
+}
+
+/*
+ * 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
+ */
+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.
+ */
+int add_admin_princs(void *handle, krb5_context context, char *realm)
+{
+ krb5_error_code ret = 0;
+
+ 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;
+ int nprincs;
+ krb5_error_code ret;
+ kadm5_principal_ent_rec ent;
+
+ memset(&ent, 0, sizeof(ent));
+
+ fullname = build_name_with_realm(name, realm);
+ if (ret = krb5_parse_name(context, fullname, &ent.principal)) {
+ com_err(whoami, ret, str_PARSE_NAME);
+ return(ERR);
+ }
+ ent.max_life = lifetime;
+ ent.attributes = attrs;
+
+ if (ret = kadm5_create_principal(handle, &ent,
+ (KADM5_PRINCIPAL |
+ KADM5_MAX_LIFE |
+ KADM5_ATTRIBUTES),
+ "to-be-random")) {
+ if (ret == KADM5_DUP)
+ ret = kadm5_modify_principal(handle, &ent,
+ (KADM5_PRINCIPAL |
+ KADM5_MAX_LIFE |
+ KADM5_ATTRIBUTES));
+
+ if (ret) {
+ com_err(whoami, ret, str_PUT_PRINC, fullname);
+ krb5_free_principal(context, ent.principal);
+ free(fullname);
+ return ERR;
+ }
+ }
+
+ ret = kadm5_randkey_principal(handle, ent.principal, NULL, NULL);
+
+ krb5_free_principal(context, ent.principal);
+ free(fullname);
+
+ if (ret) {
+ com_err(whoami, ret, str_RANDOM_KEY, fullname);
+ return ERR;
+ }
+
+ return OK;
+}
diff --git a/src/kadmin/dbutil/kdb5_create.c b/src/kadmin/dbutil/kdb5_create.c
new file mode 100644
index 0000000000..b7520d98d1
--- /dev/null
+++ b/src/kadmin/dbutil/kdb5_create.c
@@ -0,0 +1,449 @@
+/*
+ * admin/create/kdb5_create.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. M.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.
+ */
+
+#include <stdio.h>
+#include <k5-int.h>
+#include <kadm5/admin.h>
+#include <kadm5/adb.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_encrypt_block *eblock;
+ krb5_pointer rseed;
+ 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_encrypt_block *) NULL,
+ (krb5_pointer) NULL,
+ 1,
+ &def_kslist
+};
+
+struct iterate_args {
+ krb5_context ctx;
+ struct realm_info *rblock;
+ krb5_db_entry *dbentp;
+};
+
+static krb5_error_code add_principal
+ PROTOTYPE((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;
+extern krb5_encrypt_block master_encblock;
+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 */
+};
+
+static char *mkey_password = 0;
+char *whoami;
+
+extern int exit_status;
+extern osa_adb_policy_t policy_db;
+extern kadm5_config_params global_params;
+extern krb5_context util_context;
+
+static void usage()
+{
+ fprintf(stderr, "usage: %s [-s]\n", whoami);
+ exit_status++;
+}
+
+void kdb5_create(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ extern int optind;
+ int optchar;
+
+ krb5_error_code retval;
+ char *mkey_fullname;
+ char *pw_str = 0;
+ int pw_size = 0;
+ int do_stash = 0;
+ krb5_data pwd;
+
+ if (strrchr(argv[0], '/'))
+ argv[0] = strrchr(argv[0], '/')+1;
+ whoami = argv[0];
+
+ mkey_password = NULL;
+ optind = 1;
+ while ((optchar = getopt(argc, argv, "P:s")) != EOF) {
+ switch(optchar) {
+ case 's':
+ do_stash++;
+ break;
+ case 'P': /* Only used for testing!!! */
+ mkey_password = optarg;
+ break;
+ 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;
+
+ krb5_use_enctype(util_context, &master_encblock, master_keyblock.enctype);
+
+ retval = krb5_db_set_name(util_context, global_params.dbname);
+ if (!retval) retval = EEXIST;
+
+ if (retval == EEXIST || retval == EACCES || retval == EPERM) {
+ /* it exists ! */
+ com_err(argv[0], 0, "The database '%s' appears to already exist",
+ global_params.dbname);
+ 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 calculated master key salt");
+ exit_status++; return;
+ }
+ if (retval = krb5_string_to_key(util_context, &master_encblock,
+ &master_keyblock, &pwd, &master_salt)) {
+ com_err(argv[0], retval, "while transforming master key from password");
+ exit_status++; return;
+ }
+
+ if ((retval = krb5_process_key(util_context, &master_encblock,
+ &master_keyblock))) {
+ com_err(argv[0], retval, "while processing master key");
+ exit_status++; return;
+ }
+
+ rblock.eblock = &master_encblock;
+ if ((retval = krb5_init_random_key(util_context, &master_encblock,
+ &master_keyblock, &rblock.rseed))) {
+ com_err(argv[0], retval, "while initializing random key generator");
+ (void) krb5_finish_key(util_context, &master_encblock);
+ exit_status++; return;
+ }
+ if ((retval = krb5_db_create(util_context, global_params.dbname))) {
+ (void) krb5_finish_key(util_context, &master_encblock);
+ (void) krb5_finish_random_key(util_context, &master_encblock, &rblock.rseed);
+ com_err(argv[0], retval, "while creating database '%s'",
+ global_params.dbname);
+ exit_status++; return;
+ }
+ if (retval = krb5_db_fini(util_context)) {
+ (void) krb5_finish_key(util_context, &master_encblock);
+ (void) krb5_finish_random_key(util_context, &master_encblock,
+ &rblock.rseed);
+ com_err(argv[0], retval, "while closing current database");
+ exit_status++; return;
+ }
+ if ((retval = krb5_db_set_name(util_context, global_params.dbname))) {
+ (void) krb5_finish_key(util_context, &master_encblock);
+ (void) krb5_finish_random_key(util_context, &master_encblock, &rblock.rseed);
+ com_err(argv[0], retval, "while setting active database to '%s'",
+ global_params.dbname);
+ exit_status++; return;
+ }
+ if ((retval = krb5_db_init(util_context))) {
+ (void) krb5_finish_key(util_context, &master_encblock);
+ (void) krb5_finish_random_key(util_context, &master_encblock, &rblock.rseed);
+ 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);
+ (void) krb5_finish_key(util_context, &master_encblock);
+ (void) krb5_finish_random_key(util_context, &master_encblock, &rblock.rseed);
+ 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.
+ */
+ if (retval = krb5_db_store_mkey(util_context,
+ global_params.stash_file,
+ master_princ,
+ &master_keyblock)) {
+ com_err(argv[0], errno, "while storing key");
+ printf("Warning: couldn't stash master key.\n");
+ }
+ /* clean up */
+ (void) krb5_db_fini(util_context);
+ (void) krb5_finish_key(util_context, &master_encblock);
+ (void) krb5_finish_random_key(util_context, &master_encblock, &rblock.rseed);
+ 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);
+
+ /* now open the database */
+ open_db_and_mkey();
+
+ 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 random_keyblock, *key;
+ krb5_int32 ind;
+ krb5_encrypt_block random_encblock;
+ krb5_pointer rseed;
+ 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.
+ */
+ krb5_use_enctype(context, &random_encblock, ksent->ks_enctype);
+ pwd.data = mkey_password;
+ pwd.length = strlen(mkey_password);
+ if (kret = krb5_string_to_key(context, &random_encblock, &random_keyblock,
+ &pwd, &master_salt))
+ return kret;
+ if ((kret = krb5_init_random_key(context, &random_encblock,
+ &random_keyblock, &rseed)))
+ return kret;
+
+ if (!(kret = krb5_dbe_create_key_data(iargs->ctx, iargs->dbentp))) {
+ ind = iargs->dbentp->n_key_data-1;
+ if (!(kret = krb5_random_key(context,
+ &random_encblock, rseed,
+ &key))) {
+ kret = krb5_dbekd_encrypt_key_data(context,
+ iargs->rblock->eblock,
+ key,
+ NULL,
+ 1,
+ &iargs->dbentp->key_data[ind]);
+ krb5_free_keyblock(context, key);
+ }
+ }
+ memset((char *)random_keyblock.contents, 0, random_keyblock.length);
+ free(random_keyblock.contents);
+ (void) krb5_finish_random_key(context, &random_encblock, &rseed);
+ 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->eblock,
+ &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_dbe_free_contents(context, &entry);
+ return retval;
+}
diff --git a/src/kadmin/dbutil/kdb5_destroy.c b/src/kadmin/dbutil/kdb5_destroy.c
new file mode 100644
index 0000000000..7c6873df7b
--- /dev/null
+++ b/src/kadmin/dbutil/kdb5_destroy.c
@@ -0,0 +1,117 @@
+/*
+ * 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. M.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 <kadm5/adb.h>
+
+extern int errno;
+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 */
+
+static void
+usage(who, status)
+ char *who;
+ int status;
+{
+ fprintf(stderr, "usage: %s [-f]\n", who);
+}
+
+void
+kdb5_destroy(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ extern int optind;
+ int optchar;
+ char *dbname;
+ char buf[5];
+ char dbfilename[MAXPATHLEN];
+ krb5_error_code retval, retval1, retval2;
+ krb5_context context;
+ int force = 0;
+
+ krb5_init_context(&context);
+ krb5_init_ets(context);
+
+ if (strrchr(argv[0], '/'))
+ argv[0] = strrchr(argv[0], '/')+1;
+
+ dbname = global_params.dbname;
+
+ optind = 1;
+ while ((optchar = getopt(argc, argv, "f")) != EOF) {
+ switch(optchar) {
+ case 'f':
+ force++;
+ break;
+ case '?':
+ default:
+ usage(argv[0], 1);
+ 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);
+ }
+
+ if (retval = krb5_db_set_name(context, dbname)) {
+ com_err(argv[0], retval, "'%s'",dbname);
+ exit_status++; return;
+ }
+ retval1 = kdb5_db_destroy(context, dbname);
+ retval2 = osa_adb_destroy_policy_db(&global_params);
+ if (retval1) {
+ com_err(argv[0], retval1, "deleting database '%s'",dbname);
+ exit_status++; return;
+ }
+ if (retval2) {
+ com_err(argv[0], retval2, "destroying policy database");
+ exit_status++; return;
+ }
+
+ dbactive = FALSE;
+ printf("** Database '%s' destroyed.\n", dbname);
+ return;
+}
diff --git a/src/kadmin/dbutil/kdb5_edit.M b/src/kadmin/dbutil/kdb5_edit.M
new file mode 100644
index 0000000000..8405c01cd1
--- /dev/null
+++ b/src/kadmin/dbutil/kdb5_edit.M
@@ -0,0 +1,179 @@
+.\" 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. M.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 "Kerberos Version 5.0" "MIT Project Athena"
+.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/src/kadmin/dbutil/kdb5_stash.c b/src/kadmin/dbutil/kdb5_stash.c
new file mode 100644
index 0000000000..6952db7ec1
--- /dev/null
+++ b/src/kadmin/dbutil/kdb5_stash.c
@@ -0,0 +1,153 @@
+/*
+ * 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. M.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.
+ */
+
+#include "k5-int.h"
+#include "com_err.h"
+#include <kadm5/admin.h>
+#include <stdio.h>
+
+extern int errno;
+
+extern krb5_keyblock master_keyblock;
+extern krb5_principal master_princ;
+extern krb5_encrypt_block master_encblock;
+extern kadm5_config_params global_params;
+
+extern int exit_status;
+
+static void
+usage(who, status)
+char *who;
+int status;
+{
+ fprintf(stderr, "usage: %s [-f keyfile]\n", who);
+ exit_status++; return;
+}
+
+
+void
+kdb5_stash(argc, argv)
+int argc;
+char *argv[];
+{
+ extern char *optarg;
+ 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;
+ krb5_realm_params *rparams;
+
+ int enctypedone = 0;
+
+ if (strrchr(argv[0], '/'))
+ argv[0] = strrchr(argv[0], '/')+1;
+
+ krb5_init_context(&context);
+ krb5_init_ets(context);
+
+ 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:")) != EOF) {
+ switch(optchar) {
+ case 'f':
+ keyfile = optarg;
+ break;
+ case '?':
+ default:
+ usage(argv[0], 1);
+ return;
+ }
+ }
+
+ if (!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;
+ }
+
+ krb5_use_enctype(context, &master_encblock, master_keyblock.enctype);
+
+ if (retval = krb5_db_set_name(context, dbname)) {
+ com_err(argv[0], retval, "while setting active database to '%s'",
+ dbname);
+ exit_status++; return;
+ }
+
+ /* assemble & parse the master key name */
+
+ if (retval = krb5_db_setup_mkey_name(context, mkey_name, realm,
+ &mkey_fullname, &master_princ)) {
+ com_err(argv[0], retval, "while setting up master key name");
+ exit_status++; return;
+ }
+
+ if (retval = krb5_db_init(context)) {
+ com_err(argv[0], retval, "while initializing the database '%s'",
+ dbname);
+ exit_status++; return;
+ }
+
+ /* TRUE here means read the keyboard, but only once */
+ if (retval = krb5_db_fetch_mkey(context, master_princ, &master_encblock,
+ TRUE, FALSE, (char *) NULL,
+ 0, &master_keyblock)) {
+ com_err(argv[0], retval, "while reading master key");
+ (void) krb5_db_fini(context);
+ exit_status++; return;
+ }
+ if (retval = krb5_db_verify_master_key(context, master_princ,
+ &master_keyblock,&master_encblock)) {
+ com_err(argv[0], retval, "while verifying master key");
+ (void) krb5_db_fini(context);
+ exit_status++; return;
+ }
+ if (retval = krb5_db_store_mkey(context, keyfile, master_princ,
+ &master_keyblock)) {
+ 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);
+ if (retval = krb5_db_fini(context)) {
+ com_err(argv[0], retval, "closing database '%s'", dbname);
+ exit_status++; return;
+ }
+
+ return;
+}
diff --git a/src/kadmin/dbutil/kdb5_util.M b/src/kadmin/dbutil/kdb5_util.M
new file mode 100644
index 0000000000..746e018c01
--- /dev/null
+++ b/src/kadmin/dbutil/kdb5_util.M
@@ -0,0 +1,122 @@
+KDB5_UTIL(8)
+
+NAME
+ kdb5_util - Kerberos database maintainance utility
+
+SYNOPSIS
+ kdb5_util [-d dbpathname ] [-r realmname] [-R request ]
+ [-s scriptfile] [-k enctype] [-M mkeyname]
+ [-f stashfile]
+
+DESCRIPTION
+ 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 ASCII files. Additionally, kdb5_util can create a
+ Kerberos master key stash file. kdb5_util subsumes the
+ functionality of and makes obsolete the previous database
+ maintainance programs kdb5_create, kdb5_edit, kdb5_destroy,
+ and kdb5_stash.
+
+ When the program is first run, it attempts to acquire the
+ master key and open the database. Execution continues whether
+ or not it is successful, however, because the database may not
+ exist yet or the stash file may be corrupt. Commands can be
+ issued using one of three mechanisms. If a single command is
+ supplied using the request argument, then that single command
+ is processed and execution ceases. If a script file is
+ provided using the -s 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 commands may be executed.
+
+ The -r realm option specifies the realm of the database; by
+ default the realm returned by krb5_default_local_realm(3) is
+ used.
+
+ The -d dbname option specifies the name under which the
+ principal database is stored; by default the database is
+ controlled by kdc.conf. The KADM5 policy database and lock
+ file are also derived from this value.
+
+ The -k keytype option specifies the key type of the master key
+ in the database; the default is controlled by kdc.conf.
+
+ The -f stashfile option specifies the filename of the stashed
+ V5 master key. The default is controlled by kdc.conf and is
+ typically <krb5-prefix>/lib/krb5kdc/.k5.REALMNAME. (In
+ previous releases, this would have been /.k5.REALMNAME.)
+
+ The -M mkeyname option specifies the principal name for the
+ master key in the database; the default is controlled by
+ kdc.conf.
+
+ The -m option specifies that the master database password
+ should be fetched from the keyboard rather than from a file on
+ disk.
+
+AVAILABLE COMMANDS
+ create_db [-s]
+
+ Alias: create. Creates a new database. If the -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.
+
+ destroy_db [-f]
+
+ Alias: destroy. Destroys the database, first overwriting the
+ disk sectors and then unlinking the files, after prompting the
+ user for confirmation. With the -f argument, does not prompt
+ the user.
+
+ stash_mkey [-f keyfile]
+
+ Alias: stash. Stores the master principal's keys in a stash
+ file. The -f argument can be used to override the keyfile
+ specified at startup.
+
+ dump_db [-old] [-b6] [-verbose] [filename [principals...]]
+
+ Alias: ddb. Dumps the current Kerberos and KADM5 database
+ into an ASCII file. By default, the database is dumped in
+ current format, "kdb5_util load_dump version 4". The -b6
+ argument causes the dump to be in the Kerberos 5 Beta 6 format
+ ("kdb5_edit load_dump version 3.0"). The -old argument causes
+ the dump to be in the Kerberos 5 Beta 5 and earlier dump
+ format ("kdb5_edit load_dump version 2.0"). The -verbose
+ option causes the name of each principal and policy to be
+ printed as it is dumped.
+
+ load_db [-old] [-b6] [-verbose] [-update] filename dbname
+ [admin_dbname]
+
+ Alias: lddb. Loads a database dump from the named file into
+ the named database. The -old and -b6 options require the dump
+ to be in the specified format (see dump_db); otherwise, the
+ format of the dump file is detected automatically and handled
+ as appropriate. If the -update argument is specified, records
+ from the dump file are merely 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 on a successful completion. The dbname argument is
+ required (XXX probably shouldn't be) and overrides the value
+ specified on the command line or the default. The
+ admin_dbname is optional and is derived from dbname if not
+ specified.
+
+ dump_v4db [filename]
+
+ Alias: d4db. Dumps the current database into the Kerberos 4
+ database dump format.
+
+ load_v4db [-d v5dbpathname] [-t] [-n] [-r realmname] [-K]
+ [-k enctype] [-M mkeyname] -f inputfile
+
+ Alias: lddb4. Loads a Kerberos 4 database dump file. XXX Not
+ sure what all the arguments mean.
+
+SEE ALSO
+ kadm5_export(8), kadm5_import(8)
diff --git a/src/kadmin/dbutil/kdb5_util.c b/src/kadmin/dbutil/kdb5_util.c
new file mode 100644
index 0000000000..3f31fcb146
--- /dev/null
+++ b/src/kadmin/dbutil/kdb5_util.c
@@ -0,0 +1,416 @@
+/*
+ * 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. M.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 <stdio.h>
+#include <k5-int.h>
+#include <kadm5/admin.h>
+#include <kadm5/adb.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....
+ */
+static 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;
+osa_adb_policy_t policy_db;
+kadm5_config_params global_params;
+
+/*
+ * Script input, specified by -s.
+ */
+FILE *scriptfile = (FILE *) NULL;
+
+static void
+usage(who, status)
+ char *who;
+ int status;
+{
+ fprintf(stderr,
+ "usage: %s [-d dbpathname ] [-r realmname] [-R request ]\n",
+ who);
+ fprintf(stderr, "\t [-k enctype] [-M mkeyname] [-f stashfile]\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;
+int valid_master_key = 0;
+
+char *progname;
+krb5_boolean manual_mkey = FALSE;
+krb5_boolean dbactive = FALSE;
+
+char *kdb5_util_Init(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ int optchar;
+ krb5_error_code retval;
+ char *request = NULL;
+
+ retval = krb5_init_context(&util_context);
+ if (retval) {
+ fprintf(stderr, "krb5_init_context failed with error #%ld\n",
+ (long) retval);
+ exit(1);
+ }
+ krb5_init_ets(util_context);
+ initialize_adb_error_table();
+
+ if (strrchr(argv[0], '/'))
+ argv[0] = strrchr(argv[0], '/')+1;
+
+ progname = argv[0];
+
+ while ((optchar = getopt(argc, argv, "P:d:a:r:R:k:M:e:ms:f:")) != EOF) {
+ switch(optchar) {
+ case 'P': /* Only used for testing!!! */
+ mkey_password = optarg;
+ manual_mkey = TRUE;
+ break;
+ case 'd':
+ global_params.dbname = optarg;
+ global_params.mask |= KADM5_CONFIG_DBNAME;
+ break;
+ case 'a':
+ global_params.admin_dbname = optarg;
+ global_params.mask |= KADM5_CONFIG_ADBNAME;
+ break;
+ case 'r':
+ global_params.realm = optarg;
+ 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);
+ }
+ break;
+ case 'R':
+ request = optarg;
+ break;
+ case 'k':
+ if (krb5_string_to_enctype(optarg, &global_params.enctype))
+ com_err(argv[0], 0, "%s is an invalid enctype", optarg);
+ global_params.mask |= KADM5_CONFIG_ENCTYPE;
+ break;
+ case 'M': /* master key name in DB */
+ global_params.mkey_name = optarg;
+ global_params.mask |= KADM5_CONFIG_MKEY_NAME;
+ break;
+ case 'm':
+ manual_mkey = TRUE;
+ global_params.mkey_from_kbd = 1;
+ global_params.mask |= KADM5_CONFIG_MKEY_FROM_KBD;
+ break;
+ case 's':
+ /* Open the script file */
+ if (!(scriptfile = fopen(optarg, "r"))) {
+ com_err(argv[0], errno, "while opening script file %s",
+ optarg);
+ exit(1);
+ }
+ break;
+ case 'f':
+ global_params.stash_file = optarg;
+ global_params.mask |= KADM5_CONFIG_STASH_FILE;
+ break;
+ case '?':
+ default:
+ usage(progname, 1);
+ /*NOTREACHED*/
+ }
+ }
+
+ if (retval = kadm5_get_config_params(util_context, NULL, NULL,
+ &global_params, &global_params)) {
+ 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; any shells run by the
+ * ss command interface will have umask = 77 but that is not a
+ * serious problem.
+ */
+ (void) umask(077);
+
+ master_keyblock.enctype = global_params.enctype;
+ if (master_keyblock.enctype != ENCTYPE_UNKNOWN) {
+ if (!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(1);
+ }
+ krb5_use_enctype(util_context, &master_encblock,
+ master_keyblock.enctype);
+ }
+
+
+ open_db_and_mkey();
+
+ exit_status = 0; /* It's OK if we get errors in open_db_and_mkey */
+ return request;
+}
+
+#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) {
+ (void) krb5_finish_key(util_context, &master_encblock);
+ (void) krb5_finish_random_key(util_context, &master_encblock,
+ &master_random);
+ memset((char *)master_keyblock.contents, 0,
+ master_keyblock.length);
+ krb5_xfree(master_keyblock.contents);
+ 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).
+ */
+int open_db_and_mkey()
+{
+ krb5_error_code retval;
+ int nentries, i;
+ krb5_boolean more;
+ krb5_data scratch, pwd;
+
+ dbactive = FALSE;
+ valid_master_key = 0;
+
+ if ((retval = krb5_db_set_name(util_context, global_params.dbname))) {
+ com_err(progname, retval, "while setting active database to '%s'",
+ global_params.dbname);
+ exit_status++;
+ return(1);
+ }
+ if ((retval = krb5_db_init(util_context))) {
+ com_err(progname, retval, "while initializing database");
+ exit_status++;
+ return(1);
+ }
+ if (retval = osa_adb_open_policy(&policy_db, &global_params)) {
+ com_err(progname, retval, "opening policy 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 (!valid_enctype(master_keyblock.enctype)) {
+ char tmp[32];
+ if (krb5_enctype_to_string(master_keyblock.enctype,
+ tmp, sizeof(tmp)))
+ com_err(progname, KRB5_PROG_KEYTYPE_NOSUPP,
+ "while setting up enctype %d", master_keyblock.enctype);
+ else
+ com_err(progname, KRB5_PROG_KEYTYPE_NOSUPP, tmp);
+ exit(1);
+ }
+ krb5_use_enctype(util_context, &master_encblock,
+ master_keyblock.enctype);
+ }
+
+ retval = krb5_string_to_key(util_context, &master_encblock,
+ &master_keyblock, &pwd, &scratch);
+ 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_encblock, 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,&master_encblock))
+ ) {
+ com_err(progname, retval, "while verifying master key");
+ exit_status++;
+ memset((char *)master_keyblock.contents, 0, master_keyblock.length);
+ krb5_xfree(master_keyblock.contents);
+ return(1);
+ }
+ if ((retval = krb5_process_key(util_context, &master_encblock,
+ &master_keyblock))) {
+ com_err(progname, retval, "while processing master key");
+ exit_status++;
+ memset((char *)master_keyblock.contents, 0, master_keyblock.length);
+ krb5_xfree(master_keyblock.contents);
+ return(1);
+ }
+ if ((retval = krb5_init_random_key(util_context, &master_encblock,
+ &master_keyblock,
+ &master_random))) {
+ com_err(progname, retval, "while initializing random key generator");
+ exit_status++;
+ (void) krb5_finish_key(util_context, &master_encblock);
+ memset((char *)master_keyblock.contents, 0, master_keyblock.length);
+ krb5_xfree(master_keyblock.contents);
+ 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;
+ if (valid_master_key) {
+ (void) krb5_finish_key(util_context, &master_encblock);
+ (void) krb5_finish_random_key(util_context, &master_encblock,
+ &master_random);
+ }
+ 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;
+}
diff --git a/src/kadmin/dbutil/kdb5_util.h b/src/kadmin/dbutil/kdb5_util.h
new file mode 100644
index 0000000000..b580e2f6a5
--- /dev/null
+++ b/src/kadmin/dbutil/kdb5_util.h
@@ -0,0 +1,49 @@
+/*
+ * 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. M.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;
+
+void add_key
+ PROTOTYPE((char const *, char const *,
+ krb5_const_principal, const krb5_keyblock *,
+ krb5_kvno, krb5_keysalt *));
+int set_dbname_help
+ PROTOTYPE((char *, char *));
+
+char *kdb5_util_Init PROTOTYPE((int, char **));
+
+int quit();
+
+int check_for_match
+ PROTOTYPE((char *, int, krb5_db_entry *, int, int));
+
+void parse_token
+ PROTOTYPE((char *, int *, int *, char *));
+
+int create_db_entry
+ PROTOTYPE((krb5_principal, krb5_db_entry *));
diff --git a/src/kadmin/dbutil/kdb5_util_ct.ct b/src/kadmin/dbutil/kdb5_util_ct.ct
new file mode 100644
index 0000000000..bac1df125c
--- /dev/null
+++ b/src/kadmin/dbutil/kdb5_util_ct.ct
@@ -0,0 +1,56 @@
+# admin/edit/kdb5_ed_ct.ct
+#
+# 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. M.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 Kerberos administration edit
+#
+
+command_table kdb5_edit_cmds;
+
+request kdb5_create, "Create a new Kerberos database",
+ create_db, create;
+
+request kdb5_destroy, "Destroy a Kerberos database",
+ destroy_db, destroy;
+
+request kdb5_stash, "Stash the Kerberos master key",
+ stash_mkey, stash;
+
+request dump_db, "Dump database entries to a file",
+ dump_db, ddb;
+
+request dump_v4db, "Dump database entries to a V4 slave dump file",
+ dump_v4db, d4db;
+
+request load_db, "Load database entries from a file",
+ load_db, lddb;
+
+request load_v4db, "Load database entries from a V4 slave dump file",
+ load_v4db, lddb4;
+
+# 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/src/kadmin/dbutil/loadv4.c b/src/kadmin/dbutil/loadv4.c
new file mode 100644
index 0000000000..a1d37edc77
--- /dev/null
+++ b/src/kadmin/dbutil/loadv4.c
@@ -0,0 +1,881 @@
+/*
+ * admin/edit/loadv4.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. M.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.
+ */
+
+#ifdef KRB5_KRB4_COMPAT
+
+#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 long master_key_version;
+
+static char *v4_mkeyfile = "/.k";
+
+#include "k5-int.h"
+#include "com_err.h"
+#include "adm.h"
+#include "adm_proto.h"
+#include <stdio.h>
+
+#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_encrypt_block *eblock;
+ krb5_pointer rseed;
+};
+
+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 krb5_error_code add_principal
+ PROTOTYPE((krb5_context,
+ krb5_principal,
+ enum ap_op,
+ struct realm_info *));
+
+static int v4init PROTOTYPE((char *, char *, int, char *));
+static krb5_error_code enter_in_v5_db PROTOTYPE((krb5_context,
+ char *, Principal *));
+static krb5_error_code process_v4_dump PROTOTYPE((krb5_context, char *,
+ char *));
+static krb5_error_code fixup_database PROTOTYPE((krb5_context, char *));
+
+static int create_local_tgt = 0;
+
+static void
+usage(who, status)
+char *who;
+int status;
+{
+ fprintf(stderr, "usage: %s [-d v5dbpathname] [-t] [-n] [-r realmname] [-K] [-k enctype]\n\
+\t[-M mkeyname] -f inputfile\n",
+ who);
+ return;
+}
+
+static krb5_keyblock master_keyblock;
+static krb5_principal master_princ;
+static krb5_encrypt_block master_encblock;
+
+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 *v4dbname = 0;
+ char *v4dumpfile = 0;
+ char *realm = 0;
+ char *mkey_name = 0;
+ char *mkey_fullname;
+ char *defrealm;
+ int enctypedone = 0;
+ int v4manual = 0;
+ int read_mkey = 0;
+ int tempdb = 0;
+ char *tempdbname;
+ krb5_context context;
+ char *stash_file = (char *) NULL;
+ krb5_realm_params *rparams;
+ int persist, op_ind;
+
+ krb5_init_context(&context);
+
+ krb5_init_ets(context);
+
+ 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], "-d") && ((argc - op_ind) >= 2)) {
+ dbname = argv[op_ind+1];
+ op_ind++;
+ }
+ else 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], "-r") && ((argc - op_ind) >= 2)) {
+ realm = argv[op_ind+1];
+ op_ind++;
+ }
+ 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], "-k") && ((argc - op_ind) >= 2)) {
+ if (!krb5_string_to_enctype(argv[op_ind+1],
+ &master_keyblock.enctype))
+ enctypedone++;
+ else
+ com_err(argv[0], 0, "%s is an invalid enctype",
+ argv[op_ind+1]);
+ op_ind++;
+ }
+ else if (!strcmp(argv[op_ind], "-M") && ((argc - op_ind) >= 2)) {
+ mkey_name = argv[op_ind+1];
+ op_ind++;
+ }
+ else if (!strcmp(argv[op_ind], "-n")) {
+ v4manual++;
+ }
+ else if (!strcmp(argv[op_ind], "-f") && ((argc - op_ind) >= 2)) {
+ if (v4dbname) {
+ usage(PROGNAME, 1);
+ return;
+ }
+ v4dumpfile = argv[op_ind+1];
+ op_ind++;
+ }
+ else
+ persist = 0;
+ op_ind++;
+ }
+
+ /*
+ * Attempt to read the KDC profile. If we do, then read appropriate values
+ * from it and augment values supplied on the command line.
+ */
+ if (!(retval = krb5_read_realm_params(context,
+ realm,
+ (char *) NULL,
+ (char *) NULL,
+ &rparams))) {
+ /* Get the value for the database */
+ if (rparams->realm_dbname && !dbname)
+ dbname = strdup(rparams->realm_dbname);
+
+ /* Get the value for the master key name */
+ if (rparams->realm_mkey_name && !mkey_name)
+ mkey_name = strdup(rparams->realm_mkey_name);
+
+ /* Get the value for the master key type */
+ if (rparams->realm_enctype_valid && !enctypedone) {
+ master_keyblock.enctype = rparams->realm_enctype;
+ enctypedone++;
+ }
+
+ /* Get the value for the stashfile */
+ if (rparams->realm_stash_file)
+ stash_file = strdup(rparams->realm_stash_file);
+
+ /* Get the value for maximum ticket lifetime. */
+ if (rparams->realm_max_life_valid)
+ rblock.max_life = rparams->realm_max_life;
+
+ /* Get the value for maximum renewable ticket lifetime. */
+ if (rparams->realm_max_rlife_valid)
+ rblock.max_rlife = rparams->realm_max_rlife;
+
+ /* Get the value for the default principal expiration */
+ if (rparams->realm_expiration_valid)
+ rblock.expiration = rparams->realm_expiration;
+
+ /* Get the value for the default principal flags */
+ if (rparams->realm_flags_valid)
+ rblock.flags = rparams->realm_flags;
+
+ krb5_free_realm_params(context, rparams);
+ }
+
+ if (!v4dumpfile) {
+ usage(PROGNAME, 1);
+ return;
+ }
+
+ if (!enctypedone)
+ master_keyblock.enctype = DEFAULT_KDC_ENCTYPE;
+
+ if (!valid_enctype(master_keyblock.enctype)) {
+ com_err(PROGNAME, KRB5_PROG_KEYTYPE_NOSUPP,
+ "while setting up enctype %d", master_keyblock.enctype);
+ return;
+ }
+
+ krb5_use_enctype(context, &master_encblock, master_keyblock.enctype);
+
+ /* 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);
+ return;
+ }
+ tempdbname = dbname;
+ } else {
+ int dbnamelen = strlen(dbname);
+ tempdbname = malloc(dbnamelen + 2);
+ if (tempdbname == 0) {
+ com_err(PROGNAME, ENOMEM, "allocating temporary filename");
+ return;
+ }
+ strcpy(tempdbname, dbname);
+ tempdbname[dbnamelen] = '~';
+ tempdbname[dbnamelen+1] = 0;
+ (void) kdb5_db_destroy(context, tempdbname);
+ }
+
+
+ if (!realm) {
+ if (retval = krb5_get_default_realm(context, &defrealm)) {
+ com_err(PROGNAME, retval, "while retrieving default realm name");
+ return;
+ }
+ realm = defrealm;
+ }
+
+ /* assemble & parse the master key name */
+
+ if (retval = krb5_db_setup_mkey_name(context, mkey_name, realm,
+ &mkey_fullname, &master_princ)) {
+ com_err(PROGNAME, retval, "while setting up master key name");
+ 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);
+ }
+
+ if (retval = krb5_db_fetch_mkey(context, master_princ, &master_encblock,
+ read_mkey, read_mkey, stash_file, 0,
+ &master_keyblock)) {
+ com_err(PROGNAME, retval, "while reading master key");
+ return;
+ }
+ if (retval = krb5_process_key(context, &master_encblock, &master_keyblock)) {
+ com_err(PROGNAME, retval, "while processing master key");
+ return;
+ }
+
+ rblock.eblock = &master_encblock;
+ if (retval = krb5_init_random_key(context, &master_encblock,
+ &master_keyblock, &rblock.rseed)) {
+ com_err(PROGNAME, retval, "while initializing random key generator");
+ (void) krb5_finish_key(context, &master_encblock);
+ return;
+ }
+ if (retval = krb5_db_create(context, tempdbname)) {
+ (void) krb5_finish_key(context, &master_encblock);
+ (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed);
+ (void) krb5_dbm_db_destroy(context, tempdbname);
+ com_err(PROGNAME, retval, "while creating %sdatabase '%s'",
+ tempdb ? "temporary " : "", tempdbname);
+ return;
+ }
+ if (retval = krb5_db_set_name(context, tempdbname)) {
+ (void) krb5_finish_key(context, &master_encblock);
+ (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed);
+ (void) krb5_dbm_db_destroy(context, tempdbname);
+ com_err(PROGNAME, retval, "while setting active database to '%s'",
+ tempdbname);
+ return;
+ }
+ if (v4init(PROGNAME, v4dbname, v4manual, v4dumpfile)) {
+ (void) krb5_finish_key(context, &master_encblock);
+ (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed);
+ (void) krb5_dbm_db_destroy(context, tempdbname);
+ return;
+ }
+ if ((retval = krb5_db_init(context)) ||
+ (retval = krb5_dbm_db_open_database(context))) {
+ (void) krb5_finish_key(context, &master_encblock);
+ (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed);
+ (void) krb5_dbm_db_destroy(context, tempdbname);
+ com_err(PROGNAME, retval, "while initializing the database '%s'",
+ tempdbname);
+ return;
+ }
+
+ if (retval = add_principal(context, master_princ, MASTER_KEY, &rblock)) {
+ (void) krb5_db_fini(context);
+ (void) krb5_finish_key(context, &master_encblock);
+ (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed);
+ (void) krb5_dbm_db_destroy(context, tempdbname);
+ com_err(PROGNAME, retval, "while adding K/M to the database");
+ return;
+ }
+
+ if (create_local_tgt &&
+ (retval = add_principal(context, &tgt_princ, RANDOM_KEY, &rblock))) {
+ (void) krb5_db_fini(context);
+ (void) krb5_finish_key(context, &master_encblock);
+ (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed);
+ (void) krb5_dbm_db_destroy(context, tempdbname);
+ com_err(PROGNAME, retval, "while adding TGT service to the database");
+ return;
+ }
+
+ retval = process_v4_dump(context, v4dumpfile, realm);
+ 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) {
+ if (retval = krb5_db_fini (context))
+ com_err(PROGNAME, retval, "while shutting down database");
+ else if (tempdb && (retval = krb5_dbm_db_rename(context, tempdbname,
+ dbname)))
+ com_err(PROGNAME, retval, "while renaming temporary database");
+ } else {
+ (void) krb5_db_fini (context);
+ if (tempdb)
+ (void) krb5_dbm_db_destroy (context, tempdbname);
+ }
+ (void) krb5_finish_key(context, &master_encblock);
+ (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed);
+ memset((char *)master_keyblock.contents, 0, master_keyblock.length);
+ krb5_free_context(context);
+ return;
+}
+
+static int
+v4init(pname, name, manual, dumpfile)
+char *pname, *name;
+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));
+ if (retval = krb5_425_conv_principal(context, princ->name, princ->instance,
+ realm, &entry.princ))
+ return retval;
+ if (verbose) {
+ if (retval = krb5_unparse_name(context, entry.princ, &name))
+ name = strdup("<not unparsable name!>");
+ if (verbose)
+ printf("\ntranslating %s...", name);
+ free(name);
+ }
+
+ if (retval = krb5_build_principal(context, &mod_princ,
+ strlen(realm),
+ realm, princ->mod_name,
+ princ->mod_instance[0] ? princ->mod_instance : 0,
+ 0)) {
+ krb5_free_principal(context, entry.princ);
+ return retval;
+ }
+ mod_time = princ->mod_date;
+
+ 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.eblock,
+ &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) {
+ 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);
+ if (retval = krb5_build_principal(context, &entry.princ,
+ strlen(princ->instance),
+ princ->instance,
+ "krbtgt", realm, 0))
+ 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;
+ krb5_principal mod_princ;
+
+ memset((char *) &entry, 0, sizeof(entry));
+ if (retval = krb5_copy_principal(context, princ, &entry.princ))
+ 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;
+
+ if ((retval = krb5_timeofday(context, &mod_time))) {
+ krb5_db_free_principal(context, &entry, 1);
+ return retval;
+ }
+ entry.attributes = pblock->flags;
+
+ if (retval = krb5_dbe_create_key_data(context, &entry)) {
+ krb5_db_free_principal(context, &entry, 1);
+ return(retval);
+ }
+
+ switch (op) {
+ case MASTER_KEY:
+ entry.attributes |= KRB5_KDB_DISALLOW_ALL_TIX;
+ if (retval = krb5_dbekd_encrypt_key_data(context, pblock->eblock,
+ &master_keyblock,
+ (krb5_keysalt *) NULL, 1,
+ &entry.key_data[0])) {
+ krb5_db_free_principal(context, &entry, 1);
+ return retval;
+ }
+ break;
+ case RANDOM_KEY:
+ if (retval = krb5_random_key(context, pblock->eblock, pblock->rseed,
+ &rkey)) {
+ krb5_db_free_principal(context, &entry, 1);
+ return retval;
+ }
+ if (retval = krb5_dbekd_encrypt_key_data(context, pblock->eblock,
+ rkey,
+ (krb5_keysalt *) NULL, 1,
+ &entry.key_data[0])) {
+ krb5_db_free_principal(context, &entry, 1);
+ return(retval);
+ }
+ krb5_free_keyblock(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)
+krb5_context context;
+char *dumpfile;
+char *realm;
+{
+ krb5_error_code retval;
+ FILE *input_file;
+ Principal aprinc;
+ char exp_date_str[50];
+ char mod_date_str[50];
+ int temp1, temp2, temp3;
+ long time_explode();
+
+ 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 %x %x %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);
+ 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';
+ if (retval = enter_in_v5_db(context, realm, &aprinc))
+ break;
+ }
+ (void) fclose(input_file);
+ return retval;
+}
+
+static krb5_error_code fixup_database(context, realm)
+ krb5_context context;
+ char * realm;
+{
+ krb5_db_entry entry;
+ krb5_error_code retval;
+ int nprincs;
+ krb5_boolean more;
+
+ nprincs = 1;
+ if (retval = krb5_db_get_principal(context, &tgt_princ, &entry,
+ &nprincs, &more))
+ return retval;
+
+ if (nprincs == 0)
+ return 0;
+
+ entry.attributes |= KRB5_KDB_SUPPORT_DESMD5;
+
+ retval = krb5_db_put_principal(context, &entry, &nprincs);
+
+ if (nprincs)
+ krb5_db_free_principal(context, &entry, nprincs);
+
+ return retval;
+}
+
+#else /* KRB5_KRB4_COMPAT */
+void
+load_v4db(argc, argv)
+ int argc;
+ char *argv[];
+{
+ printf("This version of krb5_edit does not support the V4 load command.\n");
+}
+#endif /* KRB5_KRB4_COMPAT */
diff --git a/src/kadmin/dbutil/ss_wrapper.c b/src/kadmin/dbutil/ss_wrapper.c
new file mode 100644
index 0000000000..ada85efc9a
--- /dev/null
+++ b/src/kadmin/dbutil/ss_wrapper.c
@@ -0,0 +1,85 @@
+/*
+ * admin/edit/ss_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. M.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 kdb5_edit
+ */
+
+#include <k5-int.h>
+#include "kdb5_util.h"
+#include <ss/ss.h>
+#include <stdio.h>
+
+extern ss_request_table kdb5_edit_cmds;
+extern int exit_status;
+extern FILE *scriptfile;
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char *request;
+ krb5_error_code retval;
+ int sci_idx, code = 0;
+
+ request = kdb5_util_Init(argc, argv);
+ sci_idx = ss_create_invocation("kdb5_util", "5.0", (char *) NULL,
+ &kdb5_edit_cmds, &retval);
+ if (retval) {
+ ss_perror(sci_idx, retval, "creating invocation");
+ exit(1);
+ }
+
+ if (request) {
+ code = ss_execute_line(sci_idx, request, &code);
+ if (code != 0) {
+ ss_perror(sci_idx, code, request);
+ exit_status++;
+ }
+ } else if (scriptfile) {
+ char *command;
+ int nread;
+
+ /* Get a buffer */
+ if ((command = (char *) malloc(BUFSIZ))) {
+ /* Process commands from the script until end-of-file or error */
+ while (!feof(scriptfile) &&
+ (fgets(command, BUFSIZ, scriptfile))) {
+
+ /* Strip trailing newline */
+ if (command[strlen(command)-1] == '\n')
+ command[strlen(command)-1] = '\0';
+
+ /* Execute the command */
+ code = ss_execute_line(sci_idx, command, &code);
+ if (code != 0) {
+ ss_perror(sci_idx, code, command);
+ exit_status++;
+ break;
+ }
+ }
+ free(command);
+ }
+ } else
+ ss_listen(sci_idx, &retval);
+ return quit() ? 1 : exit_status;
+}
diff --git a/src/kadmin/dbutil/string_table.c b/src/kadmin/dbutil/string_table.c
new file mode 100644
index 0000000000..b9f86a3634
--- /dev/null
+++ b/src/kadmin/dbutil/string_table.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Header$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+/* String table of messages for kadm5_create */
+
+char *str_INITING_KCONTEXT = "while initializing the kerberos context";
+
+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 calling 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/src/kadmin/dbutil/string_table.h b/src/kadmin/dbutil/string_table.h
new file mode 100644
index 0000000000..e8cb45367c
--- /dev/null
+++ b/src/kadmin/dbutil/string_table.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Header$
+ *
+ */
+
+#ifndef _OVSEC_ADM_STRINGS_
+
+extern char *str_INITING_KCONTEXT;
+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/src/kadmin/dbutil/tcl_wrapper.c b/src/kadmin/dbutil/tcl_wrapper.c
new file mode 100644
index 0000000000..d527fa0d18
--- /dev/null
+++ b/src/kadmin/dbutil/tcl_wrapper.c
@@ -0,0 +1,235 @@
+/*
+ * 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. M.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"
+#include <tcl.h>
+
+#define CMDDECL(x) int x(clientData, interp, argc, argv)\
+ ClientData clientData;\
+ Tcl_Interp * interp;\
+ int argc;\
+ char ** argv;
+#define CMDPROTO(x) int x PROTOTYPE((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 PROTOTYPE((int, char **));
+void add_new_key PROTOTYPE((int, char **));
+void change_pwd_key PROTOTYPE((int, char **));
+void add_rnd_key PROTOTYPE((int, char **));
+void change_rnd_key PROTOTYPE((int, char **));
+void delete_entry PROTOTYPE((int, char **));
+void extract_srvtab PROTOTYPE((krb5_context, int, char **));
+void extract_v4_srvtab PROTOTYPE((int, char **));
+void list_db PROTOTYPE((int, char **));
+void dump_db PROTOTYPE((int, char **));
+void load_db PROTOTYPE((int, char **));
+void set_dbname PROTOTYPE((krb5_context, int, char **));
+void enter_master_key PROTOTYPE((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/src/kadmin/dbutil/util.c b/src/kadmin/dbutil/util.c
new file mode 100644
index 0000000000..78de2cd6f9
--- /dev/null
+++ b/src/kadmin/dbutil/util.c
@@ -0,0 +1,155 @@
+/*
+ * 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. M.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"
+
+#if defined(sysvimp) || ( defined(mips) && defined(SYSTYPE_BSD43)) || (defined(vax) && !defined(ultrix))
+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 /* sysvimp */
+
+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/src/kadmin/export/ChangeLog b/src/kadmin/export/ChangeLog
new file mode 100644
index 0000000000..97a8078c42
--- /dev/null
+++ b/src/kadmin/export/ChangeLog
@@ -0,0 +1,19 @@
+Thu Jul 18 20:39:32 1996 Marc Horowitz <marc@mit.edu>
+
+ * configure.in: removed ET_RULES, replaced with AC_PROG_AWK
+
+Mon Jul 15 16:51:51 1996 Marc Horowitz <marc@mit.edu>
+
+ * export.c (print_princ): return should return a value.
+
+ * configure.in (USE_GSSAPI_LIBRARY): shared libraries require all
+ symbols to be resolved, so this needs to be here.
+
+Wed Jul 10 01:26:18 1996 Marc Horowitz <marc@mit.edu>
+
+ * Makefile.in, configure.in: added autoconf support
+
+Tue Jul 9 16:45:52 1996 Marc Horowitz <marc@mit.edu>
+
+ * export.c: renamed <ovsec_admin/foo.h> to <kadm5/foo.h>
+
diff --git a/src/kadmin/export/Makefile.in b/src/kadmin/export/Makefile.in
new file mode 100644
index 0000000000..5fa282d89e
--- /dev/null
+++ b/src/kadmin/export/Makefile.in
@@ -0,0 +1,20 @@
+CFLAGS = $(CCOPTS) $(DEFS) -I. $(LOCALINCLUDE)
+
+PROG = kadm5_export
+OBJS = ovsec_adm_export.o export.o export_err.o
+
+all:: $(PROG)
+
+export_err.c export_err.h: $(srcdir)/export_err.et
+
+export.o: export_err.h
+ovsec_adm_export.o: export_err.h
+
+$(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/src/kadmin/export/Makefile.ov b/src/kadmin/export/Makefile.ov
new file mode 100644
index 0000000000..83e8c7219d
--- /dev/null
+++ b/src/kadmin/export/Makefile.ov
@@ -0,0 +1,24 @@
+TOP = ..
+include $(TOP)/config.mk/template
+# CFLAGS := $(CFLAGS) -Wall
+
+# The next line *shouldn't* work, because the : should be a ::.
+# However, it does work, and if I change it to :: gmake does really
+# weird things.
+ovsec_adm_export: export_err.h
+
+depend:: export_err.h
+
+PROG := kadm5_export
+OBJS := ovsec_adm_export.o export.o export_err.o
+SRCS := ovsec_adm_export.c export.c export_err.et
+ETABLES := export_err.et
+
+LIBS = $(LIBADMSRV) $(LIBRPCLIB) $(LIBKDB5) $(LIBKRB5_ALL) $(LIBDYN) $(LIBDB)
+
+expand ErrorTables
+expand InstallAdmin
+expand Depend
+
+SUBDIRS = unit-test
+expand SubdirTarget
diff --git a/src/kadmin/export/configure.in b/src/kadmin/export/configure.in
new file mode 100644
index 0000000000..992d591a11
--- /dev/null
+++ b/src/kadmin/export/configure.in
@@ -0,0 +1,12 @@
+AC_INIT(ovsec_adm_export.c)
+CONFIG_RULES
+AC_PROG_INSTALL
+AC_PROG_AWK
+USE_KADMSRV_LIBRARY
+USE_GSSRPC_LIBRARY
+USE_GSSAPI_LIBRARY
+USE_DYN_LIBRARY
+USE_KDB5_LIBRARY
+KRB5_LIBRARIES
+V5_USE_SHARED_LIB
+V5_AC_OUTPUT_MAKEFILE
diff --git a/src/kadmin/export/export.c b/src/kadmin/export/export.c
new file mode 100644
index 0000000000..3d41c4d9d7
--- /dev/null
+++ b/src/kadmin/export/export.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <sys/time.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <unistd.h>
+
+#include <kadm5/adb.h>
+#include "export_err.h"
+#include "local.h"
+
+extern int errno;
+
+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
+ *
+ */
+krb5_error_code print_princ(krb5_pointer data, krb5_db_entry *kdb)
+{
+ char *princstr;
+ int x, y, foundcrc, ret;
+ struct retdata *d;
+ krb5_tl_data tl_data;
+ osa_princ_ent_rec adb;
+ XDR xdrs;
+
+ d = (struct retdata *) 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...
+ */
+ /*
+ * 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 ((ret = krb5_dbe_lookup_tl_data(d->context, 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(OSA_ADB_XDR_FAILURE);
+ }
+ xdr_destroy(&xdrs);
+
+ krb5_unparse_name(d->context, kdb->princ, &princstr);
+ fprintf(d->fp, "princ\t%s\t", princstr);
+ if(adb.policy == NULL)
+ fputc('\t', d->fp);
+ else
+ fprintf(d->fp, "%s\t", adb.policy);
+ fprintf(d->fp, "%x\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++) {
+ if (! d->ovsec_compat)
+ fprintf(d->fp, "\t%d", adb.old_keys[x].n_key_data);
+
+ 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 (d->ovsec_compat) {
+ if (key_data->key_data_type[0] != ENCTYPE_DES_CBC_CRC)
+ continue;
+ if (foundcrc) {
+ fprintf(stderr, error_message(EXPORT_DUP_DESCRC),
+ princstr);
+ continue;
+ }
+ foundcrc++;
+ }
+ fputc('\t', d->fp);
+ print_key_data(d->fp, key_data);
+ }
+ if (d->ovsec_compat && !foundcrc)
+ fprintf(stderr, error_message(EXPORT_NO_DESCRC), princstr);
+ }
+
+ d->count++;
+ fputc('\n', d->fp);
+ free(princstr);
+ return(0);
+}
+
+/*
+ * Function: print_policy
+ *
+ * Purpose: Print the contents of a policy entry in a human readable format.
+ * This format is also suitable for consumption for dbimport.
+ *
+ * Arguments:
+ * data (input) a pointer to a structure containing a FILE *
+ * and a record counter.
+ * entry (input) policy entry
+ * <return value> void
+ *
+ * Requires:
+ * nuttin
+ *
+ * Effects:
+ * writes data to file
+ *
+ * Modifies:
+ * nuttin
+ *
+ */
+
+void
+print_policy(void *data, osa_policy_ent_t entry)
+{
+ struct retdata *d;
+
+ d = (struct retdata *) data;
+ fprintf(d->fp, "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);
+ d->count++;
+ return;
+}
+
+/*
+ * Function: export_principal
+ *
+ * Purpose: interates through the principal database with the
+ * osa_adb_iter_princ function which calls the print_princ
+ * routine with the FILE * of our filename. If the file
+ * name that gets passed in is NULL then we use stdout.
+ *
+ * Arguments:
+ * d (input) pointer to retdata.
+ * <return value> error code. 0 if sucsessful.
+ *
+ * Requires:
+ * nuttin
+ *
+ * Effects:
+ * calls osa_adb_iter_princ which calls print_princ
+ *
+ * Modifies:
+ * nuttin
+ *
+ */
+osa_adb_ret_t
+export_principal(struct retdata *d, kadm5_config_params *params)
+{
+ int ret;
+
+ if (ret = krb5_db_set_name(d->context, params->dbname))
+ return ret;
+
+ if (ret = krb5_db_init(d->context))
+ return ret;
+
+ if (ret = krb5_dbm_db_iterate(d->context, print_princ, d))
+ return ret;
+
+ if (ret = krb5_db_fini(d->context))
+ return ret;
+
+ return 0;
+}
+
+/*
+ * Function: export_policy
+ *
+ * Purpose: iterates through the policy database with the
+ * osa_adb_iter_policy function which calls the print_policy
+ * routine with the FILE * of our filename. If the file name
+ * that gets passed in is NULL then we use stdout.
+ *
+ * Arguments:
+ * d (input) a pointer to retdata
+ * <return value> error code 0 if sucsessfull.
+ *
+ * Requires:
+ * nuttin
+ *
+ * Effects:
+ * calls osa_adb_iter_policy which calls print_policy
+ *
+ * Modifies:
+ * nuttin
+ *
+ */
+osa_adb_ret_t
+export_policy(struct retdata *d, osa_adb_policy_t db)
+{
+ osa_adb_ret_t ret;
+
+ if((ret = osa_adb_iter_policy(db, print_policy, (void *) d))
+ != OSA_ADB_OK) {
+ return ret;
+ }
+ return OSA_ADB_OK;
+}
diff --git a/src/kadmin/export/export_err.et b/src/kadmin/export/export_err.et
new file mode 100644
index 0000000000..6c99a47b07
--- /dev/null
+++ b/src/kadmin/export/export_err.et
@@ -0,0 +1,19 @@
+error_table exp
+error_code EXPORT_NO_ERR, "Database export complete, %d record%s processed.\n"
+error_code EXPORT_UNK_OPTION, "Unknown Option\nUsage: ovsec_adm_export [filename]"
+error_code EXPORT_OUTPUT_OPEN, "while opening output file"
+error_code EXPORT_OUTPUT_CHMOD, "while changing mode of file"
+error_code EXPORT_OUTPUT_STAT, "while trying to stat file"
+error_code EXPORT_DATABASE_OPEN, "while opening database"
+error_code EXPORT_PRINCIPAL, "while exporting principal database"
+error_code EXPORT_POLICY, "while exporting policy database"
+error_code EXPORT_LOCK, "while locking database"
+error_code EXPORT_UNLOCK, "while unlocking database"
+error_code EXPORT_CLOSE, "while closing database"
+error_code EXPORT_SINGLE_RECORD, ""
+error_code EXPORT_PLURAL_RECORDS, "s"
+error_code EXPORT_NO_DESCRC, "Warning! No DES-CBC-CRC key for principal %s, cannot generate ovsec_adm_export-compatible record; skipping."
+error_code EXPORT_DUP_DESCRC, "Warning! Multiple DES-CBC-CRC keys for principal %s; skipping duplicates."
+error_code EXPORT_GET_CONFIG, "while retrieving configuration parameters"
+end
+
diff --git a/src/kadmin/export/local.h b/src/kadmin/export/local.h
new file mode 100644
index 0000000000..3ec895ab24
--- /dev/null
+++ b/src/kadmin/export/local.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ */
+
+struct retdata {
+ krb5_context context;
+ FILE *fp;
+ int count;
+ int ovsec_compat;
+};
+
+osa_adb_ret_t export_principal(struct retdata *, kadm5_config_params *);
+osa_adb_ret_t export_policy(struct retdata *d, osa_adb_policy_t);
diff --git a/src/kadmin/export/ovsec_adm_export.c b/src/kadmin/export/ovsec_adm_export.c
new file mode 100644
index 0000000000..ded21ba558
--- /dev/null
+++ b/src/kadmin/export/ovsec_adm_export.c
@@ -0,0 +1,159 @@
+/*
+ * 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 <sys/stat.h>
+#include <fcntl.h>
+#include <kadm5/adb.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "export_err.h"
+#include "local.h"
+
+int
+main(int argc, char *argv[])
+{
+ char *filename;
+ struct retdata d;
+ struct stat statb;
+ int ret, fd;
+ time_t now;
+ char *whoami = argv[0];
+ osa_adb_policy_t policy_db;
+ kadm5_config_params params;
+
+ memset(&params, 0, sizeof(params));
+ memset(&d, 0, sizeof(d));
+
+ filename = NULL;
+ initialize_exp_error_table();
+ initialize_adb_error_table();
+ krb5_init_context(&d.context);
+ krb5_init_ets(d.context);
+
+ while(--argc) {
+ if(*++argv == NULL)
+ break;
+ if(!strcmp(*argv, "-princ")) {
+ params.dbname = *++argv;
+ params.mask |= KADM5_CONFIG_DBNAME;
+ continue;
+ }
+ if(!strcmp(*argv, "-policy")) {
+ params.admin_dbname = *++argv;
+ params.mask |= KADM5_CONFIG_ADBNAME;
+ continue;
+ }
+ if(!strcmp(*argv, "-ovsec")) {
+ d.ovsec_compat++;
+ continue;
+ }
+ if (*argv[0] == '-') {
+ com_err(whoami, EXPORT_UNK_OPTION, NULL);
+ exit(2);
+ }
+ if(filename == NULL)
+ filename = *argv;
+ else {
+ com_err(whoami, EXPORT_UNK_OPTION, NULL);
+ exit(2);
+ }
+ }
+
+ if (ret = kadm5_get_config_params(d.context, NULL, NULL, &params,
+ &params)) {
+ com_err(whoami, ret, error_message(EXPORT_GET_CONFIG));
+ exit(2);
+ }
+#define REQUIRED_MASK (KADM5_CONFIG_DBNAME | \
+ KADM5_CONFIG_ADBNAME)
+ if ((params.mask & REQUIRED_MASK) != REQUIRED_MASK) {
+ com_err(whoami, KADM5_BAD_SERVER_PARAMS,
+ error_message(EXPORT_GET_CONFIG));
+ exit(2);
+ }
+
+ if(filename != NULL) {
+ if((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0400)) == -1) {
+ com_err(whoami, errno, "%s (%s)",
+ error_message(EXPORT_OUTPUT_OPEN), filename);
+ exit(2);
+ }
+ if(fstat(fd, &statb) == -1) {
+ com_err(whoami, errno, "%s (%s)",
+ error_message(EXPORT_OUTPUT_STAT), filename);
+ exit(2);
+ }
+ if(S_ISREG(statb.st_mode)) {
+ int mask = umask(0);
+ (void) umask(mask);
+ if (fchmod(fd, (0400 & ~mask)) == -1) {
+ com_err(whoami, errno, "%s (%s)",
+ error_message(EXPORT_OUTPUT_CHMOD), filename);
+ exit(2);
+ }
+ }
+ if ((d.fp = fdopen(fd, "w")) == NULL) {
+ com_err(whoami, errno, "%s (%s)",
+ error_message(EXPORT_OUTPUT_OPEN), filename);
+ exit(2);
+ }
+ } else d.fp = stdout;
+
+ if((ret = osa_adb_open_policy(&policy_db, &params)) != OSA_ADB_OK) {
+ com_err(argv[0], ret, error_message(EXPORT_DATABASE_OPEN));
+ exit(2);
+ }
+ if ((ret = osa_adb_get_lock(policy_db, OSA_ADB_SHARED) != OSA_ADB_OK)) {
+ com_err(argv[0], ret, error_message(EXPORT_LOCK));
+ exit(2);
+ }
+
+ d.count = 0;
+
+ now = time(NULL);
+ if (d.ovsec_compat)
+ fprintf(d.fp, "OpenV*Secure V1.0\t%s", ctime(&now));
+ else
+ fprintf(d.fp, "Kerberos KADM5 database V2.0\t%s",
+ ctime(&now));
+
+ if ((ret = export_policy(&d, policy_db)) != OSA_ADB_OK) {
+ com_err(whoami, ret, "%s (%s)", error_message(EXPORT_POLICY),
+ params.admin_dbname);
+ exit(2);
+ }
+ if ((ret = export_principal(&d, &params)) !=
+ OSA_ADB_OK) {
+ com_err(whoami, ret, "%s (%s)", error_message(EXPORT_PRINCIPAL),
+ params.dbname);
+ exit(2);
+ }
+ fprintf(d.fp, "End of Database\t%d\trecords\n", d.count);
+
+ if ((ret = osa_adb_release_lock(policy_db)) != OSA_ADB_OK) {
+ com_err(argv[0], ret, error_message(EXPORT_UNLOCK));
+ exit(2);
+ }
+ if ((ret = osa_adb_close_policy(policy_db)) != OSA_ADB_OK) {
+ com_err(argv[0], ret, error_message(EXPORT_CLOSE));
+ exit(2);
+ }
+
+ fprintf(stderr, error_message(EXPORT_NO_ERR), d.count,
+ (d.count == 1) ? error_message(EXPORT_SINGLE_RECORD) :
+ error_message(EXPORT_PLURAL_RECORDS));
+ exit(0);
+}
+
+
+
diff --git a/src/kadmin/export/unit-test/ChangeLog b/src/kadmin/export/unit-test/ChangeLog
new file mode 100644
index 0000000000..5db33c7c53
--- /dev/null
+++ b/src/kadmin/export/unit-test/ChangeLog
@@ -0,0 +1,5 @@
+Mon Jul 15 16:55:03 1996 Marc Horowitz <marc@mit.edu>
+
+ * Makefile.ov (unit-test-body), dotest.sh: ovsec_adm_*port is now
+ kadm5_*port
+
diff --git a/src/kadmin/export/unit-test/Makefile.ov b/src/kadmin/export/unit-test/Makefile.ov
new file mode 100644
index 0000000000..25b1bf6c70
--- /dev/null
+++ b/src/kadmin/export/unit-test/Makefile.ov
@@ -0,0 +1,19 @@
+#
+# $Id$
+#
+
+TOP = ../..
+include $(TOP)/config.mk/template
+
+unit-test:: unit-test-setup unit-test-body unit-test-cleanup
+
+unit-test-setup::
+ $(SAVE_FILES)
+ $(FIX_CONF_FILES)
+ $(INITDB)
+
+unit-test-body::
+ $(RUNTEST) EXPORT=../kadm5_export --tool export
+
+unit-test-cleanup::
+ $(RESTORE_FILES)
diff --git a/src/kadmin/export/unit-test/add-to-db.sh b/src/kadmin/export/unit-test/add-to-db.sh
new file mode 100644
index 0000000000..c505415463
--- /dev/null
+++ b/src/kadmin/export/unit-test/add-to-db.sh
@@ -0,0 +1,55 @@
+#!/bin/sh
+
+REALM=SECURE-TEST.OV.COM; export REALM
+DUMMY=${TESTDIR=$TOP/testing}; export TESTDIR
+DUMMY=${SRVTCL=$TESTDIR/util/ovsec_kadm_srv_tcl}; export SRVTCL
+DUMMY=${TCLUTIL=$TESTDIR/tcl/util.t}; export TCLUTIL
+
+$SRVTCL <<'EOF'
+global r
+
+source $env(TCLUTIL)
+set r $env(REALM)
+
+proc newpol { pname } {
+ puts stdout [ovsec_kadm_create_policy $server_handle [simple_policy "$pname"] {OVSEC_KADM_POLICY}]
+}
+
+proc newprinc { name } {
+ global r
+ puts stdout [ovsec_kadm_create_principal $server_handle [simple_principal "$name@$r"] {OVSEC_KADM_PRINCIPAL} $name]
+}
+
+proc chpass { princ pass } {
+ global server_handle
+ puts stdout [ovsec_kadm_chpass_principal $server_handle "$princ" "$pass"]
+}
+
+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_policy $server_handle "export_pwhist 0 0 0 0 10 0" {OVSEC_KADM_POLICY OVSEC_KADM_PW_HISTORY_NUM}]
+
+### Commented out since this isn't going to work for the december beta
+#newprinc "export_with space"
+#newprinc "export_with\"dquote"
+#newprinc "export_with\nnewline"
+
+puts stdout [ovsec_kadm_create_principal $server_handle [princ_w_pol export_hist1@$r export_pwhist] {OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY} hist1]
+
+chpass export_hist1@$r hist1_a
+
+puts stdout [ovsec_kadm_create_principal $server_handle [princ_w_pol export_hist10@$r export_pwhist] {OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY} hist10]
+
+chpass export_hist10@$r hist10_a
+chpass export_hist10@$r hist10_b
+chpass export_hist10@$r hist10_c
+chpass export_hist10@$r hist10_d
+chpass export_hist10@$r hist10_e
+chpass export_hist10@$r hist10_f
+chpass export_hist10@$r hist10_g
+chpass export_hist10@$r hist10_h
+chpass export_hist10@$r hist10_i
+
+puts stdout [ovsec_kadm_destroy $server_handle]
+
+EOF
diff --git a/src/kadmin/export/unit-test/config/unix.exp b/src/kadmin/export/unit-test/config/unix.exp
new file mode 100644
index 0000000000..e8d852f899
--- /dev/null
+++ b/src/kadmin/export/unit-test/config/unix.exp
@@ -0,0 +1,36 @@
+#
+# export_version -- extract and print the version number of export
+#
+
+proc export_version {} {
+ global EXPORT
+ set tmp [exec ident $EXPORT]
+ if [regexp {Header: .*export.c,v ([0-9]+\.[0-9]+)} $tmp \
+ dummy version] then {
+ clone_output "$EXPORT version $version\n"
+ } else {
+ clone_output "$EXPORT version <unknown>\n"
+ }
+}
+#
+# export_load -- loads the program
+#
+proc export_load {} {
+ #
+}
+
+# export_exit -- clean up and exit
+proc export_exit {} {
+ #
+}
+
+#
+# export_start -- start export running
+#
+proc export_start { args } {
+ global EXPORT
+ global spawn_id
+
+ verbose "% $EXPORT $args" 1
+ eval spawn $EXPORT $args
+}
diff --git a/src/kadmin/export/unit-test/dotest.sh b/src/kadmin/export/unit-test/dotest.sh
new file mode 100644
index 0000000000..53d4fe0abb
--- /dev/null
+++ b/src/kadmin/export/unit-test/dotest.sh
@@ -0,0 +1,75 @@
+#!/bin/sh
+
+DUMMY=${TESTDIR=$TOP/testing}
+DUMMY=${BSDDB_DUMP=$TESTDIR/util/bsddb_dump}
+DUMMY=${KDB5_EDIT=$TOP/../admin/edit/kdb5_edit}
+
+DPRINC=/tmp/dbdump.princ
+DPOL=/tmp/dbdump.policy
+
+DPRINC1=$DPRINC.1
+DPRINC2=$DPRINC.2
+
+DPOL1=$DPOL.1
+DPOL2=$DPOL.2
+
+DEXPORT=/tmp/dbexport
+
+./add-to-db.sh
+
+rm -f $DEXPORT
+../kadm5_export > $DEXPORT
+
+if $KDB5_EDIT -R ddb | sort > $DPRINC1; then
+ :
+else
+ echo "error dumping princ.1"
+fi
+if $BSDDB_DUMP /krb5/kadb5 | sort > $DPOL1; then
+ :
+else
+ echo "error dumping policy.1"
+fi
+
+rm -f /krb5/kadb5*
+touch /krb5/ovsec_adm.lock
+
+../../import/kadm5_import < $DEXPORT
+
+if $KDB5_EDIT -R ddb | sort > $DPRINC2; then
+ :
+else
+ echo "error dumping princ.2"
+fi
+if $BSDDB_DUMP /krb5/kadb5 | sort > $DPOL2; then
+ :
+else
+ echo "error dumping policy.2"
+fi
+
+
+status=0
+
+if test -s $DPRINC1 && \
+ test -s $DPRINC2 && \
+ cmp -s $DPRINC1 $DPRINC2; then
+ echo "export/import principal db succeeded"
+else
+ echo "export/import principal db failed"
+ status=1
+fi
+
+if test -s $DPOL1 && \
+ test -s $DPOL2 && \
+ cmp -s $DPOL1 $DPOL2; then
+ echo "export/import policy db succeeded"
+else
+ echo "export/import policy db failed"
+ status=1
+fi
+
+if [ $status -eq 0 ]; then
+ rm -f $DPRINC* $DPOL* $DEXPORT
+fi
+
+exit $status
diff --git a/src/kadmin/export/unit-test/export.0/dotest.exp b/src/kadmin/export/unit-test/export.0/dotest.exp
new file mode 100644
index 0000000000..93ac21250f
--- /dev/null
+++ b/src/kadmin/export/unit-test/export.0/dotest.exp
@@ -0,0 +1,29 @@
+#
+# $Id$
+#
+
+verbose "starting test: dotest.sh"
+
+spawn ./dotest.sh
+
+set timeout 60
+
+expect {
+ -re "error dumping (princ|policy)\.(\[12\])"
+ { fail $expect_out(0,string); exp_continue }
+ -re "export/import (principal|policy) db (failed|succeeded)"
+ {
+ if {![string compare $expect_out(2,string) failed]} {
+ fail $expect_out(0,string)
+ } else {
+ pass $expect_out(0,string)
+ }
+ exp_continue
+ }
+ eof break
+ timeout { fail "timeout"; close }
+}
+
+set w [wait]
+
+verbose "% Exit $w"
diff --git a/src/kadmin/export/unit-test/export.0/output.exp b/src/kadmin/export/unit-test/export.0/output.exp
new file mode 100644
index 0000000000..6e0d4144b7
--- /dev/null
+++ b/src/kadmin/export/unit-test/export.0/output.exp
@@ -0,0 +1,43 @@
+#
+# $Id$
+#
+
+set timeout 30
+
+load_lib "helpers.exp"
+
+#
+# Here are the tests
+#
+
+exec rm -f /tmp/dbexport
+
+export_win "B.25: General success" /tmp/dbexport
+
+check_mode "B.26" /tmp/dbexport 0400
+
+if {[catch "exec chmod 666 /tmp/dbexport" output]} {
+ unresolved "B.27: can't chmod /tmp/dbexport: $output"
+} else {
+ export_win "prep for B.27" /tmp/dbexport
+ check_mode "B.27" /tmp/dbexport 0400
+ exec rm -f /tmp/dbexport
+}
+
+proc test28 {} {
+ if {[catch "file stat /dev/null stats" output]} {
+ unresolved "B.28: can't stat /dev/null: $output"
+ return
+ }
+ set stats(mode) [expr $stats(mode) & 07777]
+ if {$stats(mode) == [expr 0400]} {
+ if {[catch "exec chmod 666 /dev/null" output]} {
+ unresolved "B.28: can't chmod /dev/null: $output"
+ return
+ }
+ set stats(mode) [expr 0666]
+ }
+ export_win "prep for B.28" /dev/null
+ check_mode "B.28" /dev/null $stats(mode)
+}
+test28
diff --git a/src/kadmin/export/unit-test/export.0/usage.exp b/src/kadmin/export/unit-test/export.0/usage.exp
new file mode 100644
index 0000000000..9a592c9b8d
--- /dev/null
+++ b/src/kadmin/export/unit-test/export.0/usage.exp
@@ -0,0 +1,25 @@
+#
+# $Id$
+#
+
+set timeout 30
+
+load_lib "helpers.exp"
+
+#
+# Here are the tests
+#
+
+export_lose "A.9: output file not writable" /foo/bar/baz \
+ "No such file or directory while opening output file"
+
+export_lose "A.10: two arguments" {foo bar} \
+ "Usage:"
+
+# XXX this depends on this being the last test run
+
+system {rm /krb5/kadb5}
+
+export_lose "A.2: /krb5 doesn't exist" /tmp/dbexport \
+ "No such file or directory while opening database"
+
diff --git a/src/kadmin/export/unit-test/helpers.exp b/src/kadmin/export/unit-test/helpers.exp
new file mode 100644
index 0000000000..c53630f4be
--- /dev/null
+++ b/src/kadmin/export/unit-test/helpers.exp
@@ -0,0 +1,126 @@
+#
+# $Id$
+#
+
+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 export_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 { ((![string compare $status zero]) &&
+ ([lindex $ret $wait_status_index] == 0)) ||
+ ((![string compare $status nonzero]) &&
+ ([lindex $ret $wait_status_index] != 0)) } {
+ pass "$name"
+ } else {
+ fail "$name: unexpected return status [lindex $ret $wait_status_index], should be $status"
+ }
+ }
+}
+
+proc export_win { name args } {
+ mytest "$name" "$args" zero {
+ -re "Database export complete, \[0-9\]+ records processed."
+ { mypass }
+ eof
+ { myfail "error: $expect_out(buffer)" }
+ }
+}
+
+proc export_lose { name args error } {
+ mytest "$name" "$args" nonzero {
+ -re "Database export complete, \[0-9\]+ records processed."
+ { close; myfail "unexpected success" }
+ -re "ovsec_adm_export: .*$error"
+ { mypass }
+ eof
+ { myfail "error: $expect_out(buffer)" }
+ }
+}
+
+proc check_mode { test file mode } {
+ if {[catch "file stat $file stats" output]} {
+ unresolved "$test: can't stat $file: $output"
+ } else {
+ set stats(mode) [format "%o" [expr $stats(mode) & 07777]]
+ set mode [format "%o" [expr $mode]]
+ if {$stats(mode) != $mode} {
+ fail "$test: wrong mode ($stats(mode) should be $mode)"
+ } else {
+ verbose "$test: file $file has mode $mode"
+ pass $test
+ }
+ }
+}
diff --git a/src/kadmin/import/ChangeLog b/src/kadmin/import/ChangeLog
new file mode 100644
index 0000000000..ca7c0bc2db
--- /dev/null
+++ b/src/kadmin/import/ChangeLog
@@ -0,0 +1,17 @@
+Thu Jul 18 20:40:32 1996 Marc Horowitz <marc@mit.edu>
+
+ * configure.in: removed ET_RULES, replaced with AC_PROG_AWK
+
+Mon Jul 15 16:58:08 1996 Marc Horowitz <marc@mit.edu>
+
+ * configure.in (USE_GSSAPI_LIBRARY): shared libraries require all
+ symbols to be resolved, so this needs to be here.
+
+Wed Jul 10 01:26:47 1996 Marc Horowitz <marc@mit.edu>
+
+ * Makefile.in, configure.in: added autoconf support
+
+Tue Jul 9 17:12:08 1996 Marc Horowitz <marc@mit.edu>
+
+ * ovsec_adm_import.c, import.c: renamed <ovsec_admin/foo.h> to
+ <kadm5/foo.h>
diff --git a/src/kadmin/import/Makefile.in b/src/kadmin/import/Makefile.in
new file mode 100644
index 0000000000..2f15e706f9
--- /dev/null
+++ b/src/kadmin/import/Makefile.in
@@ -0,0 +1,18 @@
+CFLAGS = $(CCOPTS) $(DEFS) -I. $(LOCALINCLUDE)
+
+PROG = kadm5_import
+OBJS = ovsec_adm_import.o import.o import_err.o strtok.o misc.o
+
+all:: $(PROG)
+
+import_err.c import_err.h: $(srcdir)/import_err.et
+$(OBJS): import_err.h
+
+$(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/src/kadmin/import/Makefile.ov b/src/kadmin/import/Makefile.ov
new file mode 100644
index 0000000000..f2750313de
--- /dev/null
+++ b/src/kadmin/import/Makefile.ov
@@ -0,0 +1,24 @@
+TOP = ..
+include $(TOP)/config.mk/template
+CFLAGS := $(CFLAGS)
+
+# The next line *shouldn't* work, because the : should be a ::.
+# However, it does work, and if I change it to :: gmake does really
+# weird things.
+ovsec_adm_import: import_err.h
+
+depend:: import_err.h
+
+PROG := kadm5_import
+OBJS := ovsec_adm_import.o import_err.o import.o strtok.o misc.o
+SRCS := ovsec_adm_import.c import.c import_err.et strtok.c misc.c
+ETABLES := import_err.et
+
+LIBS = $(LIBADMSRV) $(LIBRPCLIB) $(LIBKDB5) $(LIBKRB5_ALL) $(LIBDYN) $(LIBDB)
+
+expand ErrorTables
+expand InstallAdmin
+expand Depend
+
+SUBDIRS = unit-test
+expand SubdirTarget
diff --git a/src/kadmin/import/configure.in b/src/kadmin/import/configure.in
new file mode 100644
index 0000000000..ad66ebd7c7
--- /dev/null
+++ b/src/kadmin/import/configure.in
@@ -0,0 +1,12 @@
+AC_INIT(ovsec_adm_import.c)
+CONFIG_RULES
+AC_PROG_INSTALL
+AC_PROG_AWK
+USE_KADMSRV_LIBRARY
+USE_GSSRPC_LIBRARY
+USE_GSSAPI_LIBRARY
+USE_DYN_LIBRARY
+USE_KDB5_LIBRARY
+KRB5_LIBRARIES
+V5_USE_SHARED_LIB
+V5_AC_OUTPUT_MAKEFILE
diff --git a/src/kadmin/import/import.c b/src/kadmin/import/import.c
new file mode 100644
index 0000000000..b1a8c0a76c
--- /dev/null
+++ b/src/kadmin/import/import.c
@@ -0,0 +1,421 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <memory.h>
+
+#include <kadm5/adb.h>
+#include "import_err.h"
+#include "import.h"
+
+#define LINESIZE 32768 /* XXX */
+#define PLURAL(count) (((count) == 1) ? error_message(IMPORT_SINGLE_RECORD) : error_message(IMPORT_PLURAL_RECORDS))
+
+int parse_pw_hist_ent(current, hist, ovsec_compat)
+ char *current;
+ osa_pw_hist_ent *hist;
+ int ovsec_compat;
+{
+ int tmp, i, j, ret;
+ char *cp;
+
+ ret = 0;
+ if (!ovsec_compat) {
+ if ((cp = nstrtok((char *) NULL, "\t")) == NULL) {
+ com_err(NULL, IMPORT_BAD_RECORD, "%s", current);
+ return IMPORT_FAILED;
+ }
+ hist->n_key_data = atoi(cp);
+ } else
+ 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 sucsess, error code on failure
+ *
+ * Requires:
+ * principal database to be opened.
+ * nstrtok(3) to have a valid buffer in memory.
+ *
+ * Effects:
+ * [effects]
+ *
+ * Modifies:
+ * [modifies]
+ *
+ */
+int parse_principal(context, ovsec_compat)
+ krb5_context context;
+ int ovsec_compat;
+{
+ XDR xdrs;
+ osa_princ_ent_t rec;
+ osa_adb_ret_t ret;
+ krb5_tl_data tl_data;
+ krb5_principal princ;
+ krb5_db_entry kdb;
+ char *current;
+ char *cp;
+ int tmp, x, i, one, more;
+
+ if((cp = nstrtok((char *) NULL, "\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(context, cp, &princ)))
+ goto done;
+ krb5_unparse_name(context, princ, &current);
+ 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], ovsec_compat);
+ }
+
+ xdralloc_create(&xdrs, XDR_ENCODE);
+ if (! xdr_osa_princ_ent_rec(&xdrs, rec)) {
+ xdr_destroy(&xdrs);
+ ret = OSA_ADB_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 = xdralloc_getdata(&xdrs);
+
+ one = 1;
+ ret = krb5_db_get_principal(context, princ, &kdb, &one,
+ &more);
+ if (ret)
+ goto done;
+
+ if (ret = krb5_dbe_update_tl_data(context, &kdb,
+ &tl_data))
+ goto done;
+
+ if (ret = krb5_db_put_principal(context, &kdb, &one))
+ goto done;
+
+ xdr_destroy(&xdrs);
+
+done:
+ free(current);
+ krb5_free_principal(context, princ);
+ osa_free_princ_ent(rec);
+ return ret;
+}
+
+/*
+ * Function: parse-policy
+ *
+ * Purpose: parse the ascii text of a dump file and turn it into
+ * a policy_ent_rec.
+ *
+ * Arguments:
+ * <return value> 0 on sucsess, error code on failure;
+ *
+ * Requires:
+ * nstrtok to have a buffer in memory
+ *
+ * Effects:
+ * write data out to db.
+ *
+ * Modifies:
+ * policy db.
+ *
+ */
+int
+parse_policy(pol_db)
+ osa_adb_policy_t pol_db;
+{
+ osa_policy_ent_t rec;
+ char *cp;
+ osa_adb_ret_t ret;
+
+ if((rec = (osa_policy_ent_t) malloc(sizeof(osa_princ_ent_rec))) == NULL)
+ return ENOMEM;
+ memset(rec, 0, sizeof(osa_princ_ent_rec));
+ if((cp = nstrtok((char *) NULL, "\t")) == NULL) {
+ ret = IMPORT_BAD_FILE;
+ goto done;
+ }
+ if((rec->name = (char *) malloc(strlen(cp) + 1)) == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ strcpy(rec->name, cp);
+ if((cp = nstrtok((char *) NULL, "\t")) == NULL) {
+ com_err(NULL, IMPORT_BAD_RECORD, "%s", rec->name);
+ ret = IMPORT_FAILED;
+ goto done;
+ }
+ rec->pw_min_life = atoi(cp);
+ if((cp = nstrtok((char *) NULL, "\t")) == NULL) {
+ com_err(NULL, IMPORT_BAD_RECORD, "%s", rec->name);
+ ret = IMPORT_FAILED;
+ goto done;
+ }
+ rec->pw_max_life = atoi(cp);
+ if((cp = nstrtok((char *) NULL, "\t")) == NULL) {
+ com_err(NULL, IMPORT_BAD_RECORD, "%s", rec->name);
+ ret = IMPORT_FAILED;
+ goto done;
+ }
+ rec->pw_min_length = atoi(cp);
+ if((cp = nstrtok((char *) NULL, "\t")) == NULL) {
+ com_err(NULL, IMPORT_BAD_RECORD, "%s", rec->name);
+ ret = IMPORT_FAILED;
+ goto done;
+ }
+ rec->pw_min_classes = atoi(cp);
+ if((cp = nstrtok((char *) NULL, "\t")) == NULL) {
+ com_err(NULL, IMPORT_BAD_RECORD, "%s", rec->name);
+ ret = IMPORT_FAILED;
+ goto done;
+ }
+ rec->pw_history_num = atoi(cp);
+ if((cp = nstrtok((char *) NULL, "\t")) == NULL) {
+ com_err(NULL, IMPORT_BAD_RECORD, "%s", rec->name);
+ ret = IMPORT_FAILED;
+ goto done;
+ }
+ rec->policy_refcnt = atoi(cp);
+ ret = osa_adb_create_policy(pol_db, rec);
+done:
+ osa_free_policy_ent(rec);
+ return ret;
+}
+
+/*
+ * Function: import-file
+ *
+ * Purpose: import a flat ascii file and convert it to a db file.
+ *
+ * Arguments:
+ * fp (input) file pointer to read db.
+ * <return value> 0 or error code on error.
+ *
+ * Requires:
+ * fp be valid
+ *
+ * Effects:
+ * calls appropriate routine to write out db files.
+ *
+ * Modifies:
+ * database file.
+ *
+ */
+
+int import_file(krb5_context context, FILE *fp, int merge_princs,
+ osa_adb_policy_t pol_db)
+{
+
+ int count = 0;
+ int errcnt = 0;
+ int ret = 0;
+ int found_footer = 0;
+ int file_count;
+ int ovsec_compat;
+ char line[LINESIZE];
+ char version[BUFSIZ];
+ char date[BUFSIZ];
+ char *cp;
+
+ if(fgets(line, LINESIZE, fp) == NULL)
+ return IMPORT_BAD_FILE;
+ if ((sscanf(line, "%[^\t]\t %[^\t]", version, date)) != 2)
+ return IMPORT_BAD_FILE;
+ if(!strcmp(version, VERSION_OVSEC_10))
+ ovsec_compat++;
+ else if (strcmp(version, VERSION_KADM5_20))
+ return IMPORT_BAD_VERSION;
+
+ while(fgets(line, LINESIZE, fp) != (char *) NULL) {
+ if(found_footer) {
+ com_err(NULL, IMPORT_EXTRA_DATA, NULL);
+ break;
+ }
+ cp = nstrtok(line, "\t");
+ if(!strcasecmp(cp, "princ")) {
+ if(merge_princs &&
+ (ret = parse_principal(context, ovsec_compat)) != OSA_ADB_OK) {
+ if(ret == IMPORT_FAILED) {
+ if(!confirm())
+ break;
+ else {
+ errcnt++;
+ continue;
+ }
+ } else break;
+ } else {
+ count++;
+ continue;
+ }
+ }
+ if(!strcasecmp(cp, "policy")) {
+ if((ret = parse_policy(pol_db)) != OSA_ADB_OK) {
+ if(ret == IMPORT_FAILED) {
+ if(!confirm())
+ break;
+ else {
+ errcnt++;
+ continue;
+ }
+ } else break;
+ } else {
+ count++;
+ continue;
+ }
+ }
+ if(!strcasecmp(cp, "end of database")) {
+ found_footer = 1;
+ } else {
+ com_err(NULL, IMPORT_BAD_TOKEN, "%s", cp);
+ if(!confirm()) {
+ ret = IMPORT_BAD_FILE;
+ break;
+ } else {
+ errcnt++;
+ continue;
+ }
+ }
+ }
+ if(ret == OSA_ADB_OK && found_footer) {
+ if((cp = nstrtok(NULL, "\t")) == NULL) {
+ com_err(NULL, IMPORT_BAD_FOOTER, NULL);
+ if(!confirm())
+ ret = IMPORT_BAD_FOOTER;
+ else
+ ret = OSA_ADB_OK;
+ } else
+ file_count = atoi(cp);
+ if(file_count != (count + errcnt)) {
+ fprintf(stderr, error_message(IMPORT_COUNT_MESSAGE), file_count,
+ PLURAL(file_count), count, PLURAL(count));
+ if(!confirm())
+ ret = IMPORT_MISMATCH_COUNT;
+ else
+ ret = OSA_ADB_OK;
+ } else fprintf(stderr, error_message(IMPORT_NO_ERR), count,
+ PLURAL(count));
+ } else if(ret == OSA_ADB_OK && !found_footer) {
+ com_err(NULL, IMPORT_BAD_FOOTER, NULL);
+ if(!confirm())
+ ret = IMPORT_BAD_FOOTER;
+ else
+ ret = OSA_ADB_OK;
+ }
+
+ return ret;
+}
+
diff --git a/src/kadmin/import/import.h b/src/kadmin/import/import.h
new file mode 100644
index 0000000000..e0c3fedf91
--- /dev/null
+++ b/src/kadmin/import/import.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ *
+ * $Log$
+ * Revision 1.3 1996/07/22 20:26:27 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:02:23 marc
+ * merged in changes from OV_9510_BP to OV_9510_FINAL1
+ *
+ * Revision 1.2.2.1 1996/06/20 21:48:24 marc
+ * File added to the repository on a branch
+ *
+ * Revision 1.2 1996/06/05 20:52:28 bjaspan
+ * initial hack at porting to mit kerberos
+ *
+ * Revision 1.1 1993/11/17 06:13:23 shanzer
+ * Initial revision
+ *
+ */
+
+#include <stdio.h>
+
+/*
+ * XXX These should be defined somewhere so import and export get the
+ * same value.
+ */
+#define VERSION_OVSEC_10 "OpenV*Secure V1.0"
+#define VERSION_KADM5_20 "Kerberos KADM5 database V2.0"
+
+int import_file(krb5_context context, FILE *fp, int merge_princs,
+ osa_adb_policy_t pol_db);
+int confirm(void);
+char *nstrtok(char *str, char *delim);
diff --git a/src/kadmin/import/import_err.et b/src/kadmin/import/import_err.et
new file mode 100644
index 0000000000..e091fe33c7
--- /dev/null
+++ b/src/kadmin/import/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/src/kadmin/import/misc.c b/src/kadmin/import/misc.c
new file mode 100644
index 0000000000..bc58c7e7ff
--- /dev/null
+++ b/src/kadmin/import/misc.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ *
+ * $Log$
+ * Revision 1.4 1996/07/22 20:26:31 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.3.4.1 1996/07/18 03:02:26 marc
+ * merged in changes from OV_9510_BP to OV_9510_FINAL1
+ *
+ * Revision 1.3.2.1 1996/06/20 21:48:39 marc
+ * File added to the repository on a branch
+ *
+ * Revision 1.3 1994/04/11 23:52:10 jik
+ * Sandbox:
+ *
+ * Include <com_err.h> to get the declaration of error_message.
+ *
+ * Revision 1.3 1994/03/29 21:18:54 jik
+ * Include <com_err.h> to get the declaration of error_message.
+ *
+ * Revision 1.2 1993/12/21 18:59:25 shanzer
+ * make sure we prompt for input from /dev/tty
+ *
+ * Revision 1.1 1993/11/14 23:51:04 shanzer
+ * Initial revision
+ *
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <stdio.h>
+#include <com_err.h> /* for error_message() */
+#include "import_err.h"
+
+#ifndef TRUE
+#define TRUE (1);
+#endif
+#ifndef FALSE
+#define FALSE (0);
+#endif
+
+/*
+ * Function: confirm
+ *
+ * Purpose: ask a yes or no question you must answer
+ * with a 'y|n|Y|n'
+ *
+ * Arguments:
+ * (input) none
+ * <return value> 1 if answered yes. 0 if no.
+ *
+ * Requires:
+ * IMPORT_CONFIRM be be defined. and com_err be init.
+ *
+ * Effects:
+ * none
+ *
+ * Modifies:
+ * nuttin
+ *
+ */
+
+int
+confirm(void)
+{
+ char buf[BUFSIZ]; /* can we say overkill ... */
+ FILE *fp;
+
+ if ((fp = fopen("/dev/tty", "r")) == NULL) {
+ fprintf(stderr, error_message(IMPORT_TTY));
+ return FALSE;
+ }
+ while(1) {
+ fprintf(stderr, error_message(IMPORT_CONFIRM));
+ fgets(buf, BUFSIZ, fp);
+ if(buf[0] == 'y' || buf[0] == 'Y') {
+ fclose(fp);
+ return TRUE;
+ }
+ if(buf[0] == 'n' || buf[0] == 'N') {
+ fclose(fp);
+ return FALSE;
+ }
+ }
+}
+
diff --git a/src/kadmin/import/ovsec_adm_import.c b/src/kadmin/import/ovsec_adm_import.c
new file mode 100644
index 0000000000..4ca920434e
--- /dev/null
+++ b/src/kadmin/import/ovsec_adm_import.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <kadm5/adb.h>
+#include "import_err.h"
+#include "import.h"
+
+#define TMP_POLICY_FMT "/krb5/#ovsec_import_policy.%d"
+
+int
+main(int argc, char *argv[])
+{
+ char *filename,
+ *whoami;
+ int ret, merge_princs;
+ FILE *fp;
+ osa_adb_policy_t policy_db;
+ char pol_dbfile[BUFSIZ];
+ kadm5_config_params params;
+ krb5_context context;
+
+ filename = NULL;
+ initialize_imp_error_table();
+ initialize_adb_error_table();
+ krb5_init_context(&context);
+ krb5_init_ets(context);
+
+ whoami = argv[0];
+ merge_princs = 0;
+ while(--argc) {
+ if(*++argv == NULL)
+ break;
+ if (!strcmp(*argv, "-merge_princs")) {
+ merge_princs++;
+ continue;
+ }
+ if (*argv[0] == '-') {
+ com_err(whoami, IMPORT_UNK_OPTION, NULL);
+ exit(2);
+ }
+ if(filename == NULL)
+ filename = *argv;
+ else {
+ com_err(whoami, IMPORT_UNK_OPTION, NULL);
+ exit(2);
+ }
+ }
+ if(filename != NULL) {
+ if ((fp = fopen(filename, "r")) == NULL) {
+ com_err(whoami, errno, "%s (%s)", error_message(IMPORT_OPEN_DUMP),
+ filename);
+ exit(2);
+ }
+ } else fp = stdin;
+
+ sprintf(pol_dbfile, TMP_POLICY_FMT, getpid());
+ if(access(pol_dbfile, F_OK) == 0) {
+ if(unlink(pol_dbfile) != 0)
+ return errno;
+ }
+
+ params.mask = 0;
+ if (ret = kadm5_get_config_params(context, NULL, NULL, &params,
+ &params)) {
+ com_err(whoami, ret, error_message(IMPORT_GET_PARAMS));
+ exit(2);
+ }
+#define REQUIRED_MASK (KADM5_CONFIG_DBNAME | \
+ KADM5_CONFIG_ADBNAME)
+ if ((params.mask & REQUIRED_MASK) != REQUIRED_MASK) {
+ com_err(whoami, KADM5_BAD_SERVER_PARAMS,
+ error_message(IMPORT_GET_PARAMS));
+ exit(2);
+ }
+ /*
+ * This trick lets me use the temporary policy db name but the
+ * standard policy db lockfile, thus ensuring that no one changes
+ * the policy while this program is working.
+ */
+ params.admin_dbname = pol_dbfile;
+
+ if((ret = osa_adb_open_policy(&policy_db, &params)) != OSA_ADB_OK) {
+ com_err(whoami, ret, error_message(IMPORT_RENAME_OPEN));
+ exit(2);
+ }
+ if ((ret = osa_adb_get_lock(policy_db, OSA_ADB_PERMANENT) != OSA_ADB_OK)) {
+ com_err(whoami, ret, error_message(IMPORT_RENAME_LOCK));
+ exit(2);
+ }
+ if (merge_princs) {
+ if ((ret = krb5_db_set_name(context, params.dbname)) ||
+ (ret = krb5_db_init(context))) {
+ com_err(whoami, ret, error_message(IMPORT_RENAME_OPEN));
+ exit(2);
+ }
+ }
+
+ if((ret = import_file(context, fp, merge_princs, policy_db)) !=
+ OSA_ADB_OK) {
+ unlink(pol_dbfile);
+ com_err(whoami, ret, error_message(IMPORT_IMPORT));
+ exit(2);
+ }
+
+ if (merge_princs && (ret = krb5_db_fini(context))) {
+ com_err(whoami, ret, error_message(IMPORT_RENAME_CLOSE));
+ exit(2);
+ }
+
+ kadm5_free_config_params(context, &params);
+ params.mask = 0;
+ if (ret = kadm5_get_config_params(context, NULL, NULL, &params,
+ &params)) {
+ com_err(whoami, ret, error_message(IMPORT_GET_PARAMS));
+ exit(2);
+ }
+
+ if (access(params.admin_dbname, F_OK) == 0) {
+ puts(error_message(IMPORT_WARN_DB));
+ if(!confirm()) {
+ com_err(whoami, IMPORT_FAILED, NULL);
+ exit(2);
+ }
+ }
+
+ if((ret = osa_adb_open_policy(&policy_db, &params)) != OSA_ADB_OK) {
+ com_err(whoami, ret, error_message(IMPORT_RENAME_OPEN));
+ exit(2);
+ }
+ if ((ret = osa_adb_get_lock(policy_db, OSA_ADB_PERMANENT) != OSA_ADB_OK)) {
+ com_err(whoami, ret, error_message(IMPORT_RENAME_LOCK));
+ exit(2);
+ }
+ if (rename(pol_dbfile, params.admin_dbname) != 0) {
+ com_err(whoami, IMPORT_RENAME_FAILED, NULL);
+
+ /* WARNING! Permanent lock is not replaced. This will */
+ /* require manual administrative action! */
+ exit(2);
+ }
+ if ((ret = osa_adb_release_lock(policy_db)) != OSA_ADB_OK) {
+ com_err(whoami, ret, error_message(IMPORT_RENAME_UNLOCK));
+
+ /* WARNING! Permanent lock is not replaced. This will */
+ /* require manual administrative action! */
+ exit(2);
+ }
+ if ((ret = osa_adb_close_policy(policy_db)) != OSA_ADB_OK) {
+ com_err(whoami, ret, error_message(IMPORT_RENAME_CLOSE));
+ exit(2);
+ }
+ exit(0);
+}
diff --git a/src/kadmin/import/strtok.c b/src/kadmin/import/strtok.c
new file mode 100644
index 0000000000..7b71557860
--- /dev/null
+++ b/src/kadmin/import/strtok.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ *
+ * $Log$
+ * Revision 1.2 1996/07/22 20:26:35 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 03:02:29 marc
+ * merged in changes from OV_9510_BP to OV_9510_FINAL1
+ *
+ * Revision 1.1.2.1 1996/06/20 21:49:01 marc
+ * File added to the repository on a branch
+ *
+ * Revision 1.1 1993/11/14 23:51:23 shanzer
+ * Initial revision
+ *
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+
+/*
+ * 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strtok.c 5.7 (Berkeley) 6/1/90";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stddef.h>
+#include <string.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, *delim;
+{
+ register 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/src/kadmin/import/unit-test/Makefile.ov b/src/kadmin/import/unit-test/Makefile.ov
new file mode 100644
index 0000000000..c7ac33c0bb
--- /dev/null
+++ b/src/kadmin/import/unit-test/Makefile.ov
@@ -0,0 +1,9 @@
+#
+# $Id$
+#
+
+TOP = ../..
+include $(TOP)/config.mk/template
+
+unit-test::
+ $(RUNTEST) IMPORT=../ovsec_adm_import --tool import
diff --git a/src/kadmin/import/unit-test/config/unix.exp b/src/kadmin/import/unit-test/config/unix.exp
new file mode 100644
index 0000000000..af4ff443ea
--- /dev/null
+++ b/src/kadmin/import/unit-test/config/unix.exp
@@ -0,0 +1,36 @@
+#
+# import_version -- extract and print the version number of import
+#
+
+proc import_version {} {
+ global IMPORT
+ set tmp [exec ident $IMPORT]
+ if [regexp {Header: .*import.c,v ([0-9]+\.[0-9]+)} $tmp \
+ dummy version] then {
+ clone_output "$IMPORT version $version\n"
+ } else {
+ clone_output "$IMPORT version <unknown>\n"
+ }
+}
+#
+# import_load -- loads the program
+#
+proc import_load {} {
+ #
+}
+
+# import_exit -- clean up and exit
+proc import_exit {} {
+ #
+}
+
+#
+# import_start -- start import running
+#
+proc import_start { args } {
+ global IMPORT
+ global spawn_id
+
+ verbose "% $IMPORT $args" 1
+ eval spawn $IMPORT $args
+}
diff --git a/src/kadmin/import/unit-test/helpers.exp b/src/kadmin/import/unit-test/helpers.exp
new file mode 100644
index 0000000000..5905614e78
--- /dev/null
+++ b/src/kadmin/import/unit-test/helpers.exp
@@ -0,0 +1,93 @@
+#
+# $Id$
+#
+
+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
+
+ verbose "starting test: $name"
+
+ set mytest_name "$name"
+
+ eval import_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 0] == -1} {
+ fail "$name: wait returned error [lindex $ret 1]"
+ } else {
+ if { ((![string compare $status zero]) &&
+ ([lindex $ret 1] == 0)) ||
+ ((![string compare $status nonzero]) &&
+ ([lindex $ret 1] != 0)) } {
+ pass "$name"
+ } else {
+ fail "$name: unexpected return status [lindex $ret 1], should be $status"
+ }
+ }
+}
+
+proc import_win { name args } {
+ mytest "$name" "$args" zero {
+ -re "Successfully imported \[0-9\]+ records."
+ { mypass }
+ eof
+ { myfail "error: $expect_out(buffer)" }
+ }
+}
+
+proc import_lose { name args error } {
+ mytest "$name" "$args" nonzero {
+ -re "Successfully imported \[0-9\]+ records."
+ { myfail "unexpected success" }
+ -re "ovsec_adm_import: .*$error"
+ { mypass }
+ eof
+ { myfail "error: $expect_out(buffer)" }
+ }
+}
+
diff --git a/src/kadmin/import/unit-test/import.0/usage.exp b/src/kadmin/import/unit-test/import.0/usage.exp
new file mode 100644
index 0000000000..8e82f5a210
--- /dev/null
+++ b/src/kadmin/import/unit-test/import.0/usage.exp
@@ -0,0 +1,23 @@
+#
+# $Id$
+#
+
+set timeout 5
+
+load_lib "helpers.exp"
+
+#
+# Here are the tests
+#
+
+import_lose "C.6: input file not readable" /foo/bar/baz \
+ "No such file or directory while opening input file"
+
+import_lose "C.7: two arguments" {foo bar} \
+ "Usage:"
+
+system {rm -rf /krb5}
+
+import_lose "C.2: /krb5 doesn't exist" ./valid_export_file \
+ "Secure administration database lock file missing while importing"
+
diff --git a/src/kadmin/import/unit-test/valid_export_file b/src/kadmin/import/unit-test/valid_export_file
new file mode 100644
index 0000000000..dad19c874c
--- /dev/null
+++ b/src/kadmin/import/unit-test/valid_export_file
@@ -0,0 +1,27 @@
+OpenV*Secure V1.0 Tue Dec 21 14:18:18 1993
+policy test-pol 0 10000 8 2 3 1
+policy dict-only 0 0 1 1 1 1
+policy once-a-min 30 0 1 1 1 1
+policy test-pol-nopw 0 0 1 1 1 2
+princ admin/delete@SECURE-TEST.OV.COM 0 0 0 0
+princ test3@SECURE-TEST.OV.COM 0 0 0 0
+princ admin/modify@SECURE-TEST.OV.COM 0 0 0 0
+princ ovsec_adm/changepw@SECURE-TEST.OV.COM 0 0 0 0
+princ test2@SECURE-TEST.OV.COM 0 0 0 0
+princ admin/pol@SECURE-TEST.OV.COM test-pol-nopw 800 0 0 0
+princ admin/rename@SECURE-TEST.OV.COM 0 0 0 0
+princ test1@SECURE-TEST.OV.COM 0 0 0 0
+princ krbtgt/SECURE-TEST.OV.COM@SECURE-TEST.OV.COM 0 0 0 0
+princ pol3@SECURE-TEST.OV.COM dict-only 800 0 0 0
+princ admin/get-pol@SECURE-TEST.OV.COM test-pol-nopw 800 0 0 0
+princ admin/none@SECURE-TEST.OV.COM 0 0 0 0
+princ testuser@SECURE-TEST.OV.COM 0 0 0 0
+princ pol2@SECURE-TEST.OV.COM once-a-min 800 0 0 0
+princ K/M@SECURE-TEST.OV.COM 0 0 0 0
+princ pol1@SECURE-TEST.OV.COM test-pol 800 0 0 0
+princ ovsec_adm/history@SECURE-TEST.OV.COM 0 0 0 0
+princ admin@SECURE-TEST.OV.COM 0 0 0 0
+princ admin/add@SECURE-TEST.OV.COM 0 0 0 0
+princ admin/get@SECURE-TEST.OV.COM 0 0 0 0
+princ ovsec_adm/admin@SECURE-TEST.OV.COM 0 0 0 0
+End of Database 25 records
diff --git a/src/kadmin/kdbkeys/ChangeLog b/src/kadmin/kdbkeys/ChangeLog
new file mode 100644
index 0000000000..206aea9beb
--- /dev/null
+++ b/src/kadmin/kdbkeys/ChangeLog
@@ -0,0 +1,16 @@
+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/src/kadmin/kdbkeys/Makefile.in b/src/kadmin/kdbkeys/Makefile.in
new file mode 100644
index 0000000000..5672bd0bf0
--- /dev/null
+++ b/src/kadmin/kdbkeys/Makefile.in
@@ -0,0 +1,15 @@
+CFLAGS = $(CCOPTS) $(DEFS) $(LOCALINCLUDE)
+
+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/src/kadmin/kdbkeys/Makefile.ov b/src/kadmin/kdbkeys/Makefile.ov
new file mode 100644
index 0000000000..72c11695ad
--- /dev/null
+++ b/src/kadmin/kdbkeys/Makefile.ov
@@ -0,0 +1,21 @@
+#
+# $Id$
+#
+
+TOP = ..
+include $(TOP)/config.mk/template
+
+# Need $(STOP_SERVERS_LOCAL) because any running servers need to be
+# killed so that they won't keep the database open so that we can't
+# blow it away.
+
+unit-test:: unit-test-setup unit-test-body unit-test-cleanup
+
+unit-test-setup::
+ $(START_SERVERS_LOCAL)
+ $(STOP_SERVERS_LOCAL)
+
+unit-test-body::
+ $(PERL) ./do-test.pl 10
+
+unit-test-cleanup::
diff --git a/src/kadmin/kdbkeys/configure.in b/src/kadmin/kdbkeys/configure.in
new file mode 100644
index 0000000000..6c027fc277
--- /dev/null
+++ b/src/kadmin/kdbkeys/configure.in
@@ -0,0 +1,11 @@
+AC_INIT(kdbkeys.c)
+CONFIG_RULES
+AC_PROG_INSTALL
+AC_PROG_AWK
+USE_KADMSRV_LIBRARY
+USE_GSSRPC_LIBRARY
+USE_DYN_LIBRARY
+USE_KDB5_LIBRARY
+KRB5_LIBRARIES
+V5_USE_SHARED_LIB
+V5_AC_OUTPUT_MAKEFILE
diff --git a/src/kadmin/kdbkeys/do-test.pl b/src/kadmin/kdbkeys/do-test.pl
new file mode 100644
index 0000000000..7acb425f79
--- /dev/null
+++ b/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/src/kadmin/keytab/ChangeLog b/src/kadmin/keytab/ChangeLog
new file mode 100644
index 0000000000..5aeb2a44ed
--- /dev/null
+++ b/src/kadmin/keytab/ChangeLog
@@ -0,0 +1,13 @@
+Thu Jul 18 20:41:14 1996 Marc Horowitz <marc@mit.edu>
+
+ * keytab.c (etype_string): ifdef'd out reference to des3
+
+Mon Jul 15 16:59:35 1996 Marc Horowitz <marc@mit.edu>
+
+ * keytab.c (main): the default keytab name logic was inappropriate
+ for beta6, since it ignores the env vars, etc. This version still
+ has the problem that the default keytab probably isn't writeable.
+
+Wed Jul 10 01:27:44 1996 Marc Horowitz <marc@mit.edu>
+
+ * Makefile.in, configure.in: added autoconf support
diff --git a/src/kadmin/keytab/Makefile.in b/src/kadmin/keytab/Makefile.in
new file mode 100644
index 0000000000..74426a51fb
--- /dev/null
+++ b/src/kadmin/keytab/Makefile.in
@@ -0,0 +1,19 @@
+CFLAGS = $(CCOPTS) $(DEFS) $(LOCALINCLUDE)
+
+PROG = kadm5_keytab
+OBJS = keytab.o
+
+all:: $(PROG).local $(PROG)
+
+$(PROG).local: $(OBJS) $(SRVDEPLIBS)
+ $(CC) $(LDFLAGS) $(LDARGS) -o $(PROG).local $(OBJS) $(SRVLIBS)
+
+$(PROG): $(OBJS) $(CLNTDEPLIBS)
+ $(CC) $(LDFLAGS) $(LDARGS) -o $(PROG) $(OBJS) $(CLNTLIBS)
+
+install::
+ $(INSTALL_PROGRAM) $(PROG).local ${DESTDIR}$(ADMIN_BINDIR)/$(PROG)
+ $(INSTALL_PROGRAM) $(PROG) ${DESTDIR}$(ADMIN_BINDIR)/$(PROG)
+
+clean::
+ $(RM) $(PROG).local $(PROG) $(OBJS)
diff --git a/src/kadmin/keytab/Makefile.ov b/src/kadmin/keytab/Makefile.ov
new file mode 100644
index 0000000000..15cd6d5d9d
--- /dev/null
+++ b/src/kadmin/keytab/Makefile.ov
@@ -0,0 +1,30 @@
+#
+# Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+#
+# $Id$
+# $Source$
+#
+
+TOP = ..
+include $(TOP)/config.mk/template
+
+SRCS = keytab.c
+OBJS = keytab.o
+PROG = ovsec_edit_keytab
+
+LIBS = $(LIBADMCLNT) $(LIBCOM_ERR) $(LIBGSSAPI_KRB5) $(LIBRPCLIB) \
+ $(LIBDYN) $(LIBDB) $(LIBKRB5) $(LIBCRYPTO) $(LIBISODE) \
+ $(BSDLIB) $(NETLIB)
+
+expand InstallAdmin
+
+PROG = ovsec_edit_keytab.local
+LIBS = $(LIBADMSRV) $(LIBGSSAPI_KRB5) $(LIBKDB5) $(LIBKRB5) $(NDBMLIB) \
+ $(LIBRPCLIB) $(LIBDYN) $(LIBDB) $(LIBKRB5) $(LIBCRYPTO) \
+ $(LIBCOM_ERR) $(BSDLIB) $(NETLIB)
+
+expand InstallAdmin
+
+SUBDIRS = unit-test
+expand SubdirTarget
+
diff --git a/src/kadmin/keytab/configure.in b/src/kadmin/keytab/configure.in
new file mode 100644
index 0000000000..0e043f7e51
--- /dev/null
+++ b/src/kadmin/keytab/configure.in
@@ -0,0 +1,12 @@
+AC_INIT(keytab.c)
+CONFIG_RULES
+AC_PROG_INSTALL
+USE_KADMCLNT_LIBRARY
+USE_GSSAPI_LIBRARY
+USE_KADMSRV_LIBRARY
+USE_GSSRPC_LIBRARY
+USE_DYN_LIBRARY
+USE_KDB5_LIBRARY
+KRB5_LIBRARIES
+V5_USE_SHARED_LIB
+V5_AC_OUTPUT_MAKEFILE
diff --git a/src/kadmin/keytab/keytab.c b/src/kadmin/keytab/keytab.c
new file mode 100644
index 0000000000..2561252ef8
--- /dev/null
+++ b/src/kadmin/keytab/keytab.c
@@ -0,0 +1,528 @@
+/*
+ * 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 <string.h>
+
+#include <krb5.h>
+#include <k5-int.h>
+#include <kadm5/admin.h>
+
+int add_principal(char *keytab_str, krb5_keytab keytab, char *me_str,
+ char *princ_str, int create);
+int remove_principal(char *keytab_str, krb5_keytab keytab, char
+ *princ_str, char *kvno_str);
+static char *etype_string(krb5_enctype enctype);
+
+krb5_context context;
+char *whoami;
+int quiet;
+
+void usage()
+{
+ fprintf(stderr, "Usage: ovsec_edit_keytab [-k[eytab] keytab] [-q] cmd\n");
+ fprintf(stderr, " cmds are:\t-a[dd] [-c[reate] [-p principal] principal\n");
+ fprintf(stderr, "\t\t-c[hange] [-p principal] principal\n");
+ fprintf(stderr, "\t\t-r[emove] principal [kvno|\"all\"|\"old\"]\n");
+ exit(1);
+}
+
+main(int argc0, char **argv0)
+{
+ extern krb5_kt_ops krb5_ktf_writable_ops;
+ krb5_keytab keytab = 0;
+ char *me_str, *princ_str, *keytab_str, *kvno_str;
+ char keytab_buf[1024];
+ int argc, code, did_something, create;
+ char **argv;
+
+ whoami = strrchr(argv0[0], '/') ? strrchr(argv0[0], '/') + 1 : argv0[0];
+
+ if (code = krb5_init_context(&context)) {
+ com_err(whoami, code, "while initializing krb5 context");
+ exit(1);
+ }
+
+ krb5_init_ets(context);
+
+ /* register the WRFILE keytab type and set it as the default */
+ if (code = krb5_kt_register(context, &krb5_ktf_writable_ops)) {
+ com_err(whoami, code,
+ "while registering writable key table functions");
+ exit(1);
+ }
+
+ /* process non-action arguments first */
+ argc = argc0-1;
+ argv = argv0+1;
+ while (argc) {
+ if (strncmp(*argv, "-k", 2) == 0) {
+ argc--; argv++;
+ if (!argc) usage();
+
+ if (keytab == NULL) {
+ if (strchr(*argv, ':') != NULL) {
+ keytab_str = strdup(*argv);
+ if (keytab_str == NULL) {
+ com_err(whoami, ENOMEM,
+ "while creating keytab name");
+ exit(1);
+ }
+ } else {
+ keytab_str = (char *)
+ malloc(strlen("WRFILE:")+strlen(*argv)+1);
+ if (keytab_str == NULL) {
+ com_err(whoami, ENOMEM,
+ "while creating keytab name");
+ exit(1);
+ }
+ sprintf(keytab_str, "WRFILE:%s", *argv);
+ }
+
+ code = krb5_kt_resolve(context, keytab_str, &keytab);
+ if (code != 0) {
+ com_err(whoami, code, "while resolving keytab %s",
+ keytab_str);
+ exit(1);
+ }
+ } else {
+ usage();
+ }
+ } else if (strcmp(*argv, "-q") == 0) {
+ quiet++;
+ }
+ /* otherwise ignore the argument, for now */
+ argc--; argv++;
+ }
+
+ if (keytab == NULL) {
+ code = krb5_kt_default(context, &keytab);
+ if (code != 0) {
+ com_err(whoami, code, "while opening default keytab");
+ exit(1);
+ }
+ code = krb5_kt_get_name(context, keytab,
+ keytab_buf, sizeof(keytab_buf));
+ keytab_str = keytab_buf;
+ }
+
+ argc = argc0-1;
+ argv = argv0+1;
+
+ did_something = 0;
+
+ /* now process the action arguments */
+ while (argc) {
+ if (strncmp(*argv, "-k", 2) == 0) {
+ /* if there is no keytab argument the previous loop */
+ /* would have called usage(), so just skip it */
+ argc--; argv++;
+ } else if (strcmp(*argv, "-q") == 0) {
+ /* skip it */
+ } else if (strncmp(*argv, "-a", 2) == 0 ||
+ strncmp(*argv, "-c", 2) == 0) {
+ did_something++;
+
+ argc--; argv++;
+ if (!argc) usage();
+
+ me_str = NULL;
+ create = 0;
+ while (argc) {
+ if (strcmp(*argv, "-p") == 0) {
+ argc--; argv++;
+ if (argc < 1) usage();
+
+ me_str = *argv;
+ } else if (strncmp(*argv, "-c", 2) == 0) {
+ create++;
+ } else
+ break;
+ argc--; argv++;
+ }
+ if (argc != 1) usage();
+
+ code = add_principal(keytab_str, keytab, me_str ? me_str :
+ *argv, *argv, create);
+ break;
+ } else if (strncmp(*argv, "-r", 2) == 0) {
+ did_something++;
+
+ argc--; argv++;
+ if (!argc) usage();
+ princ_str = *argv;
+ if (argc > 0) {
+ argc--;
+ argv++;
+ kvno_str = *argv;
+ } else
+ kvno_str = NULL;
+
+ code = remove_principal(keytab_str, keytab, princ_str,
+ kvno_str);
+ break;
+ } else {
+ fprintf(stderr, "%s: Unknown command line option %s.\n",
+ whoami, *argv);
+ usage();
+ }
+
+ argc--; argv++;
+ }
+
+ /* argv ends up pointing at the last recognized argument */
+ if (!did_something || argc > 1)
+ usage();
+
+ /* use argc as temp */
+ argc = krb5_kt_close(context, keytab);
+ if (argc != 0) {
+ com_err(whoami, argc, "while closing keytab");
+ code = argc;
+ }
+
+ free(keytab_str);
+
+ return (code != 0);
+}
+
+int add_principal(char *keytab_str, krb5_keytab keytab, char *me_str,
+ char *princ_str, int create)
+{
+ kadm5_principal_ent_rec princ_rec;
+ krb5_principal me, princ;
+ krb5_keytab_entry new_entry;
+ krb5_keyblock *keys;
+ void *handle;
+ int code, code2, mask, nkeys, i;
+
+ (void) memset((char *)&princ_rec, 0, sizeof(princ_rec));
+
+ me = princ = NULL;
+ handle = NULL;
+ keys = NULL;
+ nkeys = 0;
+
+ code = krb5_parse_name(context, me_str, &me);
+ if (code != 0) {
+ com_err(whoami, code, "while parsing -p principal name %s",
+ me_str);
+ goto cleanup;
+ }
+
+ 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;
+ }
+
+ /* first try using the keytab */
+ code = kadm5_init_with_skey(me_str, keytab_str,
+ KADM5_ADMIN_SERVICE,
+ NULL, /* default configuration */
+ KADM5_STRUCT_VERSION,
+ KADM5_API_VERSION_2, &handle);
+ if (code != 0) {
+ /* KRB5_KT_NOTFOUND and ENOENT are not "errors" because this */
+ /* program does not require the keytab entry to exist */
+ if (code != KRB5_KT_NOTFOUND && code != ENOENT) {
+ if (code == KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN)
+ fprintf(stderr, "%s: Principal %s does not exist.\n",
+ whoami, me_str);
+ else
+ com_err(whoami, code, "while authenticating as principal "
+ "%s from keytab", me_str);
+ }
+
+ code2 = kadm5_init_with_password(me_str, NULL,
+ KADM5_ADMIN_SERVICE,
+ NULL,
+ KADM5_STRUCT_VERSION,
+ KADM5_API_VERSION_2,
+ &handle);
+ if (code2 != 0) {
+ if (code2 != code) /* don't dup error messages */ {
+ com_err(whoami, code2, "while authenticating as "
+ "principal %s from password", me_str);
+ }
+ goto cleanup;
+ }
+ }
+
+ if (create) {
+ /* always try to create and just ignore dup errors because it */
+ /* reduces duplicate code... and how often will this happen? */
+
+ /* be sure to create the principal with the secure sequence */
+ /* of events as specified in the functional spec */
+
+ princ_rec.principal = princ;
+ princ_rec.attributes = KRB5_KDB_DISALLOW_ALL_TIX;
+ mask = KADM5_PRINCIPAL | KADM5_ATTRIBUTES;
+ code = kadm5_create_principal(handle, &princ_rec,
+ mask, "dummy");
+ if (code == KADM5_DUP) {
+ printf("%s: Principal %s already exists.\n",
+ whoami, princ_str);
+ } else if (code != 0) {
+ if (code == KADM5_AUTH_ADD) {
+ fprintf(stderr, "%s: Operation requires "
+ "``add'' and ``modify'' privileges while creating "
+ "principal.\n", whoami);
+ } else {
+ com_err(whoami, code, "while creating "
+ "principal %s.", princ_str);
+ }
+ goto cleanup;
+ } else if (!quiet)
+ printf("%s: Created principal %s.\n", whoami, princ_str);
+ }
+
+ code = kadm5_randkey_principal(handle, 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(handle, princ, &princ_rec,
+ KADM5_PRINCIPAL_NORMAL_MASK);
+ if (code != 0) {
+ com_err(whoami, code, "while retrieving principal");
+ goto cleanup;
+ }
+
+ if (create) {
+ /* complete the secure principal-creation sequence */
+ princ_rec.attributes &= ~KRB5_KDB_DISALLOW_ALL_TIX;
+ mask = KADM5_ATTRIBUTES;
+ code = kadm5_modify_principal(handle, &princ_rec, mask);
+ if (code != 0) {
+ if (code == KADM5_AUTH_ADD) {
+ fprintf(stderr, "%s: Operation requires "
+ "``add'' and ``modify'' privileges while creating "
+ "principal.\n", whoami);
+ } else
+ com_err(whoami, code, "while modifying newly created "
+ "principal");
+ (void) kadm5_free_principal_ent(handle, &princ_rec);
+ 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(handle, &princ_rec);
+ goto cleanup;
+ }
+
+ if (!quiet)
+ printf("%s: Entry for principal %s with kvno %d, "
+ "encryption type %s added to keytab %s.\n",
+ whoami, princ_str, princ_rec.kvno,
+ etype_string(keys[i].enctype), keytab_str);
+ }
+
+ code = kadm5_free_principal_ent(handle, &princ_rec);
+ if (code != 0) {
+ com_err(whoami, code, "while freeing principal entry");
+ goto cleanup;
+ }
+
+cleanup:
+ if (handle) {
+ code2 = kadm5_destroy(handle);
+ if (code2 != 0) {
+ com_err(whoami, code2, "while closing admin server connection");
+ }
+ }
+ if (nkeys) {
+ for (i = 0; i < nkeys; i++)
+ krb5_free_keyblock(context, &keys[i]);
+ free(keys);
+ }
+ if (me)
+ krb5_free_principal(context, me);
+ 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, kvno, did_something;
+
+ 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("%s: Entry for principal %s with kvno %d "
+ "removed from keytab %s.\n", whoami,
+ 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[12];
+
+ switch (enctype) {
+ case ENCTYPE_DES_CBC_CRC:
+ return "DES-CBC-CRC";
+ break;
+ case ENCTYPE_DES_CBC_MD4:
+ return "DES-CBC-MD4";
+ break;
+ case ENCTYPE_DES_CBC_MD5:
+ return "DES-CBC-MD5";
+ break;
+#if 0
+ case ENCTYPE_DES3_CBC_MD5:
+ return "DES3-CBC-MD5";
+ break;
+#endif
+ default:
+ sprintf(buf, "etype %d", enctype);
+ return buf;
+ break;
+ }
+}
diff --git a/src/kadmin/keytab/unit-test/ChangeLog b/src/kadmin/keytab/unit-test/ChangeLog
new file mode 100644
index 0000000000..69df6be92e
--- /dev/null
+++ b/src/kadmin/keytab/unit-test/ChangeLog
@@ -0,0 +1,4 @@
+Mon Jul 15 17:03:28 1996 Marc Horowitz <marc@mit.edu>
+
+ * Makefile.ov (unit-test-body): ovsec_adm_keytab is now
+ kadm5_keytab
diff --git a/src/kadmin/keytab/unit-test/Makefile.ov b/src/kadmin/keytab/unit-test/Makefile.ov
new file mode 100644
index 0000000000..1b3366d8bd
--- /dev/null
+++ b/src/kadmin/keytab/unit-test/Makefile.ov
@@ -0,0 +1,21 @@
+#
+# $Id$
+#
+
+TOP = ../..
+include $(TOP)/config.mk/template
+
+unit-test:: unit-test-setup unit-test-body unit-test-cleanup
+
+unit-test-body::
+ $(CLNTTCL) ./del-princs.tcl
+ $(RUNTEST) KEYTAB=../kadm5_keytab \
+ KLIST=../../../clients/klist/klist \
+ QUALNAME=../../testing/scripts/qualname --tool keytab
+
+unit-test-setup::
+ $(START_SERVERS)
+ $(CLNTTCL) ./add-princs.tcl
+
+unit-test-cleanup::
+ $(STOP_SERVERS)
diff --git a/src/kadmin/keytab/unit-test/add-princs.tcl b/src/kadmin/keytab/unit-test/add-princs.tcl
new file mode 100644
index 0000000000..247a4382bc
--- /dev/null
+++ b/src/kadmin/keytab/unit-test/add-princs.tcl
@@ -0,0 +1,12 @@
+source $env(TCLUTIL)
+
+ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+ $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 server_handle
+
+ovsec_kadm_create_principal $server_handle [simple_principal kttest1] \
+ {OVSEC_KADM_PRINCIPAL} kttest1
+
+ovsec_kadm_create_principal $server_handle [simple_principal kttest2] \
+ {OVSEC_KADM_PRINCIPAL} kttest2
+
+ovsec_kadm_destroy $server_handle
diff --git a/src/kadmin/keytab/unit-test/config/unix.exp b/src/kadmin/keytab/unit-test/config/unix.exp
new file mode 100644
index 0000000000..bc07d4f6ec
--- /dev/null
+++ b/src/kadmin/keytab/unit-test/config/unix.exp
@@ -0,0 +1,46 @@
+set klist $KLIST
+set hostname hostname
+set qualname $QUALNAME
+
+set rm /bin/rm
+
+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 keytab_version {} {
+ global KEYTAB
+ puts "$KEYTAB version unknown"
+}
+
+proc keytab_load {} {
+ #
+}
+
+proc keytab_exit {} {
+ #
+}
+
+proc keytab_start { args } {
+ global KEYTAB
+ global spawn_id
+
+ verbose "% $KEYTAB $args" 1
+ eval spawn $KEYTAB $args
+}
+
+
diff --git a/src/kadmin/keytab/unit-test/del-princs.tcl b/src/kadmin/keytab/unit-test/del-princs.tcl
new file mode 100644
index 0000000000..9b9cab5c4f
--- /dev/null
+++ b/src/kadmin/keytab/unit-test/del-princs.tcl
@@ -0,0 +1,24 @@
+source $env(TCLUTIL)
+
+proc check_err {error} {
+ if {! [string match {*OVSEC_KADM_UNK_PRINC*} $error]} {
+ error $error
+ }
+}
+
+proc delprinc {princ} {
+ global server_handle
+
+ catch {ovsec_kadm_delete_principal $server_handle $princ}
+ if {[info exists errorInfo]} {
+ check_err $errorInfo
+ }
+}
+
+ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+ $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 server_handle
+
+delprinc dne1
+delprinc dne2
+
+ovsec_kadm_destroy $server_handle
diff --git a/src/kadmin/keytab/unit-test/helpers.exp b/src/kadmin/keytab/unit-test/helpers.exp
new file mode 100644
index 0000000000..a9f7ca4023
--- /dev/null
+++ b/src/kadmin/keytab/unit-test/helpers.exp
@@ -0,0 +1,132 @@
+#
+# $Id$
+#
+
+#
+# Create a keytab "name" with an entry for each element in the array
+# "entries". If "name" already exists it is destroyed. Connections
+# to the admin server are made as the principal "admin" with the
+# password "password".
+#
+proc setup_keytab { testname ktname admin password entries } {
+ global klist rm
+ global wait_error_index wait_status_index
+ global verbose
+
+ verbose "setting up test: $testname" 1
+
+ if {[regexp {(.+):(.+)} $ktname dummy type filename] == 0} {
+ set filename $ktname
+ }
+
+ if {[file exists $filename] && [catch "exec $rm $filename"] != 0} {
+ error "$testname: cannot delete keytab file $filename";
+ }
+
+ if {$type == "WRFILE"} {
+ set type "FILE"
+ }
+
+ foreach entry $entries {
+ keytab_run "$testname setup" \
+ "-k $ktname -a -p $admin $entry" 0 {
+ "Enter password:" {
+ send "$password\n"
+ }
+ }
+ # if "Enter password:" needs to be optional:
+ # { timeout { } }
+ }
+
+ if {$verbose > 1} {
+ if {[file exists $filename]} {
+ puts "% exec $klist -k $type:$filename\n"
+ if {[catch "exec $klist -k $type:$filename"] != 0} {
+ error "$testname: $klist failed"
+ }
+ }
+ }
+}
+
+#
+# Run $KEYTAB with args ktargs. Each element of args is treated as an
+# expect block for the process, in turn. If all elements match and
+# then eof occurs with exit status status, the test passes; otherwise
+# it fails.
+#
+proc keytab_run { testname ktargs status args } {
+ global spawn_id timeout
+ global wait_error_index wait_status_index
+ global progname
+
+ verbose "running $progname for test: $testname" 2
+
+ eval keytab_start $ktargs
+
+ # wait for eof after exps
+ lappend args { eof { verbose $expect_out(buffer) 2 } }
+
+ foreach exp $args {
+ uplevel 1 "expect {
+ $exp
+ timeout { close; fail \"$testname: timeout\"; return }
+ eof { fail \"$testname: eof before expected message\"; return }
+ }"
+ }
+
+ set ret [wait]
+ verbose "% Exit $ret" 2
+
+ if {[lindex $ret $wait_error_index] == -1} {
+ fail "$testname: 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 "$testname"
+ } else {
+ fail "$testname: unexpected return status [lindex $ret $wait_status_index], should be $status"
+ }
+ }
+}
+
+
+proc klist_check { testname ktname args } {
+ global klist
+
+ if {[regexp {(.+):(.+)} $ktname dummy type filename] == 0} {
+ set filename $ktname
+ }
+
+ set lines [list "^Keytab name: (WR)?FILE:$filename" \
+ "^KVNO Principal" "^---- -------"]
+
+ foreach entry $args {
+ if {[lindex $entry 1] == 0} {
+ set line "^ *\[0-9\]+ [lindex $entry 0]"
+ } else {
+ set line "^ *[lindex $entry 1] [lindex $entry 0]"
+ }
+ lappend lines $line
+ }
+
+ set kl [open "|$klist -k FILE:$filename" r]
+
+ while {[gets $kl line] >= 0} {
+ if {([llength $lines] == 0) ||
+ ([regexp [lindex $lines 0] $line] == 0)} {
+ fail "$testname: klist check: \
+ [lindex $lines 0] does not match $line"
+ }
+ set lines [lrange $lines 1 end]
+ }
+ if {[catch "close $kl" msg] != 0} {
+ fail "$testname: klist: $msg"
+ return
+ }
+
+ if {[llength $lines] == 0} {
+ pass "$testname: klist check"
+ } else {
+ fail "$testname: klist check: too few entries in keytab"
+ }
+}
diff --git a/src/kadmin/keytab/unit-test/keytab.0/ChangeLog b/src/kadmin/keytab/unit-test/keytab.0/ChangeLog
new file mode 100644
index 0000000000..1b807089a9
--- /dev/null
+++ b/src/kadmin/keytab/unit-test/keytab.0/ChangeLog
@@ -0,0 +1,4 @@
+Mon Jul 15 17:09:01 1996 Marc Horowitz <marc@mit.edu>
+
+ * keytab-spec.exp: use /krb5/v5srvtab, since /krb5 is the test
+ dir.
diff --git a/src/kadmin/keytab/unit-test/keytab.0/adding.exp b/src/kadmin/keytab/unit-test/keytab.0/adding.exp
new file mode 100644
index 0000000000..159ac638b2
--- /dev/null
+++ b/src/kadmin/keytab/unit-test/keytab.0/adding.exp
@@ -0,0 +1,119 @@
+#
+# $Id$
+#
+
+set timeout 20
+
+load_lib "helpers.exp"
+
+if {[regexp {(.*/)?([^/]*)} $KEYTAB dummy dir progname] == 0} {
+ error "cannot set progname from $KEYTAB"
+}
+
+set ktscratch_file /tmp/keytab_test
+set ktscratch WRFILE:$ktscratch_file
+set ktarg "-k $ktscratch"
+set add_admin "$ktarg -a -p admin"
+set pwprompt { "Enter password:" { send "admin\n" } }
+
+setup_keytab "A1,A6" $ktscratch admin admin {}
+keytab_run "A1,A6" "$add_admin kttest1" 0 "$pwprompt" {
+ -re \
+ "$progname: Entry.*kttest1.*kvno \[0-9\]+.*keytab $ktscratch." {}
+}
+klist_check "A1,A6" $ktscratch {kttest1 0}
+
+setup_keytab "A2" $ktscratch admin admin {}
+keytab_run "A2" "-q $add_admin kttest1" 0 "$pwprompt" {
+ -re
+ "$progname: Entry.*kttest1.*kvno \[0-9\]+.*keytab $ktscratch." {
+ close; fail "A2: -q"; return }
+ eof { break }
+}
+klist_check "A2" $ktscratch {kttest1 0}
+
+setup_keytab "A3" $ktscratch admin admin {kttest1 kttest1}
+set kvno_key1 [exec $klist -k -K FILE:$ktscratch_file | \
+ awk "/kttest1/ && NR==4 {print \$1 \" \" \$3}"]
+set kvno_key2 [exec $klist -k -K FILE:$ktscratch_file | \
+ awk "/kttest1/ && NR==5 {print \$1 \" \" \$3}"]
+if {[lindex $kvno_key1 1] == [lindex $kvno_key2 1]} {
+ fail "A3: key compare"
+} else {
+ klist_check "A3" $ktscratch "kttest1 [lindex $kvno_key1 0]" \
+ "kttest1 [expr [lindex $kvno_key1 0]+1]"
+}
+
+setup_keytab "A7" $ktscratch admin admin {}
+keytab_run "A7" "$add_admin does-not-exist" 1 "$pwprompt" {
+ -re
+ "$progname: Principal does-not-exist does not exist." {}
+}
+
+setup_keytab "A4,A10,A11,A13,A15" $ktscratch admin admin { kttest1 kttest2}
+keytab_run "A4,A10,A11,A13,A15" "$ktarg -a kttest1" 0
+keytab_run "A4,A10,A11,A13,A15" "$ktarg -a kttest2" 0
+keytab_run "A4,A10,A11,A13,A15" "$ktarg -a kttest1" 0
+keytab_run "A4,A10,A11,A13,A15" "$ktarg -a kttest2" 0
+klist_check "A4,A10,A11,A13,A15" $ktscratch { kttest1 0 } \
+ { kttest2 0 } { kttest1 0 } { kttest2 0 } { kttest1 0 } { kttest2 0 }
+
+setup_keytab "A12" $ktscratch admin admin {}
+keytab_run "A12" "$ktarg -a -p admin/get-add kttest1" 1 "$pwprompt" {
+ "Operation requires ``change-password'' privilege while changing" {}
+}
+
+setup_keytab "A14" $ktscratch admin admin {}
+# assume the exit status won't be -1, so if the password prompt
+# doesn't appear the test will fail
+keytab_run "A14" "$ktarg -a kttest1" -1 {
+ "Enter password:" { send "\n"; expect eof; pass "A14: no -p"; return }
+}
+
+setup_keytab "A16" $ktscratch admin admin {}
+keytab_run "A16" "$ktarg -a -p does-not-exist kttest1" 1 {
+ "$progname: Principal does-not-exist does not exist." {}
+}
+
+setup_keytab "A17" $ktscratch admin admin { kttest1 kttest2}
+keytab_run "A17" "$ktarg -a -p kttest2 kttest1" 1 {
+ "Enter password:" { close; fail "A17: no password prompt"; return }
+ default { break }
+}
+
+setup_keytab "A18" $ktscratch admin admin { }
+keytab_run "A18" "$ktarg -a -c -p admin dne1" 0 "$pwprompt" {
+ "$progname: Created principal dne1" {}
+} {
+ -re
+ "$progname: Entry.*dne1.*kvno \[0-9\]+.*keytab $ktscratch." {}
+}
+klist_check "A18" $ktscratch {dne1 0}
+
+setup_keytab "A19" $ktscratch admin admin {}
+keytab_run "A9" "-q $ktarg -a -c -p admin dne2" 0 "$pwprompt" {
+ "$progname: Created principal dne2" { close; fail "A19: -q"; return }
+ eof { break }
+}
+klist_check "A19" $ktscratch {dne2 0}
+
+setup_keytab "A21" $ktscratch admin admin {}
+keytab_run "A21" "$ktarg -a -c -p admin kttest1" 0 "$pwprompt" {
+ "$progname: Principal kttest1 already exists." {}
+} {
+ -re \
+ "$progname: Entry.*kttest1.*kvno \[0-9\]+.*keytab $ktscratch." {}
+}
+klist_check "A21" $ktscratch {kttest1 0}
+
+setup_keytab "A22" $ktscratch admin admin {}
+keytab_run "A22" "$ktarg -a -c -p admin/modify kttest1" 1 "$pwprompt" {
+ "Operation requires ``add'' and ``modify'' privileges while creating" {}
+}
+
+setup_keytab "A23" $ktscratch admin admin {}
+keytab_run "A23" "$ktarg -a -c -p admin/get kttest1" 1 "$pwprompt" {
+ "Operation requires ``add'' and ``modify'' privileges while creating" {}
+}
+
+exec rm -f $ktscratch_file
diff --git a/src/kadmin/keytab/unit-test/keytab.0/keytab-spec.exp b/src/kadmin/keytab/unit-test/keytab.0/keytab-spec.exp
new file mode 100644
index 0000000000..8da80eb694
--- /dev/null
+++ b/src/kadmin/keytab/unit-test/keytab.0/keytab-spec.exp
@@ -0,0 +1,47 @@
+#
+# $Id$
+#
+
+set timeout 10
+
+load_lib "helpers.exp"
+
+if {[regexp {(.*/)?([^/]*)} $KEYTAB dummy dir progname] == 0} {
+ error "cannot set progname from $KEYTAB"
+}
+
+set hname [exec $hostname]
+set qname [exec $qualname $hname]
+
+set testfile1 /tmp/keytab-test1
+set testfile2 /tmp/keytab-test2
+
+if {[info exists env(KRB5_KTNAME)]} {
+ set ktname_orig $env(KRB5_KTNAME)
+ unset env(KRB5_KTNAME)
+}
+
+setup_keytab "K1" WRFILE:/krb5/v5srvtab admin admin "host/$qname"
+klist_check "K1" FILE:/krb5/v5srvtab "host/$qname 0"
+keytab_run "K1" "-a host/$qname" 0
+klist_check "K1" FILE:/krb5/v5srvtab "host/$qname 0" "host/$qname 0"
+keytab_run "K1" "-r host/$qname old" 0
+klist_check "K1" FILE:/krb5/v5srvtab "host/$qname 0"
+
+if {[info exists ktname_orig]} {
+ set env(KRB5_KTNAME) $ktname_orig
+}
+
+setup_keytab "K2" WRFILE:$testfile1 admin admin {}
+keytab_run "K2" "-k WRFILE:$testfile1 -a -p admin kttest1" 0 {
+ "Enter password:" { send "admin\n" }
+}
+klist_check "K2" FILE:$testfile1 "kttest1 0"
+
+setup_keytab "K2" WRFILE:$testfile2 admin admin {}
+keytab_run "K3" "-k $testfile2 -a -p admin kttest1" 0 {
+ "Enter password:" { send "admin\n" }
+}
+klist_check "K3" FILE:$testfile2 "kttest1 0"
+
+exec rm -f $testfile1 $testfile2
diff --git a/src/kadmin/keytab/unit-test/keytab.0/removing.exp b/src/kadmin/keytab/unit-test/keytab.0/removing.exp
new file mode 100644
index 0000000000..a7a50f045d
--- /dev/null
+++ b/src/kadmin/keytab/unit-test/keytab.0/removing.exp
@@ -0,0 +1,125 @@
+#
+# $Id$
+#
+
+set timeout 10
+
+load_lib "helpers.exp"
+
+if {[regexp {(.*/)?([^/]*)} $KEYTAB dummy dir progname] == 0} {
+ error "cannot set progname from $KEYTAB"
+}
+
+set ktscratch_file /tmp/keytab_test
+set ktscratch WRFILE:$ktscratch_file
+set ktarg "-k $ktscratch"
+
+# Get the kvnos we will need later
+setup_keytab "setup" $ktscratch admin admin { kttest1 kttest2 }
+set kvno1 [exec $klist -k -K FILE:$ktscratch_file | \
+ awk "/kttest1/ {print \$1}"]
+set kvno2 [exec $klist -k -K FILE:$ktscratch_file | \
+ awk "/kttest2/ {print \$1}"]
+
+setup_keytab "R1" $ktscratch admin admin { kttest1 }
+set kvno1 [expr $kvno1+1]
+keytab_run "R1" "$ktarg -r kttest1" 0 {
+ -re
+ "$progname: Entry for principal kttest1 with kvno \[0-9\]+\
+ removed from keytab $ktscratch" {}
+}
+klist_check "R1" $ktscratch
+
+setup_keytab "R2" $ktscratch admin admin { kttest1 }
+set kvno1 [expr $kvno1+1]
+keytab_run "R2" "$ktarg -q -r kttest1" 0 {
+ -re
+ "$progname: Entry for principal kttest1 with kvno \[0-9\]+\
+ removed from keytab $ktscratch" { close; fail "R2: -q"; return }
+ eof { break }
+}
+klist_check "R2" $ktscratch
+
+setup_keytab "R3" $ktscratch admin admin { kttest1 }
+set kvno1 [expr $kvno1+1]
+klist_check "R3" $ktscratch "kttest1 $kvno1"
+keytab_run "R3" "$ktarg -r kttest1 $kvno1" 0
+klist_check "R3" $ktscratch
+
+setup_keytab "R4" $ktscratch admin admin { kttest1 kttest1 kttest1 }
+set kvno1 [expr $kvno1+3]
+klist_check "R4" $ktscratch "kttest1 [expr $kvno1-2]" \
+ "kttest1 [expr $kvno1-1]" "kttest1 $kvno1"
+keytab_run "R4" "$ktarg -r kttest1" 0
+klist_check "R4" $ktscratch "kttest1 [expr $kvno1-2]" \
+ "kttest1 [expr $kvno1-1]"
+
+setup_keytab "R5" $ktscratch admin admin { kttest1 kttest1 kttest1 }
+set kvno1 [expr $kvno1+3]
+keytab_run "R5" "$ktarg -r kttest1 old" 0
+klist_check "R5" $ktscratch "kttest1 $kvno1"
+
+setup_keytab "R6" $ktscratch admin admin { kttest1 kttest1 kttest1 }
+set kvno1 [expr $kvno1+3]
+keytab_run "R6" "$ktarg -r kttest1 old" 0
+klist_check "R6" $ktscratch "kttest1 $kvno1"
+
+setup_keytab "R7" $ktscratch admin admin { kttest1 kttest1 kttest1 }
+set kvno1 [expr $kvno1+3]
+keytab_run "R7" "$ktarg -r kttest1 all" 0 {
+ "$progname: Entry for principal kttest1" {}
+} {
+ "$progname: Entry for principal kttest1" {}
+} {
+ "$progname: Entry for principal kttest1" {}
+}
+klist_check "R7" $ktscratch
+
+setup_keytab "R8" $ktscratch admin admin { kttest1 }
+set kvno1 [expr $kvno1+1]
+keytab_run "R8" "$ktarg -r kttest2" 1 {
+ "$progname: No entry for principal kttest2 exists in keytab" {}
+}
+klist_check "R8" $ktscratch "kttest1 $kvno1"
+
+setup_keytab "R9" $ktscratch admin admin { kttest1 }
+set kvno1 [expr $kvno1+1]
+keytab_run "R9" "$ktarg -r kttest2 1" 1 {
+ "$progname: No entry for principal kttest2 with kvno 1 exists in keytab" {}
+}
+klist_check "R9" $ktscratch "kttest1 $kvno1"
+
+setup_keytab "R10" $ktscratch admin admin { kttest1 }
+set kvno1 [expr $kvno1+1]
+keytab_run "R10" "$ktarg -r kttest2 all" 1 {
+ "$progname: No entry for principal kttest2 exists in keytab" {}
+}
+klist_check "R10" $ktscratch "kttest1 $kvno1"
+
+setup_keytab "R11" $ktscratch admin admin { kttest1 }
+set kvno1 [expr $kvno1+1]
+keytab_run "R11" "$ktarg -r kttest1 old" 1 {
+ "$progname: There is only one entry for principal kttest1 in keytab" {}
+}
+klist_check "R11" $ktscratch "kttest1 $kvno1"
+
+setup_keytab "R13" $ktscratch admin admin { kttest1 kttest2 kttest1 }
+set kvno1 [expr $kvno1+2]
+set kvno2 [expr $kvno2+1]
+keytab_run "R13" "$ktarg -r kttest2 $kvno2" 0
+klist_check "R13" $ktscratch "kttest1 [expr $kvno1-1]" "kttest1 $kvno1"
+
+setup_keytab "R14" $ktscratch admin admin { kttest1 kttest2 kttest1 kttest2 }
+set kvno1 [expr $kvno1+2]
+set kvno2 [expr $kvno2+2]
+keytab_run "R14" "$ktarg -r kttest1 all" 0
+klist_check "R14" $ktscratch "kttest2 [expr $kvno2-1]" "kttest2 $kvno2"
+
+setup_keytab "R15" $ktscratch admin admin { kttest1 kttest2 kttest1 kttest2 }
+set kvno1 [expr $kvno1+2]
+set kvno2 [expr $kvno2+2]
+keytab_run "R15" "$ktarg -r kttest1 old" 0
+klist_check "R15" $ktscratch "kttest2 [expr $kvno2-1]" \
+ "kttest1 $kvno1" "kttest2 $kvno2"
+
+exec rm -f $ktscratch_file
diff --git a/src/kadmin/ktutil/ChangeLog b/src/kadmin/ktutil/ChangeLog
index 7c8582fd18..6ca64712d0 100644
--- a/src/kadmin/ktutil/ChangeLog
+++ b/src/kadmin/ktutil/ChangeLog
@@ -2,6 +2,10 @@ 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
diff --git a/src/kadmin/ktutil/configure.in b/src/kadmin/ktutil/configure.in
index 6be5dc2aac..7e9f3e1a0b 100644
--- a/src/kadmin/ktutil/configure.in
+++ b/src/kadmin/ktutil/configure.in
@@ -1,7 +1,6 @@
AC_INIT(ktutil.c)
CONFIG_RULES
AC_PROG_INSTALL
-USE_KADM_LIBRARY
USE_KRB4_LIBRARY
USE_SS_LIBRARY
KRB5_LIBRARIES
diff --git a/src/kadmin/passwd/ChangeLog b/src/kadmin/passwd/ChangeLog
new file mode 100644
index 0000000000..d0f4cbafca
--- /dev/null
+++ b/src/kadmin/passwd/ChangeLog
@@ -0,0 +1,20 @@
+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/src/kadmin/passwd/Kpasswd b/src/kadmin/passwd/Kpasswd
new file mode 100644
index 0000000000..a7ec03161a
--- /dev/null
+++ b/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/src/kadmin/passwd/Makefile.in b/src/kadmin/passwd/Makefile.in
new file mode 100644
index 0000000000..46e9620709
--- /dev/null
+++ b/src/kadmin/passwd/Makefile.in
@@ -0,0 +1,23 @@
+CFLAGS = $(CCOPTS) $(DEFS) $(LOCALINCLUDE) -I. -DUSE_KADM5_API_VERSION=1
+
+PROG = kpasswd
+OBJS = tty_kpasswd.o kpasswd.o kpasswd_strings.o
+
+all:: $(PROG).local $(PROG)
+
+kpasswd_strings.c kpasswd_strings.h: $(srcdir)/kpasswd_strings.et
+
+$(OBJS): kpasswd_strings.h
+
+$(PROG).local: $(OBJS) $(SRVDEPLIBS)
+ $(CC) $(LDFLAGS) $(LDARGS) -o $(PROG).local $(OBJS) $(SRVLIBS)
+
+$(PROG): $(OBJS) $(CLNTDEPLIBS)
+ $(CC) $(LDFLAGS) $(LDARGS) -o $(PROG) $(OBJS) $(CLNTLIBS)
+
+install::
+ $(INSTALL_PROGRAM) $(PROG).local ${DESTDIR}$(ADMIN_BINDIR)/$(PROG)
+ $(INSTALL_PROGRAM) $(PROG) ${DESTDIR}$(ADMIN_BINDIR)/$(PROG)
+
+clean::
+ $(RM) kpasswd_strings.c kpasswd_strings.h $(PROG).local $(PROG) $(OBJS)
diff --git a/src/kadmin/passwd/Makefile.ov b/src/kadmin/passwd/Makefile.ov
new file mode 100644
index 0000000000..8841a4762b
--- /dev/null
+++ b/src/kadmin/passwd/Makefile.ov
@@ -0,0 +1,34 @@
+TOP = ..
+include $(TOP)/config.mk/template
+
+CFLAGS := $(CFLAGS) -DUSE_KADM5_API_VERSION=1
+
+# This used as a string table, not an error table
+ETABLES = kpasswd_strings.et
+expand ErrorTables
+
+kpasswd.o: kpasswd_strings.h
+depend:: kpasswd_strings.h
+
+PROG = kpasswd
+SRCS = tty_kpasswd.c kpasswd.c kpasswd_strings.c
+OBJS = tty_kpasswd.o kpasswd.o kpasswd_strings.o
+LIBS = $(LIBADMCLNT) $(LIBCOM_ERR) $(LIBGSSAPI_KRB5) $(LIBRPCLIB) \
+ $(LIBDYN) $(LIBDB) $(LIBKDB5) $(LIBKRB5) $(LIBCRYPTO) \
+ $(LIBISODE) $(NDBMLIB) $(BSDLIB) $(NETLIB)
+
+expand NormalProgram
+
+ifndef OMIT_XM_KPASSWD
+PROG = xm_kpasswd
+CFLAGS := -I$(XM_INC) -I$(XT_INC) -I$(X_INC) $(CFLAGS)
+SRCS := xm_kpasswd.c kpasswd.c kpasswd_strings.c
+OBJS := xm_kpasswd.o kpasswd.o kpasswd_strings.o
+LIBS := $(LIBS) $(XM_LIB) $(XT_LIB) $(X_LIB) $(REGEXLIB)
+
+expand NormalProgram
+endif
+
+SUBDIRS = unit-test
+
+expand SubdirTarget
diff --git a/src/kadmin/passwd/configure.in b/src/kadmin/passwd/configure.in
new file mode 100644
index 0000000000..fe1389a832
--- /dev/null
+++ b/src/kadmin/passwd/configure.in
@@ -0,0 +1,13 @@
+AC_INIT(kpasswd.c)
+CONFIG_RULES
+AC_PROG_INSTALL
+AC_PROG_AWK
+USE_KADMCLNT_LIBRARY
+USE_GSSAPI_LIBRARY
+USE_KADMSRV_LIBRARY
+USE_GSSRPC_LIBRARY
+USE_DYN_LIBRARY
+USE_KDB5_LIBRARY
+KRB5_LIBRARIES
+V5_USE_SHARED_LIB
+V5_AC_OUTPUT_MAKEFILE
diff --git a/src/kadmin/passwd/kpasswd.c b/src/kadmin/passwd/kpasswd.c
new file mode 100644
index 0000000000..f87ad1cb00
--- /dev/null
+++ b/src/kadmin/passwd/kpasswd.c
@@ -0,0 +1,280 @@
+/*
+ * 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
+#define initialize_kpasswd_strings initialize_kpws_error_table
+
+#include <stdio.h>
+#include <pwd.h>
+#include <string.h>
+
+extern char *whoami;
+
+extern void display_intro_message();
+extern long read_old_password();
+extern long read_new_password();
+
+#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;
+ 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*/
+ }
+
+ krb5_init_ets(context);
+
+ /************************************
+ * 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((int) 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, OVSEC_KADM_CHANGEPW_SERVICE,
+ admin_realm /* we probably should take a -r */
+ /* someday */,
+ OVSEC_KADM_STRUCT_VERSION,
+ OVSEC_KADM_API_VERSION_1,
+ &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);
+ if (code = ovsec_kadm_free_principal_ent(server_handle, principal_entry)) {
+ (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);
+ }
+ if (code = 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_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. */
+ if (code = ovsec_kadm_free_principal_ent(server_handle,
+ principal_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);
+ }
+ }
+
+ 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/src/kadmin/passwd/kpasswd_strings.et b/src/kadmin/passwd/kpasswd_strings.et
new file mode 100644
index 0000000000..b78aa9d6f2
--- /dev/null
+++ b/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/src/kadmin/passwd/tty_kpasswd.c b/src/kadmin/passwd/tty_kpasswd.c
new file mode 100644
index 0000000000..6d865a020f
--- /dev/null
+++ b/src/kadmin/passwd/tty_kpasswd.c
@@ -0,0 +1,80 @@
+/*
+ * 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
+#define initialize_kpasswd_strings initialize_kpws_error_table
+
+#include <stdio.h>
+#include <pwd.h>
+#include <string.h>
+
+char *whoami;
+
+void display_intro_message(fmt_string, arg_string)
+ char *fmt_string;
+ char *arg_string;
+{
+ com_err(whoami, 0, fmt_string, arg_string);
+}
+
+long read_old_password(context, password, pwsize)
+ krb5_context context;
+ char *password;
+ int *pwsize;
+{
+ long code = krb5_read_password(context,
+ (char *)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;
+ 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;
+
+ initialize_kpasswd_strings();
+
+ whoami = (whoami = strrchr(argv[0], '/')) ? whoami + 1 : argv[0];
+
+ if (retval = krb5_init_context(&context)) {
+ com_err(whoami, retval, "initializing krb5 context");
+ exit(retval);
+ }
+ retval = kpasswd(context, argc, argv);
+
+ if (!retval)
+ printf(string_text(KPW_STR_PASSWORD_CHANGED));
+
+ exit(retval);
+}
diff --git a/src/kadmin/passwd/unit-test/Makefile.ov b/src/kadmin/passwd/unit-test/Makefile.ov
new file mode 100644
index 0000000000..db042720bf
--- /dev/null
+++ b/src/kadmin/passwd/unit-test/Makefile.ov
@@ -0,0 +1,23 @@
+#
+# $Id$
+#
+
+TOP = ../..
+include $(TOP)/config.mk/template
+
+USER = root
+
+unit-test:: unit-test-setup unit-test-body unit-test-cleanup
+
+unit-test-body::
+ $(RUNTEST) KPASSWD=../kpasswd \
+ KINIT=$(TOP)/../clients/kinit/kinit \
+ KDESTROY=$(TOP)/../clients/kdestroy/kdestroy \
+ USER=$(USER) --tool kpasswd
+
+unit-test-setup::
+ $(START_SERVERS)
+ echo "source $(TCLUTIL); catch {ovsec_kadm_init admin admin \$$OVSEC_KADM_ADMIN_SERVICE null \$$OVSEC_KADM_STRUCT_VERSION \$$OVSEC_KADM_API_VERSION_1 server_handle; ovsec_kadm_create_principal \$$server_handle [simple_principal $(USER)] {OVSEC_KADM_PRINCIPAL} $(USER); ovsec_kadm_destroy \$$server_handle;}; if {[info exists errorInfo]} { puts stderr \$$errorInfo; exit 1; }" | $(CLNTTCL)
+
+unit-test-cleanup::
+ $(STOP_SERVERS)
diff --git a/src/kadmin/passwd/unit-test/config/unix.exp b/src/kadmin/passwd/unit-test/config/unix.exp
new file mode 100644
index 0000000000..c77aa016a3
--- /dev/null
+++ b/src/kadmin/passwd/unit-test/config/unix.exp
@@ -0,0 +1,36 @@
+#
+# 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/src/kadmin/passwd/unit-test/helpers.exp b/src/kadmin/passwd/unit-test/helpers.exp
new file mode 100644
index 0000000000..9dcfbcf01e
--- /dev/null
+++ b/src/kadmin/passwd/unit-test/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 $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 {
+ 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 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:"
+ { 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:"
+ { send "$pass2\n" }
+ -re "^$s+.*$s+.*$s+.*$s+New password:"
+ { send "$pass2\n" }
+ } {
+ -re "^$s+New password \\(again\\):"
+ { 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:"
+ { 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:"
+ { 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:"
+ { send "$pass2\n" }
+ -re "^$s+.*$s+.*$s+.*$s+New password:"
+ { send "$pass2\n" }
+ } {
+ -re "^$s+New password \\(again\\):"
+ { send "$pass3\n" }
+ } {
+ -re "$s+$err2"
+ { mypass }
+ }
+}
+
diff --git a/src/kadmin/passwd/unit-test/kpasswd.0/changing.exp b/src/kadmin/passwd/unit-test/kpasswd.0/changing.exp
new file mode 100644
index 0000000000..4f0354c633
--- /dev/null
+++ b/src/kadmin/passwd/unit-test/kpasswd.0/changing.exp
@@ -0,0 +1,102 @@
+#
+# $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:"
+ { send "test1\n" }
+} {
+ -re "$s+.*$s+.*$s+.*char.*classes.*"
+ { myfail "policy description displayed" }
+ timeout { mypass }
+} {
+ -re "^$s+New password:"
+ { send "newpass\n" }
+} {
+ -re "^$s+New password \\(again\\):"
+ { 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 ovpasswd 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:"
+ { send "polAAAAAA\n" }
+} {
+ -re "$s+.*$s+.*$s+.*8 char.*2 classes.*$s+New password:"
+ { send "newpass1234\n" }
+} {
+ -re "^$s+New password \\(again\\):"
+ { 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
+
+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 .*199[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/src/kadmin/passwd/unit-test/kpasswd.0/connecting.exp b/src/kadmin/passwd/unit-test/kpasswd.0/connecting.exp
new file mode 100644
index 0000000000..2cda17a6a3
--- /dev/null
+++ b/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/src/kadmin/passwd/unit-test/kpasswd.0/principal.exp b/src/kadmin/passwd/unit-test/kpasswd.0/principal.exp
new file mode 100644
index 0000000000..e2bc205697
--- /dev/null
+++ b/src/kadmin/passwd/unit-test/kpasswd.0/principal.exp
@@ -0,0 +1,55 @@
+#
+# $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
+
+set whoami $USER
+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/src/kadmin/passwd/unit-test/kpasswd.0/usage.exp b/src/kadmin/passwd/unit-test/kpasswd.0/usage.exp
new file mode 100644
index 0000000000..e132bab2f8
--- /dev/null
+++ b/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/src/kadmin/passwd/xm_kpasswd.c b/src/kadmin/passwd/xm_kpasswd.c
new file mode 100644
index 0000000000..0db1111c64
--- /dev/null
+++ b/src/kadmin/passwd/xm_kpasswd.c
@@ -0,0 +1,450 @@
+/*
+ * 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)
+ {
+ strcpy(buf, whoami);
+ strcat(buf, ": ");
+ }
+ if (code)
+ {
+ strcat(buf, error_message(code));
+ strcat(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)
+ char *fmt_string;
+ 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;
+ 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;
+ 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/src/kadmin/scripts/inst-hdrs.sh b/src/kadmin/scripts/inst-hdrs.sh
new file mode 100644
index 0000000000..242be89e91
--- /dev/null
+++ b/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/src/kadmin/server/Makefile.in b/src/kadmin/server/Makefile.in
new file mode 100644
index 0000000000..41bea4f455
--- /dev/null
+++ b/src/kadmin/server/Makefile.in
@@ -0,0 +1,15 @@
+CFLAGS = $(CCOPTS) $(DEFS) $(LOCALINCLUDE)
+
+PROG = kadmind
+OBJS = kadm_rpc_svc.o server_stubs.o ovsec_kadmd.o misc.o server_glue_v1.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/src/kadmin/server/Makefile.ov b/src/kadmin/server/Makefile.ov
new file mode 100644
index 0000000000..4f8e489fbb
--- /dev/null
+++ b/src/kadmin/server/Makefile.ov
@@ -0,0 +1,39 @@
+TOP = ..
+include $(TOP)/config.mk/template
+CFLAGS := $(CFLAGS)
+
+ifdef KRB5B4
+CFLAGS += -DKRB5B4
+endif
+
+PROG := kadmind
+SRCS := kadm_rpc_svc.c server_stubs.c ovsec_kadmd.c misc.c server_glue_v1.c
+OBJS := kadm_rpc_svc.o server_stubs.o ovsec_kadmd.o misc.o server_glue_v1.o
+LIBS := $(LIBADMSRV) $(LIBRPCLIB) $(LIBGSSAPI_KRB5) $(LIBDYN) \
+ $(LIBKDB5) $(LIBKRB5_ALL) $(LIBDB) \
+ $(NDBMLIB) $(NETLIB) $(BSDLIB) $(REGEXLIB)
+
+expand InstallServer
+expand Depend
+
+clean::
+ $(CLEAN) acls.c
+
+expand Saber
+
+SABER_LIBS := $(LIBDB) $(LIBGSSAPI_KRB5) $(LIBDYN) $(LIBKDB5) \
+ $(LIBKRB5) $(LIBCRYPTO) $(LIBISODE) $(LIBCOM_ERR)
+SABER_FLAGS := -G
+
+saber::
+ #cd ../../rpc
+ #make saber
+ #cd ../admin/lib/adb
+ #make saber
+ #cd ../common
+ #make saber
+ #cd ../server
+ #make saber
+ #cd ../../server
+ #load /usr/local/lib/gcc-lib/sparc-sun-sunos4.1.3/2.4.5/libgcc.a
+ #load $(SABER_FLAGS) $(LDFLAGS) $(GSSLIB) $(SABER_LIBS)
diff --git a/src/kadmin/server/acls.l b/src/kadmin/server/acls.l
new file mode 100644
index 0000000000..aee4801e99
--- /dev/null
+++ b/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/src/kadmin/server/configure.in b/src/kadmin/server/configure.in
new file mode 100644
index 0000000000..98492f909c
--- /dev/null
+++ b/src/kadmin/server/configure.in
@@ -0,0 +1,17 @@
+AC_INIT(ovsec_kadmd.c)
+CONFIG_RULES
+AC_PROG_INSTALL
+dnl AC_CHECK_FUNCS(waitpid vsprintf)
+dnl AC_CHECK_HEADERS(sys/select.h)
+dnl CHECK_SIGNALS
+dnl CHECK_SETJMP
+dnl CHECK_WAIT_TYPE
+dnl ET_RULES
+USE_KADMSRV_LIBRARY
+USE_GSSRPC_LIBRARY
+USE_GSSAPI_LIBRARY
+USE_KDB5_LIBRARY
+USE_DYN_LIBRARY
+KRB5_LIBRARIES
+V5_USE_SHARED_LIB
+V5_AC_OUTPUT_MAKEFILE
diff --git a/src/kadmin/server/kadm_rpc_svc.c b/src/kadmin/server/kadm_rpc_svc.c
new file mode 100644
index 0000000000..9128821d50
--- /dev/null
+++ b/src/kadmin/server/kadm_rpc_svc.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Id$
+ * $Source$
+ *
+ * $Log$
+ * Revision 1.12 1996/07/22 20:28:53 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.11.4.1 1996/07/18 03:03:35 marc
+ * merged in changes from OV_9510_BP to OV_9510_FINAL1
+ *
+ * Revision 1.11.2.2 1996/07/09 20:07:57 marc
+ * * kadm_rpc_svc.c: renamed <ovsec_admin/foo.h> to <kadm5/foo.h>
+ *
+ * Revision 1.11.2.1 1996/06/20 21:56:44 marc
+ * File added to the repository on a branch
+ *
+ * Revision 1.11 1996/06/17 19:49:28 bjaspan
+ * use krb5_klog_syslog
+ *
+ * Revision 1.10 1996/05/29 21:07:53 bjaspan
+ * be a bit more loud when warning, and don't exit when args can't be freed
+ *
+ * Revision 1.9 1996/05/20 21:34:56 bjaspan
+ * log an error when sendreply fails
+ *
+ * Revision 1.8 1996/05/12 07:06:23 marc
+ * - fixup includes to match beta6
+ *
+ * Revision 1.7 1995/08/01 19:25:59 bjaspan
+ * [secure/1318] allow retrieval of some/all principal/policy names
+ *
+ * Revision 1.6 1994/09/20 16:25:33 bjaspan
+ * [secure-admin/2436: API versioning fixes to various admin files]
+ * [secure-releng/2502: audit secure-admin/2436: random API versioning fixes]
+ *
+ * Sandbox:
+ *
+ * More API versioning stuff -- need to add api_version field to RPC
+ * return structures in addition to calling structures.
+ *
+ * Revision 1.6 1994/09/12 20:19:16 jik
+ * More API versioning stuff -- need to add api_version field to RPC
+ * return structures in addition to calling structures.
+ *
+ * Revision 1.5 1994/08/16 18:55:46 jik
+ * Versioning changes.
+ *
+ * Revision 1.4 1994/04/25 17:05:05 bjaspan
+ * [secure-admin/1832] accept old gssapi number, log error when number
+ * is wrong
+ *
+ * Revision 1.3 1993/11/15 02:30:54 shanzer
+ * added funky procedure header comments.
+ *
+ * Revision 1.2 1993/11/10 23:11:21 bjaspan
+ * added getprivs
+ *
+ * Revision 1.1 1993/11/05 07:09:00 bjaspan
+ * Initial revision
+ *
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include <syslog.h>
+#include <memory.h>
+#include <kadm5/kadm_rpc.h>
+#include <krb5.h>
+#include <kadm5/admin.h>
+
+/*
+ * 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_1_arg;
+ dprinc_arg delete_principal_1_arg;
+ mprinc_arg modify_principal_1_arg;
+ rprinc_arg rename_principal_1_arg;
+ gprinc_arg get_principal_1_arg;
+ chpass_arg chpass_principal_1_arg;
+ chrand_arg chrand_principal_1_arg;
+ cpol_arg create_policy_1_arg;
+ dpol_arg delete_policy_1_arg;
+ mpol_arg modify_policy_1_arg;
+ gpol_arg get_policy_1_arg;
+ } argument;
+ char *result;
+ bool_t (*xdr_argument)(), (*xdr_result)();
+ char *(*local)();
+
+ if (rqstp->rq_cred.oa_flavor != AUTH_GSSAPI &&
+ rqstp->rq_cred.oa_flavor != AUTH_GSSAPI_COMPAT) {
+ krb5_klog_syslog(LOG_ERR, "Authentication attempt failed: %s, invalid "
+ "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_1;
+ break;
+
+ case DELETE_PRINCIPAL:
+ xdr_argument = xdr_dprinc_arg;
+ xdr_result = xdr_generic_ret;
+ local = (char *(*)()) delete_principal_1;
+ break;
+
+ case MODIFY_PRINCIPAL:
+ xdr_argument = xdr_mprinc_arg;
+ xdr_result = xdr_generic_ret;
+ local = (char *(*)()) modify_principal_1;
+ break;
+
+ case RENAME_PRINCIPAL:
+ xdr_argument = xdr_rprinc_arg;
+ xdr_result = xdr_generic_ret;
+ local = (char *(*)()) rename_principal_1;
+ break;
+
+ case GET_PRINCIPAL:
+ xdr_argument = xdr_gprinc_arg;
+ xdr_result = xdr_gprinc_ret;
+ local = (char *(*)()) get_principal_1;
+ break;
+
+ case GET_PRINCS:
+ xdr_argument = xdr_gprincs_arg;
+ xdr_result = xdr_gprincs_ret;
+ local = (char *(*)()) get_princs_1;
+ break;
+
+ case CHPASS_PRINCIPAL:
+ xdr_argument = xdr_chpass_arg;
+ xdr_result = xdr_generic_ret;
+ local = (char *(*)()) chpass_principal_1;
+ break;
+
+ case CHRAND_PRINCIPAL:
+ xdr_argument = xdr_chrand_arg;
+ xdr_result = xdr_chrand_ret;
+ local = (char *(*)()) chrand_principal_1;
+ break;
+
+ case CREATE_POLICY:
+ xdr_argument = xdr_cpol_arg;
+ xdr_result = xdr_generic_ret;
+ local = (char *(*)()) create_policy_1;
+ break;
+
+ case DELETE_POLICY:
+ xdr_argument = xdr_dpol_arg;
+ xdr_result = xdr_generic_ret;
+ local = (char *(*)()) delete_policy_1;
+ break;
+
+ case MODIFY_POLICY:
+ xdr_argument = xdr_mpol_arg;
+ xdr_result = xdr_generic_ret;
+ local = (char *(*)()) modify_policy_1;
+ break;
+
+ case GET_POLICY:
+ xdr_argument = xdr_gpol_arg;
+ xdr_result = xdr_gpol_ret;
+ local = (char *(*)()) get_policy_1;
+ break;
+
+ case GET_POLS:
+ xdr_argument = xdr_gpols_arg;
+ xdr_result = xdr_gpols_ret;
+ local = (char *(*)()) get_pols_1;
+ break;
+
+ case GET_PRIVS:
+ xdr_argument = xdr_u_int32;
+ xdr_result = xdr_getprivs_ret;
+ local = (char *(*)()) get_privs_1;
+ break;
+
+ case INIT:
+ xdr_argument = xdr_u_int32;
+ xdr_result = xdr_generic_ret;
+ local = (char *(*)()) init_1;
+ break;
+
+ default:
+ krb5_klog_syslog(LOG_ERR, "Invalid OVSEC_KADM 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;
+}
diff --git a/src/kadmin/server/misc.c b/src/kadmin/server/misc.c
new file mode 100644
index 0000000000..9dc3d9d28f
--- /dev/null
+++ b/src/kadmin/server/misc.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <kadm5/adb.h>
+#include <kadm5/server_internal.h>
+#include <krb5/kdb.h>
+#include "misc.h"
+
+/*
+ * Function: chpass_principal_wrapper
+ *
+ * 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
+ * passoword (input) passowrd we are going to change to.
+ * <return value> 0 on sucsess 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(void *server_handle,
+ krb5_principal principal, char *password)
+{
+ 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 (ret = krb5_timeofday(handle->context, &now))
+ return ret;
+
+ if((ret = kadm5_get_principal(handle->lhandle, principal,
+ &princ,
+ KADM5_PRINCIPAL_NORMAL_MASK)) !=
+ KADM5_OK)
+ 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)) {
+ (void) kadm5_free_policy_ent(handle->lhandle, &pol);
+ (void) kadm5_free_principal_ent(handle->lhandle, &princ);
+ return KADM5_PASS_TOOSOON;
+ }
+ if (ret = kadm5_free_policy_ent(handle->lhandle, &pol)) {
+ (void) kadm5_free_principal_ent(handle->lhandle, &princ);
+ return ret;
+ }
+ }
+ if (ret = kadm5_free_principal_ent(handle->lhandle, &princ))
+ return ret;
+
+ return kadm5_chpass_principal(server_handle, principal, password);
+}
+
+
+/*
+ * Function: randkey_principal_wrapper
+ *
+ * Purpose: wrapper to kadm5_randkey_principal which checks the
+ passwords min. life.
+ *
+ * Arguments:
+ * principal (input) krb5_principal whose password we are
+ * changing
+ * 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(void *server_handle,
+ krb5_principal principal,
+ krb5_keyblock **keys, int *n_keys)
+{
+
+ 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 (ret = krb5_timeofday(handle->context, &now))
+ return ret;
+
+ if((ret = kadm5_get_principal(handle->lhandle,
+ principal, &princ,
+ KADM5_PRINCIPAL_NORMAL_MASK)) !=
+ OSA_ADB_OK)
+ 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)) {
+ (void) kadm5_free_policy_ent(handle->lhandle, &pol);
+ (void) kadm5_free_principal_ent(handle->lhandle, &princ);
+ return KADM5_PASS_TOOSOON;
+ }
+ if (ret = kadm5_free_policy_ent(handle->lhandle, &pol)) {
+ (void) kadm5_free_principal_ent(handle->lhandle, &princ);
+ return ret;
+ }
+ }
+ if (ret = kadm5_free_principal_ent(handle->lhandle, &princ))
+ return ret;
+ return kadm5_randkey_principal(server_handle, principal, keys, n_keys);
+}
diff --git a/src/kadmin/server/misc.h b/src/kadmin/server/misc.h
new file mode 100644
index 0000000000..c92f5fe32f
--- /dev/null
+++ b/src/kadmin/server/misc.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 1994 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ *
+ * $Log$
+ * Revision 1.6 1996/07/22 20:28:56 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:03:40 marc
+ * merged in changes from OV_9510_BP to OV_9510_FINAL1
+ *
+ * Revision 1.5.2.1 1996/06/20 21:57:20 marc
+ * File added to the repository on a branch
+ *
+ * Revision 1.5 1996/05/30 21:13:24 bjaspan
+ * kadm5_get_principal_v1 takes a kadm5_principal_ent_t_v1
+ * add kadm5_get_policy_v1
+ *
+ * Revision 1.4 1996/05/20 21:39:05 bjaspan
+ * rename to kadm5
+ * add kadm5_get_principal_v1
+ *
+ * Revision 1.3 1994/09/13 18:24:41 jik
+ * Back out randkey changes.
+ *
+ * Revision 1.2 1994/09/12 20:26:12 jik
+ * randkey_principal_wrapper now takes a new_kvno option.
+ *
+ * Revision 1.1 1994/08/11 17:00:44 jik
+ * Initial revision
+ *
+ */
+
+kadm5_ret_t chpass_principal_wrapper(void *server_handle,
+ krb5_principal principal,
+ char *password);
+
+kadm5_ret_t randkey_principal_wrapper(void *server_handle,
+ krb5_principal principal,
+ krb5_keyblock **key,
+ int *n_keys);
+
+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);
diff --git a/src/kadmin/server/ovsec_kadmd.c b/src/kadmin/server/ovsec_kadmd.c
new file mode 100644
index 0000000000..34f2338934
--- /dev/null
+++ b/src/kadmin/server/ovsec_kadmd.c
@@ -0,0 +1,762 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#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 <rpc/rpc.h>
+#include <gssapi/gssapi_krb5.h>
+#include <rpc/auth_gssapi.h>
+#include <kadm5/admin.h>
+#include <kadm5/kadm_rpc.h>
+#include <string.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 */
+
+int signal_request_exit = 0;
+int signal_request_reset = 0;
+void request_exit(int);
+void request_reset_db(int);
+void reset_db(void);
+void sig_pipe(int);
+void kadm_svc_run(void);
+
+#define TIMEOUT 15
+
+gss_name_t gss_changepw_name = NULL, gss_oldchangepw_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"
+
+/*
+ * This enables us to set the keytab that gss_acquire_cred uses, but
+ * it also restricts us to linking against the Kv5 GSS-API library.
+ * Since this is *k*admind, that shouldn't be a problem.
+ */
+extern char *krb5_defkeyname;
+
+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);
+
+
+/*
+ * Function: usage
+ *
+ * Purpose: print out the server usage message
+ *
+ * Arguments:
+ * Requires:
+ * Effects:
+ * Modifies:
+ */
+
+void usage()
+{
+ fprintf(stderr, "Usage: kadmind [-r realm] [-m] [-nofork] "
+ "[-port port-number]\n");
+ exit(1);
+}
+
+/* XXX yuck. the signal handlers need this */
+static krb5_context context;
+
+int main(int argc, char *argv[])
+{
+ void kadm_1(struct svc_req *, SVCXPRT *);
+ register SVCXPRT *transp;
+ extern char *optarg;
+ extern int optind, opterr;
+ int ret, rlen, nofork, oldnames = 0;
+ OM_uint32 OMret;
+ char *whoami;
+ FILE *acl_file;
+ gss_buffer_desc in_buf;
+ struct servent *srv;
+ struct sockaddr_in addr;
+ int s;
+ short port = 0;
+ auth_gssapi_name names[4];
+ kadm5_config_params params;
+
+ 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 =
+ gss_nt_krb5_name;
+
+#ifdef PURIFY
+ purify_start_batch();
+#endif /* PURIFY */
+ whoami = argv[0];
+
+ nofork = 0;
+
+ memset((char *) &params, 0, sizeof(params));
+
+ argc--; argv++;
+ while (argc) {
+ 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;
+ } 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);
+
+ if((ret = kadm5_init("kadmind", NULL,
+ NULL, &params,
+ KADM5_STRUCT_VERSION,
+ KADM5_API_VERSION_2,
+ &global_server_handle)) !=
+ KADM5_OK) {
+ krb5_klog_syslog(LOG_ERR, "%s while initializing, aborting",
+ error_message(ret));
+ fprintf(stderr, "%s: %s while initializing, aborting\n",
+ whoami, error_message(ret));
+ krb5_klog_close();
+ exit(1);
+ }
+
+ if (ret = kadm5_get_config_params(context, NULL, NULL, &params,
+ &params)) {
+ krb5_klog_syslog(LOG_ERR, "%s: %s while initializing, aborting\n",
+ whoami, error_message(ret));
+ fprintf(stderr, "%s: %s while initializing, aborting\n",
+ whoami, error_message(ret));
+ kadm5_destroy(global_server_handle);
+ krb5_klog_close();
+ exit(1);
+ }
+
+#define REQUIRED_PARAMS (KADM5_CONFIG_REALM | KADM5_CONFIG_ACL_FILE | \
+ KADM5_CONFIG_ADMIN_KEYTAB)
+
+ if ((params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) {
+ krb5_klog_syslog(LOG_ERR, "%s: Missing required configuration values "
+ "(%x) while initializing, aborting\n", whoami,
+ (params.mask & REQUIRED_PARAMS) ^ REQUIRED_PARAMS);
+ fprintf(stderr, "%s: Missing required configuration values "
+ "(%x) while initializing, aborting\n", whoami,
+ (params.mask & REQUIRED_PARAMS) ^ REQUIRED_PARAMS);
+ krb5_klog_close();
+ 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) {
+ krb5_klog_syslog(LOG_ERR, "Cannot create TCP socket: %s",
+ error_message(errno));
+ fprintf(stderr, "Cannot create TCP socket: %s",
+ error_message(errno));
+ kadm5_destroy(global_server_handle);
+ krb5_klog_close();
+ 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) {
+ krb5_klog_syslog(LOG_ERR, "Cannot set SO_REUSEADDR: %s",
+ error_message(errno));
+ fprintf(stderr, "Cannot set SO_REUSEADDR: %s",
+ error_message(errno));
+ kadm5_destroy(global_server_handle);
+ krb5_klog_close();
+ exit(1);
+ }
+ }
+ #endif
+ if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ int oerrno = errno;
+ fprintf(stderr, "%s: Cannot bind socket.\n", whoami);
+ fprintf(stderr, "bind: %s\n", error_message(oerrno));
+ errno = oerrno;
+ krb5_klog_syslog(LOG_ERR, "Cannot bind socket: %m");
+ 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 deamon. 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();
+ 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();
+ 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();
+ 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 initialize GSS-API authentication, "
+ "failing.");
+ fprintf(stderr, "%s: Cannot initialize GSS-API authentication.\n",
+ whoami);
+ kadm5_destroy(global_server_handle);
+ krb5_klog_close();
+ exit(1);
+ }
+
+ krb5_defkeyname = params.admin_keytab;
+
+ /*
+ * 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 initialize GSS-API authentication, "
+ "failing.");
+ fprintf(stderr, "%s: Cannot initialize GSS-API authentication.\n",
+ whoami);
+ kadm5_destroy(global_server_handle);
+ krb5_klog_close();
+ 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, gss_nt_krb5_name,
+ &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, gss_nt_krb5_name,
+ &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);
+
+ if (ret = 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));
+ kadm5_destroy(global_server_handle);
+ krb5_klog_close();
+ 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));
+ kadm5_destroy(global_server_handle);
+ krb5_klog_close();
+ exit(1);
+ }
+
+ signal(SIGINT, request_exit);
+ signal(SIGTERM, request_exit);
+ signal(SIGQUIT, request_exit);
+ signal(SIGHUP, request_reset_db);
+ signal(SIGPIPE, sig_pipe);
+#ifdef PURIFY
+ signal(SIGUSR1, request_pure_report);
+ signal(SIGUSR2, request_pure_clear);
+#endif /* PURIFY */
+ krb5_klog_syslog(LOG_INFO, "starting");
+
+ kadm_svc_run();
+ krb5_klog_syslog(LOG_INFO, "finished, exiting");
+ kadm5_destroy(global_server_handle);
+ close(s);
+ krb5_klog_close();
+ exit(2);
+}
+
+/*
+ * 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(void)
+{
+ fd_set rfd;
+ int sz = _rpc_dtablesize();
+ struct timeval timeout;
+
+ while(signal_request_exit == 0) {
+ if (signal_request_reset)
+ reset_db();
+#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;
+ switch(select(sz, (fd_set *) &rfd, NULL, NULL, &timeout)) {
+ case -1:
+ if(errno == EINTR)
+ continue;
+ perror("select");
+ return;
+ case 0:
+ reset_db();
+ break;
+ default:
+ 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_reset_db
+ *
+ * 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_reset to one
+ */
+
+void request_reset_db(int signum)
+{
+ krb5_klog_syslog(LOG_DEBUG, "Got signal to request resetting the databases");
+ signal_request_reset = 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();
+ exit(3);
+ }
+#endif
+
+ signal_request_reset = 0;
+ 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)
+{
+ static const char *const proc_names[] = {
+ "kadm5_create_principal",
+ "kadm5_delete_principal",
+ "kadm5_modify_principal",
+ "kadm5_rename_principal",
+ "kadm5_get_principal",
+ "kadm5_chpass_principal",
+ "kadm5_randkey_principal",
+ "kadm5_create_policy",
+ "kadm5_delete_policy",
+ "kadm5_modify_policy",
+ "kadm5_get_policy",
+ "kadm5_get_privs",
+ };
+ OM_uint32 minor;
+ gss_buffer_desc client, server;
+ gss_OID gss_type;
+ char *a;
+
+ (void) gss_display_name(&minor, client_name, &client, &gss_type);
+ (void) gss_display_name(&minor, server_name, &server, &gss_type);
+ a = inet_ntoa(rqst->rq_xprt->xp_raddr.sin_addr);
+
+ krb5_klog_syslog(LOG_NOTICE, "WARNING! Forged/garbled request: %s, "
+ "claimed client = %s, server = %s, addr = %s",
+ proc_names[msg->rm_call.cb_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.\n");
+}
+
+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;
+ int 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!\n", msg);
+ return;
+ }
+
+ krb5_klog_syslog(LOG_NOTICE, "%s %s\n", m, (char *)msg.value);
+ (void) gss_release_buffer(&minor_stat, &msg);
+
+ if (!msg_ctx)
+ break;
+ }
+}
diff --git a/src/kadmin/server/server_glue_v1.c b/src/kadmin/server/server_glue_v1.c
new file mode 100644
index 0000000000..c0bec26e61
--- /dev/null
+++ b/src/kadmin/server/server_glue_v1.c
@@ -0,0 +1,31 @@
+#define USE_KADM5_API_VERSION 1
+#include <kadm5/admin.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/src/kadmin/server/server_stubs.c b/src/kadmin/server/server_stubs.c
new file mode 100644
index 0000000000..8107160afa
--- /dev/null
+++ b/src/kadmin/server/server_stubs.c
@@ -0,0 +1,1045 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#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 "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(acceptor_name(rqstp->rq_svccred), gss_changepw_name) |\
+ (gss_oldchangepw_name && \
+ cmp_gss_names(acceptor_name(rqstp->rq_svccred), \
+ gss_oldchangepw_name)))
+
+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);
+}
+
+/*
+ * 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, rqstp->rq_clntcred,
+ &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.
+ */
+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(rqstp->rq_clntcred, 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);
+ return -1;
+ }
+ if (gss_name_to_string(server_gss_name, server_name) != 0) {
+ gss_release_buffer(&min_stat, client_name);
+ return -1;
+ }
+ return 0;
+}
+
+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;
+}
+
+int cmp_gss_krb5_name(kadm5_server_handle_t handle,
+ gss_name_t gss_name, krb5_principal princ)
+{
+ krb5_principal princ2;
+ int stat;
+
+ if (! gss_to_krb5_name(handle, gss_name, &princ2))
+ return 0;
+ stat = krb5_principal_compare(handle->context, princ, princ2);
+ krb5_free_principal(handle->context, princ2);
+ return stat;
+}
+
+int gss_to_krb5_name(kadm5_server_handle_t handle,
+ gss_name_t gss_name, krb5_principal *princ)
+{
+ OM_uint32 stat, minor_stat;
+ gss_buffer_desc gss_str;
+ gss_OID gss_type;
+ int success;
+
+ stat = gss_display_name(&minor_stat, gss_name, &gss_str, &gss_type);
+ if ((stat != 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;
+}
+int
+gss_name_to_string(gss_name_t gss_name, gss_buffer_desc *str)
+{
+ OM_uint32 stat, minor_stat;
+ gss_OID gss_type;
+ int ret;
+
+ stat = gss_display_name(&minor_stat, gss_name, str, &gss_type);
+ if ((stat != GSS_S_COMPLETE) || (gss_type != gss_nt_krb5_name))
+ return 1;
+ return 0;
+}
+
+generic_ret *
+create_principal_1(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;
+
+ xdr_free(xdr_generic_ret, &ret);
+
+ if (ret.code = new_server_handle(arg->api_version, rqstp, &handle))
+ return &ret;
+
+ if (ret.code = check_handle((void *)handle)) {
+ free_server_handle(handle);
+ return &ret;
+ }
+
+ ret.api_version = handle->api_version;
+
+ if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+ ret.code = KADM5_FAILURE;
+ return &ret;
+ }
+ krb5_unparse_name(handle->context, arg->rec.principal, &prime_arg);
+
+ if (CHANGEPW_SERVICE(rqstp) || !acl_check(handle->context,
+ rqstp->rq_clntcred,
+ ACL_ADD,
+ arg->rec.principal)) {
+ 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);
+ krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_create_principal",
+ prime_arg,((ret.code == 0) ? "success" :
+ error_message(ret.code)),
+ client_name.value, service_name.value,
+ inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+ }
+ free_server_handle(handle);
+ free(prime_arg);
+ gss_release_buffer(&minor_stat, &client_name);
+ gss_release_buffer(&minor_stat, &service_name);
+ return &ret;
+}
+
+generic_ret *
+delete_principal_1(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))
+ return &ret;
+
+ if (ret.code = check_handle((void *)handle)) {
+ free_server_handle(handle);
+ return &ret;
+ }
+
+ ret.api_version = handle->api_version;
+
+ if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+ ret.code = KADM5_FAILURE;
+ return &ret;
+ }
+ krb5_unparse_name(handle->context, arg->princ, &prime_arg);
+
+ if (CHANGEPW_SERVICE(rqstp) || !acl_check(handle->context,
+ rqstp->rq_clntcred,
+ ACL_DELETE,
+ arg->princ)) {
+ 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);
+ krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_delete_principal", prime_arg,
+ ((ret.code == 0) ? "success" : error_message(ret.code)),
+ client_name.value, service_name.value,
+ inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+ }
+ free(prime_arg);
+ free_server_handle(handle);
+ gss_release_buffer(&minor_stat, &client_name);
+ gss_release_buffer(&minor_stat, &service_name);
+ return &ret;
+}
+
+generic_ret *
+modify_principal_1(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;
+
+ xdr_free(xdr_generic_ret, &ret);
+
+ if (ret.code = new_server_handle(arg->api_version, rqstp, &handle))
+ return &ret;
+
+ if (ret.code = check_handle((void *)handle)) {
+ free_server_handle(handle);
+ return &ret;
+ }
+
+ if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+ ret.code = KADM5_FAILURE;
+ return &ret;
+ }
+ krb5_unparse_name(handle->context, arg->rec.principal, &prime_arg);
+
+ if (CHANGEPW_SERVICE(rqstp) || !acl_check(handle->context,
+ rqstp->rq_clntcred,
+ ACL_MODIFY,
+ arg->rec.principal)) {
+ 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);
+ krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_modify_principal",
+ prime_arg, ((ret.code == 0) ? "success" :
+ error_message(ret.code)),
+ client_name.value, service_name.value,
+ inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+ }
+ free_server_handle(handle);
+ free(prime_arg);
+ gss_release_buffer(&minor_stat, &client_name);
+ gss_release_buffer(&minor_stat, &service_name);
+ return &ret;
+}
+
+generic_ret *
+rename_principal_1(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;
+
+ xdr_free(xdr_generic_ret, &ret);
+
+ if (ret.code = new_server_handle(arg->api_version, rqstp, &handle))
+ return &ret;
+
+ if (ret.code = check_handle((void *)handle)) {
+ free_server_handle(handle);
+ return &ret;
+ }
+
+ if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+ ret.code = KADM5_FAILURE;
+ return &ret;
+ }
+ krb5_unparse_name(handle->context, arg->src, &prime_arg1);
+ krb5_unparse_name(handle->context, arg->dest, &prime_arg2);
+ sprintf(prime_arg, "%s to %s", prime_arg1, prime_arg2);
+
+ ret.code = KADM5_OK;
+ if (! CHANGEPW_SERVICE(rqstp)) {
+ if (!acl_check(handle->context, rqstp->rq_clntcred,
+ ACL_DELETE, arg->src))
+ ret.code = KADM5_AUTH_DELETE;
+ if (!acl_check(handle->context, rqstp->rq_clntcred,
+ ACL_ADD, arg->dest)) {
+ 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);
+ krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_rename_principal",
+ prime_arg, ((ret.code == 0) ? "success" :
+ error_message(ret.code)),
+ client_name.value, service_name.value,
+ inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+ }
+ free_server_handle(handle);
+ free(prime_arg1);
+ free(prime_arg2);
+ gss_release_buffer(&minor_stat, &client_name);
+ gss_release_buffer(&minor_stat, &service_name);
+ return &ret;
+}
+
+gprinc_ret *
+get_principal_1(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))
+ return &ret;
+
+ if (ret.code = check_handle((void *)handle)) {
+ free_server_handle(handle);
+ return &ret;
+ }
+
+ 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;
+ return &ret;
+ }
+ krb5_unparse_name(handle->context, arg->princ, &prime_arg);
+
+ if (! cmp_gss_krb5_name(handle, rqstp->rq_clntcred, arg->princ) &&
+ (CHANGEPW_SERVICE(rqstp) || !acl_check(handle->context,
+ rqstp->rq_clntcred,
+ ACL_INQUIRE,
+ arg->princ))) {
+ 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);
+ }
+
+ krb5_klog_syslog(LOG_NOTICE, LOG_DONE, funcname,
+ prime_arg,
+ ((ret.code == 0) ? "success" : error_message(ret.code)),
+ client_name.value, service_name.value,
+ inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+ }
+ free_server_handle(handle);
+ free(prime_arg);
+ gss_release_buffer(&minor_stat, &client_name);
+ gss_release_buffer(&minor_stat, &service_name);
+ return &ret;
+}
+
+gprincs_ret *
+get_princs_1(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))
+ return &ret;
+
+ if (ret.code = check_handle((void *)handle)) {
+ free_server_handle(handle);
+ return &ret;
+ }
+
+ ret.api_version = handle->api_version;
+
+ if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+ ret.code = KADM5_FAILURE;
+ return &ret;
+ }
+ prime_arg = arg->exp;
+ if (prime_arg == NULL)
+ prime_arg = "*";
+
+ if (CHANGEPW_SERVICE(rqstp) || !acl_check(handle->context,
+ rqstp->rq_clntcred,
+ ACL_LIST,
+ 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);
+ krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_get_principals",
+ prime_arg,
+ ((ret.code == 0) ? "success" : error_message(ret.code)),
+ 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);
+ return &ret;
+}
+
+generic_ret *
+chpass_principal_1(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))
+ return &ret;
+
+ if (ret.code = check_handle((void *)handle)) {
+ free_server_handle(handle);
+ return &ret;
+ }
+
+ ret.api_version = handle->api_version;
+
+ if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+ ret.code = KADM5_FAILURE;
+ return &ret;
+ }
+ krb5_unparse_name(handle->context, arg->princ, &prime_arg);
+
+ if (cmp_gss_krb5_name(handle, rqstp->rq_clntcred, arg->princ)) {
+ ret.code = chpass_principal_wrapper((void *)handle, arg->princ,
+ arg->pass);
+ } else if (!(CHANGEPW_SERVICE(rqstp)) &&
+ acl_check(handle->context, rqstp->rq_clntcred,
+ ACL_CHANGEPW, arg->princ)) {
+ 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) {
+ krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_chpass_principal",
+ prime_arg, ((ret.code == 0) ? "success" :
+ error_message(ret.code)),
+ client_name.value, service_name.value,
+ inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+ }
+
+ free_server_handle(handle);
+ free(prime_arg);
+ gss_release_buffer(&minor_stat, &client_name);
+ gss_release_buffer(&minor_stat, &service_name);
+ return &ret;
+}
+
+chrand_ret *
+chrand_principal_1(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))
+ return &ret;
+
+ if (ret.code = check_handle((void *)handle)) {
+ free_server_handle(handle);
+ return &ret;
+ }
+
+ 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;
+ return &ret;
+ }
+ krb5_unparse_name(handle->context, arg->princ, &prime_arg);
+
+ if (cmp_gss_krb5_name(handle, rqstp->rq_clntcred, arg->princ)) {
+ ret.code = randkey_principal_wrapper((void *)handle,
+ arg->princ, &k, &nkeys);
+ } else if (!(CHANGEPW_SERVICE(rqstp)) &&
+ acl_check(handle->context, rqstp->rq_clntcred,
+ ACL_CHANGEPW, arg->princ)) {
+ 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) {
+ krb5_klog_syslog(LOG_NOTICE, LOG_DONE, funcname,
+ prime_arg, ((ret.code == 0) ? "success" :
+ error_message(ret.code)),
+ client_name.value, service_name.value,
+ inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+ }
+ free_server_handle(handle);
+ free(prime_arg);
+ gss_release_buffer(&minor_stat, &client_name);
+ gss_release_buffer(&minor_stat, &service_name);
+ return &ret;
+}
+
+generic_ret *
+create_policy_1(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))
+ return &ret;
+
+ if (ret.code = check_handle((void *)handle)) {
+ free_server_handle(handle);
+ return &ret;
+ }
+
+ ret.api_version = handle->api_version;
+
+ if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+ ret.code = KADM5_FAILURE;
+ return &ret;
+ }
+ prime_arg = arg->rec.policy;
+
+ if (CHANGEPW_SERVICE(rqstp) || !acl_check(handle->context,
+ rqstp->rq_clntcred,
+ ACL_ADD, 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);
+ krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_create_policy",
+ ((prime_arg == NULL) ? "(null)" : prime_arg),
+ ((ret.code == 0) ? "success" : error_message(ret.code)),
+ 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);
+ return &ret;
+}
+
+generic_ret *
+delete_policy_1(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))
+ return &ret;
+
+ if (ret.code = check_handle((void *)handle)) {
+ free_server_handle(handle);
+ return &ret;
+ }
+
+ ret.api_version = handle->api_version;
+
+ if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+ ret.code = KADM5_FAILURE;
+ return &ret;
+ }
+ prime_arg = arg->name;
+
+ if (CHANGEPW_SERVICE(rqstp) || !acl_check(handle->context,
+ rqstp->rq_clntcred,
+ ACL_DELETE, 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);
+ krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_delete_policy",
+ ((prime_arg == NULL) ? "(null)" : prime_arg),
+ ((ret.code == 0) ? "success" : error_message(ret.code)),
+ 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);
+ return &ret;
+}
+
+generic_ret *
+modify_policy_1(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))
+ return &ret;
+
+ if (ret.code = check_handle((void *)handle)) {
+ free_server_handle(handle);
+ return &ret;
+ }
+
+ ret.api_version = handle->api_version;
+
+ if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+ ret.code = KADM5_FAILURE;
+ return &ret;
+ }
+ prime_arg = arg->rec.policy;
+
+ if (CHANGEPW_SERVICE(rqstp) || !acl_check(handle->context,
+ rqstp->rq_clntcred,
+ ACL_MODIFY, 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);
+ krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_modify_policy",
+ ((prime_arg == NULL) ? "(null)" : prime_arg),
+ ((ret.code == 0) ? "success" : error_message(ret.code)),
+ 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);
+ return &ret;
+}
+
+gpol_ret *
+get_policy_1(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;
+ krb5_principal caller;
+ kadm5_server_handle_t handle;
+
+ xdr_free(xdr_gpol_ret, &ret);
+
+ if (ret.code = new_server_handle(arg->api_version, rqstp, &handle))
+ return &ret;
+
+ if (ret.code = check_handle((void *)handle)) {
+ free_server_handle(handle);
+ return &ret;
+ }
+
+ 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;
+ return &ret;
+ }
+ prime_arg = arg->name;
+
+ ret.code = KADM5_AUTH_GET;
+ if (!CHANGEPW_SERVICE(rqstp) && acl_check(handle->context,
+ rqstp->rq_clntcred,
+ ACL_INQUIRE, 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);
+ }
+
+ krb5_klog_syslog(LOG_NOTICE, LOG_DONE, funcname,
+ ((prime_arg == NULL) ? "(null)" : prime_arg),
+ ((ret.code == 0) ? "success" : error_message(ret.code)),
+ client_name.value, service_name.value,
+ inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+ } 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);
+ return &ret;
+
+}
+
+gpols_ret *
+get_pols_1(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))
+ return &ret;
+
+ if (ret.code = check_handle((void *)handle)) {
+ free_server_handle(handle);
+ return &ret;
+ }
+
+ ret.api_version = handle->api_version;
+
+ if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+ ret.code = KADM5_FAILURE;
+ return &ret;
+ }
+ prime_arg = arg->exp;
+ if (prime_arg == NULL)
+ prime_arg = "*";
+
+ if (CHANGEPW_SERVICE(rqstp) || !acl_check(handle->context,
+ rqstp->rq_clntcred,
+ ACL_LIST, 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);
+ krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_get_policies",
+ prime_arg,
+ ((ret.code == 0) ? "success" : error_message(ret.code)),
+ 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);
+ return &ret;
+}
+
+getprivs_ret * get_privs_1(krb5_ui_4 *arg, struct svc_req *rqstp)
+{
+ static getprivs_ret ret;
+ char *prime_arg;
+ 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))
+ return &ret;
+
+ if (ret.code = check_handle((void *)handle)) {
+ free_server_handle(handle);
+ return &ret;
+ }
+
+ ret.api_version = handle->api_version;
+
+ if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+ ret.code = KADM5_FAILURE;
+ return &ret;
+ }
+
+ ret.code = kadm5_get_privs((void *)handle, &ret.privs);
+ krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_get_privs",
+ 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));
+ free_server_handle(handle);
+ gss_release_buffer(&minor_stat, &client_name);
+ gss_release_buffer(&minor_stat, &service_name);
+ return &ret;
+}
+
+generic_ret *init_1(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))
+ return &ret;
+ 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;
+ return &ret;
+ }
+
+ krb5_klog_syslog(LOG_NOTICE, LOG_DONE,
+ (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));
+ gss_release_buffer(&minor_stat, &client_name);
+ gss_release_buffer(&minor_stat, &service_name);
+
+ return(&ret);
+}
diff --git a/src/kadmin/testing/Makefile.ov b/src/kadmin/testing/Makefile.ov
new file mode 100644
index 0000000000..206bd85510
--- /dev/null
+++ b/src/kadmin/testing/Makefile.ov
@@ -0,0 +1,8 @@
+# $Id$
+
+TOP = ..
+include $(TOP)/config.mk/template
+
+SUBDIRS=util scripts
+
+expand SubdirTarget
diff --git a/src/kadmin/testing/proto/ChangeLog b/src/kadmin/testing/proto/ChangeLog
new file mode 100644
index 0000000000..71959a3b05
--- /dev/null
+++ b/src/kadmin/testing/proto/ChangeLog
@@ -0,0 +1,9 @@
+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/src/kadmin/testing/proto/kdc.conf.proto b/src/kadmin/testing/proto/kdc.conf.proto
new file mode 100644
index 0000000000..798d6c51bd
--- /dev/null
+++ b/src/kadmin/testing/proto/kdc.conf.proto
@@ -0,0 +1,20 @@
+[kdcdefaults]
+ kdc_ports = 1750
+
+[realms]
+ __REALM__ = {
+ profile = /krb5/krb5.conf
+ database_name = /krb5/kdb5
+ admin_database_name = /krb5/kadb5
+ admin_database_lockfile = /krb5/ovsec_adm.lock
+ admin_keytab = /krb5/ovsec_adm.srvtab
+ key_stash_file = /krb5/.k5.__REALM__
+ acl_file = /krb5/ovsec_adm.acl
+ dict_file = /krb5/ovsec_adm.dict
+ kadmind_port = 1751
+ max_life = 10h 0m 0s
+ max_renewable_life = 7d 0h 0m 0s
+ master_key_type = des-cbc-crc
+ supported_enctypes = des-cbc-crc:normal des-cbc-crc:v4
+ }
+
diff --git a/src/kadmin/testing/proto/krb5.conf.proto b/src/kadmin/testing/proto/krb5.conf.proto
new file mode 100644
index 0000000000..6e0c4687d6
--- /dev/null
+++ b/src/kadmin/testing/proto/krb5.conf.proto
@@ -0,0 +1,17 @@
+[libdefaults]
+ default_realm = __REALM__
+ default_keytab_name = FILE:/krb5/v5srvtab
+
+[realms]
+ __REALM__ = {
+ kdc = localhost:1750
+ admin_server = localhost:1751
+ }
+
+[domain_realm]
+ localhost = __REALM__
+
+[logging]
+ admin_server = SYSLOG=ERR:LOCAL6
+ kdc = SYSLOG=ERR:LOCAL6
+ default = SYSLOG=ERR:LOCAL6
diff --git a/src/kadmin/testing/proto/ovsec_adm.dict b/src/kadmin/testing/proto/ovsec_adm.dict
new file mode 100644
index 0000000000..b54e3a85e1
--- /dev/null
+++ b/src/kadmin/testing/proto/ovsec_adm.dict
@@ -0,0 +1,3 @@
+Abyssinia
+Discordianism
+foo
diff --git a/src/kadmin/testing/scripts/ChangeLog b/src/kadmin/testing/scripts/ChangeLog
new file mode 100644
index 0000000000..5d7069186e
--- /dev/null
+++ b/src/kadmin/testing/scripts/ChangeLog
@@ -0,0 +1,15 @@
+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/src/kadmin/testing/scripts/Makefile.ov b/src/kadmin/testing/scripts/Makefile.ov
new file mode 100644
index 0000000000..335b636e7e
--- /dev/null
+++ b/src/kadmin/testing/scripts/Makefile.ov
@@ -0,0 +1,19 @@
+# $Id$
+
+TOP = ../..
+include $(TOP)/config.mk/template
+
+GEN_SCRIPTS = compare_dump.pl fixup-conf-files.pl make-host-keytab.pl \
+ simple_dump.pl verify_xrunner_report.pl
+
+all:: $(GEN_SCRIPTS)
+
+%.pl: %.pl.in
+ -rm -f $@.tmp
+ echo "#!$(PERL)" > $@.tmp
+ sed 1d $@.in >> $@.tmp
+ chmod +x $@.tmp
+ mv $@.tmp $@
+
+clean::
+ -rm -f $(GEN_SCRIPTS) *.tmp
diff --git a/src/kadmin/testing/scripts/compare_dump.pl.in b/src/kadmin/testing/scripts/compare_dump.pl.in
new file mode 100644
index 0000000000..df93df4a00
--- /dev/null
+++ b/src/kadmin/testing/scripts/compare_dump.pl.in
@@ -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/src/kadmin/testing/scripts/compare_dump.plin b/src/kadmin/testing/scripts/compare_dump.plin
new file mode 100644
index 0000000000..df93df4a00
--- /dev/null
+++ b/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/src/kadmin/testing/scripts/find-make.sh b/src/kadmin/testing/scripts/find-make.sh
new file mode 100644
index 0000000000..904730dfa0
--- /dev/null
+++ b/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/src/kadmin/testing/scripts/fixup-conf-files.pl.in b/src/kadmin/testing/scripts/fixup-conf-files.pl.in
new file mode 100644
index 0000000000..d7834d1c74
--- /dev/null
+++ b/src/kadmin/testing/scripts/fixup-conf-files.pl.in
@@ -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/src/kadmin/testing/scripts/fixup-conf-files.plin b/src/kadmin/testing/scripts/fixup-conf-files.plin
new file mode 100644
index 0000000000..d7834d1c74
--- /dev/null
+++ b/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/src/kadmin/testing/scripts/init_db b/src/kadmin/testing/scripts/init_db
new file mode 100644
index 0000000000..c53ff96c1e
--- /dev/null
+++ b/src/kadmin/testing/scripts/init_db
@@ -0,0 +1,181 @@
+#!/bin/sh
+
+# If it's set, set it to true
+VERBOSE=${VERBOSE_TEST:+true}
+# Otherwise, set it to false
+DUMMY=${VERBOSE:=false}
+
+if $VERBOSE; then
+ REDIRECT=
+else
+ REDIRECT='>/dev/null'
+fi
+
+# Requires that /krb5, /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
+
+IROOT=$TOP/..
+ADMIN=$TOP/create:$IROOT/admin/stash:$IROOT/admin/destroy
+BIN=$IROOT/bin
+ETC=$IROOT/etc
+SBIN=$TOP/keytab:$TOP/server
+DUMMY=${REALM=SECURE-TEST.OV.COM}; export REALM
+
+DUMMY=${TESTDIR=$TOP/testing}; export TESTDIR
+DUMMY=${SRVTCL=$TESTDIR/util/ovsec_kadm_srv_tcl}; export SRVTCL
+DUMMY=${TCLUTIL=$TESTDIR/tcl/util.t}; export TCLUTIL
+DUMMY=${LOCAL_MAKE_KEYTAB=$TESTDIR/scripts/make-host-keytab.pl}
+
+PATH=$ADMIN:$BIN:$ETC:$SBIN:$PATH; export PATH
+
+rm -rf /krb5/*
+if [ -d /krb5 ]; then
+ true
+else
+ mkdir /krb5
+fi
+
+# touch /krb5/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
+
+sed -e "s/__REALM__/$REALM/" < $TESTDIR/proto/krb5.conf.proto > /krb5/krb5.conf
+sed -e "s/__REALM__/$REALM/" < $TESTDIR/proto/kdc.conf.proto > /krb5/kdc.conf
+
+kdb5_create -P mrroot -s -r $REALM $REDIRECT
+
+cp $TESTDIR/proto/ovsec_adm.dict /krb5/ovsec_adm.dict
+
+eval $SRVTCL <<'EOF' $REDIRECT
+source $env(TCLUTIL)
+set r $env(REALM)
+
+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_destroy $server_handle}
+}
+
+foreach cmd $cmds {
+ if {[catch $cmd output]} {
+ puts stderr "Error! Command: $cmd\nError: $output"
+ exit 1
+ } else {
+ puts stdout $output
+ }
+}
+EOF
+
+if [ $? -ne 0 ]; then
+ echo "Error in $SRVTCL!" 1>&2
+ exit 1
+fi
+
+cat > /krb5/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 /krb5/ovsec_adm.srvtab $REDIRECT
+
+# Create /krb5/setup.csh to make it easy to run other programs against
+# the test db
+cat > /krb5/setup.csh <<EOF
+setenv KRB5_CONFIG $KRB5_CONFIG
+setenv KRB5_KDC_PROFILE $KRB5_KDC_PROFILE
+setenv KRB5_KTNAME $KRB5_KTNAME
+EOF
+
diff --git a/src/kadmin/testing/scripts/make-host-keytab.pl.in b/src/kadmin/testing/scripts/make-host-keytab.pl.in
new file mode 100644
index 0000000000..14d7b10b54
--- /dev/null
+++ b/src/kadmin/testing/scripts/make-host-keytab.pl.in
@@ -0,0 +1,138 @@
+#!/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');
+$EDIT_KEYTAB = ($ENV{'EDIT_KEYTAB'} || "$top/keytab/kadm5_keytab.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);
+
+ $cmd = "$EDIT_KEYTAB -k $ktfile";
+ $cmd .= " -q" if (! $verbose);
+ $cmd .= " -a -c";
+ for (@princs) {
+ if (system "$cmd $_") {
+ sleep(1);
+ die "Error in system($cmd $_)\n";
+ }
+ }
+}
+
+if (! -f $ktfile) {
+ die "$ktfile not created.\n";
+}
diff --git a/src/kadmin/testing/scripts/make-host-keytab.plin b/src/kadmin/testing/scripts/make-host-keytab.plin
new file mode 100644
index 0000000000..14d7b10b54
--- /dev/null
+++ b/src/kadmin/testing/scripts/make-host-keytab.plin
@@ -0,0 +1,138 @@
+#!/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');
+$EDIT_KEYTAB = ($ENV{'EDIT_KEYTAB'} || "$top/keytab/kadm5_keytab.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);
+
+ $cmd = "$EDIT_KEYTAB -k $ktfile";
+ $cmd .= " -q" if (! $verbose);
+ $cmd .= " -a -c";
+ for (@princs) {
+ if (system "$cmd $_") {
+ sleep(1);
+ die "Error in system($cmd $_)\n";
+ }
+ }
+}
+
+if (! -f $ktfile) {
+ die "$ktfile not created.\n";
+}
diff --git a/src/kadmin/testing/scripts/qualname b/src/kadmin/testing/scripts/qualname
new file mode 100644
index 0000000000..3d047c550a
--- /dev/null
+++ b/src/kadmin/testing/scripts/qualname
@@ -0,0 +1,18 @@
+#!/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);
+}
+print "$qualname\n";
+
diff --git a/src/kadmin/testing/scripts/save_files.sh b/src/kadmin/testing/scripts/save_files.sh
new file mode 100644
index 0000000000..b9fc37319a
--- /dev/null
+++ b/src/kadmin/testing/scripts/save_files.sh
@@ -0,0 +1,67 @@
+#!/bin/sh
+
+while [ $# -gt 0 ] ; do
+ case $1 in
+ -start_servers)
+ start_servers=$1
+ ;;
+ esac
+ shift
+done
+
+# If it's set, set it to true
+VERBOSE=${VERBOSE_TEST:+true}
+# Otherwise, set it to false
+DUMMY=${VERBOSE:=false}
+
+# 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"
+
+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/src/kadmin/testing/scripts/simple_dump.pl.in b/src/kadmin/testing/scripts/simple_dump.pl.in
new file mode 100644
index 0000000000..ea94ab2d1d
--- /dev/null
+++ b/src/kadmin/testing/scripts/simple_dump.pl.in
@@ -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/src/kadmin/testing/scripts/simple_dump.plin b/src/kadmin/testing/scripts/simple_dump.plin
new file mode 100644
index 0000000000..ea94ab2d1d
--- /dev/null
+++ b/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/src/kadmin/testing/scripts/start_servers b/src/kadmin/testing/scripts/start_servers
new file mode 100644
index 0000000000..2e395faf85
--- /dev/null
+++ b/src/kadmin/testing/scripts/start_servers
@@ -0,0 +1,70 @@
+#!/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=${SAVE_FILES=$TESTDIR/scripts/save_files.sh}
+DUMMY=${FIX_CONF_FILES=$TESTDIR/scripts/fixup-conf-files.pl}
+DUMMY=${START_SERVERS_LOCAL=$TESTDIR/scripts/start_servers_local}
+# This'll be wrong sometimes
+DUMMY=${RSH_CMD=/usr/ucb/rsh}
+
+# If it's set, set it to true
+VERBOSE=${VERBOSE_TEST:+true}
+# Otherwise, set it to false
+DUMMY=${VERBOSE:=false}
+
+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
+ $SAVE_FILES || exit 1
+ $FIX_CONF_FILES -server $hostname || exit 1
+
+# 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 -l root -n \
+ \"cd $rempath; \\\`testing/scripts/find-make.sh\\\` execute VERBOSE_TEST=$VERBOSE_TEST \
+ TOP=$rempath \
+ CMD='$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/src/kadmin/testing/scripts/start_servers_local b/src/kadmin/testing/scripts/start_servers_local
new file mode 100644
index 0000000000..a9c8e79570
--- /dev/null
+++ b/src/kadmin/testing/scripts/start_servers_local
@@ -0,0 +1,196 @@
+#!/bin/sh
+
+DUMMY=${TESTDIR=$TOP/testing}
+DUMMY=${SAVE_FILES=$TESTDIR/scripts/save_files.sh}
+DUMMY=${FIX_CONF_FILES=$TESTDIR/scripts/fixup-conf-files.pl}
+DUMMY=${INITDB=$TESTDIR/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=$TESTDIR/scripts/stop_servers_local}
+
+if [ -d /usr/tmp ]; then
+ usrtmp=/usr/tmp
+else
+ usrtmp=/var/tmp
+fi
+
+$STOP_SERVERS_LOCAL -start_servers
+
+# If it's set, set it to true
+VERBOSE=${VERBOSE_TEST:+true}
+# Otherwise, set it to false
+DUMMY=${VERBOSE:=false}
+
+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" < /krb5/kdc.conf > /krb5/kdc.conf.new
+ mv /krb5/kdc.conf.new /krb5/kdc.conf
+fi
+if [ "$kdcport" != "" ] ; then
+ sedcmd="s/\(kdc_ports = .*\)[ ]*/\1, $kdcport/"
+ sed -e "$sedcmd" < /krb5/kdc.conf > /krb5/kdc.conf.new
+ mv /krb5/kdc.conf.new /krb5/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 $hostname`; export QUALNAME
+
+eval $SRVTCL <<'EOF' $REDIRECT
+source $env(TOP)/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
+
+# 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
+
+(trap "" 2; cd $TOP/../kdc; ./krb5kdc; touch $kdc_start_file) \
+ < /dev/null > $usrtmp/kdc-log 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 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
+ 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
+ exit 1
+ fi
+done
diff --git a/src/kadmin/testing/scripts/stop_servers b/src/kadmin/testing/scripts/stop_servers
new file mode 100644
index 0000000000..fc5372dd4e
--- /dev/null
+++ b/src/kadmin/testing/scripts/stop_servers
@@ -0,0 +1,84 @@
+#!/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=${FIX_CONF_FILES=$TESTDIR/scripts/fixup-conf-files.pl}
+DUMMY=${STOP_SERVERS_LOCAL=$TESTDIR/scripts/stop_servers_local}
+# This'll be wrong sometimes
+DUMMY=${RSH_CMD=/usr/ucb/rsh}
+DUMMY=${RESTORE_FILES=$TESTDIR/scripts/restore_files.sh}
+
+# If it's set, set it to true
+VERBOSE=${VERBOSE_TEST:+true}
+# Otherwise, set it to false
+DUMMY=${VERBOSE:=false}
+
+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
+
+# $FIX_CONF_FILES -server $hostname
+#
+# KRB5CCNAME=FILE:/tmp/krb5cc_stop_servers; export KRB5CCNAME
+#
+# expect <<EOF
+#spawn kinit admin
+#expect {
+# -re "Password for admin@SECURE-TEST.OV.COM" {
+# send "admin\n"
+# }
+#}
+#expect { eof { } }
+#EOF
+
+# 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.
+
+ STOP_SERVERS_LOCAL=`echo $STOP_SERVERS_LOCAL | sed "s%$TOP%$rempath%"`
+ CMD="$RSH_CMD $hostname -l root -n\
+ \"cd $rempath; \\\`testing/scripts/find-make.sh\\\` execute VERBOSE_TEST=$VERBOSE_TEST \
+ TOP=$rempath \
+ CMD='$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
+ $RESTORE_FILES
+else
+ $STOP_SERVERS_LOCAL
+fi
diff --git a/src/kadmin/testing/scripts/stop_servers_local b/src/kadmin/testing/scripts/stop_servers_local
new file mode 100644
index 0000000000..c0a97ef271
--- /dev/null
+++ b/src/kadmin/testing/scripts/stop_servers_local
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+DUMMY=${TESTDIR=$TOP/testing}
+DUMMY=${RESTORE_FILES=$TESTDIR/scripts/restore_files.sh}
+
+# If it's set, set it to true
+VERBOSE=${VERBOSE_TEST:+true}
+# Otherwise, set it to false
+DUMMY=${VERBOSE:=false}
+
+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
+
+# restore saved system config files
+if $v4files; then
+ $RESTORE_FILES $start_servers
+fi
diff --git a/src/kadmin/testing/scripts/verify_xrunner_report.pl.in b/src/kadmin/testing/scripts/verify_xrunner_report.pl.in
new file mode 100644
index 0000000000..9d83c3ea24
--- /dev/null
+++ b/src/kadmin/testing/scripts/verify_xrunner_report.pl.in
@@ -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/src/kadmin/testing/scripts/verify_xrunner_report.plin b/src/kadmin/testing/scripts/verify_xrunner_report.plin
new file mode 100644
index 0000000000..9d83c3ea24
--- /dev/null
+++ b/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/src/kadmin/testing/tcl/util.t b/src/kadmin/testing/tcl/util.t
new file mode 100644
index 0000000000..f4688aeee3
--- /dev/null
+++ b/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/src/kadmin/testing/util/ChangeLog b/src/kadmin/testing/util/ChangeLog
new file mode 100644
index 0000000000..36df4616d2
--- /dev/null
+++ b/src/kadmin/testing/util/ChangeLog
@@ -0,0 +1,3 @@
+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/src/kadmin/testing/util/Makefile.ov b/src/kadmin/testing/util/Makefile.ov
new file mode 100644
index 0000000000..6d01590923
--- /dev/null
+++ b/src/kadmin/testing/util/Makefile.ov
@@ -0,0 +1,34 @@
+# $Id$
+
+TOP = ../..
+include $(TOP)/config.mk/template
+
+CFLAGS += -I$(TCLINC)
+
+SRCS = tcl_ovsec_kadm.c tcl_kadm5.c test.c
+OBJS = tcl_ovsec_kadm.o tcl_kadm5.o test.o
+
+PROG = ovsec_kadm_srv_tcl
+LIBS = $(LIBADMSRV) $(LIBRPCLIB) $(LIBDYN) $(LIBGSSAPI_KRB5) \
+ $(LIBKDB5) $(LIBKRB5) $(LIBCRYPTO) \
+ $(LIBISODE) $(LIBTCL) $(LIBM) $(LIBDB) $(LIBCOM_ERR) \
+ $(NDBMLIB) $(NETLIB)
+
+expand Program
+expand Depend
+
+PROG = ovsec_kadm_clnt_tcl
+LIBS = $(LIBADMCLNT) $(LIBRPCLIB) $(LIBDYN) $(LIBGSSAPI_KRB5) \
+ $(LIBKDB5) $(LIBKRB5) $(LIBCRYPTO) \
+ $(LIBISODE) $(LIBTCL) $(LIBM) $(LIBDB) $(LIBCOM_ERR) \
+ $(NDBMLIB) $(BSDLIB) $(NETLIB)
+
+expand Program
+
+PROG = bsddb_dump
+SRCS = bsddb_dump.c
+OBJS = bsddb_dump.o
+LIBS = $(LIBDB)
+
+expand Program
+expand Depend
diff --git a/src/kadmin/testing/util/bsddb_dump.c b/src/kadmin/testing/util/bsddb_dump.c
new file mode 100644
index 0000000000..ba69b84611
--- /dev/null
+++ b/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/src/kadmin/testing/util/tcl_kadm5.c b/src/kadmin/testing/util/tcl_kadm5.c
new file mode 100644
index 0000000000..b102cdfc2a
--- /dev/null
+++ b/src/kadmin/testing/util/tcl_kadm5.c
@@ -0,0 +1,2312 @@
+#include <stdio.h>
+#include <string.h>
+#include <tcl.h>
+#define USE_KADM5_API_VERSION 2
+#include <kadm5/admin.h>
+#include <com_err.h>
+#include <malloc.h>
+#include <k5-int.h>
+#include <errno.h>
+#include <stdlib.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 tcl_ret; \
+ if ((tcl_ret = get_server_handle(interp, argv[0], &server_handle)) \
+ != TCL_OK) { \
+ return tcl_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, *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 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 EINVAL: code_string = "EINVAL"; break;
+ case ENOENT: code_string = "ENOENT"; break;
+ default: fprintf(stderr, "**** CODE %d ***\n", code); code_string = "UNKNOWN"; break;
+ }
+
+ error_string = (char *) 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;
+
+ if (! (str = malloc(sizeof(*str)))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+
+ Tcl_DStringInit(str);
+ if (n_tl_data > 0 && tl_data->tl_data_contents)
+ Tcl_DStringAppendElement(str, "[cannot unparse tl data yet]");
+ else
+ Tcl_DStringAppendElement(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 tcl_ret, tmp, argc, i, retcode = TCL_OK;
+ char **argv;
+ Tcl_HashEntry *entry;
+
+ if ((tcl_ret = Tcl_GetInt(interp, str, &tmp)) == TCL_OK) {
+ *flags = tmp;
+ return TCL_OK;
+ }
+ Tcl_ResetResult(interp);
+
+ if ((tcl_ret = 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);
+ }
+
+ 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)
+{
+ 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 (krb5_ret = krb5_unparse_name(context, princ->principal, &tmp)) {
+ /* 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;
+ if (krb5_ret = krb5_unparse_name(context, princ->mod_name, &tmp)) {
+ /* 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);
+
+ 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;
+ }
+ if ((retcode = Tcl_GetInt(interp, argv1[1], &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;
+
+ free(argv1);
+ }
+
+finished:
+ if (argv1)
+ free(argv1);
+ if (*keysalts)
+ free(*keysalts);
+ 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], &params->realm)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing realm name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ if ((retcode = parse_str(interp, argv[2], &params->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], &params->admin_server))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing profile name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ if ((retcode = parse_str(interp, argv[5], &params->dbname)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing profile name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ if ((retcode = parse_str(interp, argv[6], &params->admin_dbname)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing admin_dbname name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ if ((retcode = parse_str(interp, argv[7], &params->admin_lockfile)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing admin_lockfile name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ if ((retcode = parse_str(interp, argv[8], &params->admin_keytab)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing admin_keytab name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ if ((retcode = parse_str(interp, argv[9], &params->acl_file)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing acl_file name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ if ((retcode = parse_str(interp, argv[10], &params->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], &params->stash_file)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing stash_file name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ if ((retcode = parse_str(interp, argv[13], &params->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], &params->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) {
+ 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:
+ 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, "%d", policy->pw_min_life);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", policy->pw_max_life);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", policy->pw_min_length);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", policy->pw_min_classes);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", policy->pw_history_num);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", 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:
+ 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 };
+
+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, *realm;
+ 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], &params_str)) != TCL_OK) ||
+ ((tcl_ret = parse_config_params(interp, params_str, &params))
+ != 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,
+ &params, struct_version,
+ api_version, &server_handle);
+
+ (void) krb5_cc_close(context, cc);
+ } else
+ ret = kadm5_init(client_name, pass, service_name, &params,
+ struct_version, api_version, &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;
+}
+
+int tcl_kadm5_init(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ return _tcl_kadm5_init_any(INIT_PASS, clientData, interp, argc, argv);
+}
+
+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);
+}
+
+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;
+}
+
+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;
+}
+
+
+
+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;
+ }
+}
+
+
+
+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;
+}
+
+
+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)) {
+ stash_error(interp, krb5_ret);
+ Tcl_AppendElement(interp, "while parsing source");
+ return TCL_ERROR;
+ }
+
+ if (krb5_ret = krb5_parse_name(context, argv[1], &target)) {
+ 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;
+}
+
+
+
+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 tcl_ret;
+ int retcode = TCL_OK;
+ kadm5_ret_t ret;
+
+ 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 ((tcl_ret = parse_str(interp, argv[1], &pw)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing password");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+#ifdef OVERRIDE
+ if ((tcl_ret = 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;
+}
+
+
+
+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;
+ int tcl_ret;
+ kadm5_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 ((tcl_ret = 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_ret = Tcl_GetBoolean(interp, argv[2], &override_qual))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing override_qual");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+#endif
+ if ((tcl_ret = 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 ((tcl_ret = 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);
+
+ 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;
+}
+
+
+
+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 tcl_ret;
+ int retcode = TCL_OK;
+
+ GET_HANDLE(3, 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 ((tcl_ret = parse_str(interp, argv[1], &keyblock_var)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing keyblock variable name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ if ((tcl_ret = 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;
+}
+
+
+
+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)) {
+ stash_error(interp, 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);
+ 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;
+}
+
+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;
+}
+
+
+
+int tcl_kadm5_delete_policy(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ krb5_principal princ;
+ krb5_error_code krb5_ret;
+ kadm5_ret_t ret;
+ char *policy;
+ int tcl_ret;
+
+ GET_HANDLE(1, 0);
+
+ if ((tcl_ret = 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;
+ }
+}
+
+
+
+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;
+}
+
+
+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;
+ int tcl_ret;
+ kadm5_ret_t ret;
+ int retcode = TCL_OK;
+
+ GET_HANDLE(2, 1);
+
+ if ((tcl_ret = parse_str(interp, argv[0], &policy)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing policy name");
+ return TCL_ERROR;
+ }
+
+ if ((tcl_ret = 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;
+}
+
+
+
+int tcl_kadm5_free_principal_ent(ClientData clientData,
+ Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ char *ent_name;
+ kadm5_principal_ent_t ent;
+ int tcl_ret;
+ kadm5_ret_t ret;
+
+ GET_HANDLE(1, 0);
+
+ if ((tcl_ret = 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 = Tcl_GetHashValue(entry);
+
+ if (ret = kadm5_free_principal_ent(server_handle, ent)) {
+ stash_error(interp, ret);
+ return TCL_ERROR;
+ }
+ Tcl_DeleteHashEntry(entry);
+ }
+ set_ok(interp, "Principal freed.");
+ return TCL_OK;
+}
+
+
+int tcl_kadm5_free_policy_ent(ClientData clientData,
+ Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ char *ent_name;
+ kadm5_policy_ent_t ent;
+ int tcl_ret;
+ kadm5_ret_t ret;
+
+ GET_HANDLE(1, 0);
+
+ if ((tcl_ret = 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 = Tcl_GetHashValue(entry);
+
+ if (ret = kadm5_free_policy_ent(server_handle, ent)) {
+ stash_error(interp, ret);
+ return TCL_ERROR;
+ }
+ Tcl_DeleteHashEntry(entry);
+ }
+ set_ok(interp, "Policy freed.");
+ return TCL_OK;
+}
+
+
+int tcl_kadm5_get_privs(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ int tcl_ret;
+ char *set_ret;
+ kadm5_ret_t ret;
+ char *priv_var;
+ long privs;
+
+ GET_HANDLE(1, 0);
+
+ if ((tcl_ret = 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/src/kadmin/testing/util/tcl_krb5_hash.c b/src/kadmin/testing/util/tcl_krb5_hash.c
new file mode 100644
index 0000000000..95a3451d93
--- /dev/null
+++ b/src/kadmin/testing/util/tcl_krb5_hash.c
@@ -0,0 +1,163 @@
+/*
+ * 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).
+ */
+
+#include <tcl.h>
+#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/src/kadmin/testing/util/tcl_ovsec_kadm.c b/src/kadmin/testing/util/tcl_ovsec_kadm.c
new file mode 100644
index 0000000000..0c6aaac9cb
--- /dev/null
+++ b/src/kadmin/testing/util/tcl_ovsec_kadm.c
@@ -0,0 +1,2016 @@
+#include <stdio.h>
+#include <string.h>
+#include <tcl.h>
+#define USE_KADM5_API_VERSION 1
+#include <kadm5/admin.h>
+#include <com_err.h>
+#include <malloc.h>
+#include <k5-int.h>
+#include <errno.h>
+#include <stdlib.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 tcl_ret; \
+ if ((tcl_ret = get_server_handle(interp, argv[0], &server_handle)) \
+ != TCL_OK) { \
+ return tcl_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, *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 ***\n", code); code_string = "UNKNOWN"; break;
+ }
+
+ error_string = (char *) 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 tcl_ret, tmp, argc, i, retcode = TCL_OK;
+ char **argv;
+ Tcl_HashEntry *entry;
+
+ if ((tcl_ret = Tcl_GetInt(interp, str, &tmp)) == TCL_OK) {
+ *flags = tmp;
+ return TCL_OK;
+ }
+ Tcl_ResetResult(interp);
+
+ if ((tcl_ret = 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);
+ }
+
+ 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. */
+ if (krb5_ret = krb5_unparse_name(context, princ->principal, &tmp)) {
+ /* 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;
+ if (krb5_ret = krb5_unparse_name(context, princ->mod_name, &tmp)) {
+ /* 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:
+ 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, "%d", policy->pw_min_life);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", policy->pw_max_life);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", policy->pw_min_length);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", policy->pw_min_classes);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", policy->pw_history_num);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", 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:
+ 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;
+}
+
+
+
+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, &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;
+}
+
+
+
+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;
+}
+
+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;
+}
+
+
+
+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) {
+ 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 = 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;
+ }
+}
+
+
+
+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;
+}
+
+
+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);
+
+ if (krb5_ret = krb5_parse_name(context, argv[0], &source)) {
+ stash_error(interp, krb5_ret);
+ Tcl_AppendElement(interp, "while parsing source");
+ return TCL_ERROR;
+ }
+
+ if (krb5_ret = krb5_parse_name(context, argv[1], &target)) {
+ 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;
+}
+
+
+
+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 tcl_ret;
+ int retcode = TCL_OK;
+ ovsec_kadm_ret_t ret;
+
+ 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 ((tcl_ret = parse_str(interp, argv[1], &pw)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing password");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+#ifdef OVERRIDE
+ if ((tcl_ret = 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;
+}
+
+
+
+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;
+ int tcl_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 ((tcl_ret = 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_ret = Tcl_GetBoolean(interp, argv[2], &override_qual))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing override_qual");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+#endif
+ if ((tcl_ret = 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 ((tcl_ret = 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;
+}
+
+
+
+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 tcl_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 ((tcl_ret = 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_ret = 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;
+}
+
+
+
+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, 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;
+}
+
+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;
+}
+
+
+
+int tcl_ovsec_kadm_delete_policy(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ krb5_principal princ;
+ krb5_error_code krb5_ret;
+ ovsec_kadm_ret_t ret;
+ char *policy;
+ int tcl_ret;
+
+ GET_HANDLE(1, 0);
+
+ if ((tcl_ret = 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;
+ }
+}
+
+
+
+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;
+}
+
+
+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;
+ int tcl_ret;
+ ovsec_kadm_ret_t ret;
+ int retcode = TCL_OK;
+
+ GET_HANDLE(2, 1);
+
+ if ((tcl_ret = parse_str(interp, argv[0], &policy)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing policy name");
+ return TCL_ERROR;
+ }
+
+ if ((tcl_ret = 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;
+}
+
+
+
+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;
+ int tcl_ret;
+ ovsec_kadm_ret_t ret;
+
+ GET_HANDLE(1, 0);
+
+ if ((tcl_ret = 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 = 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;
+}
+
+
+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;
+ int tcl_ret;
+ ovsec_kadm_ret_t ret;
+
+ GET_HANDLE(1, 0);
+
+ if ((tcl_ret = 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 = 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;
+}
+
+
+int tcl_ovsec_kadm_get_privs(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ int tcl_ret;
+ char *set_ret;
+ ovsec_kadm_ret_t ret;
+ char *priv_var;
+ long privs;
+
+ GET_HANDLE(1, 0);
+
+ if ((tcl_ret = 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/src/kadmin/testing/util/tcl_ovsec_kadm_syntax b/src/kadmin/testing/util/tcl_ovsec_kadm_syntax
new file mode 100644
index 0000000000..3fc77fbcbf
--- /dev/null
+++ b/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/src/kadmin/testing/util/test.c b/src/kadmin/testing/util/test.c
new file mode 100644
index 0000000000..75a0fc25f9
--- /dev/null
+++ b/src/kadmin/testing/util/test.c
@@ -0,0 +1,32 @@
+#include <tcl.h>
+
+#define IS_TCL_7_5 ((TCL_MAJOR_VERSION * 100 + TCL_MINOR_VERSION) >= 705)
+
+#if IS_TCL_7_5
+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/src/kadmin/v4server/ChangeLog b/src/kadmin/v4server/ChangeLog
new file mode 100644
index 0000000000..604014849e
--- /dev/null
+++ b/src/kadmin/v4server/ChangeLog
@@ -0,0 +1,249 @@
+Thu Jul 18 19:46:49 1996 Marc Horowitz <marc@mit.edu>
+
+ * configure.in: removed ET_RULES, replaced with AC_PROG_AWK
+
+Tue Jul 9 17:18:56 1996 Marc Horowitz <marc@mit.edu>
+
+ * kadm_stream.c: rename HAS_STDLIB_H to HAVE_STDLIB_H to conform
+ to the autoconf convention
+ * configure.in: the old configure.in seemed to be written for some
+ other directory. Now it's right.
+ * admin_server.c, kadm_ser_wrap.c, kadm_server.c: renamed
+ <ovsec_admin/foo.h> to <kadm5/foo.h>
+ * Makefile.in: complete rewrite.
+
+Thu Mar 21 20:33:43 1996 Richard Basch <basch@lehman.com>
+
+ * kadm_funcs.c: new principals were being created with two keys,
+ one of which the key_data_ver=0 and had no valid data.
+
+Tue Mar 19 19:42:37 1996 Richard Basch <basch@lehman.com>
+
+ * kadm_funcs.c:
+ changed all references of des-cbc-md5 to des-cbc-crc
+ fixed uninitialized variable
+ set kvno modulo 256 in database
+
+Wed Feb 21 23:34:31 1996 Richard Basch <basch@lehman.com>
+
+ * kadm_funcs.c: Initialize the length element of the krb5_db_entry
+ structure in kadm_princ2entry (add_entry was failing).
+
+Wed Dec 13 03:51:53 1995 Chris Provenzano (proven@mit.edu)
+
+ * kadm_funcs.c : Remove mkvno for krb5_db_entry
+
+Wed Sep 06 14:20:57 1995 Chris Provenzano (proven@mit.edu)
+
+ * admin_server.c, kadm_funcs.c kadm_ser_wrap.c :
+ s/keytype/enctype/g, s/KEYTYPE/ENCTYPE/g
+
+Tue Sep 05 22:10:34 1995 Chris Provenzano (proven@mit.edu)
+
+ * admin_server.c, kadm_funcs.c, kadm_ser_wrap.c : Remove krb5_enctype
+ references, and replace with krb5_keytype where appropriate.
+
+Tue Aug 15 14:31:37 EDT 1995 Paul Park (pjpark@mit.edu)
+ * admin_server,kadm_funcs,kadm_ser_wrap.c - Replace kadm_find_keytype()
+ with krb5_dbe_find_keytype().
+
+
+Thu Aug 10 14:48:26 EDT 1995 Paul Park (pjpark@mit.edu)
+ * kadm_funcs.c - Add kadm_find_keytype() to find a particular key/salt
+ pair. Use this to find keys instead of assuming that the
+ right one's in the first slot.
+ Fix transposed arguments to strncpy().
+ Handle mod_princ_data stuff.
+ Supply saltblock to encrypt_key_data().
+ * admin_server, kadm_ser_wrap.c - Use kadm_find_keytype() to find keys.
+
+
+Mon Aug 7 13:30:46 EDT 1995 Paul Park (pjpark@mit.edu)
+ * admin_server,kadm_funcs,kadm_ser_wrap.c - Brute force substitutions
+ to get this to compile.
+
+
+Mon Jul 17 15:12:30 EDT 1995 Paul Park (pjpark@mit.edu)
+ * kadm_ser_wrap.c - Add NULL stash file argument to krb5_db_fetch_mkey.
+
+
+Fri Jul 7 16:05:11 EDT 1995 Paul Park (pjpark@mit.edu)
+ * Makefile.in - Remove all explicit library handling and LDFLAGS.
+ * configure.in - Add USE_<mumble> and KRB5_LIBRARIES.
+
+
+Tue Jun 27 16:05:27 EDT 1995 Paul Park (pjpark@mit.edu)
+ * acl_files.c - Change check for return value from fputs(3) from NULL
+ to EOF. That's what's returned on error.
+ * admin_server.c - Cast 4th argument of setsockopt(2) to be const char *
+ * kadm_funcs.c - Cast argument to ctime(3)
+ * kadm_server.c - Cast first argument to strcpy(3) and strcat(3).
+
+Tue Jun 20 14:44:54 1995 Tom Yu (tlyu@dragons-lair)
+
+ * configure.in: add tests for TIME_WITH_SYS_TIME and sys/time.h
+
+Thu Jun 15 17:52:29 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 were
+ split out.
+ * configure.in - Add shared library usage check.
+
+Fri Jun 9 19:07:25 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:49:36 1995 Ezra Peisach <epeisach@kangaroo.mit.edu>
+
+ * kadm_stream.c (vts_long, stv_long): Change u_long to krb5_ui_4
+
+ * kadm_server.c (kadm_ser_ckpw): Change u_long to krb5_ui_4
+
+ * kadm_ser_wrap.c (errpkt, kadm_ser_in): Change u_long to krb5_ui_4
+
+ * kadm_funcs.c (kadm_add_entry): Change u_long to krb5_ui_4
+
+ * admin_server.c (process_client): Change u_long to krb5_ui_4
+
+Sat May 20 22:33:58 1995 Ezra Peisach <epeisach@kangaroo.mit.edu>
+
+ * kadm_stream.c: Based on presence of stdlib.h, include or declare
+ malloc.
+
+ * configure.in: Check for stdlib.h
+
+Sun May 7 13:49:54 1995 Ezra Peisach <epeisach@kangaroo.mit.edu>
+
+ * admin_server.c: Avoid warning of redeclaring POSIX_SIGNALS if
+ already defined.
+
+Sat Apr 29 00:34:01 1995 Theodore Y. Ts'o <tytso@dcl>
+
+ * admin_server.c (kadm_listen): Use Posix sigaction() instead of
+ signal() to set signal handlers. This allows us not to
+ worry about System V signal semantics. Make the code use
+ POSIX_SIGNALS by default.
+
+Fri Apr 28 18:08:05 1995 Mark Eichin <eichin@cygnus.com>
+
+ * Makefile.in (KLIB): put KRB4_LIB inside KLIB.
+
+Thu Apr 27 13:53:41 1995 Mark Eichin <eichin@cygnus.com>
+
+ * Makefile.in (v4kadmind): use KRB4_LIB directly.
+
+Thu Apr 20 23:21:42 1995 Theodore Y. Ts'o (tytso@dcl)
+
+ * kadm_funcs.c: Don't #include <ndbm.h>, since that's
+ automatically included by k5-config.h
+
+Thu Apr 20 15:26:48 1995 Ezra Peisach (epeisach@kangaroo.mit.edu)
+
+ * kadm_server.c (kadm_ser_cpw, kadm_ser_ckpw): krb_int32 should be
+ krb5_int32.
+
+ * acl_files.c: Declare acl_abort as static at top of file.
+
+Sun Apr 16 19:10:17 1995 Mark Eichin <eichin@cygnus.com>
+
+ * kadm_server.c (kadm_ser_cpw, kadm_ser_ckpw): use krb_int32, not
+ long, for network 4 byte quantities. Should get rid of the
+ use of memcpy at some point.
+
+Sat Mar 25 16:59:55 1995 Mark Eichin <eichin@cygnus.com>
+
+ * kadm_funcs.c (kadm_entry2princ): pass kadm_context in to
+ krb5_524_conv_principal.
+
+Tue Mar 14 16:45:18 1995 <tytso@rsx-11.mit.edu>
+
+ * Makefile.in: Don't link in the V4 DES library; use the des425
+ library to avoid linking the DES code in twice.
+
+Thu Mar 2 12:25:13 1995 Theodore Y. Ts'o <tytso@dcl>
+
+ * Makefile.in (ISODELIB): Remove reference to $(ISODELIB).
+
+Wed Mar 1 16:30:08 1995 Theodore Y. Ts'o <tytso@dcl>
+
+ * kadm_server.c: Remove declataions of malloc(); should be done by
+ header files.
+
+ * configure.in: Remove ISODE_INCLUDE, replace check for -lsocket
+ and -lnsl with WITH_NETLIB check.
+
+Tue Feb 28 02:24:56 1995 John Gilmore (gnu at toad.com)
+
+ * admin_server.c, kadm_server.c, kadm-server.h: Avoid
+ <krb5/...> includes.
+
+Tue Feb 7 16:42:54 1995 Mark Eichin <eichin@cygnus.com>
+
+ * kadm_funcs.c (kadm_del_entry): fixed call to db_delete_principal.
+
+Wed Jan 25 18:42:42 1995 Mark Eichin (eichin@tweedledumber.cygnus.com)
+
+ * kadm_server.h (DEL_ACL_FILE): new define, acl file for V4 delete
+ function.
+ * kadm_server.c (kadm_ser_add): new function, wrapper for V4 delete.
+ * kadm_funcs.c (check_access): declare int; add DEL.
+ (kadm_del_entry): new function, V4 delete from CNS.
+ (failadd): fix spelling error in log entry.
+
+Mon Dec 12 13:21:48 1994 Mark Eichin (eichin@cygnus.com)
+
+ * kadm_funcs.c (kadm_entry2princ, kadm_princ2entry,
+ kadm_chg_srvtab): V4 and V5 max_life are in *different units* so
+ use the 60*5 conversion factor.
+
+Fri Nov 18 15:51:11 1994 Theodore Y. Ts'o (tytso@dcl)
+
+ * kadm_funcs.c (kadm_add_entry, kadm_mod_entry, kadm_change): Add
+ magic numbers of keyblock structre.
+
+Fri Nov 18 01:11:58 1994 Mark Eichin <eichin@cygnus.com>
+
+ * configure.in: use CHECK_SIGNALS instead of expansion (from
+ epeisach).
+
+Wed Oct 19 18:53:45 1994 Theodore Y. Ts'o (tytso@dcl)
+
+ * kadm_ser_wrap.c (kadm_ser_init): Use krb5_use_cstype() to
+ initialize the master_encblock structure.
+
+Thu Sep 29 22:41:20 1994 Theodore Y. Ts'o (tytso@dcl)
+
+ * Makefile.in: relink executable if libraries change
+
+Thu Sep 15 10:53:37 1994 Theodore Y. Ts'o (tytso@dcl)
+
+ * admin_server.c (close_syslog, byebye): Move these two functions
+ before main(), so that they get declared properly. Otherwise
+ suncc will refuse to compile the file.
+
+ * kadm_funcs.c (kadm_add_entry, kadm_mod_entry, kadm_change,
+ kadm_chg_srvtab): use krb5_timeofday instead of time(0).
+
+Thu Aug 4 16:37:33 1994 Tom Yu (tlyu@dragons-lair)
+
+ * admin_server.c: pick up <sys/time.h> (needed to get FD_SET,
+ etc.)
+
+Sat Jul 16 09:21:22 1994 Tom Yu (tlyu at dragons-lair)
+
+ * Makefile.in: no longer trying to install v4kadmind as krb5kdc
+ :-)
+ * configure.in: another try at making dbm libs dtrt
+
+Wed Jun 29 00:24:28 1994 Tom Yu (tlyu at dragons-lair)
+
+ * admin_server.c: fixed calls that should have invoked
+ krb5_init_ets
+
+Sat Jun 25 09:07:48 1994 Tom Yu (tlyu at dragons-lair)
+
+ * kadm_ser_wrap.c: fixed lack of a terminal 0 in a call to
+ krb5_build_principal
+
diff --git a/src/kadmin/v4server/Makefile.in b/src/kadmin/v4server/Makefile.in
new file mode 100644
index 0000000000..01500167b7
--- /dev/null
+++ b/src/kadmin/v4server/Makefile.in
@@ -0,0 +1,23 @@
+CFLAGS = $(CCOPTS) $(DEFS) $(LOCALINCLUDE) \
+ -DOVSEC_KADM -DUSE_KADM5_API_VERSION=1 -DNEED_SOCKETS
+
+LOCALINCLUDE = -I$(SRCTOP)/include/kerberosIV -I$(BUILDTOP)/include/kerberosIV -I.
+
+PROG = kadmind4
+OBJS = kadm_server.o admin_server.o kadm_ser_wrap.o \
+ kadm_stream.o kadm_supp.o acl_files.o kadm_err.o
+
+all:: $(PROG)
+
+kadm_err.c kadm_err.h: $(srcdir)/kadm_err.et
+
+$(OBJS): kadm_err.h
+
+$(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/src/kadmin/v4server/Makefile.ov b/src/kadmin/v4server/Makefile.ov
new file mode 100644
index 0000000000..a365e8ea7a
--- /dev/null
+++ b/src/kadmin/v4server/Makefile.ov
@@ -0,0 +1,42 @@
+TOP = ..
+include $(TOP)/config.mk/template
+
+ifdef KRB5B4
+CFLAGS += -DKRB5B4 $(D_POSIX_SIGNALS)
+endif
+
+ETABLES = kadm_err.et
+expand ErrorTables
+
+depend:: kadm_err.h
+
+PROG := ovsec_v4adm_server
+
+SRCS := kadm_server.c admin_server.c kadm_ser_wrap.c \
+ kadm_stream.c kadm_supp.c acl_files.c kadm_err.c
+
+OBJS := kadm_server.o admin_server.o kadm_ser_wrap.o \
+ kadm_stream.o kadm_supp.o acl_files.o kadm_err.o
+
+LIBS := $(LIBADMCLNT) $(LIBRPCLIB) \
+ $(LIBKADM) $(LIBKRB) $(LIBDES425) \
+ $(LIBGSSAPI_KRB5) $(LIBKDB5) $(LIBKRB5_ALL) \
+ $(LIBDYN) $(LIBDB) $(LIBCOM_ERR) $(NDBMLIB) $(NETLIB) $(BSDLIB)
+
+ifdef WAIT_USES_INT
+WAIT_FLAGS = -DWAIT_USES_INT
+endif
+ifdef OPEN_NEEDS_FCNTL
+FCNTL_FLAGS = -DNEED_SYS_FCNTL_H
+endif
+
+CFLAGS := -DOVSEC_KADM -DUSE_KADM5_API_VERSION=1 \
+ $(WAIT_FLAGS) $(FCNLT_FLAGS) -I. \
+ -I$(TOP)/../include/kerberosIV -I$(TOP)/../../src/include/kerberosIV \
+ $(CFLAGS)
+
+expand InstallServer
+expand Depend
+
+SUBDIRS = unit-test
+expand SubdirTarget
diff --git a/src/kadmin/v4server/acl_files.c b/src/kadmin/v4server/acl_files.c
new file mode 100644
index 0000000000..ae3b0c6bff
--- /dev/null
+++ b/src/kadmin/v4server/acl_files.c
@@ -0,0 +1,536 @@
+/*
+ * kadmin/v4server/acl_files.c
+ *
+ * Copyright 1987,1989 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ */
+
+
+/*** Routines for manipulating access control list files ***/
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include "krb.h"
+
+#ifndef KRB_REALM
+#define KRB_REALM "ATHENA.MIT.EDU"
+#endif
+
+/* "aname.inst@realm" */
+#define MAX_PRINCIPAL_SIZE (ANAME_SZ + INST_SZ + REALM_SZ + 3)
+#define INST_SEP '.'
+#define REALM_SEP '@'
+
+#define LINESIZE 2048 /* Maximum line length in an acl file */
+
+#define NEW_FILE "%s.~NEWACL~" /* Format for name of altered acl file */
+#define WAIT_TIME 300 /* Maximum time allowed write acl file */
+
+#define CACHED_ACLS 8 /* How many acls to cache */
+ /* Each acl costs 1 open file descriptor */
+#define ACL_LEN 16 /* Twice a reasonable acl length */
+
+#define MAX(a,b) (((a)>(b))?(a):(b))
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+#define COR(a,b) ((a!=NULL)?(a):(b))
+
+extern int errno;
+
+extern char *malloc(), *calloc();
+extern time_t time();
+
+static int acl_abort();
+
+/* Canonicalize a principal name */
+/* If instance is missing, it becomes "" */
+/* If realm is missing, it becomes the local realm */
+/* Canonicalized form is put in canon, which must be big enough to hold
+ MAX_PRINCIPAL_SIZE characters */
+void acl_canonicalize_principal(principal, canon)
+char *principal;
+char *canon;
+{
+ char *dot, *atsign, *end;
+ int len;
+
+ dot = strchr(principal, INST_SEP);
+ atsign = strchr(principal, REALM_SEP);
+
+ /* Maybe we're done already */
+ if(dot != NULL && atsign != NULL) {
+ if(dot < atsign) {
+ /* It's for real */
+ /* Copy into canon */
+ strncpy(canon, principal, MAX_PRINCIPAL_SIZE);
+ canon[MAX_PRINCIPAL_SIZE-1] = '\0';
+ return;
+ } else {
+ /* Nope, it's part of the realm */
+ dot = NULL;
+ }
+ }
+
+ /* No such luck */
+ end = principal + strlen(principal);
+
+ /* Get the principal name */
+ len = MIN(ANAME_SZ, COR(dot, COR(atsign, end)) - principal);
+ strncpy(canon, principal, len);
+ canon += len;
+
+ /* Add INST_SEP */
+ *canon++ = INST_SEP;
+
+ /* Get the instance, if it exists */
+ if(dot != NULL) {
+ ++dot;
+ len = MIN(INST_SZ, COR(atsign, end) - dot);
+ strncpy(canon, dot, len);
+ canon += len;
+ }
+
+ /* Add REALM_SEP */
+ *canon++ = REALM_SEP;
+
+ /* Get the realm, if it exists */
+ /* Otherwise, default to local realm */
+ if(atsign != NULL) {
+ ++atsign;
+ len = MIN(REALM_SZ, end - atsign);
+ strncpy(canon, atsign, len);
+ canon += len;
+ *canon++ = '\0';
+ } else if(krb_get_lrealm(canon, 1) != KSUCCESS) {
+ strcpy(canon, KRB_REALM);
+ }
+}
+
+/* Get a lock to modify acl_file */
+/* Return new FILE pointer */
+/* or NULL if file cannot be modified */
+/* REQUIRES WRITE PERMISSION TO CONTAINING DIRECTORY */
+static FILE *acl_lock_file(acl_file)
+char *acl_file;
+{
+ struct stat s;
+ char new[LINESIZE];
+ int nfd;
+ FILE *nf;
+ int mode;
+
+ if(stat(acl_file, &s) < 0) return(NULL);
+ mode = s.st_mode;
+ sprintf(new, NEW_FILE, acl_file);
+ for(;;) {
+ /* Open the new file */
+ if((nfd = open(new, O_WRONLY|O_CREAT|O_EXCL, mode)) < 0) {
+ if(errno == EEXIST) {
+ /* Maybe somebody got here already, maybe it's just old */
+ if(stat(new, &s) < 0) return(NULL);
+ if(time(0) - s.st_ctime > WAIT_TIME) {
+ /* File is stale, kill it */
+ unlink(new);
+ continue;
+ } else {
+ /* Wait and try again */
+ sleep(1);
+ continue;
+ }
+ } else {
+ /* Some other error, we lose */
+ return(NULL);
+ }
+ }
+
+ /* If we got to here, the lock file is ours and ok */
+ /* Reopen it under stdio */
+ if((nf = fdopen(nfd, "w")) == NULL) {
+ /* Oops, clean up */
+ unlink(new);
+ }
+ return(nf);
+ }
+}
+
+/* Commit changes to acl_file written onto FILE *f */
+/* Returns zero if successful */
+/* Returns > 0 if lock was broken */
+/* Returns < 0 if some other error occurs */
+/* Closes f */
+static int acl_commit(acl_file, f)
+char *acl_file;
+FILE *f;
+{
+ char new[LINESIZE];
+ int ret;
+ struct stat s;
+
+ sprintf(new, NEW_FILE, acl_file);
+ if(fflush(f) < 0
+ || fstat(fileno(f), &s) < 0
+ || s.st_nlink == 0) {
+ acl_abort(acl_file, f);
+ return(-1);
+ }
+
+ ret = rename(new, acl_file);
+ fclose(f);
+ return(ret);
+}
+
+/* Abort changes to acl_file written onto FILE *f */
+/* Returns 0 if successful, < 0 otherwise */
+/* Closes f */
+static int acl_abort(acl_file, f)
+char *acl_file;
+FILE *f;
+{
+ char new[LINESIZE];
+ int ret;
+ struct stat s;
+
+ /* make sure we aren't nuking someone else's file */
+ if(fstat(fileno(f), &s) < 0
+ || s.st_nlink == 0) {
+ fclose(f);
+ return(-1);
+ } else {
+ sprintf(new, NEW_FILE, acl_file);
+ ret = unlink(new);
+ fclose(f);
+ return(ret);
+ }
+}
+
+/* Initialize an acl_file */
+/* Creates the file with permissions perm if it does not exist */
+/* Erases it if it does */
+/* Returns return value of acl_commit */
+int acl_initialize(acl_file, perm)
+char *acl_file;
+int perm;
+{
+ FILE *new;
+ int fd;
+
+ /* Check if the file exists already */
+ if((new = acl_lock_file(acl_file)) != NULL) {
+ return(acl_commit(acl_file, new));
+ } else {
+ /* File must be readable and writable by owner */
+ if((fd = open(acl_file, O_CREAT|O_EXCL, perm|0600)) < 0) {
+ return(-1);
+ } else {
+ close(fd);
+ return(0);
+ }
+ }
+}
+
+/* Eliminate all whitespace character in buf */
+/* Modifies its argument */
+static nuke_whitespace(buf)
+char *buf;
+{
+ register char *pin, *pout;
+
+ for(pin = pout = buf; *pin != '\0'; pin++)
+ if(!isspace(*pin)) *pout++ = *pin;
+ *pout = '\0'; /* Terminate the string */
+}
+
+/* Hash table stuff */
+
+struct hashtbl {
+ int size; /* Max number of entries */
+ int entries; /* Actual number of entries */
+ char **tbl; /* Pointer to start of table */
+};
+
+/* Make an empty hash table of size s */
+static struct hashtbl *make_hash(size)
+int size;
+{
+ struct hashtbl *h;
+
+ if(size < 1) size = 1;
+ h = (struct hashtbl *) malloc(sizeof(struct hashtbl));
+ h->size = size;
+ h->entries = 0;
+ h->tbl = (char **) calloc(size, sizeof(char *));
+ return(h);
+}
+
+/* Destroy a hash table */
+static destroy_hash(h)
+struct hashtbl *h;
+{
+ int i;
+
+ for(i = 0; i < h->size; i++) {
+ if(h->tbl[i] != NULL) free(h->tbl[i]);
+ }
+ free(h->tbl);
+ free(h);
+}
+
+/* Compute hash value for a string */
+static unsigned hashval(s)
+register char *s;
+{
+ register unsigned hv;
+
+ for(hv = 0; *s != '\0'; s++) {
+ hv ^= ((hv << 3) ^ *s);
+ }
+ return(hv);
+}
+
+/* Add an element to a hash table */
+static add_hash(h, el)
+struct hashtbl *h;
+char *el;
+{
+ unsigned hv;
+ char *s;
+ char **old;
+ int i;
+
+ /* Make space if it isn't there already */
+ if(h->entries + 1 > (h->size >> 1)) {
+ old = h->tbl;
+ h->tbl = (char **) calloc(h->size << 1, sizeof(char *));
+ for(i = 0; i < h->size; i++) {
+ if(old[i] != NULL) {
+ hv = hashval(old[i]) % (h->size << 1);
+ while(h->tbl[hv] != NULL) hv = (hv+1) % (h->size << 1);
+ h->tbl[hv] = old[i];
+ }
+ }
+ h->size = h->size << 1;
+ free(old);
+ }
+
+ hv = hashval(el) % h->size;
+ while(h->tbl[hv] != NULL && strcmp(h->tbl[hv], el)) hv = (hv+1) % h->size;
+ s = malloc(strlen(el)+1);
+ strcpy(s, el);
+ h->tbl[hv] = s;
+ h->entries++;
+}
+
+/* Returns nonzero if el is in h */
+static check_hash(h, el)
+struct hashtbl *h;
+char *el;
+{
+ unsigned hv;
+
+ for(hv = hashval(el) % h->size;
+ h->tbl[hv] != NULL;
+ hv = (hv + 1) % h->size) {
+ if(!strcmp(h->tbl[hv], el)) return(1);
+ }
+ return(0);
+}
+
+struct acl {
+ char filename[LINESIZE]; /* Name of acl file */
+ int fd; /* File descriptor for acl file */
+ struct stat status; /* File status at last read */
+ struct hashtbl *acl; /* Acl entries */
+};
+
+static struct acl acl_cache[CACHED_ACLS];
+
+static int acl_cache_count = 0;
+static int acl_cache_next = 0;
+
+/* Returns < 0 if unsuccessful in loading acl */
+/* Returns index into acl_cache otherwise */
+/* Note that if acl is already loaded, this is just a lookup */
+static int acl_load(name)
+char *name;
+{
+ int i;
+ FILE *f;
+ struct stat s;
+ char buf[MAX_PRINCIPAL_SIZE];
+ char canon[MAX_PRINCIPAL_SIZE];
+
+ /* See if it's there already */
+ for(i = 0; i < acl_cache_count; i++) {
+ if(!strcmp(acl_cache[i].filename, name)
+ && acl_cache[i].fd >= 0) goto got_it;
+ }
+
+ /* It isn't, load it in */
+ /* maybe there's still room */
+ if(acl_cache_count < CACHED_ACLS) {
+ i = acl_cache_count++;
+ } else {
+ /* No room, clean one out */
+ i = acl_cache_next;
+ acl_cache_next = (acl_cache_next + 1) % CACHED_ACLS;
+ close(acl_cache[i].fd);
+ if(acl_cache[i].acl) {
+ destroy_hash(acl_cache[i].acl);
+ acl_cache[i].acl = (struct hashtbl *) 0;
+ }
+ }
+
+ /* Set up the acl */
+ strcpy(acl_cache[i].filename, name);
+ if((acl_cache[i].fd = open(name, O_RDONLY, 0)) < 0) return(-1);
+ /* Force reload */
+ acl_cache[i].acl = (struct hashtbl *) 0;
+
+ got_it:
+ /*
+ * See if the stat matches
+ *
+ * Use stat(), not fstat(), as the file may have been re-created by
+ * acl_add or acl_delete. If this happens, the old inode will have
+ * no changes in the mod-time and the following test will fail.
+ */
+ if(stat(acl_cache[i].filename, &s) < 0) return(-1);
+ if(acl_cache[i].acl == (struct hashtbl *) 0
+ || s.st_nlink != acl_cache[i].status.st_nlink
+ || s.st_mtime != acl_cache[i].status.st_mtime
+ || s.st_ctime != acl_cache[i].status.st_ctime) {
+ /* Gotta reload */
+ if(acl_cache[i].fd >= 0) close(acl_cache[i].fd);
+ if((acl_cache[i].fd = open(name, O_RDONLY, 0)) < 0) return(-1);
+ if((f = fdopen(acl_cache[i].fd, "r")) == NULL) return(-1);
+ if(acl_cache[i].acl) destroy_hash(acl_cache[i].acl);
+ acl_cache[i].acl = make_hash(ACL_LEN);
+ while(fgets(buf, sizeof(buf), f) != NULL) {
+ nuke_whitespace(buf);
+ acl_canonicalize_principal(buf, canon);
+ add_hash(acl_cache[i].acl, canon);
+ }
+ fclose(f);
+ acl_cache[i].status = s;
+ }
+ return(i);
+}
+
+/* Returns nonzero if it can be determined that acl contains principal */
+/* Principal is not canonicalized, and no wildcarding is done */
+acl_exact_match(acl, principal)
+char *acl;
+char *principal;
+{
+ int idx;
+
+ return((idx = acl_load(acl)) >= 0
+ && check_hash(acl_cache[idx].acl, principal));
+}
+
+/* Returns nonzero if it can be determined that acl contains principal */
+/* Recognizes wildcards in acl of the form
+ name.*@realm, *.*@realm, and *.*@* */
+acl_check(acl, principal)
+char *acl;
+char *principal;
+{
+ char buf[MAX_PRINCIPAL_SIZE];
+ char canon[MAX_PRINCIPAL_SIZE];
+ char *realm, *tmp;
+
+ acl_canonicalize_principal(principal, canon);
+
+ /* Is it there? */
+ if(acl_exact_match(acl, canon)) return(1);
+
+ /* Try the wildcards */
+ realm = strchr(canon, REALM_SEP);
+ tmp = strchr(canon, INST_SEP);
+ *tmp = '\0'; /* Chuck the instance */
+
+ sprintf(buf, "%s.*%s", canon, realm);
+ if(acl_exact_match(acl, buf)) return(1);
+
+ sprintf(buf, "*.*%s", realm);
+ if(acl_exact_match(acl, buf) || acl_exact_match(acl, "*.*@*")) return(1);
+
+ return(0);
+}
+
+/* Adds principal to acl */
+/* Wildcards are interpreted literally */
+acl_add(acl, principal)
+char *acl;
+char *principal;
+{
+ int idx;
+ int i;
+ FILE *new;
+ char canon[MAX_PRINCIPAL_SIZE];
+
+ acl_canonicalize_principal(principal, canon);
+
+ if((new = acl_lock_file(acl)) == NULL) return(-1);
+ if((acl_exact_match(acl, canon))
+ || (idx = acl_load(acl)) < 0) {
+ acl_abort(acl, new);
+ return(-1);
+ }
+ /* It isn't there yet, copy the file and put it in */
+ for(i = 0; i < acl_cache[idx].acl->size; i++) {
+ if(acl_cache[idx].acl->tbl[i] != NULL) {
+ if(fputs(acl_cache[idx].acl->tbl[i], new) == EOF
+ || putc('\n', new) != '\n') {
+ acl_abort(acl, new);
+ return(-1);
+ }
+ }
+ }
+ fputs(canon, new);
+ putc('\n', new);
+ return(acl_commit(acl, new));
+}
+
+/* Removes principal from acl */
+/* Wildcards are interpreted literally */
+acl_delete(acl, principal)
+char *acl;
+char *principal;
+{
+ int idx;
+ int i;
+ FILE *new;
+ char canon[MAX_PRINCIPAL_SIZE];
+
+ acl_canonicalize_principal(principal, canon);
+
+ if((new = acl_lock_file(acl)) == NULL) return(-1);
+ if((!acl_exact_match(acl, canon))
+ || (idx = acl_load(acl)) < 0) {
+ acl_abort(acl, new);
+ return(-1);
+ }
+ /* It isn't there yet, copy the file and put it in */
+ for(i = 0; i < acl_cache[idx].acl->size; i++) {
+ if(acl_cache[idx].acl->tbl[i] != NULL
+ && strcmp(acl_cache[idx].acl->tbl[i], canon)) {
+ fputs(acl_cache[idx].acl->tbl[i], new);
+ putc('\n', new);
+ }
+ }
+ return(acl_commit(acl, new));
+}
+
diff --git a/src/kadmin/v4server/acl_files.doc b/src/kadmin/v4server/acl_files.doc
new file mode 100644
index 0000000000..78c448a6d6
--- /dev/null
+++ b/src/kadmin/v4server/acl_files.doc
@@ -0,0 +1,107 @@
+PROTOTYPE ACL LIBRARY
+
+Introduction
+
+An access control list (ACL) is a list of principals, where each
+principal is is represented by a text string which cannot contain
+whitespace. The library allows application programs to refer to named
+access control lists to test membership and to atomically add and
+delete principals using a natural and intuitive interface. At
+present, the names of access control lists are required to be Unix
+filenames, and refer to human-readable Unix files; in the future, when
+a networked ACL server is implemented, the names may refer to a
+different namespace specific to the ACL service.
+
+
+Usage
+
+cc <files> -lacl -lkrb.
+
+
+
+Principal Names
+
+Principal names have the form
+
+<name>[.<instance>][@<realm>]
+
+e.g.
+
+asp
+asp.root
+asp@ATHENA.MIT.EDU
+asp.@ATHENA.MIT.EDU
+asp.root@ATHENA.MIT.EDU
+
+It is possible for principals to be underspecified. If instance is
+missing, it is assumed to be "". If realm is missing, it is assumed
+to be local_realm. The canonical form contains all of name, instance,
+and realm; the acl_add and acl_delete routines will always
+leave the file in that form. Note that the canonical form of
+asp@ATHENA.MIT.EDU is actually asp.@ATHENA.MIT.EDU.
+
+
+Routines
+
+acl_canonicalize_principal(principal, buf)
+char *principal;
+char *buf; /*RETVAL*/
+
+Store the canonical form of principal in buf. Buf must contain enough
+space to store a principal, given the limits on the sizes of name,
+instance, and realm specified in /usr/include/krb.h.
+
+acl_check(acl, principal)
+char *acl;
+char *principal;
+
+Returns nonzero if principal appears in acl. Returns 0 if principal
+does not appear in acl, or if an error occurs. Canonicalizes
+principal before checking, and allows the ACL to contain wildcards.
+
+acl_exact_match(acl, principal)
+char *acl;
+char *principal;
+
+Like acl_check, but does no canonicalization or wildcarding.
+
+acl_add(acl, principal)
+char *acl;
+char *principal;
+
+Atomically adds principal to acl. Returns 0 if successful, nonzero
+otherwise. It is considered a failure if principal is already in acl.
+This routine will canonicalize principal, but will treat wildcards
+literally.
+
+acl_delete(acl, principal)
+char *acl;
+char *principal;
+
+Atomically deletes principal from acl. Returns 0 if successful,
+nonzero otherwise. It is consider a failure if principal is not
+already in acl. This routine will canonicalize principal, but will
+treat wildcards literally.
+
+acl_initialize(acl, mode)
+char *acl;
+int mode;
+
+Initialize acl. If acl file does not exist, creates it with mode
+mode. If acl exists, removes all members. Returns 0 if successful,
+nonzero otherwise. WARNING: Mode argument is likely to change with
+the eventual introduction of an ACL service.
+
+
+Known problems
+
+In the presence of concurrency, there is a very small chance that
+acl_add or acl_delete could report success even though it would have
+had no effect. This is a necessary side effect of using lock files
+for concurrency control rather than flock(2), which is not supported
+by NFS.
+
+The current implementation caches ACLs in memory in a hash-table
+format for increased efficiency in checking membership; one effect of
+the caching scheme is that one file descriptor will be kept open for
+each ACL cached, up to a maximum of 8.
diff --git a/src/kadmin/v4server/admin_server.c b/src/kadmin/v4server/admin_server.c
new file mode 100644
index 0000000000..7a207d7c5e
--- /dev/null
+++ b/src/kadmin/v4server/admin_server.c
@@ -0,0 +1,684 @@
+/*
+ * kadmin/v4server/admin_server.c
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * Top-level loop of the kerberos Administration server
+ */
+
+#include <mit-copyright.h>
+/*
+ admin_server.c
+ this holds the main loop and initialization and cleanup code for the server
+*/
+
+#ifdef _AIX
+#include <sys/select.h>
+#endif
+
+/* define it for now */
+#ifndef POSIX_SIGNALS
+#define POSIX_SIGNALS
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <signal.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifndef POSIX_SIGNALS
+#ifndef sigmask
+#define sigmask(m) (1 <<((m)-1))
+#endif
+#endif /* POSIX_SIGNALS */
+#include <sys/wait.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <syslog.h>
+
+#ifdef OVSEC_KADM
+#include <kadm5/admin.h>
+void *ovsec_handle;
+kadm5_config_params params;
+#endif
+
+#include "k5-int.h"
+#include <kadm.h>
+#include <kadm_err.h>
+#include <krb_db.h>
+#include "com_err.h"
+#include "kadm_server.h"
+
+#ifdef POSIX_SIGTYPE
+#define SIGNAL_RETURN return
+#else
+#define SIGNAL_RETURN return(0)
+#endif
+
+/* Almost all procs and such need this, so it is global */
+admin_params prm; /* The command line parameters struct */
+
+char prog[32]; /* WHY IS THIS NEEDED??????? */
+char *progname = prog;
+char *acldir = DEFAULT_ACL_DIR;
+char krbrlm[REALM_SZ];
+extern Kadm_Server server_parm;
+krb5_context kadm_context;
+int debug;
+
+/* close the system log file */
+void close_syslog()
+{
+ syslog(LOG_INFO, "Shutting down V4 admin server");
+}
+
+void byebye() /* say goodnight gracie */
+{
+ printf("Admin Server (kadm server) has completed operation.\n");
+}
+
+/*
+** Main does the logical thing, it sets up the database and RPC interface,
+** as well as handling the creation and maintenance of the syslog file...
+*/
+main(argc, argv) /* admin_server main routine */
+int argc;
+char *argv[];
+{
+ int errval;
+ int c;
+ char *lrealm;
+ extern char *optarg;
+ extern int fascist_cpw;
+
+#ifdef OVSEC_KADM
+ memset(&params, 0, sizeof(params));
+#endif
+
+ krb5_init_context(&kadm_context);
+ krb5_init_ets(kadm_context);
+ initialize_kadm_error_table();
+ prog[sizeof(prog)-1]='\0'; /* Terminate... */
+ (void) strncpy(prog, argv[0], sizeof(prog)-1);
+
+ /* initialize the admin_params structure */
+ prm.sysfile = KADM_SYSLOG; /* default file name */
+ prm.inter = 1;
+
+ memset(krbrlm, 0, sizeof(krbrlm));
+
+ fascist_cpw = 1; /* by default, enable fascist mode */
+ while ((c = getopt(argc, argv, "Df:hnd:a:r:FN")) != EOF)
+ switch(c) {
+ case 'D':
+ debug++;
+ break;
+ case 'f': /* Syslog file name change */
+ prm.sysfile = optarg;
+ break;
+ case 'n':
+ prm.inter = 0;
+ break;
+ case 'a': /* new acl directory */
+ acldir = optarg;
+ break;
+ case 'd':
+#ifdef OVSEC_KADM
+ params.dbname = optarg;
+ params.mask |= KADM5_CONFIG_DBNAME;
+#else
+ if (errval = krb5_db_set_name(kadm_context, optarg)) {
+ com_err(argv[0], errval, "while setting dbname");
+ exit(1);
+ }
+#endif
+ break;
+ case 'F':
+ fascist_cpw++;
+ break;
+ case 'N':
+ fascist_cpw = 0;
+ break;
+ case 'r':
+ (void) strncpy(krbrlm, optarg, sizeof(krbrlm) - 1);
+ break;
+ case 'h': /* get help on using admin_server */
+ default:
+ printf("Usage: admin_server [-h] [-n] [-F] [-N] [-r realm] [-d dbname] [-f filename] [-a acldir]\n");
+ exit(-1); /* failure */
+ }
+
+ if (krbrlm[0] == 0) {
+ if (errval = krb5_get_default_realm(kadm_context, &lrealm)) {
+ com_err(argv[0], errval, "while attempting to get local realm");
+ exit(1);
+ }
+ (void) strncpy(krbrlm, lrealm, sizeof(krbrlm) - 1);
+ }
+
+#ifdef OVSEC_KADM
+ params.realm = krbrlm;
+ params.mask |= KADM5_CONFIG_REALM;
+
+ if (errval = kadm5_get_config_params(kadm_context, NULL, NULL,
+ &params, &params)) {
+ com_err(argv[0], errval, "while retrieving kadm5 params");
+ exit(1);
+ }
+ if (errval = krb5_db_set_name(kadm_context, params.dbname)) {
+ com_err(argv[0], errval, "while setting dbname");
+ exit(1);
+ }
+#endif /* OVSEC_KADM */
+
+ printf("KADM Server %s initializing\n",KADM_VERSTR);
+ printf("Please do not use 'kill -9' to kill this job, use a\n");
+ printf("regular kill instead\n\n");
+
+#ifdef OVSEC_KADM
+ printf("KADM Server starting in the OVSEC_KADM mode (%sprocess id %d).\n",
+ debug ? "" : "parent ", getpid());
+#else
+ printf("KADM Server starting in %s mode for the purposes for password changing\n\n", fascist_cpw ? "fascist" : "NON-FASCIST");
+#endif
+
+ openlog(argv[0], LOG_CONS|LOG_NDELAY|LOG_PID, LOG_LOCAL6); /* XXX */
+ syslog(LOG_INFO, "V4 admin server starting");
+
+ errval = krb5_db_init(kadm_context); /* Open the Kerberos database */
+ if (errval) {
+ fprintf(stderr, "error: krb5_db_init() failed");
+ close_syslog();
+ byebye();
+ exit(1);
+ }
+ if (errval = krb5_db_set_lockmode(kadm_context, TRUE)) {
+ com_err(argv[0], errval, "while setting db to nonblocking");
+ close_syslog();
+ byebye();
+ exit(1);
+ }
+ /* set up the server_parm struct */
+ if ((errval = kadm_ser_init(prm.inter, krbrlm
+#ifdef OVSEC_KADM
+ , &params
+#endif
+ ))==KADM_SUCCESS) {
+ krb5_db_fini(kadm_context); /* Close the Kerberos database--
+ will re-open later */
+ errval = kadm_listen(); /* listen for calls to server from
+ clients */
+ }
+ if (errval != KADM_SUCCESS) {
+ fprintf(stderr,"error: %s\n",error_message(errval));
+ krb5_db_fini(kadm_context); /* Close if error */
+ }
+ close_syslog(); /* Close syslog file, print
+ closing note */
+ byebye(); /* Say bye bye on the terminal
+ in use */
+ return 0;
+} /* procedure main */
+
+
+static void clear_secrets()
+{
+ krb5_finish_key(kadm_context, &server_parm.master_encblock);
+ memset((char *)&server_parm.master_encblock, 0,
+ sizeof (server_parm.master_encblock));
+ memset((char *)server_parm.master_keyblock.contents, 0,
+ server_parm.master_keyblock.length);
+ server_parm.mkvno = 0L;
+ return;
+}
+
+static exit_now = 0;
+
+krb5_sigtype
+doexit(sig)
+ int sig;
+{
+ exit_now = 1;
+ SIGNAL_RETURN;
+}
+
+unsigned pidarraysize = 0;
+int *pidarray = (int *)0;
+int unknown_child = 0;
+
+/*
+kadm_listen
+listen on the admin servers port for a request
+*/
+kadm_listen()
+{
+ extern int errno;
+ int found;
+ int admin_fd;
+ int peer_fd;
+ fd_set mask, readfds;
+ struct sockaddr_in peer;
+ int addrlen;
+ void process_client(), kill_children();
+ int pid;
+ krb5_sigtype do_child();
+#ifdef POSIX_SIGNALS
+ struct sigaction new_act;
+
+ new_act.sa_handler = doexit;
+ sigemptyset(&new_act.sa_mask);
+ sigaction(SIGINT, &new_act, 0);
+ sigaction(SIGTERM, &new_act, 0);
+ sigaction(SIGHUP, &new_act, 0);
+ sigaction(SIGQUIT, &new_act, 0);
+ sigaction(SIGALRM, &new_act, 0);
+ new_act.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &new_act, 0);
+ new_act.sa_handler = do_child;
+ sigaction(SIGCHLD, &new_act, 0);
+#else
+ signal(SIGINT, doexit);
+ signal(SIGTERM, doexit);
+ signal(SIGHUP, doexit);
+ signal(SIGQUIT, doexit);
+ signal(SIGPIPE, SIG_IGN); /* get errors on write() */
+ signal(SIGALRM, doexit);
+ signal(SIGCHLD, do_child);
+#endif
+
+ if ((admin_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+ return KADM_NO_SOCK;
+ if (debug) {
+ int one = 1;
+ if (setsockopt(admin_fd, SOL_SOCKET, SO_REUSEADDR, &one,
+ sizeof(int)) < 0) {
+ syslog(LOG_ERR, "setsockopt: %m");
+ return KADM_NO_BIND;
+ }
+ }
+ if (bind(admin_fd, (struct sockaddr *)&server_parm.admin_addr,
+ sizeof(struct sockaddr_in)) < 0)
+ return KADM_NO_BIND;
+ (void) listen(admin_fd, 1);
+ FD_ZERO(&mask);
+ FD_SET(admin_fd, &mask);
+
+ for (;;) { /* loop nearly forever */
+ if (exit_now) {
+ clear_secrets();
+ kill_children();
+ return(0);
+ }
+ readfds = mask;
+ if ((found = select(admin_fd+1,&readfds,(fd_set *)0,
+ (fd_set *)0, (struct timeval *)0)) == 0)
+ continue; /* no things read */
+ if (found < 0) {
+ if (errno != EINTR)
+ syslog(LOG_ERR, "select: %s", error_message(errno));
+ continue;
+ }
+ if (FD_ISSET(admin_fd, &readfds)) {
+ /* accept the conn */
+ addrlen = sizeof(peer);
+ if ((peer_fd = accept(admin_fd, (struct sockaddr *)&peer,
+ &addrlen)) < 0) {
+ syslog(LOG_ERR, "accept: %s", error_message(errno));
+ continue;
+ }
+
+ if (debug) {
+ process_client(peer_fd, &peer);
+ } else if (pid = fork()) {
+ /* parent */
+ if (pid < 0) {
+ syslog(LOG_ERR, "fork: %s", error_message(errno));
+ (void) close(peer_fd);
+ continue;
+ }
+ /* fork succeeded: keep tabs on child */
+ (void) close(peer_fd);
+ if (unknown_child != pid) {
+ if (pidarray) {
+ pidarray = (int *)realloc((char *)pidarray,
+ (++pidarraysize * sizeof(int)));
+ pidarray[pidarraysize-1] = pid;
+ } else {
+ pidarray = (int *)malloc((pidarraysize = 1) * sizeof(int));
+ pidarray[0] = pid;
+ }
+ } /* End if unknown_child != pid.*/
+ } else {
+ /* child */
+ (void) close(admin_fd);
+ process_client(peer_fd, &peer);
+ }
+ } else {
+ syslog(LOG_ERR, "something else woke me up!");
+ return(0);
+ }
+ }
+ /*NOTREACHED*/
+}
+
+void process_client(fd, who)
+ int fd;
+ struct sockaddr_in *who;
+{
+ u_char *dat;
+ int dat_len;
+ u_short dlen;
+ int retval;
+ int on = 1;
+ int nentries = 1;
+ krb5_db_entry sprinc_entries;
+ krb5_boolean more;
+ krb5_keyblock cpw_skey;
+ krb5_key_data *kdatap;
+ int status;
+
+#ifdef OVSEC_KADM
+#define OVSEC_KADM_SRVTAB "FILE:/krb5/ovsec_adm.srvtab"
+ char *service_name;
+
+ service_name = (char *) malloc(strlen(server_parm.sname) +
+ strlen(server_parm.sinst) +
+ strlen(server_parm.krbrlm) + 3);
+ if (service_name == NULL) {
+ syslog(LOG_ERR, "error: out of memory allocating service name");
+ cleanexit(1);
+ }
+ sprintf(service_name, "%s/%s@%s", server_parm.sname,
+ server_parm.sinst, server_parm.krbrlm);
+
+ retval = ovsec_kadm_init_with_skey(service_name,
+ OVSEC_KADM_SRVTAB,
+ OVSEC_KADM_ADMIN_SERVICE, krbrlm,
+ OVSEC_KADM_STRUCT_VERSION,
+ OVSEC_KADM_API_VERSION_1,
+ &ovsec_handle);
+ if (retval) {
+ syslog(LOG_ERR, "error: ovsec_kadm_init failed: %s",
+ error_message(retval));
+ cleanexit(1);
+ }
+ free(service_name);
+
+ if (retval = krb5_db_set_name(kadm_context, params.dbname)) {
+ syslog(LOG_ERR, "%s while setting dbname", error_message(retval));
+ cleanexit(1);
+ }
+#endif
+
+#ifndef NOENCRYPTION
+ /* Must do it here, since this is after the fork() call */
+ des_init_random_number_generator(server_parm.master_keyblock.contents);
+#endif /* NOENCRYPTION */
+
+ if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
+ (const char *) &on, sizeof(on)) < 0)
+ syslog(LOG_ERR, "setsockopt keepalive: %d", errno);
+
+ server_parm.recv_addr = *who;
+
+ if (retval = krb5_db_init(kadm_context)) { /* Open as client */
+ syslog(LOG_ERR, "can't open krb db: %s", error_message(retval));
+ cleanexit(1);
+ }
+ /* need to set service key to changepw.KRB_MASTER */
+
+ status = krb5_db_get_principal(kadm_context, server_parm.sprinc,
+ &sprinc_entries,
+ &nentries, &more);
+ /* ugh... clean this up later */
+ if (status == KRB5_KDB_DB_INUSE) {
+ /* db locked */
+ krb5_ui_4 retcode = KADM_DB_INUSE;
+ char *pdat;
+
+ dat_len = KADM_VERSIZE + sizeof(krb5_ui_4);
+ dat = (u_char *) malloc((unsigned)dat_len);
+ pdat = (char *) dat;
+ retcode = htonl((krb5_ui_4) KADM_DB_INUSE);
+ (void) strncpy(pdat, KADM_ULOSE, KADM_VERSIZE);
+ memcpy(&pdat[KADM_VERSIZE], (char *)&retcode, sizeof(krb5_ui_4));
+ goto out;
+ } else if (!nentries) {
+ syslog(LOG_ERR, "no service %s.%s", server_parm.sname, server_parm.sinst);
+ cleanexit(2);
+ } else if (status) {
+ syslog(LOG_ERR, error_message(status));
+ cleanexit(2);
+ }
+
+ status = krb5_dbe_find_enctype(kadm_context,
+ &sprinc_entries,
+ ENCTYPE_DES_CBC_MD5,
+ -1,
+ -1,
+ &kdatap);
+ if (status) {
+ syslog(LOG_ERR, "find enctype failed: %s", error_message(status));
+ cleanexit(1);
+ }
+
+ status = krb5_dbekd_decrypt_key_data(kadm_context,
+ &server_parm.master_encblock,
+ kdatap,
+ &cpw_skey,
+ (krb5_keysalt *) NULL);
+ if (status) {
+ syslog(LOG_ERR, "decrypt_key failed: %s", error_message(status));
+ cleanexit(1);
+ }
+ /* if error, will show up when rd_req fails */
+ (void) krb_set_key((char *)cpw_skey.contents, 0);
+ while (1) {
+ if ((retval = krb_net_read(fd, (char *)&dlen, sizeof(u_short))) !=
+ sizeof(u_short)) {
+ if (retval < 0)
+ syslog(LOG_ERR, "dlen read: %s", error_message(errno));
+ else if (retval)
+ syslog(LOG_ERR, "short dlen read: %d", retval);
+ (void) close(fd);
+#ifdef OVSEC_KADM
+ (void) ovsec_kadm_destroy(ovsec_handle);
+#endif
+ cleanexit(retval ? 3 : 0);
+ }
+ if (exit_now) {
+ cleanexit(0);
+ }
+ dat_len = (int) ntohs(dlen);
+ dat = (u_char *) malloc((unsigned)dat_len);
+ if (!dat) {
+ syslog(LOG_ERR, "malloc: No memory");
+ (void) close(fd);
+ cleanexit(4);
+ }
+ if ((retval = krb_net_read(fd, (char *)dat, dat_len)) != dat_len) {
+ if (retval < 0)
+ syslog(LOG_ERR, "data read: %s", error_message(errno));
+ else
+ syslog(LOG_ERR, "short read: %d vs. %d", dat_len, retval);
+ (void) close(fd);
+ cleanexit(5);
+ }
+ if (exit_now) {
+ cleanexit(0);
+ }
+ if ((retval = kadm_ser_in(&dat,&dat_len)) != KADM_SUCCESS)
+ syslog(LOG_ERR, "processing request: %s", error_message(retval));
+
+ /* kadm_ser_in did the processing and returned stuff in
+ dat & dat_len , return the appropriate data */
+
+ out:
+ dlen = (u_short) dat_len;
+
+ if (dat_len != (int)dlen) {
+ clear_secrets();
+ abort(); /* XXX */
+ }
+ dlen = htons(dlen);
+
+ if (krb_net_write(fd, (char *)&dlen, sizeof(u_short)) < 0) {
+ syslog(LOG_ERR, "writing dlen to client: %s", error_message(errno));
+ (void) close(fd);
+ cleanexit(6);
+ }
+
+ if (krb_net_write(fd, (char *)dat, dat_len) < 0) {
+ syslog(LOG_ERR, "writing to client: %s", error_message(errno));
+ (void) close(fd);
+ cleanexit(7);
+ }
+ free((char *)dat);
+ }
+ /*NOTREACHED*/
+}
+
+krb5_sigtype
+do_child(sig)
+ int sig;
+{
+ /* SIGCHLD brings us here */
+ int pid;
+ register int i, j;
+
+#ifdef WAIT_USES_INT
+ int status;
+#else
+ union wait status;
+#endif
+
+ pid = wait(&status);
+
+ for (i = 0; i < pidarraysize; i++)
+ if (pidarray[i] == pid) {
+ /* found it */
+ for (j = i; j < pidarraysize-1; j++)
+ /* copy others down */
+ pidarray[j] = pidarray[j+1];
+ pidarraysize--;
+#ifdef WAIT_USES_INT
+ if (WIFEXITED(status) || WIFSIGNALED(status))
+ if (WTERMSIG(status) || WEXITSTATUS(status))
+ syslog(LOG_ERR, "child %d: termsig %d, retcode %d", pid,
+ WTERMSIG(status), WEXITSTATUS(status));
+
+#else
+ if (status.w_retcode || status.w_coredump || status.w_termsig)
+ syslog(LOG_ERR, "child %d: termsig %d, coredump %d, retcode %d",
+ pid, status.w_termsig, status.w_coredump, status.w_retcode);
+
+#endif
+ SIGNAL_RETURN;
+ }
+ unknown_child = pid;
+#ifdef WAIT_USES_INT
+ syslog(LOG_ERR, "child %d not in list: termsig %d, retcode %d", pid,
+ WTERMSIG(status), WEXITSTATUS(status));
+
+#else
+ syslog(LOG_ERR, "child %d not in list: termsig %d, coredump %d, retcode %d",
+ pid, status.w_termsig, status.w_coredump, status.w_retcode);
+
+#endif
+ SIGNAL_RETURN;
+}
+
+cleanexit(val)
+{
+ krb5_db_fini(kadm_context);
+ clear_secrets();
+ exit(val);
+}
+
+void
+kill_children()
+{
+ register int i;
+#ifdef POSIX_SIGNALS
+ sigset_t oldmask, igmask;
+#else
+ int osigmask;
+#endif
+
+#ifdef POSIX_SIGNALS
+ sigemptyset(&igmask);
+ sigaddset(&igmask, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &igmask, &oldmask);
+#else
+ osigmask = sigblock(sigmask(SIGCHLD));
+#endif
+
+ for (i = 0; i < pidarraysize; i++) {
+ kill(pidarray[i], SIGINT);
+ syslog(LOG_ERR, "killing child %d", pidarray[i]);
+ }
+#ifdef POSIX_SIGNALS
+ sigprocmask(SIG_SETMASK, &oldmask, (sigset_t*)0);
+#else
+ sigsetmask(osigmask);
+#endif
+ return;
+}
+
+#ifdef OVSEC_KADM
+krb5_ui_4 convert_ovsec_to_kadm(val)
+ krb5_ui_4 val;
+{
+ switch (val) {
+ case KADM5_AUTH_GET:
+ case KADM5_AUTH_ADD:
+ case KADM5_AUTH_MODIFY:
+ case KADM5_AUTH_DELETE:
+ case KADM5_AUTH_INSUFFICIENT:
+ case KADM5_AUTH_LIST:
+ case KADM5_AUTH_CHANGEPW:
+ return KADM_UNAUTH;
+ case KADM5_BAD_DB:
+ return KADM_UK_RERROR;
+ case KADM5_DUP:
+ case KADM5_POLICY_REF:
+ return KADM_INUSE;
+ case KADM5_RPC_ERROR:
+ return KADM_NO_CONN;
+ case KADM5_NO_SRV:
+ return KADM_NO_HOST;
+ case KADM5_UNK_PRINC:
+ case KADM5_UNK_POLICY:
+ return KADM_NOENTRY;
+ case KADM5_PASS_Q_TOOSHORT:
+ case KADM5_PASS_Q_CLASS:
+ case KADM5_PASS_Q_DICT:
+ case KADM5_PASS_REUSE:
+ case KADM5_PASS_TOOSOON:
+ case CHPASS_UTIL_PASSWORD_TOO_SOON:
+ return KADM_INSECURE_PW;
+ case KADM5_BAD_PASSWORD:
+ return KADM_NO_CRED;
+ case KADM5_PROTECT_PRINCIPAL:
+ return KADM_NO_OPCODE;
+ case KADM5_NOT_INIT:
+ case KADM5_BAD_HIST_KEY:
+ case KADM5_BAD_MASK:
+ case KADM5_BAD_CLASS:
+ case KADM5_BAD_LENGTH:
+ case KADM5_BAD_POLICY:
+ case KADM5_BAD_PRINCIPAL:
+ case KADM5_BAD_AUX_ATTR:
+ case KADM5_BAD_HISTORY:
+ case KADM5_BAD_MIN_PASS_LIFE:
+ return -1;
+ }
+ return val;
+}
+#endif
diff --git a/src/kadmin/v4server/attic/ChangeLog b/src/kadmin/v4server/attic/ChangeLog
new file mode 100644
index 0000000000..6eefc24c70
--- /dev/null
+++ b/src/kadmin/v4server/attic/ChangeLog
@@ -0,0 +1,25 @@
+Thu Jul 18 19:47:58 1996 Marc Horowitz <marc@mit.edu>
+
+ * configure.in: removed ET_RULES, replaced with AC_PROG_AWK
+
+Thu Aug 4 16:37:33 1994 Tom Yu (tlyu@dragons-lair)
+
+ * admin_server.c: pick up <sys/time.h> (needed to get FD_SET,
+ etc.)
+
+Sat Jul 16 09:21:22 1994 Tom Yu (tlyu at dragons-lair)
+
+ * Makefile.in: no longer trying to install v4kadmind as krb5kdc
+ :-)
+ * configure.in: another try at making dbm libs dtrt
+
+Wed Jun 29 00:24:28 1994 Tom Yu (tlyu at dragons-lair)
+
+ * admin_server.c: fixed calls that should have invoked
+ krb5_init_ets
+
+Sat Jun 25 09:07:48 1994 Tom Yu (tlyu at dragons-lair)
+
+ * kadm_ser_wrap.c: fixed lack of a terminal 0 in a call to
+ krb5_build_principal
+
diff --git a/src/kadmin/v4server/attic/Imakefile b/src/kadmin/v4server/attic/Imakefile
new file mode 100644
index 0000000000..e1449ef32b
--- /dev/null
+++ b/src/kadmin/v4server/attic/Imakefile
@@ -0,0 +1,49 @@
+# $Source$
+# $Author$
+# $Header$
+#
+# Copyright 1989 by the Massachusetts Institute of Technology.
+#
+# For copying and distribution information,
+# please see the file <mit-copyright.h>.
+#
+# Imakefile for Kerberos admin server library.
+
+DEFINES = $(KRB4DEF)
+INCLUDES = $(KRB4INCLUDES) -I.
+SRCS = \
+ kadm_server.c \
+ kadm_funcs.c \
+ admin_server.c \
+ kadm_ser_wrap.c \
+ kadm_stream.c \
+ kadm_supp.c \
+ kadm_err.c \
+ acl_files.c
+OBJS = \
+ kadm_server.o \
+ kadm_funcs.o \
+ admin_server.o \
+ kadm_ser_wrap.o \
+ kadm_stream.o \
+ kadm_supp.o \
+ kadm_err.o \
+ acl_files.o
+
+ErrorTableObjectRule()
+
+all:: v4kadmind
+
+depend:: kadm_err.c
+
+kadm_err.c: kadm_err.et
+
+NormalProgramTarget(v4kadmind,$(OBJS),$(KDBDEPLIB) $(DEPKLIB), \
+ $(KDBLIB) $(KRB4LIB) $(KLIB) ,)
+
+Krb5InstallServerProgram(v4kadmind)
+
+clean::
+ $(RM) kadm_err.c kadm_err.h
+
+DependTarget()
diff --git a/src/kadmin/v4server/attic/Makefile b/src/kadmin/v4server/attic/Makefile
new file mode 100644
index 0000000000..d0acac0219
--- /dev/null
+++ b/src/kadmin/v4server/attic/Makefile
@@ -0,0 +1,39 @@
+TOP = ../..
+include $(TOP)/config.mk/template
+
+ifdef KRB5B4
+CFLAGS += -DKRB5B4 $(D_POSIX_SIGNALS)
+endif
+
+PROG := ovsec_v4adm_server
+
+SRCS := kadm_server.c admin_server.c kadm_ser_wrap.c \
+ kadm_stream.c kadm_supp.c acl_files.c
+
+OBJS := kadm_server.o admin_server.o kadm_ser_wrap.o \
+ kadm_stream.o kadm_supp.o acl_files.o
+
+LIBS := $(LIBADMCLNT) $(LIBRPCLIB) $(LIBGSSAPI_KRB5) $(LIBKRB5) \
+ $(LIBKADM) $(LIBKRB) $(LIBDES425) $(LIBKDB5) \
+ $(LIBCRYPTO) $(LIBISODE) \
+ $(LIBDYN) $(LIBDB) $(LIBCOM_ERR) $(NDBMLIB) $(NETLIB) $(BSDLIB)
+
+ifdef WAIT_USES_INT
+WAIT_FLAGS = -DWAIT_USES_INT
+endif
+ifdef OPEN_NEEDS_FCNTL
+FCNTL_FLAGS = -DNEED_SYS_FCNTL_H
+endif
+
+# XXX the -D's should probably be moved somewhere; in krb5.4.2 they
+# are in osconf.h
+CFLAGS := -DOVSEC_KADM \
+ -DKADM_SYSLOG="\"/krb5/admin_server.syslog\"" \
+ -DDEFAULT_ACL_DIR="\"/krb5\"" $(WAIT_FLAGS) $(FCNTL_FLAGS) \
+ $(CFLAGS)
+
+expand InstallServer
+expand Depend
+
+SUBDIRS = unit-test
+expand SubdirTarget
diff --git a/src/kadmin/v4server/attic/Makefile.in b/src/kadmin/v4server/attic/Makefile.in
new file mode 100644
index 0000000000..f5206aa66f
--- /dev/null
+++ b/src/kadmin/v4server/attic/Makefile.in
@@ -0,0 +1,53 @@
+CFLAGS = $(CCOPTS) $(DEFS) $(LOCALINCLUDE)
+LDFLAGS = -g
+
+ISODELIB=@ISODELIB@
+COMERRLIB=$(BUILDTOP)/util/et/libcom_err.a
+DBMLIB=
+KDBLIB=$(TOPLIBD)/libkdb5.a
+
+KRB4LIB = $(KRB4)/lib/libkrb.a $(TOPLIBD)/libdes425.a
+
+KLIB = $(TOPLIBD)/libkrb5.a $(TOPLIBD)/libcrypto.a $(ISODELIB) $(COMERRLIB) $(DBMLIB)
+
+LOCALINCLUDE=-I$(SRCTOP)/include/kerberosIV -I$(BUILDTOP)/include/kerberosIV -I.
+
+SRCS = \
+ $(srcdir)/kadm_server.c \
+ $(srcdir)/kadm_funcs.c \
+ $(srcdir)/admin_server.c \
+ $(srcdir)/kadm_ser_wrap.c \
+ $(srcdir)/kadm_stream.c \
+ $(srcdir)/kadm_supp.c \
+ $(srcdir)/kadm_err.c \
+ $(srcdir)/acl_files.c
+OBJS = \
+ kadm_server.o \
+ kadm_funcs.o \
+ admin_server.o \
+ kadm_ser_wrap.o \
+ kadm_stream.o \
+ kadm_supp.o \
+ kadm_err.o \
+ acl_files.o
+
+all:: kadm_err.h v4kadmind
+
+depend:: kadm_err.c
+
+kadm_err.c: kadm_err.et
+
+kadm_err.h: kadm_err.et
+
+v4kadmind: $(OBJS) $(KDBDEPLIB) $(DEPKLIB)
+ $(CC) $(CFLAGS) -o v4kadmind $(OBJS) $(KDBLIB) $(KLIB) $(KRB4LIB) $(LIBS) $(KRB4)/lib/libdes.a
+
+install::
+ $(INSTALL_PROGRAM) v4kadmind ${DESTDIR}$(SERVER_BINDIR)/v4kadmind
+
+clean::
+ $(RM) kadm_err.h kadm_err.c
+
+clean::
+ $(RM) v4kadmind
+
diff --git a/src/kadmin/v4server/attic/acl_files.c b/src/kadmin/v4server/attic/acl_files.c
new file mode 100644
index 0000000000..81275ae26f
--- /dev/null
+++ b/src/kadmin/v4server/attic/acl_files.c
@@ -0,0 +1,541 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1987,1989 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ */
+
+#ifndef lint
+static char rcsid_acl_files_c[] = "$Id$";
+#endif lint
+
+
+/*** Routines for manipulating access control list files ***/
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/errno.h>
+#include <ctype.h>
+#ifdef NEED_SYS_FCNTL_H
+#include <sys/fcntl.h>
+#endif
+#include "krb.h"
+#include <krb5/krb5.h>
+
+#ifndef KRB_REALM
+#define KRB_REALM "ATHENA.MIT.EDU"
+#endif
+
+/* "aname.inst@realm" */
+#define MAX_PRINCIPAL_SIZE (ANAME_SZ + INST_SZ + REALM_SZ + 3)
+#define INST_SEP '.'
+#define REALM_SEP '@'
+
+#define LINESIZE 2048 /* Maximum line length in an acl file */
+
+#define NEW_FILE "%s.~NEWACL~" /* Format for name of altered acl file */
+#define WAIT_TIME 300 /* Maximum time allowed write acl file */
+
+#define CACHED_ACLS 8 /* How many acls to cache */
+ /* Each acl costs 1 open file descriptor */
+#define ACL_LEN 16 /* Twice a reasonable acl length */
+
+#define MAX(a,b) (((a)>(b))?(a):(b))
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+#define COR(a,b) ((a!=NULL)?(a):(b))
+
+extern int errno;
+
+extern char *malloc(), *calloc();
+extern time_t time();
+
+static int acl_abort PROTOTYPE((char *acl_file, FILE *f));
+
+/* Canonicalize a principal name */
+/* If instance is missing, it becomes "" */
+/* If realm is missing, it becomes the local realm */
+/* Canonicalized form is put in canon, which must be big enough to hold
+ MAX_PRINCIPAL_SIZE characters */
+acl_canonicalize_principal(principal, canon)
+char *principal;
+char *canon;
+{
+ char *dot, *atsign, *end;
+ int len;
+
+ dot = strchr(principal, INST_SEP);
+ atsign = strchr(principal, REALM_SEP);
+
+ /* Maybe we're done already */
+ if(dot != NULL && atsign != NULL) {
+ if(dot < atsign) {
+ /* It's for real */
+ /* Copy into canon */
+ strncpy(canon, principal, MAX_PRINCIPAL_SIZE);
+ canon[MAX_PRINCIPAL_SIZE-1] = '\0';
+ return;
+ } else {
+ /* Nope, it's part of the realm */
+ dot = NULL;
+ }
+ }
+
+ /* No such luck */
+ end = principal + strlen(principal);
+
+ /* Get the principal name */
+ len = MIN(ANAME_SZ, COR(dot, COR(atsign, end)) - principal);
+ strncpy(canon, principal, len);
+ canon += len;
+
+ /* Add INST_SEP */
+ *canon++ = INST_SEP;
+
+ /* Get the instance, if it exists */
+ if(dot != NULL) {
+ ++dot;
+ len = MIN(INST_SZ, COR(atsign, end) - dot);
+ strncpy(canon, dot, len);
+ canon += len;
+ }
+
+ /* Add REALM_SEP */
+ *canon++ = REALM_SEP;
+
+ /* Get the realm, if it exists */
+ /* Otherwise, default to local realm */
+ if(atsign != NULL) {
+ ++atsign;
+ len = MIN(REALM_SZ, end - atsign);
+ strncpy(canon, atsign, len);
+ canon += len;
+ *canon++ = '\0';
+ } else if(krb_get_lrealm(canon, 1) != KSUCCESS) {
+ strcpy(canon, KRB_REALM);
+ }
+}
+
+/* Get a lock to modify acl_file */
+/* Return new FILE pointer */
+/* or NULL if file cannot be modified */
+/* REQUIRES WRITE PERMISSION TO CONTAINING DIRECTORY */
+static FILE *acl_lock_file(acl_file)
+char *acl_file;
+{
+ struct stat s;
+ char new[LINESIZE];
+ int nfd;
+ FILE *nf;
+ int mode;
+
+ if(stat(acl_file, &s) < 0) return(NULL);
+ mode = s.st_mode;
+ sprintf(new, NEW_FILE, acl_file);
+ for(;;) {
+ /* Open the new file */
+ if((nfd = open(new, O_WRONLY|O_CREAT|O_EXCL, mode)) < 0) {
+ if(errno == EEXIST) {
+ /* Maybe somebody got here already, maybe it's just old */
+ if(stat(new, &s) < 0) return(NULL);
+ if(time(0) - s.st_ctime > WAIT_TIME) {
+ /* File is stale, kill it */
+ unlink(new);
+ continue;
+ } else {
+ /* Wait and try again */
+ sleep(1);
+ continue;
+ }
+ } else {
+ /* Some other error, we lose */
+ return(NULL);
+ }
+ }
+
+ /* If we got to here, the lock file is ours and ok */
+ /* Reopen it under stdio */
+ if((nf = fdopen(nfd, "w")) == NULL) {
+ /* Oops, clean up */
+ unlink(new);
+ }
+ return(nf);
+ }
+}
+
+/* Commit changes to acl_file written onto FILE *f */
+/* Returns zero if successful */
+/* Returns > 0 if lock was broken */
+/* Returns < 0 if some other error occurs */
+/* Closes f */
+static int acl_commit(acl_file, f)
+char *acl_file;
+FILE *f;
+{
+ char new[LINESIZE];
+ int ret;
+ struct stat s;
+
+ sprintf(new, NEW_FILE, acl_file);
+ if(fflush(f) < 0
+ || fstat(fileno(f), &s) < 0
+ || s.st_nlink == 0) {
+ acl_abort(acl_file, f);
+ return(-1);
+ }
+
+ ret = rename(new, acl_file);
+ fclose(f);
+ return(ret);
+}
+
+/* Abort changes to acl_file written onto FILE *f */
+/* Returns 0 if successful, < 0 otherwise */
+/* Closes f */
+static int acl_abort(acl_file, f)
+char *acl_file;
+FILE *f;
+{
+ char new[LINESIZE];
+ int ret;
+ struct stat s;
+
+ /* make sure we aren't nuking someone else's file */
+ if(fstat(fileno(f), &s) < 0
+ || s.st_nlink == 0) {
+ fclose(f);
+ return(-1);
+ } else {
+ sprintf(new, NEW_FILE, acl_file);
+ ret = unlink(new);
+ fclose(f);
+ return(ret);
+ }
+}
+
+/* Initialize an acl_file */
+/* Creates the file with permissions perm if it does not exist */
+/* Erases it if it does */
+/* Returns return value of acl_commit */
+int acl_initialize(acl_file, perm)
+char *acl_file;
+int perm;
+{
+ FILE *new;
+ int fd;
+
+ /* Check if the file exists already */
+ if((new = acl_lock_file(acl_file)) != NULL) {
+ return(acl_commit(acl_file, new));
+ } else {
+ /* File must be readable and writable by owner */
+ if((fd = open(acl_file, O_CREAT|O_EXCL, perm|0600)) < 0) {
+ return(-1);
+ } else {
+ close(fd);
+ return(0);
+ }
+ }
+}
+
+/* Eliminate all whitespace character in buf */
+/* Modifies its argument */
+static nuke_whitespace(buf)
+char *buf;
+{
+ register char *pin, *pout;
+
+ for(pin = pout = buf; *pin != '\0'; pin++)
+ if(!isspace(*pin)) *pout++ = *pin;
+ *pout = '\0'; /* Terminate the string */
+}
+
+/* Hash table stuff */
+
+struct hashtbl {
+ int size; /* Max number of entries */
+ int entries; /* Actual number of entries */
+ char **tbl; /* Pointer to start of table */
+};
+
+/* Make an empty hash table of size s */
+static struct hashtbl *make_hash(size)
+int size;
+{
+ struct hashtbl *h;
+
+ if(size < 1) size = 1;
+ h = (struct hashtbl *) malloc(sizeof(struct hashtbl));
+ h->size = size;
+ h->entries = 0;
+ h->tbl = (char **) calloc(size, sizeof(char *));
+ return(h);
+}
+
+/* Destroy a hash table */
+static destroy_hash(h)
+struct hashtbl *h;
+{
+ int i;
+
+ for(i = 0; i < h->size; i++) {
+ if(h->tbl[i] != NULL) free(h->tbl[i]);
+ }
+ free(h->tbl);
+ free(h);
+}
+
+/* Compute hash value for a string */
+static unsigned hashval(s)
+register char *s;
+{
+ register unsigned hv;
+
+ for(hv = 0; *s != '\0'; s++) {
+ hv ^= ((hv << 3) ^ *s);
+ }
+ return(hv);
+}
+
+/* Add an element to a hash table */
+static add_hash(h, el)
+struct hashtbl *h;
+char *el;
+{
+ unsigned hv;
+ char *s;
+ char **old;
+ int i;
+
+ /* Make space if it isn't there already */
+ if(h->entries + 1 > (h->size >> 1)) {
+ old = h->tbl;
+ h->tbl = (char **) calloc(h->size << 1, sizeof(char *));
+ for(i = 0; i < h->size; i++) {
+ if(old[i] != NULL) {
+ hv = hashval(old[i]) % (h->size << 1);
+ while(h->tbl[hv] != NULL) hv = (hv+1) % (h->size << 1);
+ h->tbl[hv] = old[i];
+ }
+ }
+ h->size = h->size << 1;
+ free(old);
+ }
+
+ hv = hashval(el) % h->size;
+ while(h->tbl[hv] != NULL && strcmp(h->tbl[hv], el)) hv = (hv+1) % h->size;
+ s = malloc(strlen(el)+1);
+ strcpy(s, el);
+ h->tbl[hv] = s;
+ h->entries++;
+}
+
+/* Returns nonzero if el is in h */
+static check_hash(h, el)
+struct hashtbl *h;
+char *el;
+{
+ unsigned hv;
+
+ for(hv = hashval(el) % h->size;
+ h->tbl[hv] != NULL;
+ hv = (hv + 1) % h->size) {
+ if(!strcmp(h->tbl[hv], el)) return(1);
+ }
+ return(0);
+}
+
+struct acl {
+ char filename[LINESIZE]; /* Name of acl file */
+ int fd; /* File descriptor for acl file */
+ struct stat status; /* File status at last read */
+ struct hashtbl *acl; /* Acl entries */
+};
+
+static struct acl acl_cache[CACHED_ACLS];
+
+static int acl_cache_count = 0;
+static int acl_cache_next = 0;
+
+/* Returns < 0 if unsuccessful in loading acl */
+/* Returns index into acl_cache otherwise */
+/* Note that if acl is already loaded, this is just a lookup */
+static int acl_load(name)
+char *name;
+{
+ int i;
+ FILE *f;
+ struct stat s;
+ char buf[MAX_PRINCIPAL_SIZE];
+ char canon[MAX_PRINCIPAL_SIZE];
+
+ /* See if it's there already */
+ for(i = 0; i < acl_cache_count; i++) {
+ if(!strcmp(acl_cache[i].filename, name)
+ && acl_cache[i].fd >= 0) goto got_it;
+ }
+
+ /* It isn't, load it in */
+ /* maybe there's still room */
+ if(acl_cache_count < CACHED_ACLS) {
+ i = acl_cache_count++;
+ } else {
+ /* No room, clean one out */
+ i = acl_cache_next;
+ acl_cache_next = (acl_cache_next + 1) % CACHED_ACLS;
+ close(acl_cache[i].fd);
+ if(acl_cache[i].acl) {
+ destroy_hash(acl_cache[i].acl);
+ acl_cache[i].acl = (struct hashtbl *) 0;
+ }
+ }
+
+ /* Set up the acl */
+ strcpy(acl_cache[i].filename, name);
+ if((acl_cache[i].fd = open(name, O_RDONLY, 0)) < 0) return(-1);
+ /* Force reload */
+ acl_cache[i].acl = (struct hashtbl *) 0;
+
+ got_it:
+ /*
+ * See if the stat matches
+ *
+ * Use stat(), not fstat(), as the file may have been re-created by
+ * acl_add or acl_delete. If this happens, the old inode will have
+ * no changes in the mod-time and the following test will fail.
+ */
+ if(stat(acl_cache[i].filename, &s) < 0) return(-1);
+ if(acl_cache[i].acl == (struct hashtbl *) 0
+ || s.st_nlink != acl_cache[i].status.st_nlink
+ || s.st_mtime != acl_cache[i].status.st_mtime
+ || s.st_ctime != acl_cache[i].status.st_ctime) {
+ /* Gotta reload */
+ if(acl_cache[i].fd >= 0) close(acl_cache[i].fd);
+ if((acl_cache[i].fd = open(name, O_RDONLY, 0)) < 0) return(-1);
+ if((f = fdopen(acl_cache[i].fd, "r")) == NULL) return(-1);
+ if(acl_cache[i].acl) destroy_hash(acl_cache[i].acl);
+ acl_cache[i].acl = make_hash(ACL_LEN);
+ while(fgets(buf, sizeof(buf), f) != NULL) {
+ nuke_whitespace(buf);
+ acl_canonicalize_principal(buf, canon);
+ add_hash(acl_cache[i].acl, canon);
+ }
+ fclose(f);
+ acl_cache[i].status = s;
+ }
+ return(i);
+}
+
+/* Returns nonzero if it can be determined that acl contains principal */
+/* Principal is not canonicalized, and no wildcarding is done */
+acl_exact_match(acl, principal)
+char *acl;
+char *principal;
+{
+ int idx;
+
+ return((idx = acl_load(acl)) >= 0
+ && check_hash(acl_cache[idx].acl, principal));
+}
+
+/* Returns nonzero if it can be determined that acl contains principal */
+/* Recognizes wildcards in acl of the form
+ name.*@realm, *.*@realm, and *.*@* */
+acl_check(acl, principal)
+char *acl;
+char *principal;
+{
+ char buf[MAX_PRINCIPAL_SIZE];
+ char canon[MAX_PRINCIPAL_SIZE];
+ char *realm, *tmp;
+
+ acl_canonicalize_principal(principal, canon);
+
+ /* Is it there? */
+ if(acl_exact_match(acl, canon)) return(1);
+
+ /* Try the wildcards */
+ realm = strchr(canon, REALM_SEP);
+ tmp = strchr(canon, INST_SEP);
+ *tmp = '\0'; /* Chuck the instance */
+
+ sprintf(buf, "%s.*%s", canon, realm);
+ if(acl_exact_match(acl, buf)) return(1);
+
+ sprintf(buf, "*.*%s", realm);
+ if(acl_exact_match(acl, buf) || acl_exact_match(acl, "*.*@*")) return(1);
+
+ return(0);
+}
+
+/* Adds principal to acl */
+/* Wildcards are interpreted literally */
+acl_add(acl, principal)
+char *acl;
+char *principal;
+{
+ int idx;
+ int i;
+ FILE *new;
+ char canon[MAX_PRINCIPAL_SIZE];
+
+ acl_canonicalize_principal(principal, canon);
+
+ if((new = acl_lock_file(acl)) == NULL) return(-1);
+ if((acl_exact_match(acl, canon))
+ || (idx = acl_load(acl)) < 0) {
+ acl_abort(acl, new);
+ return(-1);
+ }
+ /* It isn't there yet, copy the file and put it in */
+ for(i = 0; i < acl_cache[idx].acl->size; i++) {
+ if(acl_cache[idx].acl->tbl[i] != NULL) {
+ if((fputs(acl_cache[idx].acl->tbl[i], new) == EOF)
+ || (putc('\n', new) != '\n')) {
+ acl_abort(acl, new);
+ return(-1);
+ }
+ }
+ }
+ fputs(canon, new);
+ putc('\n', new);
+ return(acl_commit(acl, new));
+}
+
+/* Removes principal from acl */
+/* Wildcards are interpreted literally */
+acl_delete(acl, principal)
+char *acl;
+char *principal;
+{
+ int idx;
+ int i;
+ FILE *new;
+ char canon[MAX_PRINCIPAL_SIZE];
+
+ acl_canonicalize_principal(principal, canon);
+
+ if((new = acl_lock_file(acl)) == NULL) return(-1);
+ if((!acl_exact_match(acl, canon))
+ || (idx = acl_load(acl)) < 0) {
+ acl_abort(acl, new);
+ return(-1);
+ }
+ /* It isn't there yet, copy the file and put it in */
+ for(i = 0; i < acl_cache[idx].acl->size; i++) {
+ if(acl_cache[idx].acl->tbl[i] != NULL
+ && strcmp(acl_cache[idx].acl->tbl[i], canon)) {
+ fputs(acl_cache[idx].acl->tbl[i], new);
+ putc('\n', new);
+ }
+ }
+ return(acl_commit(acl, new));
+}
+
diff --git a/src/kadmin/v4server/attic/acl_files.doc b/src/kadmin/v4server/attic/acl_files.doc
new file mode 100644
index 0000000000..78c448a6d6
--- /dev/null
+++ b/src/kadmin/v4server/attic/acl_files.doc
@@ -0,0 +1,107 @@
+PROTOTYPE ACL LIBRARY
+
+Introduction
+
+An access control list (ACL) is a list of principals, where each
+principal is is represented by a text string which cannot contain
+whitespace. The library allows application programs to refer to named
+access control lists to test membership and to atomically add and
+delete principals using a natural and intuitive interface. At
+present, the names of access control lists are required to be Unix
+filenames, and refer to human-readable Unix files; in the future, when
+a networked ACL server is implemented, the names may refer to a
+different namespace specific to the ACL service.
+
+
+Usage
+
+cc <files> -lacl -lkrb.
+
+
+
+Principal Names
+
+Principal names have the form
+
+<name>[.<instance>][@<realm>]
+
+e.g.
+
+asp
+asp.root
+asp@ATHENA.MIT.EDU
+asp.@ATHENA.MIT.EDU
+asp.root@ATHENA.MIT.EDU
+
+It is possible for principals to be underspecified. If instance is
+missing, it is assumed to be "". If realm is missing, it is assumed
+to be local_realm. The canonical form contains all of name, instance,
+and realm; the acl_add and acl_delete routines will always
+leave the file in that form. Note that the canonical form of
+asp@ATHENA.MIT.EDU is actually asp.@ATHENA.MIT.EDU.
+
+
+Routines
+
+acl_canonicalize_principal(principal, buf)
+char *principal;
+char *buf; /*RETVAL*/
+
+Store the canonical form of principal in buf. Buf must contain enough
+space to store a principal, given the limits on the sizes of name,
+instance, and realm specified in /usr/include/krb.h.
+
+acl_check(acl, principal)
+char *acl;
+char *principal;
+
+Returns nonzero if principal appears in acl. Returns 0 if principal
+does not appear in acl, or if an error occurs. Canonicalizes
+principal before checking, and allows the ACL to contain wildcards.
+
+acl_exact_match(acl, principal)
+char *acl;
+char *principal;
+
+Like acl_check, but does no canonicalization or wildcarding.
+
+acl_add(acl, principal)
+char *acl;
+char *principal;
+
+Atomically adds principal to acl. Returns 0 if successful, nonzero
+otherwise. It is considered a failure if principal is already in acl.
+This routine will canonicalize principal, but will treat wildcards
+literally.
+
+acl_delete(acl, principal)
+char *acl;
+char *principal;
+
+Atomically deletes principal from acl. Returns 0 if successful,
+nonzero otherwise. It is consider a failure if principal is not
+already in acl. This routine will canonicalize principal, but will
+treat wildcards literally.
+
+acl_initialize(acl, mode)
+char *acl;
+int mode;
+
+Initialize acl. If acl file does not exist, creates it with mode
+mode. If acl exists, removes all members. Returns 0 if successful,
+nonzero otherwise. WARNING: Mode argument is likely to change with
+the eventual introduction of an ACL service.
+
+
+Known problems
+
+In the presence of concurrency, there is a very small chance that
+acl_add or acl_delete could report success even though it would have
+had no effect. This is a necessary side effect of using lock files
+for concurrency control rather than flock(2), which is not supported
+by NFS.
+
+The current implementation caches ACLs in memory in a hash-table
+format for increased efficiency in checking membership; one effect of
+the caching scheme is that one file descriptor will be kept open for
+each ACL cached, up to a maximum of 8.
diff --git a/src/kadmin/v4server/attic/aclocal.m4 b/src/kadmin/v4server/attic/aclocal.m4
new file mode 100644
index 0000000000..70bf66a7d6
--- /dev/null
+++ b/src/kadmin/v4server/attic/aclocal.m4
@@ -0,0 +1,3 @@
+sinclude([./../../aclocal.m4])dnl
+undefine([AC_BUILDTOP])dnl
+define(AC_BUILDTOP,[./../..])dnl
diff --git a/src/kadmin/v4server/attic/admin_server.c b/src/kadmin/v4server/attic/admin_server.c
new file mode 100644
index 0000000000..04155bca17
--- /dev/null
+++ b/src/kadmin/v4server/attic/admin_server.c
@@ -0,0 +1,668 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * Top-level loop of the kerberos Administration server
+ */
+
+#include <mit-copyright.h>
+
+/*
+ admin_server.c
+ this holds the main loop and initialization and cleanup code for the server
+*/
+
+#ifdef _AIX
+#include <sys/select.h>
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <string.h>
+
+#ifndef POSIX_SIGNALS
+#ifndef sigmask
+#define sigmask(m) (1 <<((m)-1))
+#endif
+#endif /* POSIX_SIGNALS */
+#ifdef _AIX
+#include <sys/resource.h>
+#endif /* _AIX */
+#include <sys/wait.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <syslog.h>
+
+#include <krb5/krb5.h>
+#include <krb5/kdb.h>
+#include <krb5/kdb_dbm.h>
+#include <krb5/los-proto.h>
+#include <krb5/config.h>
+
+#ifdef OVSEC_KADM
+#include <ovsec_admin/admin.h>
+void *ovsec_handle;
+#endif
+
+#include <kadm.h>
+#include <kadm_err.h>
+#include <krb_db.h>
+#include "kadm_server.h"
+
+/* Almost all procs and such need this, so it is global */
+admin_params prm; /* The command line parameters struct */
+
+char prog[32]; /* WHY IS THIS NEEDED??????? */
+char *progname = prog;
+char *acldir = DEFAULT_ACL_DIR;
+char krbrlm[REALM_SZ];
+extern Kadm_Server server_parm;
+int des_debug; /* used by the des425 libraries */
+int debug = 0;
+
+/*
+** Main does the logical thing, it sets up the database and RPC interface,
+** as well as handling the creation and maintenance of the syslog file...
+*/
+main(argc, argv) /* admin_server main routine */
+int argc;
+char *argv[];
+{
+ int errval;
+ int c;
+ char *db_name, *lrealm;
+ extern char *optarg;
+ extern int fascist_cpw;
+
+ krb5_init_ets();
+ initialize_kadm_error_table();
+ prog[sizeof(prog)-1]='\0'; /* Terminate... */
+ (void) strncpy(prog, argv[0], sizeof(prog)-1);
+
+ /* initialize the admin_params structure */
+ prm.sysfile = KADM_SYSLOG; /* default file name */
+ prm.inter = 1;
+
+ memset(krbrlm, 0, sizeof(krbrlm));
+
+ fascist_cpw = 1; /* by default, enable fascist mode */
+ while ((c = getopt(argc, argv, "f:hnd:Da:r:FN")) != EOF)
+ switch(c) {
+ case 'd':
+ if (errval = krb5_db_set_name(optarg)) {
+ com_err(argv[0], errval, "while setting dbname");
+ exit(1);
+ }
+ break;
+ case 'D':
+ debug++;
+ break;
+#ifndef OVSEC_KADM
+ case 'f': /* Syslog file name change */
+ prm.sysfile = optarg;
+ break;
+ case 'F':
+ fascist_cpw++;
+ break;
+ case 'N':
+ fascist_cpw = 0;
+ break;
+#endif
+ case 'n':
+ prm.inter = 0;
+ break;
+ case 'a': /* new acl directory */
+ acldir = optarg;
+ break;
+ case 'r':
+ (void) strncpy(krbrlm, optarg, sizeof(krbrlm) - 1);
+ break;
+ case 'h': /* get help on using admin_server */
+ default:
+#ifdef OVSEC_KADM
+ fprintf(stderr, "Usage: ovsec_v4adm_server [-D] [-h] [-n] [-r realm] [-d dbname] [-a acldir]\n");
+
+#else
+ printf("Usage: admin_server [-D] [-h] [-n] [-F] [-N] [-r realm] [-d dbname] [-f filename] [-a acldir]\n");
+#endif
+ exit(-1); /* failure */
+ }
+
+ if (krbrlm[0] == 0) {
+ if (errval = krb5_get_default_realm(&lrealm)) {
+ com_err(argv[0], errval, "while attempting to get local realm");
+ exit(1);
+ }
+ (void) strncpy(krbrlm, lrealm, sizeof(krbrlm) - 1);
+ }
+ printf("KADM Server %s initializing\n",KADM_VERSTR);
+ printf("Please do not use 'kill -9' to kill this job, use a\n");
+ printf("regular kill instead\n\n");
+
+#ifdef OVSEC_KADM
+ printf("KADM Server starting in the OVSEC_KADM mode (%sprocess id %d).\n",
+ debug ? "" : "parent ", getpid());
+#else
+ printf("KADM Server starting in %s mode for the purposes for password changing\n\n", fascist_cpw ? "fascist" : "NON-FASCIST");
+#endif
+
+ open_syslog(argv[0], "V4 admin server (parent) starting");
+
+ errval = krb5_db_init(); /* Open the Kerberos database */
+ if (errval) {
+ fprintf(stderr, "error: krb5_db_init() failed");
+ close_syslog();
+ byebye();
+ exit(1);
+ }
+ if (errval = krb5_db_set_lockmode(TRUE)) {
+ com_err(argv[0], errval, "while setting db to nonblocking");
+ close_syslog();
+ byebye();
+ exit(1);
+ }
+
+ /* set up the server_parm struct */
+ if ((errval = kadm_ser_init(prm.inter, krbrlm)) != KADM_SUCCESS) {
+ fprintf(stderr, "error initializing: %s\n", error_message(errval));
+ krb5_db_fini();
+ close_syslog();
+ byebye();
+ exit(1);
+ }
+
+ /* detach from the terminal */
+ if (!debug) {
+ if (
+#ifdef KRB5B4
+ daemon(0, 0)
+#else
+ errval = krb5_detach_process()
+#endif
+ ) {
+#ifdef KRB5B4
+ errval = errno;
+#endif
+ fprintf(stderr, "error detaching from terminal: %s\n",
+ error_message(errval));
+ syslog(LOG_ERR, "error detaching from terminal: %s",
+ error_message(errval));
+ krb5_db_fini();
+ close_syslog();
+ byebye();
+ exit(1);
+ }
+ open_syslog(argv[0], "V4 admin server (child) starting");
+ }
+
+ krb5_db_fini();
+
+ if (errval = kadm_listen()) {
+ fprintf(stderr, "error while listening for requests: %s\n",
+ error_message(errval));
+ syslog(LOG_ERR, "error while listening for requests: %s",
+ error_message(errval));
+ krb5_db_fini();
+ close_syslog();
+ byebye();
+ exit(1);
+ }
+
+ close_syslog();
+ byebye();
+ exit(0);
+} /* procedure main */
+
+
+/* open the system log file */
+open_syslog(whoami, message)
+ char *whoami, *message;
+{
+ static int opened = 0;
+
+ if (opened) {
+ closelog();
+ }
+ openlog(whoami, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_LOCAL6); /* XXX */
+ syslog(LOG_INFO, message);
+ opened++;
+}
+
+/* close the system log file */
+close_syslog()
+{
+ syslog(LOG_INFO, "Shutting down V4 admin server");
+}
+
+byebye() /* say goodnight gracie */
+{
+ printf("Admin Server (kadm server) has completed operation.\n");
+}
+
+static clear_secrets()
+{
+ krb5_finish_key(&server_parm.master_encblock);
+ memset((char *)&server_parm.master_encblock, 0,
+ sizeof (server_parm.master_encblock));
+ memset((char *)server_parm.master_keyblock.contents, 0,
+ server_parm.master_keyblock.length);
+ server_parm.mkvno = 0L;
+ return;
+}
+
+static exit_now = 0;
+
+krb5_sigtype doexit()
+{
+ exit_now = 1;
+}
+
+unsigned pidarraysize = 0;
+int *pidarray = (int *)0;
+int unknown_child = 0;
+
+/*
+kadm_listen
+listen on the admin servers port for a request
+*/
+kadm_listen()
+{
+ extern int errno;
+ int found;
+ int admin_fd;
+ int peer_fd;
+ fd_set mask, readfds;
+ struct sockaddr_in peer;
+ int addrlen;
+ void process_client(), kill_children();
+ int pid;
+ krb5_sigtype do_child();
+
+ (void) signal(SIGINT, doexit);
+ (void) signal(SIGTERM, doexit);
+ (void) signal(SIGHUP, doexit);
+ (void) signal(SIGQUIT, doexit);
+ (void) signal(SIGPIPE, SIG_IGN); /* get errors on write() */
+ (void) signal(SIGALRM, doexit);
+ (void) signal(SIGCHLD, do_child);
+
+ if ((admin_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+ return KADM_NO_SOCK;
+ if (bind(admin_fd, (struct sockaddr *)&server_parm.admin_addr,
+ sizeof(struct sockaddr_in)) < 0)
+ return KADM_NO_BIND;
+ (void) listen(admin_fd, 1);
+ FD_ZERO(&mask);
+ FD_SET(admin_fd, &mask);
+
+ for (;;) { /* loop nearly forever */
+ if (exit_now) {
+ clear_secrets();
+ kill_children();
+ return(0);
+ }
+ readfds = mask;
+ if ((found = select(admin_fd+1,&readfds,(fd_set *)0,
+ (fd_set *)0, (struct timeval *)0)) == 0)
+ continue; /* no things read */
+ if (found < 0) {
+ if (errno != EINTR)
+ syslog(LOG_ERR, "select: %s", error_message(errno));
+ continue;
+ }
+ if (FD_ISSET(admin_fd, &readfds)) {
+ /* accept the conn */
+ addrlen = sizeof(peer);
+ if ((peer_fd = accept(admin_fd, (struct sockaddr *)&peer,
+ &addrlen)) < 0) {
+ syslog(LOG_ERR, "accept: %s", error_message(errno));
+ continue;
+ }
+
+ if (debug) {
+ process_client(peer_fd, &peer);
+ } else if (pid = fork()) {
+ /* parent */
+ if (pid < 0) {
+ syslog(LOG_ERR, "fork: %s", error_message(errno));
+ (void) close(peer_fd);
+ continue;
+ }
+ /* fork succeeded: keep tabs on child */
+ (void) close(peer_fd);
+ if (unknown_child != pid) {
+ if (pidarray) {
+ pidarray = (int *)realloc((char *)pidarray,
+ (++pidarraysize * sizeof(int)));
+ pidarray[pidarraysize-1] = pid;
+ } else {
+ pidarray = (int *)malloc((pidarraysize = 1) *
+ sizeof(int));
+ pidarray[0] = pid;
+ }
+ } /* End if unknown_child != pid.*/
+ } else {
+ /* child */
+ (void) close(admin_fd);
+ process_client(peer_fd, &peer);
+ }
+ } else {
+ syslog(LOG_ERR, "something else woke me up!");
+ return(0);
+ }
+ }
+ /*NOTREACHED*/
+}
+
+void process_client(fd, who)
+ int fd;
+ struct sockaddr_in *who;
+{
+ u_char *dat;
+ int dat_len;
+ u_short dlen;
+ int retval;
+ int on = 1;
+ Principal service;
+ des_cblock skey;
+ int nentries = 1;
+ krb5_db_entry sprinc_entries;
+ krb5_boolean more;
+ krb5_keyblock cpw_skey;
+ int status;
+
+#ifdef OVSEC_KADM
+#define OVSEC_KADM_SRVTAB "FILE:/krb5/ovsec_adm.srvtab"
+ char *service_name;
+
+ service_name = (char *) malloc(strlen(server_parm.sname) +
+ strlen(server_parm.sinst) +
+ strlen(server_parm.krbrlm) + 3);
+ if (service_name == NULL) {
+ syslog(LOG_ERR, "error: out of memory allocating service name");
+ }
+ sprintf(service_name, "%s/%s@%s", server_parm.sname,
+ server_parm.sinst, server_parm.krbrlm);
+
+ retval = ovsec_kadm_init_with_skey(service_name,
+ OVSEC_KADM_SRVTAB,
+ OVSEC_KADM_ADMIN_SERVICE, krbrlm,
+ OVSEC_KADM_STRUCT_VERSION,
+ OVSEC_KADM_API_VERSION_1,
+ &ovsec_handle);
+ if (retval) {
+ syslog(LOG_ERR, "error: ovsec_kadm_init failed: %s",
+ error_message(retval));
+ cleanexit(1);
+ }
+ free(service_name);
+
+#endif
+
+#if !defined(NOENCRYPTION)
+ /* Must do it here, since this is after the fork() call. */
+ des_init_random_number_generator(server_parm.master_keyblock.contents);
+#endif
+
+ if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on)) < 0)
+ syslog(LOG_ERR, "setsockopt keepalive: %d", errno);
+
+ server_parm.recv_addr = *who;
+
+ if (krb5_db_init()) { /* Open as client */
+ syslog(LOG_ERR, "can't open krb db");
+ cleanexit(1);
+ }
+
+ /* need to set service key to changepw.KRB_MASTER */
+
+ status = krb5_db_get_principal(server_parm.sprinc,
+ &sprinc_entries,
+ &nentries, &more);
+ /* ugh... clean this up later */
+ if (status == KRB5_KDB_DB_INUSE) {
+ /* db locked */
+ krb5_ui_4 retcode = KADM_DB_INUSE;
+ char *pdat;
+
+ dat_len = KADM_VERSIZE + sizeof(u_int);
+ dat = (u_char *) malloc((unsigned)dat_len);
+ pdat = (char *) dat;
+ /* This must be 32 bit integer due to the htonl */
+ retcode = htonl((krb5_ui_4) KADM_DB_INUSE);
+ (void) strncpy(pdat, KADM_ULOSE, KADM_VERSIZE);
+ memcpy(&pdat[KADM_VERSIZE], (char *)&retcode, sizeof(krb5_ui_4));
+ goto out;
+ } else if (!nentries) {
+ syslog(LOG_ERR, "no service %s.%s", server_parm.sname, server_parm.sinst);
+ cleanexit(2);
+ } else if (status) {
+ syslog(LOG_ERR, error_message(status));
+ cleanexit(2);
+ }
+
+ status = krb5_kdb_decrypt_key(&server_parm.master_encblock,
+ &sprinc_entries.key,
+ &cpw_skey);
+ if (status) {
+ syslog(LOG_ERR, "decrypt_key failed: %s", error_message(status));
+ cleanexit(1);
+ }
+ /* if error, will show up when rd_req fails */
+ (void) krb_set_key((char *)cpw_skey.contents, 0);
+#ifdef KRB5_FREE_KEYBLOCK_CONTENTS_EXISTS
+ krb5_free_keyblock_contents(&cpw_skey);
+#else
+ memset((char*)cpw_skey.contents, 0, cpw_skey.length);
+ free(cpw_skey.contents);
+#endif
+
+ krb5_dbm_db_free_principal(&sprinc_entries, nentries);
+
+ while (1) {
+ if ((retval = krb_net_read(fd, (char *)&dlen, sizeof(u_short))) !=
+ sizeof(u_short)) {
+ if (retval < 0)
+ syslog(LOG_ERR, "dlen read: %s", error_message(errno));
+ else if (retval)
+ syslog(LOG_ERR, "short dlen read: %d", retval);
+ (void) close(fd);
+#ifdef OVSEC_KADM
+ (void) ovsec_kadm_destroy(ovsec_handle);
+#endif
+ if (debug)
+ return;
+ else
+ cleanexit(retval ? 3 : 0);
+ }
+ if (exit_now) {
+ cleanexit(0);
+ }
+ dat_len = (int) ntohs(dlen);
+ dat = (u_char *) malloc((unsigned)dat_len);
+ if (!dat) {
+ syslog(LOG_ERR, "malloc: No memory");
+ (void) close(fd);
+ cleanexit(4);
+ }
+ if ((retval = krb_net_read(fd, (char *)dat, dat_len)) != dat_len) {
+ if (retval < 0)
+ syslog(LOG_ERR, "data read: %s", error_message(errno));
+ else
+ syslog(LOG_ERR, "short read: %d vs. %d", dat_len, retval);
+ (void) close(fd);
+ cleanexit(5);
+ }
+ if (exit_now) {
+ cleanexit(0);
+ }
+ if ((retval = kadm_ser_in(&dat,&dat_len)) != KADM_SUCCESS)
+ syslog(LOG_ERR, "processing request: %s", error_message(retval));
+
+ /* kadm_ser_in did the processing and returned stuff in
+ dat & dat_len , return the appropriate data */
+
+ out:
+ dlen = (u_short) dat_len;
+
+ if (dat_len != (int)dlen) {
+ clear_secrets();
+ abort(); /* XXX */
+ }
+ dlen = htons(dlen);
+
+ if (krb_net_write(fd, (char *)&dlen, sizeof(u_short)) < 0) {
+ syslog(LOG_ERR, "writing dlen to client: %s", error_message(errno));
+ (void) close(fd);
+ cleanexit(6);
+ }
+
+ if (krb_net_write(fd, (char *)dat, dat_len) < 0) {
+ syslog(LOG_ERR, "writing to client: %s", error_message(errno));
+ (void) close(fd);
+ cleanexit(7);
+ }
+ free((char *)dat);
+ }
+ /*NOTREACHED*/
+}
+
+krb5_sigtype do_child()
+{
+ /* SIGCHLD brings us here */
+ int pid;
+ register int i, j;
+
+#ifdef WAIT_USES_INT
+ int status;
+#else
+ union wait status;
+#endif
+
+ pid = wait(&status);
+
+ for (i = 0; i < pidarraysize; i++)
+ if (pidarray[i] == pid) {
+ /* found it */
+ for (j = i; j < pidarraysize-1; j++)
+ /* copy others down */
+ pidarray[j] = pidarray[j+1];
+ pidarraysize--;
+#ifdef WAIT_USES_INT
+ if (WIFEXITED(status) || WIFSIGNALED(status))
+ syslog(LOG_ERR, "child %d: termsig %d, retcode %d", pid,
+ WTERMSIG(status), WEXITSTATUS(status));
+
+#else
+ if (status.w_retcode || status.w_coredump || status.w_termsig)
+ syslog(LOG_ERR, "child %d: termsig %d, coredump %d, retcode %d",
+ pid, status.w_termsig, status.w_coredump, status.w_retcode);
+
+#endif
+ goto done; /* use goto to avoid figuring out whether to
+ return a value */
+ }
+ unknown_child = pid;
+#ifdef WAIT_USES_INT
+ syslog(LOG_ERR, "child %d not in list: termsig %d, retcode %d", pid,
+ WTERMSIG(status), WEXITSTATUS(status));
+#else
+ syslog(LOG_ERR, "child %d not in list: termsig %d, coredump %d, retcode %d",
+ pid, status.w_termsig, status.w_coredump, status.w_retcode);
+#endif
+
+ done:
+}
+
+cleanexit(val)
+{
+ krb5_db_fini();
+ clear_secrets();
+ exit(val);
+}
+
+void kill_children()
+{
+ register int i;
+#ifdef POSIX_SIGNALS
+ sigset_t oldmask, igmask;
+#else
+ int osigmask;
+#endif
+
+#ifdef POSIX_SIGNALS
+ sigemptyset(&igmask);
+ sigaddset(&igmask, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &igmask, &oldmask);
+#else
+ osigmask = sigblock(sigmask(SIGCHLD));
+#endif
+
+ for (i = 0; i < pidarraysize; i++) {
+ kill(pidarray[i], SIGINT);
+ syslog(LOG_ERR, "killing child %d", pidarray[i]);
+ }
+#ifdef POSIX_SIGNALS
+ sigprocmask(SIG_SETMASK, &oldmask, (sigset_t*)0);
+#else
+ sigsetmask(osigmask);
+#endif
+ return;
+}
+
+#ifdef OVSEC_KADM
+krb5_ui_4 convert_ovsec_to_kadm(val)
+ krb5_ui_4 val;
+{
+ switch (val) {
+ case OVSEC_KADM_AUTH_GET:
+ case OVSEC_KADM_AUTH_ADD:
+ case OVSEC_KADM_AUTH_MODIFY:
+ case OVSEC_KADM_AUTH_DELETE:
+ case OVSEC_KADM_AUTH_INSUFFICIENT:
+ return KADM_UNAUTH;
+ case OVSEC_KADM_BAD_DB:
+ return KADM_UK_RERROR;
+ case OVSEC_KADM_DUP:
+ case OVSEC_KADM_POLICY_REF:
+ return KADM_INUSE;
+ case OVSEC_KADM_RPC_ERROR:
+ return KADM_NO_CONN;
+ case OVSEC_KADM_NO_SRV:
+ return KADM_NO_HOST;
+ case OVSEC_KADM_UNK_PRINC:
+ case OVSEC_KADM_UNK_POLICY:
+ return KADM_NOENTRY;
+ case OVSEC_KADM_PASS_Q_TOOSHORT:
+ case OVSEC_KADM_PASS_Q_CLASS:
+ case OVSEC_KADM_PASS_Q_DICT:
+ case OVSEC_KADM_PASS_REUSE:
+ case OVSEC_KADM_PASS_TOOSOON:
+ case CHPASS_UTIL_PASSWORD_TOO_SOON:
+ return KADM_INSECURE_PW;
+ case OVSEC_KADM_BAD_PASSWORD:
+ return KADM_NO_CRED;
+ case OVSEC_KADM_PROTECT_PRINCIPAL:
+ return KADM_NO_OPCODE;
+ case OVSEC_KADM_NOT_INIT:
+ case OVSEC_KADM_BAD_HIST_KEY:
+ case OVSEC_KADM_BAD_MASK:
+ case OVSEC_KADM_BAD_CLASS:
+ case OVSEC_KADM_BAD_LENGTH:
+ case OVSEC_KADM_BAD_POLICY:
+ case OVSEC_KADM_BAD_PRINCIPAL:
+ case OVSEC_KADM_BAD_AUX_ATTR:
+ case OVSEC_KADM_BAD_HISTORY:
+ case OVSEC_KADM_BAD_MIN_PASS_LIFE:
+ return -1;
+ }
+ return val;
+}
+#endif
diff --git a/src/kadmin/v4server/attic/configure.in b/src/kadmin/v4server/attic/configure.in
new file mode 100644
index 0000000000..f09ba3a28c
--- /dev/null
+++ b/src/kadmin/v4server/attic/configure.in
@@ -0,0 +1,22 @@
+AC_INIT(admin_server.c)
+WITH_CCOPTS
+CONFIG_RULES
+AC_SET_BUILDTOP
+AC_PROG_INSTALL
+AC_HAVE_LIBRARY(socket)
+AC_HAVE_LIBRARY(nsl)
+AC_HAVE_LIBRARY(-lndbm)
+AC_HAVE_LIBRARY(-ldbm)
+CHECK_WAIT_TYPE
+CHECK_FCNTL
+AC_FUNC_CHECK(sigprocmask,
+AC_COMPILE_CHECK([sigset_t],
+[#include <signal.h>],
+[sigset_t x],
+AC_DEFINE(POSIX_SIGNALS)))
+AC_PROG_AWK
+KRB_INCLUDE
+ISODE_INCLUDE
+WITH_KRB4
+WITH_KRB5ROOT
+AC_OUTPUT(Makefile,[EXTRA_RULES])
diff --git a/src/kadmin/v4server/attic/kadm_err.et b/src/kadmin/v4server/attic/kadm_err.et
new file mode 100644
index 0000000000..a192730833
--- /dev/null
+++ b/src/kadmin/v4server/attic/kadm_err.et
@@ -0,0 +1,57 @@
+# 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"
+end
diff --git a/src/kadmin/v4server/attic/kadm_funcs.c b/src/kadmin/v4server/attic/kadm_funcs.c
new file mode 100644
index 0000000000..7ce9c7b4f7
--- /dev/null
+++ b/src/kadmin/v4server/attic/kadm_funcs.c
@@ -0,0 +1,876 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * Kerberos administration server-side database manipulation routines
+ */
+
+#ifndef lint
+static char rcsid_kadm_funcs_c[] =
+"$Id$";
+#endif lint
+
+#include <mit-copyright.h>
+/*
+kadm_funcs.c
+the actual database manipulation code
+*/
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <ndbm.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <sys/file.h>
+#include <kadm.h>
+#include <kadm_err.h>
+#include <krb_db.h>
+#include <syslog.h>
+#ifdef NEED_SYS_FCNTL_H
+#include <sys/fcntl.h>
+#endif
+
+#include "kadm_server.h"
+
+extern Kadm_Server server_parm;
+
+krb5_error_code
+kadm_entry2princ(entry, princ)
+ krb5_db_entry entry;
+ Principal *princ;
+{
+ char realm[REALM_SZ]; /* dummy values only */
+ krb5_error_code retval;
+ time_t lcltim;
+
+ /* NOTE: does not convert the key */
+ memset(princ, 0, sizeof (*princ));
+ retval = krb5_524_conv_principal(entry.principal,
+ princ->name, princ->instance, realm);
+ if (retval)
+ return retval;
+ princ->exp_date = entry.expiration;
+ lcltim = entry.expiration;
+ strncpy(princ->exp_date_txt, ctime(&lcltim),
+ DATE_SZ);
+ lcltim = princ->mod_date = entry.mod_date;
+ strncpy(princ->mod_date_txt, ctime(&lcltim),
+ DATE_SZ);
+ princ->attributes = entry.attributes;
+ princ->max_life = entry.max_life;
+ princ->kdc_key_ver = entry.mkvno;
+ princ->key_version = entry.kvno;
+ retval = krb5_524_conv_principal(entry.mod_name,
+ princ->mod_name, princ->mod_instance,
+ realm);
+ if (retval)
+ return retval;
+ return 0;
+}
+
+krb5_error_code
+kadm_princ2entry(princ, entry)
+ Principal princ;
+ krb5_db_entry *entry;
+{
+ krb5_error_code retval;
+
+ /* NOTE: does not convert the key */
+ memset(entry, 0, sizeof (*entry));
+ /* yeah yeah stupid v4 database doesn't store realm names */
+ retval = krb5_425_conv_principal(princ.name, princ.instance,
+ server_parm.krbrlm, &entry->principal);
+ if (retval)
+ return retval;
+ entry->kvno = princ.key_version;
+ entry->max_life = princ.max_life;
+ entry->max_renewable_life = server_parm.max_rlife; /* XXX yeah well */
+ entry->mkvno = server_parm.mkvno; /* XXX */
+ entry->expiration = princ.exp_date;
+ retval = krb5_425_conv_principal(princ.mod_name, princ.mod_instance,
+ server_parm.krbrlm, &entry->mod_name);
+ if (retval)
+ return retval;
+ entry->mod_date = princ.mod_date;
+ entry->attributes = princ.attributes;
+ entry->salt_type = KRB5_KDB_SALTTYPE_V4;
+}
+
+check_access(pname, pinst, prealm, acltype)
+char *pname;
+char *pinst;
+char *prealm;
+enum acl_types acltype;
+{
+ char checkname[MAX_K_NAME_SZ];
+ char filename[MAXPATHLEN];
+ extern char *acldir;
+
+ (void) sprintf(checkname, "%s.%s@%s", pname, pinst, prealm);
+
+ switch (acltype) {
+ case ADDACL:
+ (void) sprintf(filename, "%s%s", acldir, ADD_ACL_FILE);
+ break;
+ case GETACL:
+ (void) sprintf(filename, "%s%s", acldir, GET_ACL_FILE);
+ break;
+ case MODACL:
+ (void) sprintf(filename, "%s%s", acldir, MOD_ACL_FILE);
+ break;
+ case STABACL:
+ (void) sprintf(filename, "%s%s", acldir, STAB_ACL_FILE);
+ break;
+ }
+ return(acl_check(filename, checkname));
+}
+
+int
+wildcard(str)
+char *str;
+{
+ if (!strcmp(str, WILDCARD_STR))
+ return(1);
+ return(0);
+}
+
+#define failadd(code) { (void) syslog(LOG_ERR, "FAILED addding '%s.%s' (%s)", valsin->name, valsin->instance, error_message(code)); return code; }
+
+kadm_add_entry (rname, rinstance, rrealm, valsin, valsout)
+char *rname; /* requestors name */
+char *rinstance; /* requestors instance */
+char *rrealm; /* requestors realm */
+Kadm_vals *valsin;
+Kadm_vals *valsout;
+{
+ Principal data_i, data_o; /* temporary principal */
+ u_char flags[4];
+ krb5_principal default_princ;
+ krb5_error_code retval;
+ krb5_db_entry newentry, tmpentry;
+ krb5_boolean more;
+ krb5_keyblock newpw;
+ krb5_encrypted_keyblock encpw;
+ int numfound;
+
+ if (!check_access(rname, rinstance, rrealm, ADDACL)) {
+ syslog(LOG_WARNING, "WARNING: '%s.%s@%s' tried to add an entry for '%s.%s'",
+ rname, rinstance, rrealm, valsin->name, valsin->instance);
+ return KADM_UNAUTH;
+ }
+
+ /* Need to check here for "legal" name and instance */
+ if (wildcard(valsin->name) || wildcard(valsin->instance)) {
+ failadd(KADM_ILL_WILDCARD);
+ }
+
+ syslog(LOG_INFO, "request to add an entry for '%s.%s' from '%s.%s@%s'",
+ valsin->name, valsin->instance, rname, rinstance, rrealm);
+
+ kadm_vals_to_prin(valsin->fields, &data_i, valsin);
+ (void) strncpy(data_i.name, valsin->name, ANAME_SZ);
+ (void) strncpy(data_i.instance, valsin->instance, INST_SZ);
+
+ if (!IS_FIELD(KADM_EXPDATE,valsin->fields))
+ data_i.exp_date = server_parm.expiration;
+ if (!IS_FIELD(KADM_ATTR,valsin->fields))
+ data_i.attributes = server_parm.flags;
+ if (!IS_FIELD(KADM_MAXLIFE,valsin->fields))
+ data_i.max_life = server_parm.max_life;
+
+ if ((newpw.contents = (krb5_octet *)malloc(8)) == NULL)
+ failadd(KADM_NOMEM);
+ data_i.key_low = ntohl(data_i.key_low);
+ data_i.key_high = ntohl(data_i.key_high);
+ memcpy(newpw.contents, &data_i.key_low, 4);
+ memcpy((char *)(((krb4_int32 *) newpw.contents) + 1), &data_i.key_high, 4);
+ newpw.length = 8;
+ newpw.keytype = KEYTYPE_DES;
+ /* encrypt new key in master key */
+ retval = krb5_kdb_encrypt_key(&server_parm.master_encblock,
+ &newpw, &encpw);
+ memset((char *)newpw.contents, 0, newpw.length);
+ free(newpw.contents);
+ if (retval) {
+ failadd(retval);
+ }
+ data_o = data_i;
+
+ retval = kadm_princ2entry(data_i, &newentry);
+ if (retval) {
+ memset((char *)encpw.contents, 0, encpw.length);
+ free(encpw.contents);
+ krb5_db_free_principal(&newentry, 1);
+ failadd(retval);
+ }
+
+ newentry.key = encpw;
+ numfound = 1;
+ retval = krb5_db_get_principal(newentry.principal,
+ &tmpentry, &numfound, &more);
+
+ if (retval) {
+ krb5_db_free_principal(&newentry, 1);
+ failadd(retval);
+ }
+ krb5_db_free_principal(&tmpentry, numfound);
+ if (numfound) {
+ krb5_db_free_principal(&newentry, 1);
+ failadd(KADM_INUSE);
+ } else {
+ newentry.kvno = ++data_i.key_version;
+ if (retval = krb5_timeofday(&newentry.mod_date)) {
+ krb5_db_free_principal(&newentry, 1);
+ failadd(retval);
+ }
+ if (newentry.mod_name)
+ krb5_free_principal(newentry.mod_name);
+ newentry.mod_name = NULL; /* in case the following breaks */
+ retval = krb5_425_conv_principal(rname, rinstance, rrealm,
+ &newentry.mod_name);
+ if (retval) {
+ krb5_db_free_principal(&newentry, 1);
+ failadd(retval);
+ }
+
+ numfound = 1;
+ retval = krb5_db_put_principal(&newentry, &numfound);
+ if (retval) {
+ krb5_db_free_principal(&newentry, 1);
+ failadd(retval);
+ }
+ if (!numfound) {
+ krb5_db_free_principal(&newentry, 1);
+ failadd(KADM_UK_SERROR);
+ } else {
+ numfound = 1;
+ retval = krb5_db_get_principal(newentry.principal,
+ &tmpentry,
+ &numfound, &more);
+ krb5_db_free_principal(&newentry, 1);
+ if (retval) {
+ failadd(retval);
+ } else if (numfound != 1 || more) {
+ krb5_db_free_principal(&tmpentry, numfound);
+ failadd(KADM_UK_RERROR);
+ }
+ kadm_entry2princ(tmpentry, &data_o);
+ krb5_db_free_principal(&tmpentry, numfound);
+ memset((char *)flags, 0, sizeof(flags));
+ SET_FIELD(KADM_NAME,flags);
+ SET_FIELD(KADM_INST,flags);
+ SET_FIELD(KADM_EXPDATE,flags);
+ SET_FIELD(KADM_ATTR,flags);
+ SET_FIELD(KADM_MAXLIFE,flags);
+ kadm_prin_to_vals(flags, valsout, &data_o);
+ syslog(LOG_INFO, "'%s.%s' added.", valsin->name, valsin->instance);
+ return KADM_DATA; /* Set all the appropriate fields */
+ }
+ }
+}
+#undef failadd
+
+#define failget(code) { (void) syslog(LOG_ERR, "FAILED retrieving '%s.%s' (%s)", valsin->name, valsin->instance, error_message(code)); return code; }
+
+kadm_get_entry (rname, rinstance, rrealm, valsin, flags, valsout)
+char *rname; /* requestors name */
+char *rinstance; /* requestors instance */
+char *rrealm; /* requestors realm */
+Kadm_vals *valsin; /* what they wannt to get */
+u_char *flags; /* which fields we want */
+Kadm_vals *valsout; /* what data is there */
+{
+ int numfound; /* check how many were returned */
+ krb5_boolean more; /* To point to more name.instances */
+ Principal data_o; /* Data object to hold Principal */
+ krb5_principal inprinc;
+ krb5_db_entry entry;
+ krb5_error_code retval;
+
+ if (!check_access(rname, rinstance, rrealm, GETACL)) {
+ syslog(LOG_WARNING, "WARNING: '%s.%s@%s' tried to get '%s.%s's entry",
+ rname, rinstance, rrealm, valsin->name, valsin->instance);
+ return KADM_UNAUTH;
+ }
+
+ if (wildcard(valsin->name) || wildcard(valsin->instance)) {
+ failget(KADM_ILL_WILDCARD);
+ }
+
+ syslog(LOG_INFO, "retrieve '%s.%s's entry for '%s.%s@%s'",
+ valsin->name, valsin->instance, rname, rinstance, rrealm);
+
+ retval = krb5_425_conv_principal(valsin->name, valsin->instance,
+ server_parm.krbrlm, &inprinc);
+ if (retval)
+ failget(retval);
+ /* Look up the record in the database */
+ numfound = 1;
+ retval = krb5_db_get_principal(inprinc, &entry, &numfound, &more);
+ krb5_free_principal(inprinc);
+ if (retval) {
+ failget(retval);
+ } else if (!numfound || more) {
+ failget(KADM_NOENTRY);
+ }
+ retval = kadm_entry2princ(entry, &data_o);
+ krb5_db_free_principal(&entry, 1);
+ if (retval) {
+ failget(retval);
+ }
+ kadm_prin_to_vals(flags, valsout, &data_o);
+ syslog(LOG_INFO, "'%s.%s' retrieved.", valsin->name, valsin->instance);
+ return KADM_DATA; /* Set all the appropriate fields */
+}
+#undef failget
+
+#define failmod(code) { (void) syslog(LOG_ERR, "FAILED modifying '%s.%s' (%s)", valsin1->name, valsin1->instance, error_message(code)); return code; }
+
+kadm_mod_entry (rname, rinstance, rrealm, valsin1, valsin2, valsout)
+char *rname; /* requestors name */
+char *rinstance; /* requestors instance */
+char *rrealm; /* requestors realm */
+Kadm_vals *valsin1, *valsin2; /* holds the parameters being
+ passed in */
+Kadm_vals *valsout; /* the actual record which is returned */
+{
+ int numfound;
+ krb5_boolean more;
+ Principal data_o, temp_key;
+ u_char fields[4];
+ krb5_keyblock newpw;
+ krb5_encrypted_keyblock encpw;
+ krb5_error_code retval;
+ krb5_principal theprinc, rprinc;
+ krb5_db_entry newentry, odata;
+
+ if (wildcard(valsin1->name) || wildcard(valsin1->instance)) {
+ failmod(KADM_ILL_WILDCARD);
+ }
+
+ if (!check_access(rname, rinstance, rrealm, MODACL)) {
+ syslog(LOG_WARNING, "WARNING: '%s.%s@%s' tried to change '%s.%s's entry",
+ rname, rinstance, rrealm, valsin1->name, valsin1->instance);
+ return KADM_UNAUTH;
+ }
+
+ syslog(LOG_INFO, "request to modify '%s.%s's entry from '%s.%s@%s' ",
+ valsin1->name, valsin1->instance, rname, rinstance, rrealm);
+ krb5_425_conv_principal(valsin1->name, valsin1->instance,
+ server_parm.krbrlm, &theprinc);
+ if (retval)
+ failmod(retval);
+ numfound = 1;
+ retval = krb5_db_get_principal(theprinc, &newentry, &numfound, &more);
+ if (retval) {
+ krb5_free_principal(theprinc);
+ failmod(retval);
+ } else if (numfound == 1) {
+ kadm_vals_to_prin(valsin2->fields, &temp_key, valsin2);
+ krb5_free_principal(newentry.principal);
+ newentry.principal = theprinc;
+ if (IS_FIELD(KADM_EXPDATE,valsin2->fields))
+ newentry.expiration = temp_key.exp_date;
+ if (IS_FIELD(KADM_ATTR,valsin2->fields))
+ newentry.attributes = temp_key.attributes;
+ if (IS_FIELD(KADM_MAXLIFE,valsin2->fields))
+ newentry.max_life = temp_key.max_life;
+ if (IS_FIELD(KADM_DESKEY,valsin2->fields)) {
+ newentry.kvno++;
+ newentry.mkvno = server_parm.mkvno;
+ if ((newpw.contents = (krb5_octet *)malloc(8)) == NULL) {
+ krb5_db_free_principal(&newentry, 1);
+ memset((char *)&temp_key, 0, sizeof (temp_key));
+ failmod(KADM_NOMEM);
+ }
+ newpw.length = 8;
+ newpw.keytype = KEYTYPE_DES;
+ temp_key.key_low = ntohl(temp_key.key_low);
+ temp_key.key_high = ntohl(temp_key.key_high);
+ memcpy(newpw.contents, &temp_key.key_low, 4);
+ memcpy(newpw.contents + 4, &temp_key.key_high, 4);
+ /* encrypt new key in master key */
+ retval = krb5_kdb_encrypt_key(&server_parm.master_encblock,
+ &newpw, &encpw);
+ memset(newpw.contents, 0, newpw.length);
+ free(newpw.contents);
+ memset((char *)&temp_key, 0, sizeof(temp_key));
+ if (retval) {
+ krb5_db_free_principal(&newentry, 1);
+ failmod(retval);
+ }
+ if (newentry.key.contents) {
+ memset((char *)newentry.key.contents, 0, newentry.key.length);
+ free(newentry.key.contents);
+ }
+ newentry.key = encpw;
+ }
+ if (retval = krb5_timeofday(&newentry.mod_date)) {
+ krb5_db_free_principal(&newentry, 1);
+ failmod(retval);
+ }
+ retval = krb5_425_conv_principal(rname, rinstance, rrealm,
+ &newentry.mod_name);
+ if (retval) {
+ krb5_db_free_principal(&newentry, 1);
+ failmod(retval);
+ }
+ numfound = 1;
+ retval = krb5_db_put_principal(&newentry, &numfound);
+ memset((char *)&data_o, 0, sizeof(data_o));
+ if (retval) {
+ krb5_db_free_principal(&newentry, 1);
+ failmod(retval);
+ } else {
+ numfound = 1;
+ retval = krb5_db_get_principal(newentry.principal, &odata,
+ &numfound, &more);
+ krb5_db_free_principal(&newentry, 1);
+ if (retval) {
+ failmod(retval);
+ } else if (numfound != 1 || more) {
+ krb5_db_free_principal(&odata, numfound);
+ failmod(KADM_UK_RERROR);
+ }
+ retval = kadm_entry2princ(odata, &data_o);
+ krb5_db_free_principal(&odata, 1);
+ if (retval)
+ failmod(retval);
+ memset((char *) fields, 0, sizeof(fields));
+ SET_FIELD(KADM_NAME,fields);
+ SET_FIELD(KADM_INST,fields);
+ SET_FIELD(KADM_EXPDATE,fields);
+ SET_FIELD(KADM_ATTR,fields);
+ SET_FIELD(KADM_MAXLIFE,fields);
+ kadm_prin_to_vals(fields, valsout, &data_o);
+ syslog(LOG_INFO, "'%s.%s' modified.", valsin1->name, valsin1->instance);
+ return KADM_DATA; /* Set all the appropriate fields */
+ }
+ } else {
+ failmod(KADM_NOENTRY);
+ }
+}
+#undef failmod
+
+#define failchange(code) { syslog(LOG_ERR, "FAILED changing key for '%s.%s@%s' (%s)", rname, rinstance, rrealm, error_message(code)); return code; }
+
+kadm_change (rname, rinstance, rrealm, newpw)
+char *rname;
+char *rinstance;
+char *rrealm;
+des_cblock newpw;
+{
+ int numfound;
+ krb5_boolean more;
+ krb5_principal rprinc;
+ krb5_error_code retval;
+ krb5_keyblock localpw;
+ krb5_encrypted_keyblock encpw;
+ krb5_db_entry odata;
+
+ if (strcmp(server_parm.krbrlm, rrealm)) {
+ syslog(LOG_ERR, "change key request from wrong realm, '%s.%s@%s'!\n",
+ rname, rinstance, rrealm);
+ return(KADM_WRONG_REALM);
+ }
+
+ if (wildcard(rname) || wildcard(rinstance)) {
+ failchange(KADM_ILL_WILDCARD);
+ }
+ syslog(LOG_INFO, "'%s.%s@%s' wants to change its password",
+ rname, rinstance, rrealm);
+ retval = krb5_425_conv_principal(rname, rinstance,
+ server_parm.krbrlm, &rprinc);
+ if (retval)
+ failchange(retval);
+ if ((localpw.contents = (krb5_octet *)malloc(8)) == NULL)
+ failchange(KADM_NOMEM);
+ memcpy(localpw.contents, newpw, 8);
+ localpw.keytype = KEYTYPE_DES;
+ localpw.length = 8;
+ /* encrypt new key in master key */
+ retval = krb5_kdb_encrypt_key(&server_parm.master_encblock,
+ &localpw, &encpw);
+ memset((char *)localpw.contents, 0, 8);
+ free(localpw.contents);
+ if (retval) {
+ krb5_free_principal(rprinc);
+ failchange(retval);
+ }
+ numfound = 1;
+ retval = krb5_db_get_principal(rprinc, &odata, &numfound, &more);
+ krb5_free_principal(rprinc);
+ if (retval) {
+ failchange(retval);
+ } else if (numfound == 1) {
+ odata.key = encpw;
+ odata.kvno++;
+ odata.mkvno = server_parm.mkvno;
+ if (retval = krb5_timeofday(&odata.mod_date)) {
+ krb5_db_free_principal(&odata, 1);
+ failchange(retval);
+ }
+ krb5_425_conv_principal(rname, rinstance,
+ server_parm.krbrlm, &odata.mod_name);
+ if (retval) {
+ krb5_db_free_principal(&odata, 1);
+ failchange(retval);
+ }
+ numfound = 1;
+ retval = krb5_db_put_principal(&odata, &numfound);
+ krb5_db_free_principal(&odata, 1);
+ if (retval) {
+ failchange(retval);
+ } else if (more) {
+ failchange(KADM_UK_SERROR);
+ } else {
+ syslog(LOG_INFO,
+ "'%s.%s@%s' password changed.", rname, rinstance, rrealm);
+ return KADM_SUCCESS;
+ }
+ }
+ else {
+ failchange(KADM_NOENTRY);
+ }
+}
+#undef failchange
+
+check_pw(newpw, checkstr)
+ des_cblock newpw;
+ char *checkstr;
+{
+#ifdef NOENCRYPTION
+ return 0;
+#else /* !NOENCRYPTION */
+ des_cblock checkdes;
+
+ (void) des_string_to_key(checkstr, checkdes);
+ return(!memcmp(checkdes, newpw, sizeof(des_cblock)));
+#endif /* NOENCRYPTION */
+}
+
+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);
+}
+
+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);
+}
+
+des_check_gecos(gecos, newpw)
+ char *gecos;
+ des_cblock newpw;
+{
+ 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 (check_pw(newpw, cp))
+ return(KADM_INSECURE_PW);
+ tcp = reverse(cp);
+ if (check_pw(newpw, tcp))
+ return(KADM_INSECURE_PW);
+ if (lower(cp)) {
+ if (check_pw(newpw, cp))
+ return(KADM_INSECURE_PW);
+ tcp = reverse(cp);
+ if (check_pw(newpw, tcp))
+ return(KADM_INSECURE_PW);
+ }
+ cp = ncp;
+ } else
+ break;
+ }
+ return(0);
+}
+
+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(KADM_INSECURE_PW);
+ tcp = reverse(cp);
+ if (!strcasecmp(pwstr, tcp))
+ return(KADM_INSECURE_PW);
+ cp = ncp;
+ } else
+ break;
+ }
+ return(0);
+}
+
+
+kadm_approve_pw(rname, rinstance, rrealm, newpw, pwstring)
+char *rname;
+char *rinstance;
+char *rrealm;
+des_cblock newpw;
+char *pwstring;
+{
+ static DBM *pwfile = NULL;
+ int retval;
+ datum passwd, entry;
+ struct passwd *ent;
+#ifdef HESIOD
+ extern struct passwd *hes_getpwnam();
+#endif
+
+ if (pwstring && !check_pw(newpw, pwstring))
+ /*
+ * Someone's trying to toy with us....
+ */
+ return(KADM_PW_MISMATCH);
+ if (pwstring && (strlen(pwstring) < 5))
+ return(KADM_INSECURE_PW);
+ if (!pwfile) {
+ pwfile = dbm_open(PW_CHECK_FILE, O_RDONLY, 0644);
+ }
+ if (pwfile) {
+ passwd.dptr = (char *) newpw;
+ passwd.dsize = 8;
+ entry = dbm_fetch(pwfile, passwd);
+ if (entry.dptr)
+ return(KADM_INSECURE_PW);
+ }
+ if (check_pw(newpw, rname) || check_pw(newpw, reverse(rname)))
+ return(KADM_INSECURE_PW);
+#ifdef HESIOD
+ ent = hes_getpwnam(rname);
+#else
+ ent = getpwnam(rname);
+#endif
+ if (ent && ent->pw_gecos) {
+ if (pwstring)
+ retval = str_check_gecos(ent->pw_gecos, pwstring);
+ else
+ retval = des_check_gecos(ent->pw_gecos, newpw);
+ if (retval)
+ return(retval);
+ }
+ return(0);
+}
+
+/*
+ * This routine checks to see if a principal should be considered an
+ * allowable service name which can be changed by kadm_change_srvtab.
+ *
+ * We do this check by using the ACL library. This makes the
+ * (relatively) reasonable assumption that both the name and the
+ * instance will not contain '.' or '@'.
+ */
+kadm_check_srvtab(name, instance)
+ char *name;
+ char *instance;
+{
+ FILE *f;
+ char filename[MAXPATHLEN];
+ char buf[ANAME_SZ], *cp;
+ extern char *acldir;
+
+ (void) sprintf(filename, "%s%s", acldir, STAB_SERVICES_FILE);
+ if (!acl_check(filename, name))
+ return(KADM_NOT_SERV_PRINC);
+
+ (void) sprintf(filename, "%s%s", acldir, STAB_HOSTS_FILE);
+ if (acl_check(filename, instance))
+ return(KADM_NOT_SERV_PRINC);
+ return 0;
+}
+
+/*
+ * Routine to allow some people to change the key of a srvtab
+ * principal to a random key, which the admin server will return to
+ * the client.
+ */
+#define failsrvtab(code) { syslog(LOG_ERR, "change_srvtab: FAILED changing '%s.%s' by '%s.%s@%s' (%s)", values->name, values->instance, rname, rinstance, rrealm, error_message(code)); return code; }
+
+kadm_chg_srvtab(rname, rinstance, rrealm, values)
+ char *rname; /* requestors name */
+ char *rinstance; /* requestors instance */
+ char *rrealm; /* requestors realm */
+ Kadm_vals *values;
+{
+ int numfound, ret, isnew = 0;
+ des_cblock new_key;
+ Principal principal;
+ krb5_principal inprinc;
+ krb5_error_code retval;
+ krb5_db_entry odata;
+ krb5_boolean more;
+ krb5_keyblock newpw;
+ krb5_encrypted_keyblock encpw;
+
+ if (!check_access(rname, rinstance, rrealm, STABACL))
+ failsrvtab(KADM_UNAUTH);
+ if (wildcard(rname) || wildcard(rinstance))
+ failsrvtab(KADM_ILL_WILDCARD);
+ if (ret = kadm_check_srvtab(values->name, values->instance))
+ failsrvtab(ret);
+
+ retval = krb5_425_conv_principal(values->name, values->instance,
+ server_parm.krbrlm, &inprinc);
+ if (retval)
+ failsrvtab(retval);
+ /*
+ * OK, get the entry
+ */
+ numfound = 1;
+ retval = krb5_db_get_principal(inprinc, &odata, &numfound, &more);
+ if (retval) {
+ krb5_free_principal(inprinc);
+ failsrvtab(retval);
+ } else if (numfound) {
+ odata.kvno++;
+ } else {
+ /*
+ * This is a new srvtab entry that we're creating
+ */
+ isnew = 1;
+ memset((char *)&odata, 0, sizeof (odata));
+ odata.principal = inprinc;
+ odata.kvno = 1;
+ odata.max_life = server_parm.max_life;
+ odata.max_renewable_life = server_parm.max_rlife;
+ odata.mkvno = server_parm.mkvno;
+ odata.expiration = server_parm.expiration;
+ odata.attributes = 0;
+ }
+
+#ifdef NOENCRYPTION
+ memset(new_key, 0, sizeof(new_key));
+ new_key[0] = 127;
+#else
+ des_new_random_key(new_key);
+#endif
+ /*
+ * Store the new key in the return structure; also fill in the
+ * rest of the fields.
+ */
+ if ((newpw.contents = (krb5_octet *)malloc(8)) == NULL) {
+ krb5_db_free_principal(&odata, 1);
+ failsrvtab(KADM_NOMEM);
+ }
+ newpw.keytype = KEYTYPE_DES;
+ newpw.length = 8;
+ memcpy((char *)newpw.contents, new_key, 8);
+ memset((char *)new_key, 0, sizeof (new_key));
+ memcpy((char *)&values->key_low, newpw.contents, 4);
+ memcpy((char *)&values->key_high, newpw.contents + 4, 4);
+ values->key_low = htonl(values->key_low);
+ values->key_high = htonl(values->key_high);
+ values->max_life = odata.kvno;
+ values->exp_date = odata.expiration;
+ values->attributes = odata.attributes;
+ memset(values->fields, 0, sizeof(values->fields));
+ SET_FIELD(KADM_NAME, values->fields);
+ SET_FIELD(KADM_INST, values->fields);
+ SET_FIELD(KADM_EXPDATE, values->fields);
+ SET_FIELD(KADM_ATTR, values->fields);
+ SET_FIELD(KADM_MAXLIFE, values->fields);
+ SET_FIELD(KADM_DESKEY, values->fields);
+
+ /*
+ * Encrypt the new key with the master key, and then update
+ * the database record
+ */
+ retval = krb5_kdb_encrypt_key(&server_parm.master_encblock,
+ &newpw, &encpw);
+ memset((char *)newpw.contents, 0, 8);
+ free(newpw.contents);
+ if (odata.key.contents) {
+ memset((char *)odata.key.contents, 0, odata.key.length);
+ free(odata.key.contents);
+ }
+ odata.key = encpw;
+ if (retval) {
+ krb5_db_free_principal(&odata, 1);
+ failsrvtab(retval);
+ }
+ if (retval = krb5_timeofday(&odata.mod_date)) {
+ krb5_db_free_principal(&odata, 1);
+ failsrvtab(retval);
+ }
+ retval = krb5_425_conv_principal(rname, rinstance,
+ server_parm.krbrlm, &odata.mod_name);
+ if (retval) {
+ krb5_db_free_principal(&odata, 1);
+ failsrvtab(retval);
+ }
+ numfound = 1;
+ retval = krb5_db_put_principal(&odata, &numfound);
+ krb5_db_free_principal(&odata, 1);
+ if (retval) {
+ failsrvtab(retval);
+ }
+ else if (!numfound) {
+ failsrvtab(KADM_UK_SERROR);
+ } else {
+ syslog(LOG_INFO, "change_srvtab: service '%s.%s' %s by %s.%s@%s.",
+ values->name, values->instance,
+ numfound ? "changed" : "created",
+ rname, rinstance, rrealm);
+ return KADM_DATA;
+ }
+}
+
+#undef failsrvtab
diff --git a/src/kadmin/v4server/attic/kadm_ser_wrap.c b/src/kadmin/v4server/attic/kadm_ser_wrap.c
new file mode 100644
index 0000000000..bca8b8e054
--- /dev/null
+++ b/src/kadmin/v4server/attic/kadm_ser_wrap.c
@@ -0,0 +1,288 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * Kerberos administration server-side support functions
+ */
+
+#ifndef lint
+static char rcsid_module_c[] =
+"$Header$";
+#endif lint
+
+#include <mit-copyright.h>
+/*
+kadm_ser_wrap.c
+unwraps wrapped packets and calls the appropriate server subroutine
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <krb.h>
+#include <kadm.h>
+#include <kadm_err.h>
+#include <krb_err.h>
+#include <syslog.h>
+#include "kadm_server.h"
+
+#ifdef OVSEC_KADM
+#include <ovsec_admin/admin.h>
+extern void *ovsec_handle;
+#endif
+
+Kadm_Server server_parm;
+
+/*
+kadm_ser_init
+set up the server_parm structure
+*/
+kadm_ser_init(inter, realm)
+ int inter; /* interactive or from file */
+ char realm[];
+{
+ struct servent *sep;
+ struct hostent *hp;
+ char hostname[MAXHOSTNAMELEN];
+ char *mkey_name;
+ krb5_error_code retval;
+ int numfound = 1;
+ krb5_boolean more;
+ krb5_db_entry master_entry;
+
+ if (gethostname(hostname, sizeof(hostname)))
+ return KADM_NO_HOSTNAME;
+
+ (void) strcpy(server_parm.sname, PWSERV_NAME);
+ (void) strcpy(server_parm.sinst, KRB_MASTER);
+ (void) strcpy(server_parm.krbrlm, realm);
+ if (krb5_build_principal(&server_parm.sprinc,
+ strlen(realm),
+ realm,
+ PWSERV_NAME,
+ KRB_MASTER, 0))
+ return KADM_NO_MAST;
+
+ /* setting up the addrs */
+ server_parm.admin_fd = -1;
+ if ((sep = getservbyname(KADM_SNAME, "tcp")) == NULL)
+ return KADM_NO_SERV;
+ memset((char *)&server_parm.admin_addr, 0,sizeof(server_parm.admin_addr));
+ server_parm.admin_addr.sin_family = AF_INET;
+ if ((hp = gethostbyname(hostname)) == NULL)
+ return KADM_NO_HOSTNAME;
+ memcpy((char *) &server_parm.admin_addr.sin_addr.s_addr, hp->h_addr,
+ hp->h_length);
+ server_parm.admin_addr.sin_port = sep->s_port;
+
+ /* setting up the database */
+ mkey_name = KRB5_KDB_M_NAME;
+ server_parm.master_keyblock.keytype = KEYTYPE_DES;
+#ifdef PROVIDE_DES_CBC_CRC
+#ifdef KRB5B4
+ server_parm.master_encblock.crypto_entry = krb5_des_cst_entry.system;
+#else
+ server_parm.master_encblock.crypto_entry = &mit_des_cryptosystem_entry;
+#endif /* KRB5B4 */
+#else
+ error(You gotta figure out what cryptosystem to use in the KDC);
+#endif
+ retval = krb5_db_setup_mkey_name(mkey_name, realm, (char **) 0,
+ &server_parm.master_princ);
+ if (retval)
+ return KADM_NO_MAST;
+ krb5_db_fetch_mkey(server_parm.master_princ,
+ &server_parm.master_encblock,
+ (inter == 1), FALSE, NULL,
+ &server_parm.master_keyblock);
+ if (retval)
+ return KADM_NO_MAST;
+ retval = krb5_db_verify_master_key(server_parm.master_princ,
+ &server_parm.master_keyblock,
+ &server_parm.master_encblock);
+ if (retval)
+ return KADM_NO_VERI;
+ retval = krb5_process_key(&server_parm.master_encblock,
+ &server_parm.master_keyblock);
+ if (retval)
+ return KADM_NO_VERI;
+
+ retval = krb5_db_get_principal(server_parm.master_princ,
+ &master_entry, &numfound, &more);
+ if (retval || more || !numfound)
+ return KADM_NO_VERI;
+ server_parm.max_life = master_entry.max_life;
+ server_parm.max_rlife = master_entry.max_renewable_life;
+ server_parm.expiration = master_entry.expiration;
+ server_parm.mkvno = master_entry.kvno;
+ /* don't set flags, as master has some extra restrictions
+ (??? quoted from kdb_edit.c) */
+ krb5_db_free_principal(&master_entry, numfound);
+ return KADM_SUCCESS;
+}
+
+
+static void errpkt(dat, dat_len, code)
+u_char **dat;
+int *dat_len;
+int code;
+{
+ krb4_uint32 retcode;
+ char *pdat;
+
+ free((char *)*dat); /* free up req */
+ *dat_len = KADM_VERSIZE + sizeof(krb4_uint32);
+ *dat = (u_char *) malloc((unsigned)*dat_len);
+ if (!(*dat)) {
+ syslog(LOG_ERR, "malloc(%d) returned null while in errpkt!", *dat_len);
+ abort();
+ }
+ pdat = (char *) *dat;
+ retcode = htonl((krb4_uint32) code);
+ (void) strncpy(pdat, KADM_ULOSE, KADM_VERSIZE);
+ memcpy(&pdat[KADM_VERSIZE], (char *)&retcode, sizeof(krb4_uint32));
+ return;
+}
+
+/*
+kadm_ser_in
+unwrap the data stored in dat, process, and return it.
+*/
+kadm_ser_in(dat,dat_len)
+u_char **dat;
+int *dat_len;
+{
+ u_char *in_st; /* pointer into the sent packet */
+ int in_len,retc; /* where in packet we are, for
+ returns */
+ krb4_uint32 r_len; /* length of the actual packet */
+ KTEXT_ST authent; /* the authenticator */
+ AUTH_DAT ad; /* who is this, klink */
+ krb4_uint32 ncksum; /* checksum of encrypted data */
+ des_key_schedule sess_sched; /* our schedule */
+ MSG_DAT msg_st;
+ u_char *retdat, *tmpdat;
+ int retval, retlen;
+
+ if (strncmp(KADM_VERSTR, (char *)*dat, KADM_VERSIZE)) {
+ errpkt(dat, dat_len, KADM_BAD_VER);
+ return KADM_BAD_VER;
+ }
+ in_len = KADM_VERSIZE;
+ /* get the length */
+ if ((retc = stv_long(*dat, &r_len, in_len, *dat_len)) < 0)
+ return KADM_LENGTH_ERROR;
+ in_len += retc;
+ authent.length = *dat_len - r_len - KADM_VERSIZE - sizeof(krb4_uint32);
+ memcpy((char *)authent.dat, (char *)(*dat) + in_len, authent.length);
+ authent.mbz = 0;
+ /* service key should be set before here */
+ if (retc = krb_rd_req(&authent, server_parm.sname, server_parm.sinst,
+ server_parm.recv_addr.sin_addr.s_addr, &ad, (char *)0))
+ {
+ errpkt(dat, dat_len,retc + krb_err_base);
+ return retc + krb_err_base;
+ }
+
+#define clr_cli_secrets() {memset((char *)sess_sched, 0, sizeof(sess_sched)); memset((char *)ad.session, 0, sizeof(ad.session));}
+
+ in_st = *dat + *dat_len - r_len;
+#ifdef NOENCRYPTION
+ ncksum = 0;
+#else
+ ncksum = quad_cksum((des_cblock *)in_st, (des_cblock *)0, (krb4_int32) r_len, 0,
+ (des_cblock *)ad.session);
+#endif
+ if (ncksum!=ad.checksum) { /* yow, are we correct yet */
+ clr_cli_secrets();
+ errpkt(dat, dat_len,KADM_BAD_CHK);
+ return KADM_BAD_CHK;
+ }
+#ifdef NOENCRYPTION
+ memset(sess_sched, 0, sizeof(sess_sched));
+#else
+ des_key_sched(ad.session, sess_sched);
+#endif
+ if (retc = (int) krb_rd_priv(in_st, r_len, sess_sched, ad.session,
+ &server_parm.recv_addr,
+ &server_parm.admin_addr, &msg_st)) {
+ clr_cli_secrets();
+ errpkt(dat, dat_len,retc + krb_err_base);
+ return retc + krb_err_base;
+ }
+ switch (msg_st.app_data[0]) {
+ case CHANGE_PW:
+ retval = kadm_ser_cpw(msg_st.app_data+1,(int) msg_st.app_length,&ad,
+ &retdat, &retlen);
+ break;
+#ifndef OVSEC_KADM
+ case ADD_ENT:
+ retval = kadm_ser_add(msg_st.app_data+1,(int) msg_st.app_length,&ad,
+ &retdat, &retlen);
+ break;
+ case GET_ENT:
+ retval = kadm_ser_get(msg_st.app_data+1,(int) msg_st.app_length,&ad,
+ &retdat, &retlen);
+ break;
+ case MOD_ENT:
+ retval = kadm_ser_mod(msg_st.app_data+1,(int) msg_st.app_length,&ad,
+ &retdat, &retlen);
+ break;
+ case CHECK_PW:
+ retval = kadm_ser_ckpw(msg_st.app_data+1,(int) msg_st.app_length,&ad,
+ &retdat, &retlen);
+ break;
+ case CHG_STAB:
+ retval = kadm_ser_stab(msg_st.app_data+1,(int) msg_st.app_length,&ad,
+ &retdat, &retlen);
+ break;
+#endif /* OVSEC_KADM */
+ default:
+ clr_cli_secrets();
+ errpkt(dat, dat_len, KADM_NO_OPCODE);
+ return KADM_NO_OPCODE;
+ }
+ /* Now seal the response back into a priv msg */
+ free((char *)*dat);
+ tmpdat = (u_char *) malloc((unsigned)(retlen + KADM_VERSIZE +
+ sizeof(krb4_uint32)));
+ if (!tmpdat) {
+ clr_cli_secrets();
+ syslog(LOG_ERR, "malloc(%d) returned null while in kadm_ser_in!",
+ retlen + KADM_VERSIZE + sizeof(krb4_uint32));
+ errpkt(dat, dat_len, KADM_NOMEM);
+ return KADM_NOMEM;
+ }
+ (void) strncpy((char *)tmpdat, KADM_VERSTR, KADM_VERSIZE);
+ retval = htonl((krb4_uint32)retval);
+ memcpy((char *)tmpdat + KADM_VERSIZE, (char *)&retval, sizeof(krb4_uint32));
+ if (retlen) {
+ memcpy((char *)tmpdat + KADM_VERSIZE + sizeof(krb4_uint32), (char *)retdat,
+ retlen);
+ free((char *)retdat);
+ }
+ /* slop for mk_priv stuff */
+ *dat = (u_char *) malloc((unsigned) (retlen + KADM_VERSIZE +
+ sizeof(krb4_uint32) + 200));
+ if ((*dat_len = krb_mk_priv(tmpdat, *dat,
+ (krb4_uint32) (retlen + KADM_VERSIZE +
+ sizeof(krb4_uint32)),
+ sess_sched,
+ ad.session, &server_parm.admin_addr,
+ &server_parm.recv_addr)) < 0) {
+ clr_cli_secrets();
+ errpkt(dat, dat_len, KADM_NO_ENCRYPT);
+ free(tmpdat);
+ return KADM_NO_ENCRYPT;
+ }
+ clr_cli_secrets();
+ free(tmpdat);
+ return KADM_SUCCESS;
+}
diff --git a/src/kadmin/v4server/attic/kadm_server.c b/src/kadmin/v4server/attic/kadm_server.c
new file mode 100644
index 0000000000..143af5d4e4
--- /dev/null
+++ b/src/kadmin/v4server/attic/kadm_server.c
@@ -0,0 +1,546 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * Kerberos administration server-side subroutines
+ */
+
+#ifndef lint
+static char rcsid_kadm_server_c[] =
+"$Header$";
+#endif lint
+
+#include <mit-copyright.h>
+
+#include <krb5/osconf.h>
+#include <krb5/wordsize.h>
+
+#include <stdio.h>
+#ifdef USE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#include <string.h>
+
+#ifdef OVSEC_KADM
+#include <com_err.h>
+#include <ovsec_admin/admin.h>
+#include <ovsec_admin/chpass_util_strings.h>
+#include <krb5/kdb.h>
+extern void *ovsec_handle;
+#endif
+
+#include <kadm.h>
+#include <kadm_err.h>
+
+int fascist_cpw = 0; /* Be fascist about insecure passwords? */
+
+#ifdef OVSEC_KADM
+char pw_required[] = "The version of kpasswd that you are using is not compatible with the\nOpenV*Secure V4 Administration Server. Please contact your security\nadministrator.\n\n";
+
+#else /* !OVSEC_KADM */
+
+char bad_pw_err[] =
+ "\007\007\007ERROR: Insecure password not accepted. Please choose another.\n\n";
+
+char bad_pw_warn[] =
+ "\007\007\007WARNING: You have chosen an insecure password. You may wish to\nchoose a better password.\n\n";
+
+char check_pw_msg[] =
+ "You have entered an insecure password. You should choose another.\n\n";
+
+char pw_blurb[] =
+"A good password is something which is easy for you to remember, but that\npeople who know you won't easily guess; so don't use your name, or your\ndog's name, or a word from the dictionary. Passwords should be at least\n6 characters long, and may contain UPPER- and lower-case letters,\nnumbers, or punctuation. A good password can be:\n\n -- some initials, like \"GykoR-66\" for \"Get your kicks on Rte 66.\"\n -- an easily pronounced nonsense word, like \"slaRooBey\" or \"krang-its\"\n -- a mis-spelled phrase, like \"2HotPeetzas\" or \"ItzAGurl\"\n\nPlease Note: It is important that you do not tell ANYONE your password,\nincluding your friends, or even people from Athena or Information\nSystems. Remember, *YOU* are assumed to be responsible for anything\ndone using your password.\n";
+
+#endif /* OVSEC_KADM */
+
+/* from V4 month_sname.c -- was not part of API */
+/*
+ * 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.
+ */
+
+static char *month_sname(n)
+ int n;
+{
+ static char *name[] = {
+ "Jan","Feb","Mar","Apr","May","Jun",
+ "Jul","Aug","Sep","Oct","Nov","Dec"
+ };
+ return((n < 1 || n > 12) ? 0 : name [n-1]);
+}
+
+/* from V4 log.c -- was not part of API */
+
+/*
+ * 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.
+ */
+
+/* static char *log_name = KRBLOG; */
+/* KRBLOG is in the V4 klog.h but may not correspond to anything installed. */
+static char *log_name = KADM_SYSLOG;
+
+static void krb_log(format,a1,a2,a3,a4,a5,a6,a7,a8,a9,a0)
+ char *format;
+ int a1,a2,a3,a4,a5,a6,a7,a8,a9,a0;
+{
+ FILE *logfile, *fopen();
+ time_t now;
+ struct tm *tm;
+
+ if ((logfile = fopen(log_name,"a")) == NULL)
+ return;
+
+ (void) time(&now);
+ tm = localtime(&now);
+
+ fprintf(logfile,"%2d-%s-%02d %02d:%02d:%02d ",tm->tm_mday,
+ month_sname(tm->tm_mon + 1),tm->tm_year,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+ fprintf(logfile,format,a1,a2,a3,a4,a5,a6,a7,a8,a9,a0);
+ fprintf(logfile,"\n");
+ (void) fclose(logfile);
+ return;
+}
+
+
+/*
+kadm_ser_cpw - the server side of the change_password routine
+ recieves : KTEXT, {key}
+ returns : CKSUM, RETCODE
+ acl : caller can change only own password
+
+Replaces the password (i.e. des key) of the caller with that specified in key.
+Returns no actual data from the master server, since this is called by a user
+*/
+kadm_ser_cpw(dat, len, ad, datout, outlen)
+u_char *dat;
+int len;
+AUTH_DAT *ad;
+u_char **datout;
+int *outlen;
+{
+ krb5_ui_4 keylow, keyhigh;
+ char pword[MAX_KPW_LEN];
+ int no_pword = 0;
+ des_cblock newkey;
+ int status, stvlen = 0;
+ int retval;
+ extern char *malloc();
+ extern int kadm_approve_pw();
+#ifdef OVSEC_KADM
+ ovsec_kadm_principal_ent_t princ_ent;
+ ovsec_kadm_policy_ent_t pol_ent;
+ krb5_principal user_princ;
+ char msg_ret[1024], *time_string, *ptr;
+ const char *msg_ptr;
+ krb5_int32 now;
+ time_t until;
+#endif
+
+ /* take key off the stream, and change the database */
+
+ if ((status = stv_long(dat, &keyhigh, 0, len)) < 0)
+ return(KADM_LENGTH_ERROR);
+ stvlen += status;
+ if ((status = stv_long(dat, &keylow, stvlen, len)) < 0)
+ return(KADM_LENGTH_ERROR);
+ stvlen += status;
+ if ((stvlen = stv_string(dat, pword, stvlen, sizeof(pword), len)) < 0) {
+ no_pword++;
+ pword[0]='\0';
+ }
+ stvlen += status;
+
+ keylow = ntohl(keylow);
+ keyhigh = ntohl(keyhigh);
+ memcpy((((krb5_int32 *)newkey) + 1), &keyhigh, 4);
+ memcpy(newkey, &keylow, 4);
+
+#ifdef OVSEC_KADM
+ /* we don't use the client-provided key itself */
+ keylow = keyhigh = 0;
+ memset(newkey, 0, sizeof(newkey));
+
+ if (no_pword) {
+ krb_log("Old-style change password request from '%s.%s@%s'!",
+ ad->pname, ad->pinst, ad->prealm);
+ *outlen = strlen(pw_required)+1;
+ if (*datout = (u_char *) malloc(*outlen)) {
+ strcpy(*datout, pw_required);
+ } else {
+ *outlen = 0;
+ }
+ return KADM_INSECURE_PW;
+ }
+
+ if (krb5_build_principal(&user_princ,
+ strlen(ad->prealm),
+ ad->prealm,
+ ad->pname,
+ *ad->pinst ? ad->pinst : 0, 0))
+ /* this should never happen */
+ return KADM_NOENTRY;
+
+ *outlen = 0;
+
+ if (retval = krb5_timeofday(&now)) {
+ msg_ptr = error_message(retval);
+ goto send_response;
+ }
+
+ retval = ovsec_kadm_get_principal(ovsec_handle, user_princ,
+ &princ_ent);
+ if (retval != 0) {
+ msg_ptr = error_message(retval);
+ goto send_response;
+ }
+
+ /*
+ * This daemon necessarily has the modify privilege, so
+ * ovsec_kadm_chpass_principal will allow it to violate the
+ * policy's minimum lifetime. Since that's A Bad Thing, we need
+ * to enforce it ourselves. Unfortunately, this means we are
+ * duplicating code from both ovsec_adm_server and
+ * ovsec_kadm_chpass_util().
+ */
+ if (princ_ent->aux_attributes & OVSEC_KADM_POLICY) {
+ retval = ovsec_kadm_get_policy(ovsec_handle,
+ princ_ent->policy,
+ &pol_ent);
+ if (retval != 0) {
+ (void) ovsec_kadm_free_principal_ent(ovsec_handle, princ_ent);
+ msg_ptr = error_message(retval);
+ goto send_response;
+ }
+
+ /* make "now" a boolean, true == too soon */
+ now = ((now - princ_ent->last_pwd_change) < pol_ent->pw_min_life);
+
+ (void) ovsec_kadm_free_policy_ent(ovsec_handle, pol_ent);
+
+ if(now && !(princ_ent->attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
+ (void) ovsec_kadm_free_principal_ent(ovsec_handle, princ_ent);
+ retval = CHPASS_UTIL_PASSWORD_TOO_SOON;
+
+ until = princ_ent->last_pwd_change + pol_ent->pw_min_life;
+ time_string = ctime(&until);
+
+ if (*(ptr = &time_string[strlen(time_string)-1]) == '\n')
+ *ptr = '\0';
+
+ sprintf(msg_ret, error_message(CHPASS_UTIL_PASSWORD_TOO_SOON),
+ time_string);
+ msg_ptr = msg_ret;
+
+ goto send_response;
+ }
+ }
+
+ (void) ovsec_kadm_free_principal_ent(ovsec_handle, princ_ent);
+
+ retval = ovsec_kadm_chpass_principal_util(ovsec_handle, user_princ,
+ pword, NULL, msg_ret);
+ msg_ptr = msg_ret;
+ (void) krb5_free_principal(user_princ);
+
+send_response:
+
+ retval = convert_ovsec_to_kadm(retval);
+
+ if (retval) {
+ /* don't send message on success because kpasswd.v4 will */
+ /* print "password changed" too */
+ *outlen = strlen(msg_ptr)+2;
+ if (*datout = (u_char *) malloc(*outlen)) {
+ strcpy(*datout, msg_ptr);
+ strcat(*datout, "\n");
+ } else
+ *outlen = 0;
+ }
+ if (retval == KADM_INSECURE_PW) {
+ krb_log("'%s.%s@%s' tried to use an insecure password in changepw",
+ ad->pname, ad->pinst, ad->prealm);
+ }
+
+#else /* !OVSEC_KADM */
+
+ if (retval = kadm_approve_pw(ad->pname, ad->pinst, ad->prealm,
+ newkey, no_pword ? 0 : pword)) {
+ if (retval == KADM_PW_MISMATCH) {
+ /*
+ * Very strange!!! This means that the cleartext
+ * password which was sent and the DES cblock
+ * didn't match!
+ */
+ (void) krb_log("'%s.%s@%s' sent a password string which didn't match with the DES key?!?",
+ ad->pname, ad->pinst, ad->prealm);
+ return(retval);
+ }
+ if (fascist_cpw) {
+ *outlen = strlen(bad_pw_err)+strlen(pw_blurb)+1;
+ if (*datout = (u_char *) malloc(*outlen)) {
+ strcpy(*datout, bad_pw_err);
+ strcat(*datout, pw_blurb);
+ } else
+ *outlen = 0;
+ (void) krb_log("'%s.%s@%s' tried to use an insecure password in changepw",
+ ad->pname, ad->pinst, ad->prealm);
+#ifdef notdef
+ /* For debugging only, probably a bad idea */
+ if (!no_pword)
+ (void) krb_log("The password was %s\n", pword);
+#endif
+ return(retval);
+ } else {
+ *outlen = strlen(bad_pw_warn) + strlen(pw_blurb)+1;
+ if (*datout = (u_char *) malloc(*outlen)) {
+ strcpy(*datout, bad_pw_warn);
+ strcat(*datout, pw_blurb);
+ } else
+ *outlen = 0;
+ (void) krb_log("'%s.%s@%s' used an insecure password in changepw",
+ ad->pname, ad->pinst, ad->prealm);
+ }
+ } else {
+ *datout = 0;
+ *outlen = 0;
+ }
+
+ retval = kadm_change(ad->pname, ad->pinst, ad->prealm, newkey);
+ keylow = keyhigh = 0;
+ memset(newkey, 0, sizeof(newkey));
+#endif /* OVSEC_KADM */
+
+ return retval;
+}
+
+/**********************************************************************/
+#ifndef OVSEC_KADM
+
+/*
+kadm_ser_add - the server side of the add_entry routine
+ recieves : KTEXT, {values}
+ returns : CKSUM, RETCODE, {values}
+ acl : su, sms (as alloc)
+
+Adds and entry containing values to the database
+returns the values of the entry, so if you leave certain fields blank you will
+ be able to determine the default values they are set to
+*/
+kadm_ser_add(dat,len,ad, datout, outlen)
+u_char *dat;
+int len;
+AUTH_DAT *ad;
+u_char **datout;
+int *outlen;
+{
+ Kadm_vals values, retvals;
+ int status;
+
+ if ((status = stream_to_vals(dat, &values, len)) < 0)
+ return(KADM_LENGTH_ERROR);
+ if ((status = kadm_add_entry(ad->pname, ad->pinst, ad->prealm,
+ &values, &retvals)) == KADM_DATA) {
+ *outlen = vals_to_stream(&retvals,datout);
+ retvals.key_low = retvals.key_high = 0;
+ return KADM_SUCCESS;
+ } else {
+ *outlen = 0;
+ return status;
+ }
+}
+
+/*
+kadm_ser_mod - the server side of the mod_entry routine
+ recieves : KTEXT, {values, values}
+ returns : CKSUM, RETCODE, {values}
+ acl : su, sms (as register or dealloc)
+
+Modifies all entries corresponding to the first values so they match the
+ second values.
+returns the values for the changed entries
+*/
+kadm_ser_mod(dat,len,ad, datout, outlen)
+u_char *dat;
+int len;
+AUTH_DAT *ad;
+u_char **datout;
+int *outlen;
+{
+ Kadm_vals vals1, vals2, retvals;
+ int wh;
+ int status;
+
+ if ((wh = stream_to_vals(dat, &vals1, len)) < 0)
+ return KADM_LENGTH_ERROR;
+ if ((status = stream_to_vals(dat+wh,&vals2, len-wh)) < 0)
+ return KADM_LENGTH_ERROR;
+ if ((status = kadm_mod_entry(ad->pname, ad->pinst, ad->prealm, &vals1,
+ &vals2, &retvals)) == KADM_DATA) {
+ *outlen = vals_to_stream(&retvals,datout);
+ retvals.key_low = retvals.key_high = 0;
+ return KADM_SUCCESS;
+ } else {
+ *outlen = 0;
+ return status;
+ }
+}
+
+/*
+kadm_ser_get
+ recieves : KTEXT, {values, flags}
+ returns : CKSUM, RETCODE, {count, values, values, values}
+ acl : su
+
+gets the fields requested by flags from all entries matching values
+returns this data for each matching recipient, after a count of how many such
+ matches there were
+*/
+kadm_ser_get(dat,len,ad, datout, outlen)
+u_char *dat;
+int len;
+AUTH_DAT *ad;
+u_char **datout;
+int *outlen;
+{
+ Kadm_vals values, retvals;
+ u_char fl[FLDSZ];
+ int loop,wh;
+ int status;
+
+ if ((wh = stream_to_vals(dat, &values, len)) < 0)
+ return KADM_LENGTH_ERROR;
+ if (wh + FLDSZ > len)
+ return KADM_LENGTH_ERROR;
+ for (loop=FLDSZ-1; loop>=0; loop--)
+ fl[loop] = dat[wh++];
+ if ((status = kadm_get_entry(ad->pname, ad->pinst, ad->prealm,
+ &values, fl, &retvals)) == KADM_DATA) {
+ *outlen = vals_to_stream(&retvals,datout);
+ retvals.key_low = retvals.key_high = 0;
+ return KADM_SUCCESS;
+ } else {
+ *outlen = 0;
+ return status;
+ }
+}
+
+/*
+kadm_ser_ckpw - the server side of the check_password routine
+ recieves : KTEXT, {key}
+ returns : CKSUM, RETCODE
+ acl : none
+
+Checks to see if the des key passed from the caller is a "secure" password.
+*/
+kadm_ser_ckpw(dat, len, ad, datout, outlen)
+u_char *dat;
+int len;
+AUTH_DAT *ad;
+u_char **datout;
+int *outlen;
+{
+ krb5_ui_4 keylow, keyhigh;
+ char pword[MAX_KPW_LEN];
+ int no_pword = 0;
+ des_cblock newkey;
+ int stvlen = 0,status;
+ int retval;
+ extern char *malloc();
+ extern int kadm_approve_pw();
+
+ /* take key off the stream, and check it */
+
+ if ((status = stv_long(dat, &keyhigh, 0, len)) < 0)
+ return(KADM_LENGTH_ERROR);
+ stvlen += status;
+ if ((status = stv_long(dat, &keylow, stvlen, len)) < 0)
+ return(KADM_LENGTH_ERROR);
+ stvlen += status;
+ if ((status = stv_string(dat, pword, stvlen, sizeof(pword), len)) < 0) {
+ no_pword++;
+ pword[0]='\0';
+ }
+ stvlen += status;
+
+ keylow = ntohl(keylow);
+ keyhigh = ntohl(keyhigh);
+ memcpy((char *)(((krb5_int32 *)newkey) + 1), (char *)&keyhigh, 4);
+ memcpy((char *)newkey, (char *)&keylow, 4);
+ keylow = keyhigh = 0;
+ retval = kadm_approve_pw(ad->pname, ad->pinst, ad->prealm, newkey,
+ no_pword ? 0 : pword);
+ memset(newkey, 0, sizeof(newkey));
+ if (retval) {
+ *outlen = strlen(check_pw_msg)+strlen(pw_blurb)+1;
+ if (*datout = (u_char *) malloc(*outlen)) {
+ strcpy(*datout, check_pw_msg);
+ strcat(*datout, pw_blurb);
+ } else
+ *outlen = 0;
+ (void) krb_log("'%s.%s@%s' sent an insecure password to be checked",
+ ad->pname, ad->pinst, ad->prealm);
+ return(retval);
+ } else {
+ *datout = 0;
+ *outlen = 0;
+ (void) krb_log("'%s.%s@%s' sent a secure password to be checked",
+ ad->pname, ad->pinst, ad->prealm);
+ }
+ return(0);
+}
+
+/*
+kadm_ser_stab - the server side of the change_srvtab routine
+ recieves : KTEXT, {values}
+ returns : CKSUM, RETCODE, {values}
+ acl : su, sms (as register or dealloc)
+
+Creates or modifies the specified service principal to have a random
+key, which is sent back to the client. The key version is returned in
+the max_life field of the values structure. It's a hack, but it's a
+backwards compatible hack....
+*/
+kadm_ser_stab(dat, len, ad, datout, outlen)
+u_char *dat;
+int len;
+AUTH_DAT *ad;
+u_char **datout;
+int *outlen;
+{
+ Kadm_vals values;
+ int status;
+
+ if ((status = stream_to_vals(dat, &values, len)) < 0)
+ return KADM_LENGTH_ERROR;
+ status = kadm_chg_srvtab(ad->pname, ad->pinst, ad->prealm, &values);
+ if (status == KADM_DATA) {
+ *outlen = vals_to_stream(&values,datout);
+ values.key_low = values.key_high = 0;
+ return KADM_SUCCESS;
+ } else {
+ *outlen = 0;
+ return status;
+ }
+}
+
+#endif /* !OVSEC_KADM */
diff --git a/src/kadmin/v4server/attic/kadm_server.h b/src/kadmin/v4server/attic/kadm_server.h
new file mode 100644
index 0000000000..4e6fd8c468
--- /dev/null
+++ b/src/kadmin/v4server/attic/kadm_server.h
@@ -0,0 +1,64 @@
+/*
+ * $Source$
+ * $Author$
+ * $Header$
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * Definitions for Kerberos administration server & client
+ */
+
+#ifndef KADM_SERVER_DEFS
+#define KADM_SERVER_DEFS
+
+#include <mit-copyright.h>
+/*
+ * kadm_server.h
+ * Header file for the fourth attempt at an admin server
+ * Doug Church, December 28, 1989, MIT Project Athena
+ * ps. Yes that means this code belongs to athena etc...
+ * as part of our ongoing attempt to copyright all greek names
+ */
+
+#include <sys/types.h>
+#include <krb.h>
+#include <des.h>
+
+#include <krb5/krb5.h>
+#include <krb5/kdb.h>
+#include <krb5/osconf.h>
+#include <krb5/config.h>
+#ifdef PROVIDE_DES_CBC_CRC
+#include <krb5/mit-des.h>
+#endif
+
+typedef struct {
+ struct sockaddr_in admin_addr;
+ struct sockaddr_in recv_addr;
+ int recv_addr_len;
+ int admin_fd; /* our link to clients */
+ char sname[ANAME_SZ];
+ char sinst[INST_SZ];
+ char krbrlm[REALM_SZ];
+ krb5_principal sprinc;
+ krb5_encrypt_block master_encblock;
+ krb5_principal master_princ;
+ krb5_keyblock master_keyblock;
+ krb5_deltat max_life;
+ krb5_deltat max_rlife;
+ krb5_timestamp expiration;
+ krb5_flags flags;
+ krb5_kvno mkvno;
+} Kadm_Server;
+
+#define ADD_ACL_FILE "/v4acl.add"
+#define GET_ACL_FILE "/v4acl.get"
+#define MOD_ACL_FILE "/v4acl.mod"
+#define STAB_ACL_FILE "/v4acl.srvtab"
+#define STAB_SERVICES_FILE "/v4stab_services"
+#define STAB_HOSTS_FILE "/v4stab_bad_hosts"
+
+#endif /* KADM_SERVER_DEFS */
diff --git a/src/kadmin/v4server/attic/kadm_stream.c b/src/kadmin/v4server/attic/kadm_stream.c
new file mode 100644
index 0000000000..83aaa295c7
--- /dev/null
+++ b/src/kadmin/v4server/attic/kadm_stream.c
@@ -0,0 +1,276 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * Stream conversion functions for Kerberos administration server
+ */
+
+#ifndef lint
+static char rcsid_kadm_stream_c[] =
+"$Header$";
+#endif lint
+
+#include <mit-copyright.h>
+/*
+ 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, krb4_int32, short]
+ stream_to_vals: converts a stream to a vals struct
+ internals check_field_header, stv_[string, char, krb4_int32, short]
+ error: prints out a kadm error message, returns
+ fatal: prints out a kadm fatal error message, exits
+*/
+
+#include "kadm.h"
+#include <string.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
+*/
+vals_to_stream(dt_in, dt_out)
+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(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);
+}
+
+build_field_header(cont, st)
+u_char *cont; /* container for fields data */
+u_char **st; /* stream */
+{
+ *st = (u_char *) malloc (4);
+ memcpy((void *) *st, (void *) cont, 4);
+ return 4; /* return pointer to current stream location */
+}
+
+vts_string(dat, st, loc)
+char *dat; /* a string to put on the stream */
+u_char **st; /* base pointer to the stream */
+int loc; /* offset into the stream for current data */
+{
+ *st = (u_char *) realloc ((char *)*st, (unsigned) (loc + strlen(dat) + 1));
+ memcpy((char *)(*st + loc), dat, strlen(dat)+1);
+ return strlen(dat)+1;
+}
+
+vts_short(dat, st, loc)
+u_short dat; /* the attributes field */
+u_char **st; /* a base pointer to the stream */
+int loc; /* offset into the stream for current data */
+{
+ u_short temp; /* to hold the net order short */
+
+ temp = htons(dat); /* convert to network order */
+ *st = (u_char *) realloc ((char *)*st, (unsigned)(loc + sizeof(u_short)));
+ memcpy((char *)(*st + loc), (char *) &temp, sizeof(u_short));
+ return sizeof(u_short);
+}
+
+vts_long(dat, st, loc)
+krb4_uint32 dat; /* the attributes field */
+u_char **st; /* a base pointer to the stream */
+int loc; /* offset into the stream for current data */
+{
+ krb4_uint32 temp; /* to hold the net order short */
+
+ temp = htonl(dat); /* convert to network order */
+ *st = (u_char *) realloc ((char *)*st, (unsigned)(loc + sizeof(krb4_uint32)));
+ memcpy((char *)(*st + loc), (char *) &temp, sizeof(krb4_uint32));
+ return sizeof(krb4_uint32);
+}
+
+
+vts_char(dat, st, loc)
+u_char dat; /* the attributes field */
+u_char **st; /* a base pointer to the stream */
+int loc; /* offset into the stream for current data */
+{
+ *st = (u_char *) realloc ((char *)*st, (unsigned)(loc + sizeof(u_char)));
+ (*st)[loc] = (u_char) dat;
+ 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
+*/
+stream_to_vals(dt_in, dt_out, maxlen)
+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;
+ krb4_int32 lcllong;
+
+ memset((char *) 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:
+ if ((status = stv_string(dt_in, dt_out->name, stsize,
+ sizeof(dt_out->name), maxlen)) < 0)
+ return(-1);
+ stsize += status;
+ break;
+ case KADM_INST:
+ if ((status = stv_string(dt_in, dt_out->instance, stsize,
+ sizeof(dt_out->instance), maxlen)) < 0)
+ return(-1);
+ stsize += status;
+ break;
+ case KADM_EXPDATE:
+ if ((status = stv_long(dt_in, &lcllong, stsize,
+ maxlen)) < 0)
+ return(-1);
+ dt_out->exp_date = lcllong;
+ stsize += status;
+ break;
+ case KADM_ATTR:
+ if ((status = stv_short(dt_in, &dt_out->attributes, stsize,
+ maxlen)) < 0)
+ return(-1);
+ stsize += status;
+ break;
+ case KADM_MAXLIFE:
+ if ((status = stv_char(dt_in, &dt_out->max_life, stsize,
+ maxlen)) < 0)
+ return(-1);
+ stsize += status;
+ break;
+ case KADM_DESKEY:
+ if ((status = stv_long(dt_in, &dt_out->key_high, stsize,
+ maxlen)) < 0)
+ return(-1);
+ stsize += status;
+ if ((status = stv_long(dt_in, &dt_out->key_low, stsize,
+ maxlen)) < 0)
+ return(-1);
+ stsize += status;
+ break;
+ default:
+ break;
+ }
+ return stsize;
+}
+
+check_field_header(st, cont, maxlen)
+u_char *st; /* stream */
+u_char *cont; /* container for fields data */
+int maxlen;
+{
+ if (4 > maxlen)
+ return(-1);
+ memcpy((char *) cont, (char *) st, 4);
+ return 4; /* return pointer to current stream location */
+}
+
+stv_string(st, dat, loc, stlen, maxlen)
+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 */
+
+ maxcount = min(maxlen - loc, stlen);
+
+ (void) strncpy(dat, (char *)st + loc, maxcount);
+
+ if (dat[maxcount-1]) /* not null-term --> not enuf room */
+ return(-1);
+ return strlen(dat)+1;
+}
+
+stv_short(st, dat, loc, maxlen)
+u_char *st; /* a base pointer to the stream */
+u_short *dat; /* the attributes field */
+int loc; /* offset into the stream for current data */
+int maxlen;
+{
+ u_short temp; /* to hold the net order short */
+
+ if (loc + sizeof(u_short) > maxlen)
+ return(-1);
+ memcpy((char *) &temp, (char *)((long)st+(krb4_uint32)loc), sizeof(u_short));
+ *dat = ntohs(temp); /* convert to network order */
+ return sizeof(u_short);
+}
+
+stv_long(st, dat, loc, maxlen)
+u_char *st; /* a base pointer to the stream */
+krb4_uint32 *dat; /* the attributes field */
+int loc; /* offset into the stream for current data */
+int maxlen; /* maximum length of st */
+{
+ krb4_uint32 temp; /* to hold the net order short */
+
+ if (loc + sizeof(krb4_uint32) > maxlen)
+ return(-1);
+ memcpy((char *) &temp, (char *)((long)st+(krb4_uint32)loc), sizeof(krb4_uint32));
+ *dat = ntohl(temp); /* convert to network order */
+ return sizeof(krb4_uint32);
+}
+
+stv_char(st, dat, loc, maxlen)
+u_char *st; /* a base pointer to the stream */
+u_char *dat; /* the attributes field */
+int loc; /* offset into the stream for current data */
+int maxlen;
+{
+ if (loc + 1 > maxlen)
+ return(-1);
+ *dat = *(st + loc);
+ return 1;
+}
+
diff --git a/src/kadmin/v4server/attic/kadm_supp.c b/src/kadmin/v4server/attic/kadm_supp.c
new file mode 100644
index 0000000000..cf4ba40f4c
--- /dev/null
+++ b/src/kadmin/v4server/attic/kadm_supp.c
@@ -0,0 +1,114 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * Support functions for Kerberos administration server & clients
+ */
+
+#ifndef lint
+static char rcsid_kadm_supp_c[] =
+"$Header$";
+#endif lint
+
+#include <mit-copyright.h>
+/*
+ kadm_supp.c
+ this holds the support routines for the kerberos administration server
+
+ error: prints out a kadm error message, returns
+ fatal: prints out a kadm fatal error message, exits
+ prin_vals: prints out data associated with a Principal in the vals
+ structure
+*/
+
+#include "kadm.h"
+#include "krb_db.h"
+
+/*
+prin_vals:
+ recieves : a vals structure
+*/
+prin_vals(vals)
+Kadm_vals *vals;
+{
+ printf("Info in Database for %s.%s:\n", vals->name, vals->instance);
+ printf(" Max Life: %d Exp Date: %s\n",vals->max_life,
+ asctime(localtime(&vals->exp_date)));
+ printf(" Attribs: %.2x key: %u %u\n",vals->attributes,
+ vals->key_low, vals->key_high);
+}
+
+#ifdef notdef
+nierror(s)
+int s;
+{
+ extern char *error_message();
+ printf("Kerberos admin server loses..... %s\n",error_message(s));
+ return(s);
+}
+#endif
+
+/* kadm_prin_to_vals takes a fields arguments, a Kadm_vals and a Principal,
+ it copies the fields in Principal specified by fields into Kadm_vals,
+ i.e from old to new */
+
+kadm_prin_to_vals(fields, new, old)
+u_char fields[FLDSZ];
+Kadm_vals *new;
+Principal *old;
+{
+ memset((char *)new, 0, sizeof(*new));
+ if (IS_FIELD(KADM_NAME,fields)) {
+ (void) strncpy(new->name, old->name, ANAME_SZ);
+ SET_FIELD(KADM_NAME, new->fields);
+ }
+ if (IS_FIELD(KADM_INST,fields)) {
+ (void) strncpy(new->instance, old->instance, INST_SZ);
+ SET_FIELD(KADM_INST, new->fields);
+ }
+ if (IS_FIELD(KADM_EXPDATE,fields)) {
+ new->exp_date = old->exp_date;
+ SET_FIELD(KADM_EXPDATE, new->fields);
+ }
+ if (IS_FIELD(KADM_ATTR,fields)) {
+ new->attributes = old->attributes;
+ SET_FIELD(KADM_MAXLIFE, new->fields);
+ }
+ if (IS_FIELD(KADM_MAXLIFE,fields)) {
+ new->max_life = old->max_life;
+ SET_FIELD(KADM_MAXLIFE, new->fields);
+ }
+ if (IS_FIELD(KADM_DESKEY,fields)) {
+ new->key_low = old->key_low;
+ new->key_high = old->key_high;
+ SET_FIELD(KADM_DESKEY, new->fields);
+ }
+}
+
+kadm_vals_to_prin(fields, new, old)
+u_char fields[FLDSZ];
+Principal *new;
+Kadm_vals *old;
+{
+
+ memset((char *)new, 0, sizeof(*new));
+ if (IS_FIELD(KADM_NAME,fields))
+ (void) strncpy(new->name, old->name, ANAME_SZ);
+ if (IS_FIELD(KADM_INST,fields))
+ (void) strncpy(new->instance, old->instance, INST_SZ);
+ if (IS_FIELD(KADM_EXPDATE,fields))
+ new->exp_date = old->exp_date;
+ if (IS_FIELD(KADM_ATTR,fields))
+ new->attributes = old->attributes;
+ if (IS_FIELD(KADM_MAXLIFE,fields))
+ new->max_life = old->max_life;
+ if (IS_FIELD(KADM_DESKEY,fields)) {
+ new->key_low = old->key_low;
+ new->key_high = old->key_high;
+ }
+}
diff --git a/src/kadmin/v4server/configure.in b/src/kadmin/v4server/configure.in
new file mode 100644
index 0000000000..9d45c1e165
--- /dev/null
+++ b/src/kadmin/v4server/configure.in
@@ -0,0 +1,16 @@
+AC_INIT(admin_server.c)
+CONFIG_RULES
+AC_PROG_INSTALL
+AC_CHECK_HEADERS(sys/time.h unistd.h stdlib.h)
+CHECK_SIGNALS
+CHECK_WAIT_TYPE
+AC_PROG_AWK
+USE_KADMCLNT_LIBRARY
+USE_GSSRPC_LIBRARY
+USE_GSSAPI_LIBRARY
+USE_DYN_LIBRARY
+USE_KDB5_LIBRARY
+USE_KRB4_LIBRARY
+KRB5_LIBRARIES
+V5_USE_SHARED_LIB
+V5_AC_OUTPUT_MAKEFILE
diff --git a/src/kadmin/v4server/kadm_err.et b/src/kadmin/v4server/kadm_err.et
new file mode 100644
index 0000000000..a192730833
--- /dev/null
+++ b/src/kadmin/v4server/kadm_err.et
@@ -0,0 +1,57 @@
+# 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"
+end
diff --git a/src/kadmin/v4server/kadm_funcs.c b/src/kadmin/v4server/kadm_funcs.c
new file mode 100644
index 0000000000..5025e3acb2
--- /dev/null
+++ b/src/kadmin/v4server/kadm_funcs.c
@@ -0,0 +1,1066 @@
+/*
+ * kadmin/v4server/kadm_funcs.c
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * Kerberos administration server-side database manipulation routines
+ */
+
+
+#include <mit-copyright.h>
+/*
+kadm_funcs.c
+the actual database manipulation code
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/param.h>
+/* #include <ndbm.h> Gotten by kadmin_server.h */
+#include <ctype.h>
+#include <pwd.h>
+#include <sys/file.h>
+#include <kadm.h>
+#include <kadm_err.h>
+#include <krb_db.h>
+#include <syslog.h>
+#include <fcntl.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 "kadm_server.h"
+
+extern Kadm_Server server_parm;
+
+krb5_error_code
+kadm_entry2princ(entry, princ)
+ krb5_db_entry entry;
+ Principal *princ;
+{
+ char realm[REALM_SZ]; /* dummy values only */
+ krb5_tl_mod_princ *mprinc;
+ krb5_key_data *pkey;
+ krb5_error_code retval;
+
+ /* NOTE: does not convert the key */
+ memset(princ, 0, sizeof (*princ));
+ retval = krb5_524_conv_principal(kadm_context, entry.princ,
+ princ->name, princ->instance, realm);
+ if (retval)
+ return retval;
+ princ->exp_date = entry.expiration;
+ strncpy(princ->exp_date_txt, ctime((const time_t *) &entry.expiration),
+ DATE_SZ);
+ princ->attributes = entry.attributes;
+ princ->max_life = entry.max_life / (60 * 5);
+ princ->kdc_key_ver = 1; /* entry.mkvno; */
+ princ->key_version = entry.key_data[0].key_data_kvno;
+
+ retval = krb5_dbe_decode_mod_princ_data(kadm_context, &entry, &mprinc);
+ if (retval)
+ return retval;
+ princ->mod_date = mprinc->mod_date;
+ strncpy(princ->mod_date_txt,
+ ctime((const time_t *) &mprinc->mod_date),
+ DATE_SZ);
+ krb5_free_principal(kadm_context, mprinc->mod_princ);
+ krb5_xfree(mprinc);
+
+ /* Find the V4 key */
+ retval = krb5_dbe_find_enctype(kadm_context,
+ &entry,
+ ENCTYPE_DES_CBC_CRC,
+ KRB5_KDB_SALTTYPE_V4,
+ -1,
+ &pkey);
+ if (retval)
+ return retval;
+ princ->key_version = pkey->key_data_kvno;
+
+ return 0;
+}
+
+krb5_error_code
+kadm_princ2entry(princ, entry)
+ Principal princ;
+ krb5_db_entry *entry;
+{
+ krb5_error_code retval;
+ krb5_tl_mod_princ mprinc;
+ krb5_key_data *kdatap;
+
+ /* NOTE: does not convert the key */
+ memset(entry, 0, sizeof (*entry));
+ /* yeah yeah stupid v4 database doesn't store realm names */
+ retval = krb5_425_conv_principal(kadm_context, princ.name, princ.instance,
+ server_parm.krbrlm, &entry->princ);
+ if (retval)
+ return retval;
+
+ entry->len = KRB5_KDB_V1_BASE_LENGTH;
+ entry->max_life = princ.max_life * (60 * 5);
+ entry->max_renewable_life = server_parm.max_rlife; /* XXX yeah well */
+ entry->expiration = princ.exp_date;
+ entry->attributes = princ.attributes;
+
+ retval = krb5_425_conv_principal(kadm_context, princ.mod_name,
+ princ.mod_instance,
+ server_parm.krbrlm, &mprinc.mod_princ);
+ if (retval)
+ return(retval);
+ mprinc.mod_date = princ.mod_date;
+
+ retval = krb5_dbe_encode_mod_princ_data(kadm_context, &mprinc, entry);
+ if (retval)
+ return(retval);
+
+ if (mprinc.mod_princ)
+ krb5_free_principal(kadm_context, mprinc.mod_princ);
+
+ if (retval = krb5_dbe_find_enctype(kadm_context,
+ entry,
+ ENCTYPE_DES_CBC_CRC,
+ KRB5_KDB_SALTTYPE_V4,
+ -1,
+ &kdatap)) {
+ if (!(retval = krb5_dbe_create_key_data(kadm_context, entry)))
+ kdatap = &entry->key_data[entry->n_key_data-1];
+ }
+ if (kdatap) {
+ kdatap->key_data_ver = 2;
+ kdatap->key_data_type[0] = (krb5_int16) ENCTYPE_DES_CBC_CRC;
+ kdatap->key_data_type[1] = (krb5_int16) KRB5_KDB_SALTTYPE_V4;
+ kdatap->key_data_kvno = (krb5_int16) princ.key_version;
+ }
+ return(retval);
+}
+
+int
+check_access(pname, pinst, prealm, acltype)
+char *pname;
+char *pinst;
+char *prealm;
+enum acl_types acltype;
+{
+ char checkname[MAX_K_NAME_SZ];
+ char filename[MAXPATHLEN];
+ extern char *acldir;
+
+ (void) sprintf(checkname, "%s.%s@%s", pname, pinst, prealm);
+
+ switch (acltype) {
+ case ADDACL:
+ (void) sprintf(filename, "%s%s", acldir, ADD_ACL_FILE);
+ break;
+ case GETACL:
+ (void) sprintf(filename, "%s%s", acldir, GET_ACL_FILE);
+ break;
+ case MODACL:
+ (void) sprintf(filename, "%s%s", acldir, MOD_ACL_FILE);
+ break;
+ case DELACL:
+ (void) sprintf(filename, "%s%s", acldir, DEL_ACL_FILE);
+ break;
+ case STABACL:
+ (void) sprintf(filename, "%s%s", acldir, STAB_ACL_FILE);
+ break;
+ }
+ return(acl_check(filename, checkname));
+}
+
+int
+wildcard(str)
+char *str;
+{
+ if (!strcmp(str, WILDCARD_STR))
+ return(1);
+ return(0);
+}
+
+#define failadd(code) { (void) syslog(LOG_ERR, "FAILED adding '%s.%s' (%s)", valsin->name, valsin->instance, error_message(code)); return code; }
+
+kadm_add_entry (rname, rinstance, rrealm, valsin, valsout)
+char *rname; /* requestors name */
+char *rinstance; /* requestors instance */
+char *rrealm; /* requestors realm */
+Kadm_vals *valsin;
+Kadm_vals *valsout;
+{
+ Principal data_i, data_o; /* temporary principal */
+ u_char flags[4];
+ krb5_principal default_princ;
+ krb5_error_code retval;
+ krb5_db_entry newentry, tmpentry;
+ krb5_boolean more;
+ krb5_keyblock newpw;
+ krb5_tl_mod_princ mprinc;
+ krb5_key_data *pkey;
+ krb5_keysalt sblock;
+ int numfound;
+
+ if (!check_access(rname, rinstance, rrealm, ADDACL)) {
+ syslog(LOG_WARNING, "WARNING: '%s.%s@%s' tried to add an entry for '%s.%s'",
+ rname, rinstance, rrealm, valsin->name, valsin->instance);
+ return KADM_UNAUTH;
+ }
+
+ /* Need to check here for "legal" name and instance */
+ if (wildcard(valsin->name) || wildcard(valsin->instance)) {
+ failadd(KADM_ILL_WILDCARD);
+ }
+
+ syslog(LOG_INFO, "request to add an entry for '%s.%s' from '%s.%s@%s'",
+ valsin->name, valsin->instance, rname, rinstance, rrealm);
+
+ kadm_vals_to_prin(valsin->fields, &data_i, valsin);
+ (void) strncpy(data_i.name, valsin->name, ANAME_SZ);
+ (void) strncpy(data_i.instance, valsin->instance, INST_SZ);
+
+ if (!IS_FIELD(KADM_EXPDATE,valsin->fields))
+ data_i.exp_date = server_parm.expiration;
+ if (!IS_FIELD(KADM_ATTR,valsin->fields))
+ data_i.attributes = server_parm.flags;
+ if (!IS_FIELD(KADM_MAXLIFE,valsin->fields))
+ data_i.max_life = server_parm.max_life;
+
+ retval = kadm_princ2entry(data_i, &newentry);
+ if (retval) {
+ krb5_db_free_principal(kadm_context, &newentry, 1);
+ failadd(retval);
+ }
+
+ newpw.magic = KV5M_KEYBLOCK;
+ if ((newpw.contents = (krb5_octet *)malloc(8)) == NULL)
+ failadd(KADM_NOMEM);
+
+ retval = krb5_dbe_find_enctype(kadm_context,
+ &newentry,
+ ENCTYPE_DES_CBC_CRC,
+ KRB5_KDB_SALTTYPE_V4,
+ -1,
+ &pkey);
+ if (retval)
+ failadd(retval);
+
+ data_i.key_low = ntohl(data_i.key_low);
+ data_i.key_high = ntohl(data_i.key_high);
+ memcpy(newpw.contents, &data_i.key_low, 4);
+ memcpy((char *)(((krb5_int32 *) newpw.contents) + 1), &data_i.key_high, 4);
+ newpw.length = 8;
+ newpw.enctype = ENCTYPE_DES_CBC_CRC;
+ sblock.type = KRB5_KDB_SALTTYPE_V4;
+ sblock.data.length = 0;
+ sblock.data.data = (char *) NULL;
+ /* encrypt new key in master key */
+ retval = krb5_dbekd_encrypt_key_data(kadm_context,
+ &server_parm.master_encblock,
+ &newpw,
+ &sblock,
+ (int) ++data_i.key_version,
+ pkey);
+ memset((char *)newpw.contents, 0, newpw.length);
+ free(newpw.contents);
+ if (retval) {
+ failadd(retval);
+ }
+ data_o = data_i;
+
+ numfound = 1;
+ retval = krb5_db_get_principal(kadm_context, newentry.princ,
+ &tmpentry, &numfound, &more);
+
+ if (retval) {
+ krb5_db_free_principal(kadm_context, &newentry, 1);
+ failadd(retval);
+ }
+ krb5_db_free_principal(kadm_context, &tmpentry, numfound);
+ if (numfound) {
+ krb5_db_free_principal(kadm_context, &newentry, 1);
+ failadd(KADM_INUSE);
+ } else {
+ if (retval = krb5_timeofday(kadm_context, &mprinc.mod_date)) {
+ krb5_db_free_principal(kadm_context, &newentry, 1);
+ failadd(retval);
+ }
+ mprinc.mod_princ = NULL; /* in case the following breaks */
+ retval = krb5_425_conv_principal(kadm_context, rname, rinstance, rrealm,
+ &mprinc.mod_princ);
+ if (retval) {
+ krb5_db_free_principal(kadm_context, &newentry, 1);
+ failadd(retval);
+ }
+
+ retval = krb5_dbe_encode_mod_princ_data(kadm_context,
+ &mprinc,
+ &newentry);
+ krb5_free_principal(kadm_context, mprinc.mod_princ);
+ if (retval) {
+ krb5_db_free_principal(kadm_context, &newentry, 1);
+ failadd(retval);
+ }
+
+ numfound = 1;
+ retval = krb5_db_put_principal(kadm_context, &newentry, &numfound);
+ if (retval) {
+ krb5_db_free_principal(kadm_context, &newentry, 1);
+ failadd(retval);
+ }
+ if (!numfound) {
+ krb5_db_free_principal(kadm_context, &newentry, 1);
+ failadd(KADM_UK_SERROR);
+ } else {
+ numfound = 1;
+ retval = krb5_db_get_principal(kadm_context, newentry.princ,
+ &tmpentry,
+ &numfound, &more);
+ krb5_db_free_principal(kadm_context, &newentry, 1);
+ if (retval) {
+ failadd(retval);
+ } else if (numfound != 1 || more) {
+ krb5_db_free_principal(kadm_context, &tmpentry, numfound);
+ failadd(KADM_UK_RERROR);
+ }
+ kadm_entry2princ(tmpentry, &data_o);
+ krb5_db_free_principal(kadm_context, &tmpentry, numfound);
+ memset((char *)flags, 0, sizeof(flags));
+ SET_FIELD(KADM_NAME,flags);
+ SET_FIELD(KADM_INST,flags);
+ SET_FIELD(KADM_EXPDATE,flags);
+ SET_FIELD(KADM_ATTR,flags);
+ SET_FIELD(KADM_MAXLIFE,flags);
+ kadm_prin_to_vals(flags, valsout, &data_o);
+ syslog(LOG_INFO, "'%s.%s' added.", valsin->name, valsin->instance);
+ return KADM_DATA; /* Set all the appropriate fields */
+ }
+ }
+}
+#undef failadd
+
+#define faildel(code) { (void) syslog(LOG_ERR, "FAILED deleting '%s.%s' (%s)", valsin->name, valsin->instance, error_message(code)); return code; }
+
+kadm_del_entry (rname, rinstance, rrealm, valsin, valsout)
+char *rname; /* requestors name */
+char *rinstance; /* requestors instance */
+char *rrealm; /* requestors realm */
+Kadm_vals *valsin;
+Kadm_vals *valsout;
+{
+ int numfound; /* check how many we get written */
+ krb5_boolean more; /* pointer to more grabbed records */
+ Principal data_i, data_o; /* temporary principal */
+ u_char flags[4];
+ krb5_db_entry entry, odata;
+ krb5_error_code retval;
+ krb5_principal inprinc;
+
+ if (!check_access(rname, rinstance, rrealm, DELACL)) {
+ (void) syslog(LOG_WARNING, "WARNING: '%s.%s@%s' tried to delete an entry for '%s.%s'",
+ rname, rinstance, rrealm, valsin->name, valsin->instance);
+ return KADM_UNAUTH;
+ }
+
+ /* Need to check here for "legal" name and instance */
+ if (wildcard(valsin->name) || wildcard(valsin->instance)) {
+ faildel(KADM_ILL_WILDCARD);
+ }
+
+ syslog(LOG_INFO, "request to delete an entry for '%s.%s' from '%s.%s@%s'",
+ valsin->name, valsin->instance, rname, rinstance, rrealm);
+
+ retval = krb5_425_conv_principal(kadm_context, valsin->name,
+ valsin->instance,
+ server_parm.krbrlm, &inprinc);
+ if (retval)
+ faildel(retval);
+
+ numfound = 1;
+ retval = krb5_db_get_principal(kadm_context, inprinc, &entry, &numfound,
+ &more);
+
+ if (retval) {
+ krb5_db_free_principal(kadm_context, &entry, numfound);
+ faildel(retval);
+ } else if (!numfound || more) {
+ faildel(KADM_NOENTRY);
+ }
+
+ retval = krb5_db_delete_principal(kadm_context, inprinc, &numfound);
+ if (retval) {
+ krb5_db_free_principal(kadm_context, &entry, numfound);
+ faildel(retval);
+ }
+ if (!numfound) {
+ krb5_db_free_principal(kadm_context, &entry, numfound);
+ faildel(KADM_UK_SERROR);
+ } else {
+ if (retval) {
+ faildel(retval);
+ } else if (numfound != 1 || more) {
+ krb5_db_free_principal(kadm_context, &entry, numfound);
+ faildel(KADM_UK_RERROR);
+ }
+ kadm_entry2princ(entry, &data_o);
+ krb5_db_free_principal(kadm_context, &entry, numfound);
+ memset((char *)flags, 0, sizeof(flags));
+ SET_FIELD(KADM_NAME,flags);
+ SET_FIELD(KADM_INST,flags);
+ SET_FIELD(KADM_EXPDATE,flags);
+ SET_FIELD(KADM_ATTR,flags);
+ SET_FIELD(KADM_MAXLIFE,flags);
+ kadm_prin_to_vals(flags, valsout, &data_o);
+ syslog(LOG_INFO, "'%s.%s' deleted.", valsin->name, valsin->instance);
+ return KADM_DATA; /* Set all the appropriate fields */
+ }
+}
+#undef faildel
+
+#define failget(code) { (void) syslog(LOG_ERR, "FAILED retrieving '%s.%s' (%s)", valsin->name, valsin->instance, error_message(code)); return code; }
+
+kadm_get_entry (rname, rinstance, rrealm, valsin, flags, valsout)
+char *rname; /* requestors name */
+char *rinstance; /* requestors instance */
+char *rrealm; /* requestors realm */
+Kadm_vals *valsin; /* what they wannt to get */
+u_char *flags; /* which fields we want */
+Kadm_vals *valsout; /* what data is there */
+{
+ int numfound; /* check how many were returned */
+ krb5_boolean more; /* To point to more name.instances */
+ Principal data_o; /* Data object to hold Principal */
+ krb5_principal inprinc;
+ krb5_db_entry entry;
+ krb5_error_code retval;
+
+ if (!check_access(rname, rinstance, rrealm, GETACL)) {
+ syslog(LOG_WARNING, "WARNING: '%s.%s@%s' tried to get '%s.%s's entry",
+ rname, rinstance, rrealm, valsin->name, valsin->instance);
+ return KADM_UNAUTH;
+ }
+
+ if (wildcard(valsin->name) || wildcard(valsin->instance)) {
+ failget(KADM_ILL_WILDCARD);
+ }
+
+ syslog(LOG_INFO, "retrieve '%s.%s's entry for '%s.%s@%s'",
+ valsin->name, valsin->instance, rname, rinstance, rrealm);
+
+ retval = krb5_425_conv_principal(kadm_context, valsin->name,
+ valsin->instance,
+ server_parm.krbrlm, &inprinc);
+ if (retval)
+ failget(retval);
+ /* Look up the record in the database */
+ numfound = 1;
+ retval = krb5_db_get_principal(kadm_context, inprinc, &entry, &numfound,
+ &more);
+ krb5_free_principal(kadm_context, inprinc);
+ if (retval) {
+ failget(retval);
+ } else if (!numfound || more) {
+ failget(KADM_NOENTRY);
+ }
+ retval = kadm_entry2princ(entry, &data_o);
+ krb5_db_free_principal(kadm_context, &entry, 1);
+ if (retval) {
+ failget(retval);
+ }
+ kadm_prin_to_vals(flags, valsout, &data_o);
+ syslog(LOG_INFO, "'%s.%s' retrieved.", valsin->name, valsin->instance);
+ return KADM_DATA; /* Set all the appropriate fields */
+}
+#undef failget
+
+#define failmod(code) { (void) syslog(LOG_ERR, "FAILED modifying '%s.%s' (%s)", valsin1->name, valsin1->instance, error_message(code)); return code; }
+
+kadm_mod_entry (rname, rinstance, rrealm, valsin1, valsin2, valsout)
+char *rname; /* requestors name */
+char *rinstance; /* requestors instance */
+char *rrealm; /* requestors realm */
+Kadm_vals *valsin1, *valsin2; /* holds the parameters being
+ passed in */
+Kadm_vals *valsout; /* the actual record which is returned */
+{
+ int numfound;
+ krb5_boolean more;
+ Principal data_o, temp_key;
+ u_char fields[4];
+ krb5_keyblock newpw;
+ krb5_error_code retval;
+ krb5_principal theprinc;
+ krb5_db_entry newentry, odata;
+ krb5_tl_mod_princ mprinc;
+ krb5_key_data *pkey;
+ krb5_keysalt sblock;
+
+ if (wildcard(valsin1->name) || wildcard(valsin1->instance)) {
+ failmod(KADM_ILL_WILDCARD);
+ }
+
+ if (!check_access(rname, rinstance, rrealm, MODACL)) {
+ syslog(LOG_WARNING, "WARNING: '%s.%s@%s' tried to change '%s.%s's entry",
+ rname, rinstance, rrealm, valsin1->name, valsin1->instance);
+ return KADM_UNAUTH;
+ }
+
+ syslog(LOG_INFO, "request to modify '%s.%s's entry from '%s.%s@%s' ",
+ valsin1->name, valsin1->instance, rname, rinstance, rrealm);
+ retval = krb5_425_conv_principal(kadm_context,
+ valsin1->name, valsin1->instance,
+ server_parm.krbrlm, &theprinc);
+ if (retval)
+ failmod(retval);
+ numfound = 1;
+ retval = krb5_db_get_principal(kadm_context, theprinc, &newentry,
+ &numfound, &more);
+ if (retval) {
+ krb5_free_principal(kadm_context, theprinc);
+ failmod(retval);
+ } else if (numfound == 1) {
+ kadm_vals_to_prin(valsin2->fields, &temp_key, valsin2);
+ krb5_free_principal(kadm_context, newentry.princ);
+ newentry.princ = theprinc;
+ if (IS_FIELD(KADM_EXPDATE,valsin2->fields))
+ newentry.expiration = temp_key.exp_date;
+ if (IS_FIELD(KADM_ATTR,valsin2->fields))
+ newentry.attributes = temp_key.attributes;
+ if (IS_FIELD(KADM_MAXLIFE,valsin2->fields))
+ newentry.max_life = temp_key.max_life;
+ if (IS_FIELD(KADM_DESKEY,valsin2->fields)) {
+ if ((newpw.contents = (krb5_octet *)malloc(8)) == NULL) {
+ krb5_db_free_principal(kadm_context, &newentry, 1);
+ memset((char *)&temp_key, 0, sizeof (temp_key));
+ failmod(KADM_NOMEM);
+ }
+ newpw.magic = KV5M_KEYBLOCK;
+ newpw.length = 8;
+ newpw.enctype = ENCTYPE_DES_CBC_CRC;
+ temp_key.key_low = ntohl(temp_key.key_low);
+ temp_key.key_high = ntohl(temp_key.key_high);
+ memcpy(newpw.contents, &temp_key.key_low, 4);
+ memcpy(newpw.contents + 4, &temp_key.key_high, 4);
+ if (retval = krb5_dbe_find_enctype(kadm_context,
+ &newentry,
+ ENCTYPE_DES_CBC_CRC,
+ KRB5_KDB_SALTTYPE_V4,
+ -1,
+ &pkey)) {
+ krb5_db_free_principal(kadm_context, &newentry, 1);
+ memset((char *)&temp_key, 0, sizeof (temp_key));
+ failmod(retval);
+ }
+ if (pkey->key_data_contents[0]) {
+ krb5_xfree(pkey->key_data_contents[0]);
+ pkey->key_data_contents[0] = (krb5_octet *) NULL;
+ }
+ /* encrypt new key in master key */
+ sblock.type = KRB5_KDB_SALTTYPE_V4;
+ sblock.data.length = 0;
+ sblock.data.data = (char *) NULL;
+ retval = krb5_dbekd_encrypt_key_data(kadm_context,
+ &server_parm.master_encblock,
+ &newpw,
+ &sblock,
+ (int) pkey->key_data_kvno+1,
+ pkey);
+ memset(newpw.contents, 0, newpw.length);
+ free(newpw.contents);
+ memset((char *)&temp_key, 0, sizeof(temp_key));
+ if (retval) {
+ krb5_db_free_principal(kadm_context, &newentry, 1);
+ failmod(retval);
+ }
+ }
+ if (retval = krb5_timeofday(kadm_context, &mprinc.mod_date)) {
+ krb5_db_free_principal(kadm_context, &newentry, 1);
+ failmod(retval);
+ }
+ retval = krb5_425_conv_principal(kadm_context, rname, rinstance, rrealm,
+ &mprinc.mod_princ);
+ if (retval) {
+ krb5_db_free_principal(kadm_context, &newentry, 1);
+ failmod(retval);
+ }
+
+ retval = krb5_dbe_encode_mod_princ_data(kadm_context,
+ &mprinc,
+ &newentry);
+ krb5_free_principal(kadm_context, mprinc.mod_princ);
+ if (retval) {
+ krb5_db_free_principal(kadm_context, &newentry, 1);
+ failmod(retval);
+ }
+
+ numfound = 1;
+ retval = krb5_db_put_principal(kadm_context, &newentry, &numfound);
+ memset((char *)&data_o, 0, sizeof(data_o));
+ if (retval) {
+ krb5_db_free_principal(kadm_context, &newentry, 1);
+ failmod(retval);
+ } else {
+ numfound = 1;
+ retval = krb5_db_get_principal(kadm_context, newentry.princ, &odata,
+ &numfound, &more);
+ krb5_db_free_principal(kadm_context, &newentry, 1);
+ if (retval) {
+ failmod(retval);
+ } else if (numfound != 1 || more) {
+ krb5_db_free_principal(kadm_context, &odata, numfound);
+ failmod(KADM_UK_RERROR);
+ }
+ retval = kadm_entry2princ(odata, &data_o);
+ krb5_db_free_principal(kadm_context, &odata, 1);
+ if (retval)
+ failmod(retval);
+ memset((char *) fields, 0, sizeof(fields));
+ SET_FIELD(KADM_NAME,fields);
+ SET_FIELD(KADM_INST,fields);
+ SET_FIELD(KADM_EXPDATE,fields);
+ SET_FIELD(KADM_ATTR,fields);
+ SET_FIELD(KADM_MAXLIFE,fields);
+ kadm_prin_to_vals(fields, valsout, &data_o);
+ syslog(LOG_INFO, "'%s.%s' modified.", valsin1->name, valsin1->instance);
+ return KADM_DATA; /* Set all the appropriate fields */
+ }
+ } else {
+ failmod(KADM_NOENTRY);
+ }
+}
+#undef failmod
+
+#define failchange(code) { syslog(LOG_ERR, "FAILED changing key for '%s.%s@%s' (%s)", rname, rinstance, rrealm, error_message(code)); return code; }
+
+kadm_change (rname, rinstance, rrealm, newpw)
+char *rname;
+char *rinstance;
+char *rrealm;
+des_cblock newpw;
+{
+ int numfound;
+ krb5_boolean more;
+ krb5_principal rprinc;
+ krb5_error_code retval;
+ krb5_keyblock localpw;
+ krb5_db_entry odata;
+ krb5_key_data *pkey;
+ krb5_keysalt sblock;
+
+ if (strcmp(server_parm.krbrlm, rrealm)) {
+ syslog(LOG_ERR, "change key request from wrong realm, '%s.%s@%s'!\n",
+ rname, rinstance, rrealm);
+ return(KADM_WRONG_REALM);
+ }
+
+ if (wildcard(rname) || wildcard(rinstance)) {
+ failchange(KADM_ILL_WILDCARD);
+ }
+ syslog(LOG_INFO, "'%s.%s@%s' wants to change its password",
+ rname, rinstance, rrealm);
+ retval = krb5_425_conv_principal(kadm_context, rname, rinstance,
+ server_parm.krbrlm, &rprinc);
+ if (retval)
+ failchange(retval);
+ if ((localpw.contents = (krb5_octet *)malloc(8)) == NULL)
+ failchange(KADM_NOMEM);
+ memcpy(localpw.contents, newpw, 8);
+ localpw.magic = KV5M_KEYBLOCK;
+ localpw.enctype = ENCTYPE_DES_CBC_CRC;
+ localpw.length = 8;
+ numfound = 1;
+ retval = krb5_db_get_principal(kadm_context, rprinc, &odata,
+ &numfound, &more);
+ krb5_free_principal(kadm_context, rprinc);
+ if (retval) {
+ memset(localpw.contents, 0, localpw.length);
+ free(localpw.contents);
+ failchange(retval);
+ } else if (numfound == 1) {
+ if (retval = krb5_dbe_find_enctype(kadm_context,
+ &odata,
+ ENCTYPE_DES_CBC_CRC,
+ KRB5_KDB_SALTTYPE_V4,
+ -1,
+ &pkey)) {
+ failchange(retval);
+ }
+ pkey->key_data_kvno++;
+ pkey->key_data_kvno %= 256;
+ numfound = 1;
+ sblock.type = KRB5_KDB_SALTTYPE_V4;
+ sblock.data.length = 0;
+ sblock.data.data = (char *) NULL;
+ retval = krb5_dbekd_encrypt_key_data(kadm_context,
+ &server_parm.master_encblock,
+ &localpw,
+ &sblock,
+ (int) pkey->key_data_kvno,
+ pkey);
+ memset(localpw.contents, 0, localpw.length);
+ free(localpw.contents);
+ if (retval) {
+ failchange(retval);
+ }
+ retval = krb5_db_put_principal(kadm_context, &odata, &numfound);
+ krb5_db_free_principal(kadm_context, &odata, 1);
+ if (retval) {
+ failchange(retval);
+ } else if (more) {
+ failchange(KADM_UK_SERROR);
+ } else {
+ syslog(LOG_INFO,
+ "'%s.%s@%s' password changed.", rname, rinstance, rrealm);
+ return KADM_SUCCESS;
+ }
+ }
+ else {
+ failchange(KADM_NOENTRY);
+ }
+}
+#undef failchange
+
+check_pw(newpw, checkstr)
+ des_cblock newpw;
+ char *checkstr;
+{
+#ifdef NOENCRYPTION
+ return 0;
+#else /* !NOENCRYPTION */
+ des_cblock checkdes;
+
+ (void) des_string_to_key(checkstr, checkdes);
+ return(!memcmp(checkdes, newpw, sizeof(des_cblock)));
+#endif /* NOENCRYPTION */
+}
+
+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);
+}
+
+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);
+}
+
+des_check_gecos(gecos, newpw)
+ char *gecos;
+ des_cblock newpw;
+{
+ 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 (check_pw(newpw, cp))
+ return(KADM_INSECURE_PW);
+ tcp = reverse(cp);
+ if (check_pw(newpw, tcp))
+ return(KADM_INSECURE_PW);
+ if (lower(cp)) {
+ if (check_pw(newpw, cp))
+ return(KADM_INSECURE_PW);
+ tcp = reverse(cp);
+ if (check_pw(newpw, tcp))
+ return(KADM_INSECURE_PW);
+ }
+ cp = ncp;
+ } else
+ break;
+ }
+ return(0);
+}
+
+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(KADM_INSECURE_PW);
+ tcp = reverse(cp);
+ if (!strcasecmp(pwstr, tcp))
+ return(KADM_INSECURE_PW);
+ cp = ncp;
+ } else
+ break;
+ }
+ return(0);
+}
+
+
+kadm_approve_pw(rname, rinstance, rrealm, newpw, pwstring)
+char *rname;
+char *rinstance;
+char *rrealm;
+des_cblock newpw;
+char *pwstring;
+{
+ static DBM *pwfile = NULL;
+ int retval;
+ datum passwd, entry;
+ struct passwd *ent;
+#ifdef HESIOD
+ extern struct passwd *hes_getpwnam();
+#endif
+
+ if (pwstring && !check_pw(newpw, pwstring))
+ /*
+ * Someone's trying to toy with us....
+ */
+ return(KADM_PW_MISMATCH);
+ if (pwstring && (strlen(pwstring) < 5))
+ return(KADM_INSECURE_PW);
+ if (!pwfile) {
+ pwfile = dbm_open(PW_CHECK_FILE, O_RDONLY, 0644);
+ }
+ if (pwfile) {
+ passwd.dptr = (char *) newpw;
+ passwd.dsize = 8;
+ entry = dbm_fetch(pwfile, passwd);
+ if (entry.dptr)
+ return(KADM_INSECURE_PW);
+ }
+ if (check_pw(newpw, rname) || check_pw(newpw, reverse(rname)))
+ return(KADM_INSECURE_PW);
+#ifdef HESIOD
+ ent = hes_getpwnam(rname);
+#else
+ ent = getpwnam(rname);
+#endif
+ if (ent && ent->pw_gecos) {
+ if (pwstring)
+ retval = str_check_gecos(ent->pw_gecos, pwstring);
+ else
+ retval = des_check_gecos(ent->pw_gecos, newpw);
+ if (retval)
+ return(retval);
+ }
+ return(0);
+}
+
+/*
+ * This routine checks to see if a principal should be considered an
+ * allowable service name which can be changed by kadm_change_srvtab.
+ *
+ * We do this check by using the ACL library. This makes the
+ * (relatively) reasonable assumption that both the name and the
+ * instance will not contain '.' or '@'.
+ */
+kadm_check_srvtab(name, instance)
+ char *name;
+ char *instance;
+{
+ char filename[MAXPATHLEN];
+ extern char *acldir;
+
+ (void) sprintf(filename, "%s%s", acldir, STAB_SERVICES_FILE);
+ if (!acl_check(filename, name))
+ return(KADM_NOT_SERV_PRINC);
+
+ (void) sprintf(filename, "%s%s", acldir, STAB_HOSTS_FILE);
+ if (acl_check(filename, instance))
+ return(KADM_NOT_SERV_PRINC);
+ return 0;
+}
+
+/*
+ * Routine to allow some people to change the key of a srvtab
+ * principal to a random key, which the admin server will return to
+ * the client.
+ */
+#define failsrvtab(code) { syslog(LOG_ERR, "change_srvtab: FAILED changing '%s.%s' by '%s.%s@%s' (%s)", values->name, values->instance, rname, rinstance, rrealm, error_message(code)); return code; }
+
+kadm_chg_srvtab(rname, rinstance, rrealm, values)
+ char *rname; /* requestors name */
+ char *rinstance; /* requestors instance */
+ char *rrealm; /* requestors realm */
+ Kadm_vals *values;
+{
+ int numfound, ret, isnew = 0;
+ des_cblock new_key;
+ krb5_principal inprinc;
+ krb5_error_code retval;
+ krb5_db_entry odata;
+ krb5_boolean more;
+ krb5_keyblock newpw;
+ krb5_key_data *pkey;
+
+ if (!check_access(rname, rinstance, rrealm, STABACL))
+ failsrvtab(KADM_UNAUTH);
+ if (wildcard(rname) || wildcard(rinstance))
+ failsrvtab(KADM_ILL_WILDCARD);
+ if (ret = kadm_check_srvtab(values->name, values->instance))
+ failsrvtab(ret);
+
+ retval = krb5_425_conv_principal(kadm_context, values->name,
+ values->instance,
+ server_parm.krbrlm, &inprinc);
+ if (retval)
+ failsrvtab(retval);
+ /*
+ * OK, get the entry
+ */
+ numfound = 1;
+ retval = krb5_db_get_principal(kadm_context, inprinc, &odata,
+ &numfound, &more);
+ if (retval) {
+ krb5_free_principal(kadm_context, inprinc);
+ failsrvtab(retval);
+ } else if (numfound) {
+ retval = krb5_dbe_find_enctype(kadm_context,
+ &odata,
+ ENCTYPE_DES_CBC_CRC,
+ KRB5_KDB_SALTTYPE_V4,
+ -1,
+ &pkey);
+ if (retval) {
+ krb5_free_principal(kadm_context, inprinc);
+ failsrvtab(retval);
+ }
+ }
+ else {
+ /*
+ * This is a new srvtab entry that we're creating
+ */
+ isnew = 1;
+ memset((char *)&odata, 0, sizeof (odata));
+ odata.princ = inprinc;
+ odata.max_life = server_parm.max_life;
+ odata.max_renewable_life = server_parm.max_rlife;
+ odata.expiration = server_parm.expiration;
+ odata.attributes = 0;
+ if (!krb5_dbe_create_key_data(kadm_context, &odata)) {
+ pkey = &odata.key_data[0];
+ memset(pkey, 0, sizeof(*pkey));
+ pkey->key_data_ver = 2;
+ pkey->key_data_type[0] = ENCTYPE_DES_CBC_CRC;
+ pkey->key_data_type[1] = KRB5_KDB_SALTTYPE_V4;
+ }
+ }
+ pkey->key_data_kvno++;
+
+#ifdef NOENCRYPTION
+ memset(new_key, 0, sizeof(new_key));
+ new_key[0] = 127;
+#else
+ des_new_random_key(new_key);
+#endif
+ /*
+ * Store the new key in the return structure; also fill in the
+ * rest of the fields.
+ */
+ if ((newpw.contents = (krb5_octet *)malloc(8)) == NULL) {
+ krb5_db_free_principal(kadm_context, &odata, 1);
+ failsrvtab(KADM_NOMEM);
+ }
+ newpw.enctype = ENCTYPE_DES_CBC_CRC;
+ newpw.length = 8;
+ memcpy((char *)newpw.contents, new_key, 8);
+ memset((char *)new_key, 0, sizeof (new_key));
+ memcpy((char *)&values->key_low, newpw.contents, 4);
+ memcpy((char *)&values->key_high, newpw.contents + 4, 4);
+ values->key_low = htonl(values->key_low);
+ values->key_high = htonl(values->key_high);
+ values->max_life = odata.max_life / (60 * 5);
+ values->exp_date = odata.expiration;
+ values->attributes = odata.attributes;
+ memset(values->fields, 0, sizeof(values->fields));
+ SET_FIELD(KADM_NAME, values->fields);
+ SET_FIELD(KADM_INST, values->fields);
+ SET_FIELD(KADM_EXPDATE, values->fields);
+ SET_FIELD(KADM_ATTR, values->fields);
+ SET_FIELD(KADM_MAXLIFE, values->fields);
+ SET_FIELD(KADM_DESKEY, values->fields);
+
+ /*
+ * Encrypt the new key with the master key, and then update
+ * the database record
+ */
+ retval = krb5_dbekd_encrypt_key_data(kadm_context,
+ &server_parm.master_encblock,
+ &newpw,
+ (krb5_keysalt *) NULL,
+ (int) pkey->key_data_kvno,
+ pkey);
+ memset((char *)newpw.contents, 0, 8);
+ free(newpw.contents);
+ if (retval) {
+ krb5_db_free_principal(kadm_context, &odata, 1);
+ failsrvtab(retval);
+ }
+ numfound = 1;
+ retval = krb5_db_put_principal(kadm_context, &odata, &numfound);
+ krb5_db_free_principal(kadm_context, &odata, 1);
+ if (retval) {
+ failsrvtab(retval);
+ }
+ else if (!numfound) {
+ failsrvtab(KADM_UK_SERROR);
+ } else {
+ syslog(LOG_INFO, "change_srvtab: service '%s.%s' %s by %s.%s@%s.",
+ values->name, values->instance,
+ numfound ? "changed" : "created",
+ rname, rinstance, rrealm);
+ return KADM_DATA;
+ }
+}
+
+#undef failsrvtab
diff --git a/src/kadmin/v4server/kadm_ser_wrap.c b/src/kadmin/v4server/kadm_ser_wrap.c
new file mode 100644
index 0000000000..5e7f485083
--- /dev/null
+++ b/src/kadmin/v4server/kadm_ser_wrap.c
@@ -0,0 +1,310 @@
+/*
+ * kadmin/v4server/kadm_ser_wrap.c
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * Kerberos administration server-side support functions
+ */
+
+
+#include <mit-copyright.h>
+/*
+kadm_ser_wrap.c
+unwraps wrapped packets and calls the appropriate server subroutine
+*/
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include "kadm_server.h"
+#include <kadm.h>
+#include <kadm_err.h>
+#include <krb_err.h>
+#include <syslog.h>
+
+#ifdef OVSEC_KADM
+#include <kadm5/admin.h>
+extern void *ovsec_handle;
+#endif
+
+Kadm_Server server_parm;
+
+/*
+kadm_ser_init
+set up the server_parm structure
+*/
+#ifdef OVSEC_KADM
+kadm_ser_init(inter, realm, params)
+ int inter; /* interactive or from file */
+ char realm[];
+ kadm5_config_params *params;
+#else
+kadm_ser_init(inter, realm)
+ int inter; /* interactive or from file */
+ char realm[];
+#endif
+{
+ struct servent *sep;
+ struct hostent *hp;
+ char hostname[MAXHOSTNAMELEN];
+ char *mkey_name;
+ krb5_error_code retval;
+ int numfound = 1;
+ krb5_boolean more;
+ krb5_db_entry master_entry;
+ krb5_key_data *kdatap;
+
+ if (gethostname(hostname, sizeof(hostname)))
+ return KADM_NO_HOSTNAME;
+
+ (void) strcpy(server_parm.sname, PWSERV_NAME);
+ (void) strcpy(server_parm.sinst, KRB_MASTER);
+ (void) strcpy(server_parm.krbrlm, realm);
+ if (krb5_build_principal(kadm_context,
+ &server_parm.sprinc,
+ strlen(realm),
+ realm,
+ PWSERV_NAME,
+ KRB_MASTER, 0))
+ return KADM_NO_MAST;
+ server_parm.admin_fd = -1;
+ /* setting up the addrs */
+ if ((sep = getservbyname(KADM_SNAME, "tcp")) == NULL)
+ return KADM_NO_SERV;
+ memset((char *)&server_parm.admin_addr, 0,sizeof(server_parm.admin_addr));
+ server_parm.admin_addr.sin_family = AF_INET;
+ if ((hp = gethostbyname(hostname)) == NULL)
+ return KADM_NO_HOSTNAME;
+ memcpy((char *) &server_parm.admin_addr.sin_addr.s_addr, hp->h_addr,
+ hp->h_length);
+ server_parm.admin_addr.sin_port = sep->s_port;
+ /* setting up the database */
+ mkey_name = KRB5_KDB_M_NAME;
+
+#ifdef OVSEC_KADM
+ server_parm.master_keyblock.enctype = params->enctype;
+ krb5_use_enctype(kadm_context, &server_parm.master_encblock,
+ server_parm.master_keyblock.enctype);
+#else
+ if (inter == 1) {
+ server_parm.master_keyblock.enctype = ENCTYPE_DES_CBC_MD5;
+ krb5_use_enctype(kadm_context, &server_parm.master_encblock,
+ server_parm.master_keyblock.enctype);
+ } else
+ server_parm.master_keyblock.enctype = ENCTYPE_UNKNOWN;
+#endif
+
+ retval = krb5_db_setup_mkey_name(kadm_context, mkey_name, realm,
+ (char **) 0,
+ &server_parm.master_princ);
+ if (retval)
+ return KADM_NO_MAST;
+ krb5_db_fetch_mkey(kadm_context, server_parm.master_princ,
+ &server_parm.master_encblock,
+ (inter == 1), FALSE,
+#ifdef OVSEC_KADM
+ params->stash_file,
+#else
+ (char *) NULL,
+#endif
+ NULL,
+ &server_parm.master_keyblock);
+ if (retval)
+ return KADM_NO_MAST;
+ retval = krb5_db_verify_master_key(kadm_context, server_parm.master_princ,
+ &server_parm.master_keyblock,
+ &server_parm.master_encblock);
+ if (retval)
+ return KADM_NO_VERI;
+ retval = krb5_process_key(kadm_context, &server_parm.master_encblock,
+ &server_parm.master_keyblock);
+ if (retval)
+ return KADM_NO_VERI;
+ retval = krb5_db_get_principal(kadm_context, server_parm.master_princ,
+ &master_entry, &numfound, &more);
+ if (retval || more || !numfound)
+ return KADM_NO_VERI;
+
+ retval = krb5_dbe_find_enctype(kadm_context,
+ &master_entry,
+ -1, -1, -1,
+ &kdatap);
+ if (retval)
+ return KRB5_PROG_KEYTYPE_NOSUPP;
+ server_parm.max_life = master_entry.max_life;
+ server_parm.max_rlife = master_entry.max_renewable_life;
+ server_parm.expiration = master_entry.expiration;
+ server_parm.mkvno = kdatap->key_data_kvno;
+ /* don't set flags, as master has some extra restrictions
+ (??? quoted from kdb_edit.c) */
+ krb5_db_free_principal(kadm_context, &master_entry, numfound);
+ return KADM_SUCCESS;
+}
+
+
+static void errpkt(dat, dat_len, code)
+u_char **dat;
+int *dat_len;
+int code;
+{
+ krb5_ui_4 retcode;
+ char *pdat;
+
+ free((char *)*dat); /* free up req */
+ *dat_len = KADM_VERSIZE + sizeof(krb5_ui_4);
+ *dat = (u_char *) malloc((unsigned)*dat_len);
+ if (!(*dat)) {
+ syslog(LOG_ERR, "malloc(%d) returned null while in errpkt!", *dat_len);
+ abort();
+ }
+ pdat = (char *) *dat;
+ retcode = htonl((krb5_ui_4) code);
+ (void) strncpy(pdat, KADM_ULOSE, KADM_VERSIZE);
+ memcpy(&pdat[KADM_VERSIZE], (char *)&retcode, sizeof(krb5_ui_4));
+ return;
+}
+
+/*
+kadm_ser_in
+unwrap the data stored in dat, process, and return it.
+*/
+kadm_ser_in(dat,dat_len)
+u_char **dat;
+int *dat_len;
+{
+ u_char *in_st; /* pointer into the sent packet */
+ int in_len,retc; /* where in packet we are, for
+ returns */
+ krb5_ui_4 r_len; /* length of the actual packet */
+ KTEXT_ST authent; /* the authenticator */
+ AUTH_DAT ad; /* who is this, klink */
+ krb5_ui_4 ncksum; /* checksum of encrypted data */
+ des_key_schedule sess_sched; /* our schedule */
+ MSG_DAT msg_st;
+ u_char *retdat, *tmpdat;
+ int retval, retlen;
+
+ if (strncmp(KADM_VERSTR, (char *)*dat, KADM_VERSIZE)) {
+ errpkt(dat, dat_len, KADM_BAD_VER);
+ return KADM_BAD_VER;
+ }
+ in_len = KADM_VERSIZE;
+ /* get the length */
+ if ((retc = stv_long(*dat, &r_len, in_len, *dat_len)) < 0)
+ return KADM_LENGTH_ERROR;
+ in_len += retc;
+ authent.length = *dat_len - r_len - KADM_VERSIZE - sizeof(krb5_ui_4);
+ memcpy((char *)authent.dat, (char *)(*dat) + in_len, authent.length);
+ authent.mbz = 0;
+ /* service key should be set before here */
+ if (retc = krb_rd_req(&authent, server_parm.sname, server_parm.sinst,
+ server_parm.recv_addr.sin_addr.s_addr, &ad, (char *)0))
+ {
+ errpkt(dat, dat_len,retc + krb_err_base);
+ return retc + krb_err_base;
+ }
+
+#define clr_cli_secrets() {memset((char *)sess_sched, 0, sizeof(sess_sched)); memset((char *)ad.session, 0, sizeof(ad.session));}
+
+ in_st = *dat + *dat_len - r_len;
+#ifdef NOENCRYPTION
+ ncksum = 0;
+#else
+ ncksum = quad_cksum(in_st, (krb5_ui_4 *)0, (long) r_len, 0, ad.session);
+#endif
+ if (ncksum!=ad.checksum) { /* yow, are we correct yet */
+ clr_cli_secrets();
+ errpkt(dat, dat_len,KADM_BAD_CHK);
+ return KADM_BAD_CHK;
+ }
+#ifdef NOENCRYPTION
+ memset(sess_sched, 0, sizeof(sess_sched));
+#else
+ des_key_sched(ad.session, sess_sched);
+#endif
+ if (retc = (int) krb_rd_priv(in_st, r_len, sess_sched, ad.session,
+ &server_parm.recv_addr,
+ &server_parm.admin_addr, &msg_st)) {
+ clr_cli_secrets();
+ errpkt(dat, dat_len,retc + krb_err_base);
+ return retc + krb_err_base;
+ }
+ switch (msg_st.app_data[0]) {
+ case CHANGE_PW:
+ retval = kadm_ser_cpw(msg_st.app_data+1,(int) msg_st.app_length,&ad,
+ &retdat, &retlen);
+ break;
+#ifndef OVSEC_KADM
+ case ADD_ENT:
+ retval = kadm_ser_add(msg_st.app_data+1,(int) msg_st.app_length,&ad,
+ &retdat, &retlen);
+ break;
+ case DEL_ENT:
+ retval = kadm_ser_del(msg_st.app_data+1,(int) msg_st.app_length,&ad,
+ &retdat, &retlen);
+ break;
+ case GET_ENT:
+ retval = kadm_ser_get(msg_st.app_data+1,(int) msg_st.app_length,&ad,
+ &retdat, &retlen);
+ break;
+ case MOD_ENT:
+ retval = kadm_ser_mod(msg_st.app_data+1,(int) msg_st.app_length,&ad,
+ &retdat, &retlen);
+ break;
+ case CHECK_PW:
+ retval = kadm_ser_ckpw(msg_st.app_data+1,(int) msg_st.app_length,&ad,
+ &retdat, &retlen);
+ break;
+ case CHG_STAB:
+ retval = kadm_ser_stab(msg_st.app_data+1,(int) msg_st.app_length,&ad,
+ &retdat, &retlen);
+ break;
+#endif /* OVSEC_KADM */
+ default:
+ clr_cli_secrets();
+ errpkt(dat, dat_len, KADM_NO_OPCODE);
+ return KADM_NO_OPCODE;
+ }
+ /* Now seal the response back into a priv msg */
+ free((char *)*dat);
+ tmpdat = (u_char *) malloc((unsigned)(retlen + KADM_VERSIZE +
+ sizeof(krb5_ui_4)));
+ if (!tmpdat) {
+ clr_cli_secrets();
+ syslog(LOG_ERR, "malloc(%d) returned null while in kadm_ser_in!",
+ retlen + KADM_VERSIZE + sizeof(krb5_ui_4));
+ errpkt(dat, dat_len, KADM_NOMEM);
+ return KADM_NOMEM;
+ }
+ (void) strncpy((char *)tmpdat, KADM_VERSTR, KADM_VERSIZE);
+ retval = htonl((krb5_ui_4)retval);
+ memcpy((char *)tmpdat + KADM_VERSIZE, (char *)&retval, sizeof(krb5_ui_4));
+ if (retlen) {
+ memcpy((char *)tmpdat + KADM_VERSIZE + sizeof(krb5_ui_4), (char *)retdat,
+ retlen);
+ free((char *)retdat);
+ }
+ /* slop for mk_priv stuff */
+ *dat = (u_char *) malloc((unsigned) (retlen + KADM_VERSIZE +
+ sizeof(krb5_ui_4) + 200));
+ if ((*dat_len = krb_mk_priv(tmpdat, *dat,
+ (u_long) (retlen + KADM_VERSIZE +
+ sizeof(krb5_ui_4)),
+ sess_sched,
+ ad.session, &server_parm.admin_addr,
+ &server_parm.recv_addr)) < 0) {
+ clr_cli_secrets();
+ errpkt(dat, dat_len, KADM_NO_ENCRYPT);
+ return KADM_NO_ENCRYPT;
+ }
+ clr_cli_secrets();
+ return KADM_SUCCESS;
+}
diff --git a/src/kadmin/v4server/kadm_server.c b/src/kadmin/v4server/kadm_server.c
new file mode 100644
index 0000000000..81e43f128f
--- /dev/null
+++ b/src/kadmin/v4server/kadm_server.c
@@ -0,0 +1,571 @@
+/*
+ * kadmin/v4server/kadm_server.c
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * Kerberos administration server-side subroutines
+ */
+
+
+#include <mit-copyright.h>
+
+#include "k5-int.h"
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#ifdef TIME_WITH_SYS_TIME
+#include <time.h>
+#endif
+#else
+#include <time.h>
+#endif
+
+#ifdef OVSEC_KADM
+#include <com_err.h>
+#include <kadm5/admin.h>
+#include <kadm5/chpass_util_strings.h>
+#include <krb5/kdb.h>
+extern void *ovsec_handle;
+#endif
+
+#include <kadm.h>
+#include <kadm_err.h>
+
+extern krb5_context kadm_context;
+int fascist_cpw = 0; /* Be fascist about insecure passwords? */
+
+#ifdef OVSEC_KADM
+char pw_required[] = "The version of kpasswd that you are using is not compatible with the\nOpenV*Secure V4 Administration Server. Please contact your security\nadministrator.\n\n";
+
+#else /* !OVSEC_KADM */
+
+char bad_pw_err[] =
+ "\007\007\007ERROR: Insecure password not accepted. Please choose another.\n\n";
+
+char bad_pw_warn[] =
+ "\007\007\007WARNING: You have chosen an insecure password. You may wish to\nchoose a better password.\n\n";
+
+char check_pw_msg[] =
+ "You have entered an insecure password. You should choose another.\n\n";
+
+char pw_blurb[] =
+"A good password is something which is easy for you to remember, but that\npeople who know you won't easily guess; so don't use your name, or your\ndog's name, or a word from the dictionary. Passwords should be at least\n6 characters long, and may contain UPPER- and lower-case letters,\nnumbers, or punctuation. A good password can be:\n\n -- some initials, like \"GykoR-66\" for \"Get your kicks on Rte 66.\"\n -- an easily pronounced nonsense word, like \"slaRooBey\" or \"krang-its\"\n -- a mis-spelled phrase, like \"2HotPeetzas\" or \"ItzAGurl\"\n\nPlease Note: It is important that you do not tell ANYONE your password,\nincluding your friends, or even people from Athena or Information\nSystems. Remember, *YOU* are assumed to be responsible for anything\ndone using your password.\n";
+
+#endif /* OVSEC_KADM */
+
+/* from V4 month_sname.c -- was not part of API */
+/*
+ * 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.
+ */
+
+static char *month_sname(n)
+ int n;
+{
+ static char *name[] = {
+ "Jan","Feb","Mar","Apr","May","Jun",
+ "Jul","Aug","Sep","Oct","Nov","Dec"
+ };
+ return((n < 1 || n > 12) ? 0 : name [n-1]);
+}
+
+/* from V4 log.c -- was not part of API */
+
+/*
+ * 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.
+ */
+
+/* static char *log_name = KRBLOG; */
+/* KRBLOG is in the V4 klog.h but may not correspond to anything installed. */
+static char *log_name = KADM_SYSLOG;
+
+static void krb_log(format,a1,a2,a3,a4,a5,a6,a7,a8,a9,a0)
+ char *format;
+ char *a1,*a2,*a3,*a4,*a5,*a6,*a7,*a8,*a9,*a0;
+{
+ FILE *logfile;
+ time_t now;
+ struct tm *tm;
+
+ if ((logfile = fopen(log_name,"a")) == NULL)
+ return;
+
+ (void) time(&now);
+ tm = localtime(&now);
+
+ fprintf(logfile,"%2d-%s-%02d %02d:%02d:%02d ",tm->tm_mday,
+ month_sname(tm->tm_mon + 1),tm->tm_year,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+ fprintf(logfile,format,a1,a2,a3,a4,a5,a6,a7,a8,a9,a0);
+ fprintf(logfile,"\n");
+ (void) fclose(logfile);
+ return;
+}
+
+
+/*
+kadm_ser_cpw - the server side of the change_password routine
+ recieves : KTEXT, {key}
+ returns : CKSUM, RETCODE
+ acl : caller can change only own password
+
+Replaces the password (i.e. des key) of the caller with that specified in key.
+Returns no actual data from the master server, since this is called by a user
+*/
+kadm_ser_cpw(dat, len, ad, datout, outlen)
+u_char *dat;
+int len;
+AUTH_DAT *ad;
+u_char **datout;
+int *outlen;
+{
+ krb5_int32 keylow, keyhigh;
+ char pword[MAX_KPW_LEN];
+ int no_pword = 0;
+ des_cblock newkey;
+ int status, stvlen = 0;
+ int retval;
+ extern int kadm_approve_pw();
+#ifdef OVSEC_KADM
+ ovsec_kadm_principal_ent_t princ_ent;
+ ovsec_kadm_policy_ent_t pol_ent;
+ krb5_principal user_princ;
+ char msg_ret[1024], *time_string, *ptr;
+ const char *msg_ptr;
+ krb5_int32 now;
+ time_t until;
+#endif
+
+ /* take key off the stream, and change the database */
+
+ if ((status = stv_long(dat, &keyhigh, 0, len)) < 0)
+ return(KADM_LENGTH_ERROR);
+ stvlen += status;
+ if ((status = stv_long(dat, &keylow, stvlen, len)) < 0)
+ return(KADM_LENGTH_ERROR);
+ stvlen += status;
+ if ((stvlen = stv_string(dat, pword, stvlen, sizeof(pword), len)) < 0) {
+ no_pword++;
+ pword[0]='\0';
+ }
+ stvlen += status;
+
+ keylow = ntohl(keylow);
+ keyhigh = ntohl(keyhigh);
+ memcpy((char *)(((krb5_int32 *)newkey) + 1), (char *)&keyhigh, 4);
+ memcpy((char *)newkey, (char *)&keylow, 4);
+
+#ifdef OVSEC_KADM
+ /* we don't use the client-provided key itself */
+ keylow = keyhigh = 0;
+ memset(newkey, 0, sizeof(newkey));
+
+ if (no_pword) {
+ krb_log("Old-style change password request from '%s.%s@%s'!",
+ ad->pname, ad->pinst, ad->prealm);
+ *outlen = strlen(pw_required)+1;
+ if (*datout = (u_char *) malloc(*outlen)) {
+ strcpy(*datout, pw_required);
+ } else {
+ *outlen = 0;
+ }
+ return KADM_INSECURE_PW;
+ }
+
+ if (krb5_build_principal(kadm_context, &user_princ,
+ strlen(ad->prealm),
+ ad->prealm,
+ ad->pname,
+ *ad->pinst ? ad->pinst : 0, 0))
+ /* this should never happen */
+ return KADM_NOENTRY;
+
+ *outlen = 0;
+
+ if (retval = krb5_timeofday(kadm_context, &now)) {
+ msg_ptr = error_message(retval);
+ goto send_response;
+ }
+
+ retval = ovsec_kadm_get_principal(ovsec_handle, user_princ,
+ &princ_ent);
+ if (retval != 0) {
+ msg_ptr = error_message(retval);
+ goto send_response;
+ }
+
+ /*
+ * This daemon necessarily has the modify privilege, so
+ * ovsec_kadm_chpass_principal will allow it to violate the
+ * policy's minimum lifetime. Since that's A Bad Thing, we need
+ * to enforce it ourselves. Unfortunately, this means we are
+ * duplicating code from both ovsec_adm_server and
+ * ovsec_kadm_chpass_util().
+ */
+ if (princ_ent->aux_attributes & OVSEC_KADM_POLICY) {
+ retval = ovsec_kadm_get_policy(ovsec_handle,
+ princ_ent->policy,
+ &pol_ent);
+ if (retval != 0) {
+ (void) ovsec_kadm_free_principal_ent(ovsec_handle, princ_ent);
+ msg_ptr = error_message(retval);
+ goto send_response;
+ }
+
+ /* make "now" a boolean, true == too soon */
+ now = ((now - princ_ent->last_pwd_change) < pol_ent->pw_min_life);
+
+ (void) ovsec_kadm_free_policy_ent(ovsec_handle, pol_ent);
+
+ if(now && !(princ_ent->attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
+ (void) ovsec_kadm_free_principal_ent(ovsec_handle, princ_ent);
+ retval = CHPASS_UTIL_PASSWORD_TOO_SOON;
+
+ until = princ_ent->last_pwd_change + pol_ent->pw_min_life;
+ time_string = ctime(&until);
+
+ if (*(ptr = &time_string[strlen(time_string)-1]) == '\n')
+ *ptr = '\0';
+
+ sprintf(msg_ret, error_message(CHPASS_UTIL_PASSWORD_TOO_SOON),
+ time_string);
+ msg_ptr = msg_ret;
+
+ goto send_response;
+ }
+ }
+
+ (void) ovsec_kadm_free_principal_ent(ovsec_handle, princ_ent);
+
+ retval = ovsec_kadm_chpass_principal_util(ovsec_handle, user_princ,
+ pword, NULL, msg_ret);
+ msg_ptr = msg_ret;
+ (void) krb5_free_principal(kadm_context, user_princ);
+
+send_response:
+
+ retval = convert_ovsec_to_kadm(retval);
+
+ if (retval) {
+ /* don't send message on success because kpasswd.v4 will */
+ /* print "password changed" too */
+ *outlen = strlen(msg_ptr)+2;
+ if (*datout = (u_char *) malloc(*outlen)) {
+ strcpy(*datout, msg_ptr);
+ strcat(*datout, "\n");
+ } else
+ *outlen = 0;
+ }
+ if (retval == KADM_INSECURE_PW) {
+ krb_log("'%s.%s@%s' tried to use an insecure password in changepw",
+ ad->pname, ad->pinst, ad->prealm);
+ }
+#else /* OVSEC_KADM */
+ if (retval = kadm_approve_pw(ad->pname, ad->pinst, ad->prealm,
+ newkey, no_pword ? 0 : pword)) {
+ if (retval == KADM_PW_MISMATCH) {
+ /*
+ * Very strange!!! This means that the cleartext
+ * password which was sent and the DES cblock
+ * didn't match!
+ */
+ (void) krb_log("'%s.%s@%s' sent a password string which didn't match with the DES key?!?",
+ ad->pname, ad->pinst, ad->prealm);
+ return(retval);
+ }
+ if (fascist_cpw) {
+ *outlen = strlen(bad_pw_err)+strlen(pw_blurb)+1;
+ if (*datout = (u_char *) malloc(*outlen)) {
+ strcpy((char *) *datout, bad_pw_err);
+ strcat((char *) *datout, pw_blurb);
+ } else
+ *outlen = 0;
+ (void) krb_log("'%s.%s@%s' tried to use an insecure password in changepw",
+ ad->pname, ad->pinst, ad->prealm);
+#ifdef notdef
+ /* For debugging only, probably a bad idea */
+ if (!no_pword)
+ (void) krb_log("The password was %s\n", pword);
+#endif
+ return(retval);
+ } else {
+ *outlen = strlen(bad_pw_warn) + strlen(pw_blurb)+1;
+ if (*datout = (u_char *) malloc(*outlen)) {
+ strcpy((char *) *datout, bad_pw_warn);
+ strcat((char *) *datout, pw_blurb);
+ } else
+ *outlen = 0;
+ (void) krb_log("'%s.%s@%s' used an insecure password in changepw",
+ ad->pname, ad->pinst, ad->prealm);
+ }
+ } else {
+ *datout = 0;
+ *outlen = 0;
+ }
+
+ retval = kadm_change(ad->pname, ad->pinst, ad->prealm, newkey);
+ keylow = keyhigh = 0;
+ memset(newkey, 0, sizeof(newkey));
+#endif /* OVSEC_KADM */
+
+ return retval;
+}
+
+#ifndef OVSEC_KADM
+/*
+kadm_ser_add - the server side of the add_entry routine
+ recieves : KTEXT, {values}
+ returns : CKSUM, RETCODE, {values}
+ acl : su, sms (as alloc)
+
+Adds and entry containing values to the database
+returns the values of the entry, so if you leave certain fields blank you will
+ be able to determine the default values they are set to
+*/
+int
+kadm_ser_add(dat,len,ad, datout, outlen)
+u_char *dat;
+int len;
+AUTH_DAT *ad;
+u_char **datout;
+int *outlen;
+{
+ Kadm_vals values, retvals;
+ int status;
+
+ if ((status = stream_to_vals(dat, &values, len)) < 0)
+ return(KADM_LENGTH_ERROR);
+ if ((status = kadm_add_entry(ad->pname, ad->pinst, ad->prealm,
+ &values, &retvals)) == KADM_DATA) {
+ *outlen = vals_to_stream(&retvals,datout);
+ retvals.key_low = retvals.key_high = 0;
+ return KADM_SUCCESS;
+ } else {
+ *outlen = 0;
+ return status;
+ }
+}
+
+/*
+kadm_ser_del - the server side of the del_entry routine
+ recieves : KTEXT, {values}
+ returns : CKSUM, RETCODE, {values}
+ acl : su, sms (as alloc)
+
+Deletes an entry containing values to the database
+returns the values of the entry, so if you leave certain fields blank you will
+ be able to determine the default values they are set to
+*/
+kadm_ser_del(dat,len,ad, datout, outlen)
+u_char *dat;
+int len;
+AUTH_DAT *ad;
+u_char **datout;
+int *outlen;
+{
+ Kadm_vals values, retvals;
+ int status;
+
+ if ((status = stream_to_vals(dat, &values, len)) < 0)
+ return(KADM_LENGTH_ERROR);
+ if ((status = kadm_del_entry(ad->pname, ad->pinst, ad->prealm,
+ &values, &retvals)) == KADM_DATA) {
+ *outlen = vals_to_stream(&retvals,datout);
+ retvals.key_low = retvals.key_high = 0;
+ return KADM_SUCCESS;
+ } else {
+ *outlen = 0;
+ return status;
+ }
+}
+
+/*
+kadm_ser_mod - the server side of the mod_entry routine
+ recieves : KTEXT, {values, values}
+ returns : CKSUM, RETCODE, {values}
+ acl : su, sms (as register or dealloc)
+
+Modifies all entries corresponding to the first values so they match the
+ second values.
+returns the values for the changed entries
+*/
+kadm_ser_mod(dat,len,ad, datout, outlen)
+u_char *dat;
+int len;
+AUTH_DAT *ad;
+u_char **datout;
+int *outlen;
+{
+ Kadm_vals vals1, vals2, retvals;
+ int wh;
+ int status;
+
+ if ((wh = stream_to_vals(dat, &vals1, len)) < 0)
+ return KADM_LENGTH_ERROR;
+ if ((status = stream_to_vals(dat+wh,&vals2, len-wh)) < 0)
+ return KADM_LENGTH_ERROR;
+ if ((status = kadm_mod_entry(ad->pname, ad->pinst, ad->prealm, &vals1,
+ &vals2, &retvals)) == KADM_DATA) {
+ *outlen = vals_to_stream(&retvals,datout);
+ retvals.key_low = retvals.key_high = 0;
+ return KADM_SUCCESS;
+ } else {
+ *outlen = 0;
+ return status;
+ }
+}
+
+/*
+kadm_ser_get
+ recieves : KTEXT, {values, flags}
+ returns : CKSUM, RETCODE, {count, values, values, values}
+ acl : su
+
+gets the fields requested by flags from all entries matching values
+returns this data for each matching recipient, after a count of how many such
+ matches there were
+*/
+kadm_ser_get(dat,len,ad, datout, outlen)
+u_char *dat;
+int len;
+AUTH_DAT *ad;
+u_char **datout;
+int *outlen;
+{
+ Kadm_vals values, retvals;
+ u_char fl[FLDSZ];
+ int loop,wh;
+ int status;
+
+ if ((wh = stream_to_vals(dat, &values, len)) < 0)
+ return KADM_LENGTH_ERROR;
+ if (wh + FLDSZ > len)
+ return KADM_LENGTH_ERROR;
+ for (loop=FLDSZ-1; loop>=0; loop--)
+ fl[loop] = dat[wh++];
+ if ((status = kadm_get_entry(ad->pname, ad->pinst, ad->prealm,
+ &values, fl, &retvals)) == KADM_DATA) {
+ *outlen = vals_to_stream(&retvals,datout);
+ retvals.key_low = retvals.key_high = 0;
+ return KADM_SUCCESS;
+ } else {
+ *outlen = 0;
+ return status;
+ }
+}
+
+/*
+kadm_ser_ckpw - the server side of the check_password routine
+ recieves : KTEXT, {key}
+ returns : CKSUM, RETCODE
+ acl : none
+
+Checks to see if the des key passed from the caller is a "secure" password.
+*/
+kadm_ser_ckpw(dat, len, ad, datout, outlen)
+u_char *dat;
+int len;
+AUTH_DAT *ad;
+u_char **datout;
+int *outlen;
+{
+ krb5_ui_4 keylow, keyhigh;
+ char pword[MAX_KPW_LEN];
+ int no_pword = 0;
+ des_cblock newkey;
+ int stvlen = 0,status;
+ int retval;
+ extern int kadm_approve_pw();
+
+ /* take key off the stream, and check it */
+
+ if ((status = stv_long(dat, &keyhigh, 0, len)) < 0)
+ return(KADM_LENGTH_ERROR);
+ stvlen += status;
+ if ((status = stv_long(dat, &keylow, stvlen, len)) < 0)
+ return(KADM_LENGTH_ERROR);
+ stvlen += status;
+ if ((status = stv_string(dat, pword, stvlen, sizeof(pword), len)) < 0) {
+ no_pword++;
+ pword[0]='\0';
+ }
+ stvlen += status;
+
+ keylow = ntohl(keylow);
+ keyhigh = ntohl(keyhigh);
+ memcpy((char *)(((krb5_int32 *)newkey) + 1), (char *)&keyhigh, 4);
+ memcpy((char *)newkey, (char *)&keylow, 4);
+ keylow = keyhigh = 0;
+ retval = kadm_approve_pw(ad->pname, ad->pinst, ad->prealm, newkey,
+ no_pword ? 0 : pword);
+ memset(newkey, 0, sizeof(newkey));
+ if (retval) {
+ *outlen = strlen(check_pw_msg)+strlen(pw_blurb)+1;
+ if (*datout = (u_char *) malloc(*outlen)) {
+ strcpy((char *) *datout, check_pw_msg);
+ strcat((char *) *datout, pw_blurb);
+ } else
+ *outlen = 0;
+ (void) krb_log("'%s.%s@%s' sent an insecure password to be checked",
+ ad->pname, ad->pinst, ad->prealm);
+ return(retval);
+ } else {
+ *datout = 0;
+ *outlen = 0;
+ (void) krb_log("'%s.%s@%s' sent a secure password to be checked",
+ ad->pname, ad->pinst, ad->prealm);
+ }
+ return(0);
+}
+
+/*
+kadm_ser_stab - the server side of the change_srvtab routine
+ recieves : KTEXT, {values}
+ returns : CKSUM, RETCODE, {values}
+ acl : su, sms (as register or dealloc)
+
+Creates or modifies the specified service principal to have a random
+key, which is sent back to the client. The key version is returned in
+the max_life field of the values structure. It's a hack, but it's a
+backwards compatible hack....
+*/
+kadm_ser_stab(dat, len, ad, datout, outlen)
+u_char *dat;
+int len;
+AUTH_DAT *ad;
+u_char **datout;
+int *outlen;
+{
+ Kadm_vals values;
+ int status;
+
+ if ((status = stream_to_vals(dat, &values, len)) < 0)
+ return KADM_LENGTH_ERROR;
+ status = kadm_chg_srvtab(ad->pname, ad->pinst, ad->prealm, &values);
+ if (status == KADM_DATA) {
+ *outlen = vals_to_stream(&values,datout);
+ values.key_low = values.key_high = 0;
+ return KADM_SUCCESS;
+ } else {
+ *outlen = 0;
+ return status;
+ }
+}
+#endif /* !OVSEC_KADM */
diff --git a/src/kadmin/v4server/kadm_server.h b/src/kadmin/v4server/kadm_server.h
new file mode 100644
index 0000000000..d852bcaabb
--- /dev/null
+++ b/src/kadmin/v4server/kadm_server.h
@@ -0,0 +1,58 @@
+/*
+ * kadmin/v4server/kadm_server.h
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * Definitions for Kerberos administration server & client
+ */
+
+#ifndef KADM_SERVER_DEFS
+#define KADM_SERVER_DEFS
+
+#include <mit-copyright.h>
+/*
+ * kadm_server.h
+ * Header file for the fourth attempt at an admin server
+ * Doug Church, December 28, 1989, MIT Project Athena
+ * ps. Yes that means this code belongs to athena etc...
+ * as part of our ongoing attempt to copyright all greek names
+ */
+
+#include <sys/types.h>
+#include <krb.h>
+#include <des.h>
+#include "k5-int.h"
+
+typedef struct {
+ struct sockaddr_in admin_addr;
+ struct sockaddr_in recv_addr;
+ int recv_addr_len;
+ int admin_fd; /* our link to clients */
+ char sname[ANAME_SZ];
+ char sinst[INST_SZ];
+ char krbrlm[REALM_SZ];
+ krb5_principal sprinc;
+ krb5_encrypt_block master_encblock;
+ krb5_principal master_princ;
+ krb5_keyblock master_keyblock;
+ krb5_deltat max_life;
+ krb5_deltat max_rlife;
+ krb5_timestamp expiration;
+ krb5_flags flags;
+ krb5_kvno mkvno;
+} Kadm_Server;
+
+#define ADD_ACL_FILE "/v4acl.add"
+#define GET_ACL_FILE "/v4acl.get"
+#define MOD_ACL_FILE "/v4acl.mod"
+#define DEL_ACL_FILE "/v4acl.del"
+#define STAB_ACL_FILE "/v4acl.srvtab"
+#define STAB_SERVICES_FILE "/v4stab_services"
+#define STAB_HOSTS_FILE "/v4stab_bad_hosts"
+
+krb5_context kadm_context;
+
+#endif /* KADM_SERVER_DEFS */
diff --git a/src/kadmin/v4server/kadm_stream.c b/src/kadmin/v4server/kadm_stream.c
new file mode 100644
index 0000000000..86da6c64fe
--- /dev/null
+++ b/src/kadmin/v4server/kadm_stream.c
@@ -0,0 +1,277 @@
+/*
+ * kadmin/v4server/kadm_stream.c
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * Stream conversion functions for Kerberos administration server
+ */
+
+
+#include <mit-copyright.h>
+#include <string.h>
+#include "k5-int.h"
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#else
+extern char *malloc(), *calloc(), *realloc();
+#endif
+
+/*
+ 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 "kadm.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
+*/
+vals_to_stream(dt_in, dt_out)
+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(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);
+}
+
+build_field_header(cont, st)
+u_char *cont; /* container for fields data */
+u_char **st; /* stream */
+{
+ *st = (u_char *) malloc (4);
+ memcpy((char *) *st, (char *) cont, 4);
+ return 4; /* return pointer to current stream location */
+}
+
+vts_string(dat, st, loc)
+char *dat; /* a string to put on the stream */
+u_char **st; /* base pointer to the stream */
+int loc; /* offset into the stream for current data */
+{
+ *st = (u_char *) realloc ((char *)*st, (unsigned) (loc + strlen(dat) + 1));
+ memcpy((char *)(*st + loc), dat, strlen(dat)+1);
+ return strlen(dat)+1;
+}
+
+vts_short(dat, st, loc)
+u_short dat; /* the attributes field */
+u_char **st; /* a base pointer to the stream */
+int loc; /* offset into the stream for current data */
+{
+ u_short temp; /* to hold the net order short */
+
+ temp = htons(dat); /* convert to network order */
+ *st = (u_char *) realloc ((char *)*st, (unsigned)(loc + sizeof(u_short)));
+ memcpy((char *)(*st + loc), (char *) &temp, sizeof(u_short));
+ return sizeof(u_short);
+}
+
+vts_long(dat, st, loc)
+krb5_ui_4 dat; /* the attributes field */
+u_char **st; /* a base pointer to the stream */
+int loc; /* offset into the stream for current data */
+{
+ krb5_ui_4 temp; /* to hold the net order short */
+
+ temp = htonl(dat); /* convert to network order */
+ *st = (u_char *) realloc ((char *)*st, (unsigned)(loc + sizeof(krb5_ui_4)));
+ memcpy((char *)(*st + loc), (char *) &temp, sizeof(krb5_ui_4));
+ return sizeof(krb5_ui_4);
+}
+
+
+vts_char(dat, st, loc)
+u_char dat; /* the attributes field */
+u_char **st; /* a base pointer to the stream */
+int loc; /* offset into the stream for current data */
+{
+ *st = (u_char *) realloc ((char *)*st, (unsigned)(loc + sizeof(u_char)));
+ (*st)[loc] = (u_char) dat;
+ 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
+*/
+stream_to_vals(dt_in, dt_out, maxlen)
+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((char *) 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:
+ if ((status = stv_string(dt_in, dt_out->name, stsize,
+ sizeof(dt_out->name), maxlen)) < 0)
+ return(-1);
+ stsize += status;
+ break;
+ case KADM_INST:
+ if ((status = stv_string(dt_in, dt_out->instance, stsize,
+ sizeof(dt_out->instance), maxlen)) < 0)
+ return(-1);
+ stsize += status;
+ break;
+ case KADM_EXPDATE:
+ if ((status = stv_long(dt_in, &dt_out->exp_date, stsize,
+ maxlen)) < 0)
+ return(-1);
+ stsize += status;
+ break;
+ case KADM_ATTR:
+ if ((status = stv_short(dt_in, &dt_out->attributes, stsize,
+ maxlen)) < 0)
+ return(-1);
+ stsize += status;
+ break;
+ case KADM_MAXLIFE:
+ if ((status = stv_char(dt_in, &dt_out->max_life, stsize,
+ maxlen)) < 0)
+ return(-1);
+ stsize += status;
+ break;
+ case KADM_DESKEY:
+ if ((status = stv_long(dt_in, &dt_out->key_high, stsize,
+ maxlen)) < 0)
+ return(-1);
+ stsize += status;
+ if ((status = stv_long(dt_in, &dt_out->key_low, stsize,
+ maxlen)) < 0)
+ return(-1);
+ stsize += status;
+ break;
+ default:
+ break;
+ }
+ return stsize;
+}
+
+check_field_header(st, cont, maxlen)
+u_char *st; /* stream */
+u_char *cont; /* container for fields data */
+int maxlen;
+{
+ if (4 > maxlen)
+ return(-1);
+ memcpy((char *) cont, (char *) st, 4);
+ return 4; /* return pointer to current stream location */
+}
+
+stv_string(st, dat, loc, stlen, maxlen)
+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 */
+
+ maxcount = min(maxlen - loc, stlen);
+
+ (void) strncpy(dat, (char *)st + loc, maxcount);
+
+ if (dat[maxcount-1]) /* not null-term --> not enuf room */
+ return(-1);
+ return strlen(dat)+1;
+}
+
+stv_short(st, dat, loc, maxlen)
+u_char *st; /* a base pointer to the stream */
+u_short *dat; /* the attributes field */
+int loc; /* offset into the stream for current data */
+int maxlen;
+{
+ u_short temp; /* to hold the net order short */
+
+ if (loc + sizeof(u_short) > maxlen)
+ return(-1);
+ memcpy((char *) &temp, (char *) st+ loc, sizeof(u_short));
+ *dat = ntohs(temp); /* convert to network order */
+ return sizeof(u_short);
+}
+
+stv_long(st, dat, loc, maxlen)
+u_char *st; /* a base pointer to the stream */
+krb5_ui_4 *dat; /* the attributes field */
+int loc; /* offset into the stream for current data */
+int maxlen; /* maximum length of st */
+{
+ krb5_ui_4 temp; /* to hold the net order short */
+
+ if (loc + sizeof(krb5_ui_4) > maxlen)
+ return(-1);
+ memcpy((char *) &temp, (char *) st + loc, sizeof(krb5_ui_4));
+ *dat = ntohl(temp); /* convert to network order */
+ return sizeof(krb5_ui_4);
+}
+
+stv_char(st, dat, loc, maxlen)
+u_char *st; /* a base pointer to the stream */
+u_char *dat; /* the attributes field */
+int loc; /* offset into the stream for current data */
+int maxlen;
+{
+ if (loc + 1 > maxlen)
+ return(-1);
+ *dat = *(st + loc);
+ return 1;
+}
+
diff --git a/src/kadmin/v4server/kadm_supp.c b/src/kadmin/v4server/kadm_supp.c
new file mode 100644
index 0000000000..9d2f8deb29
--- /dev/null
+++ b/src/kadmin/v4server/kadm_supp.c
@@ -0,0 +1,113 @@
+/*
+ * kadmin/v4server/kadm_supp.c
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * Support functions for Kerberos administration server & clients
+ */
+
+
+#include <mit-copyright.h>
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+/*
+ kadm_supp.c
+ this holds the support routines for the kerberos administration server
+
+ error: prints out a kadm error message, returns
+ fatal: prints out a kadm fatal error message, exits
+ prin_vals: prints out data associated with a Principal in the vals
+ structure
+*/
+
+#include "kadm.h"
+#include "krb_db.h"
+
+/*
+prin_vals:
+ recieves : a vals structure
+*/
+void prin_vals(vals)
+Kadm_vals *vals;
+{
+ printf("Info in Database for %s.%s:\n", vals->name, vals->instance);
+ printf(" Max Life: %d Exp Date: %s\n",vals->max_life,
+ asctime(localtime((long *)&vals->exp_date)));
+ printf(" Attribs: %.2x key: %u %u\n",vals->attributes,
+ vals->key_low, vals->key_high);
+}
+
+#ifdef notdef
+nierror(s)
+int s;
+{
+ extern char *error_message();
+ printf("Kerberos admin server loses..... %s\n",error_message(s));
+ return(s);
+}
+#endif
+
+/* kadm_prin_to_vals takes a fields arguments, a Kadm_vals and a Principal,
+ it copies the fields in Principal specified by fields into Kadm_vals,
+ i.e from old to new */
+
+kadm_prin_to_vals(fields, new, old)
+u_char fields[FLDSZ];
+Kadm_vals *new;
+Principal *old;
+{
+ memset((char *)new, 0, sizeof(*new));
+ if (IS_FIELD(KADM_NAME,fields)) {
+ (void) strncpy(new->name, old->name, ANAME_SZ);
+ SET_FIELD(KADM_NAME, new->fields);
+ }
+ if (IS_FIELD(KADM_INST,fields)) {
+ (void) strncpy(new->instance, old->instance, INST_SZ);
+ SET_FIELD(KADM_INST, new->fields);
+ }
+ if (IS_FIELD(KADM_EXPDATE,fields)) {
+ new->exp_date = old->exp_date;
+ SET_FIELD(KADM_EXPDATE, new->fields);
+ }
+ if (IS_FIELD(KADM_ATTR,fields)) {
+ new->attributes = old->attributes;
+ SET_FIELD(KADM_MAXLIFE, new->fields);
+ }
+ if (IS_FIELD(KADM_MAXLIFE,fields)) {
+ new->max_life = old->max_life;
+ SET_FIELD(KADM_MAXLIFE, new->fields);
+ }
+ if (IS_FIELD(KADM_DESKEY,fields)) {
+ new->key_low = old->key_low;
+ new->key_high = old->key_high;
+ SET_FIELD(KADM_DESKEY, new->fields);
+ }
+}
+
+kadm_vals_to_prin(fields, new, old)
+u_char fields[FLDSZ];
+Principal *new;
+Kadm_vals *old;
+{
+
+ memset((char *)new, 0, sizeof(*new));
+ if (IS_FIELD(KADM_NAME,fields))
+ (void) strncpy(new->name, old->name, ANAME_SZ);
+ if (IS_FIELD(KADM_INST,fields))
+ (void) strncpy(new->instance, old->instance, INST_SZ);
+ if (IS_FIELD(KADM_EXPDATE,fields))
+ new->exp_date = old->exp_date;
+ if (IS_FIELD(KADM_ATTR,fields))
+ new->attributes = old->attributes;
+ if (IS_FIELD(KADM_MAXLIFE,fields))
+ new->max_life = old->max_life;
+ if (IS_FIELD(KADM_DESKEY,fields)) {
+ new->key_low = old->key_low;
+ new->key_high = old->key_high;
+ }
+}
diff --git a/src/kadmin/v4server/unit-test/ChangeLog b/src/kadmin/v4server/unit-test/ChangeLog
new file mode 100644
index 0000000000..93120b8a41
--- /dev/null
+++ b/src/kadmin/v4server/unit-test/ChangeLog
@@ -0,0 +1,13 @@
+Mon Jul 15 17:15:51 1996 Marc Horowitz <marc@mit.edu>
+
+ * helpers.exp (exp_prog): the check for non-newline-terminated
+ stdout was causing failures where there weren't any. Barry
+ doesn't remember why this was here to begin with.
+ * Makefile.ov (unit-test-body), helpers.exp: some versions of
+ runtest do not like digits in command-line variable names.
+ * Makefile.ov (unit-test-body), helpers.exp: ovsec_v4adm_server
+ renamed to kadmind4
+ * getpid.sh: grep out any programs with expect or kadmind4 in
+ their names.
+
+
diff --git a/src/kadmin/v4server/unit-test/Makefile.ov b/src/kadmin/v4server/unit-test/Makefile.ov
new file mode 100644
index 0000000000..3af65607ed
--- /dev/null
+++ b/src/kadmin/v4server/unit-test/Makefile.ov
@@ -0,0 +1,19 @@
+#
+# $Id$
+#
+
+TOP = ../..
+include $(TOP)/config.mk/template
+
+unit-test:: unit-test-setup unit-test-body unit-test-cleanup
+
+unit-test-setup::
+ $(START_SERVERS_LOCAL) -v4files -kdcport 750 -keysalt des-cbc-crc:v4
+ $(LOCAL_MAKE_KEYTAB) -princ changepw/kerberos /krb5/ovsec_adm.srvtab
+
+unit-test-body::
+ $(RUNTEST) VFOURSERVER=../kadmind4 --tool v4server \
+ KDBFIVE_EDIT=../../../admin/edit/kdb5_edit
+
+unit-test-cleanup::
+ $(STOP_SERVERS_LOCAL) -v4files
diff --git a/src/kadmin/v4server/unit-test/config/ChangeLog b/src/kadmin/v4server/unit-test/config/ChangeLog
new file mode 100644
index 0000000000..aa01abc17f
--- /dev/null
+++ b/src/kadmin/v4server/unit-test/config/ChangeLog
@@ -0,0 +1,7 @@
+Mon Jul 15 17:18:56 1996 Marc Horowitz <marc@mit.edu>
+
+ * unix.exp: some versions of runtest do not like digits in
+ command-line variable names. ovsec_edit_keytab renamed to
+ kadm5_keytab
+
+
diff --git a/src/kadmin/v4server/unit-test/config/unix.exp b/src/kadmin/v4server/unit-test/config/unix.exp
new file mode 100644
index 0000000000..874092311e
--- /dev/null
+++ b/src/kadmin/v4server/unit-test/config/unix.exp
@@ -0,0 +1,42 @@
+global env
+
+set kill /bin/kill
+
+if {[file exists /bin/sleep]} {
+ set sleep /bin/sleep
+} else {
+ set sleep /usr/bin/sleep
+}
+
+set kpasswd_v4 /usr/athena/bin/kpasswd
+set ovpasswd $env(TOP)/kpasswd/kpasswd
+set kadmin_local $env(TOP)/cli/kadmin.local
+set kdb5_edit $KDBFIVE_EDIT
+set remove_changepw_perms ./remove_changepw_perms.sh
+set getpid ./getpid.sh
+set ovsec_adm_server $env(TOP)/server/kadmind
+set ovsec_edit_keytab $env(TOP)/keytab/kadm5_keytab
+set hostname [exec hostname]
+
+# change-password.exp sends ^C to kpasswd to kill it; on HP-UX the
+# default intr character is DEL, and setting it on all platforms
+# won't hurt
+set stty_init "intr \\^c"
+
+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
+}
diff --git a/src/kadmin/v4server/unit-test/getpid.sh b/src/kadmin/v4server/unit-test/getpid.sh
new file mode 100644
index 0000000000..5c1b1a6903
--- /dev/null
+++ b/src/kadmin/v4server/unit-test/getpid.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+# tcl sucks big fat hairy rocks
+
+$PS_ALL | awk "/$1/"' && !/awk/ && !/getpid/ && !/expect/ && !/kadmind4/ { print $2 }'
diff --git a/src/kadmin/v4server/unit-test/helpers.exp b/src/kadmin/v4server/unit-test/helpers.exp
new file mode 100644
index 0000000000..7f23b65c8f
--- /dev/null
+++ b/src/kadmin/v4server/unit-test/helpers.exp
@@ -0,0 +1,232 @@
+proc server_pids { } {
+ global env
+
+ return [eval [concat exec $env(PS_ALL) | \
+ awk {{/kadmind4/ && !/awk/ && !/expect/ {printf("%d ", $2)}}}]]
+}
+
+proc server_exit { name status } {
+ global wait_error_index wait_errno_index wait_status_index
+ global server_id
+ global kill
+
+ verbose "$name: stopping V4 kpasswd server." 1
+
+ # We can't know whether the process exists or not, so we have
+ # to ignore errors. XXX will close ever time out?
+ catch {close $server_id}
+ set pids [server_pids]
+ if {$pids != {}} {
+ verbose "server_exit killing process(es) $pids"
+ catch {exec $kill $pids}
+ } else {
+ verbose "server_exit: couldn't find running server(s) to kill"
+ }
+
+ # wait hangs on AIX if the process was killed; since status == -1
+ # in that case, solve the problem by not waiting; the zombies will
+ # be cleaned up when the test finishes
+ if {$status == -1} {
+ return 1
+ }
+
+ set ret [wait -i $server_id]
+ verbose "% Exit $ret" 2
+
+ if {[lindex $ret $wait_error_index] == -1} {
+ fail "$name: wait returned error [lindex $ret $wait_errno_index]"
+ return 0
+ } 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"
+ return 0
+ }
+ }
+
+ return 1
+}
+
+proc myfail { msg } {
+ global mytest_status
+ fail "$msg"
+ set mytest_status 1
+}
+
+proc server_start { name cmdline should_listen args } {
+ global spawn_id server_id
+ global VFOURSERVER
+ global mytest_status
+ global sleep hostname
+
+ set max_tries 60
+
+ verbose "$name: starting V4 kpasswd server." 1
+
+ for {set num_tries 0} {$num_tries <= $max_tries} {incr num_tries} {
+ if {$num_tries} {
+ exec $sleep 5
+ verbose "Couldn't connect to V4 kpasswd server; retrying ($num_tries so far)."
+ }
+
+ spawn $VFOURSERVER $cmdline
+ set server_id $spawn_id
+
+ foreach test $args {
+ set mytest_status 0
+ uplevel 1 "expect {
+ -i $server_id
+ $test
+ timeout { myfail \"$name: timeout\" }
+ eof { myfail \"$name: eof while expecting string\" }
+ }"
+
+ if {$mytest_status == 1} {
+ return 0
+ }
+ }
+
+ set pids [server_pids]
+
+ if {$should_listen} {
+ exec $sleep 1
+ set save_spawn_id $spawn_id
+ spawn telnet $hostname kerberos_master
+ expect {
+ {Connection refused} {
+ close -i $save_spawn_id
+ wait -i $save_spawn_id
+ close
+ wait
+ continue
+ }
+ {Connected} {
+ send "close\n"
+ close
+ wait
+ set spawn_id $save_spawn_id
+ break
+ }
+ default {
+ close -i $save_spawn_id
+ wait -i $save_spawn_id
+ catch {close}
+ wait
+ continue
+ }
+ }
+ } else {
+ break
+ }
+ }
+
+ if {$pids == {}} {
+ # Try twice to find the server processes. Not sure why,
+ # but there seems to be some sort of race condition in the OS.
+
+ verbose "server_start: couldn't find server process(es) -- trying again"
+ exec $sleep 1
+ set pids [server_pids]
+ }
+
+ if {$num_tries > $max_tries} {
+ myfail "$name: couldn't connect to V4 kpasswd server"
+ return 0
+ } else {
+ if {$pids != {}} {
+ verbose "server_start: server process ID(s) is/are $pids"
+ }
+ pass "$name"
+ return 1
+ }
+}
+
+proc exp_prog { name prog cmdline status args } {
+ global spawn_id spawn_pid
+ global mytest_status
+ global wait_error_index wait_errno_index wait_status_index
+
+ verbose "$name: spawning $prog $cmdline" 1
+
+ set spawn_pid [eval "spawn $prog $cmdline"]
+
+ # at the end, eof is success
+
+# lappend args { eof { if {[regexp "\[\r\n\]$" $expect_out(buffer)] == 0} { myfail "final status message not newline-terminated" } } }
+ lappend args { eof {} }
+
+ foreach test $args {
+ set mytest_status 0
+ uplevel 1 "expect {
+ $test
+ timeout { close; myfail \"$name: timeout\" }
+ eof { myfail \"$name: eof while expecting string\" }
+ }"
+
+ if {$mytest_status == 1} { return 0 }
+ }
+
+ # at this point, the id is closed and we can wait on it.
+
+ set ret [wait]
+ verbose "% Exit $ret" 2
+
+ if {$status == -1} { return 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"
+ }
+ }
+
+ return 1
+}
+
+proc fix_salt { name fullname oldpw newpw } {
+ global kdb5_edit
+
+ exp_prog "$name: kdb5_edit" $kdb5_edit "" 0 {
+ "kdb5_edit:" { send "cpw $fullname\n" }
+ } {
+ "Enter password:" { send "$newpw\n" }
+ } {
+ "Re-enter password for verification:" { send "$newpw\n" }
+ } {
+ "kdb5_edit:" { send "quit\n" }
+ }
+}
+
+proc unexpire { name fullname } {
+ global kadmin_local
+
+ # While we're at it, make sure they aren't expired.
+ exp_prog "$name: kadmin.local" $kadmin_local "" 0 {
+ "kadmin.local:" {
+ send "modprinc -expire \"May 6, 1999\" $fullname\n"
+ }
+ } {
+ -re "Principal .* modified." { send "quit\n" }
+ }
+}
+
+proc kpasswd_v4 { name fullname status oldpw newpw args } {
+ global kpasswd_v4 s
+
+ eval [concat {
+ exp_prog $name $kpasswd_v4 "-u $fullname" $status {
+ -re "Old password for $fullname:" { send "$oldpw\n" }
+ } {
+ -re "New Password for $fullname:" { send "$newpw\n" }
+ } {
+ -re "Verifying, please re-enter New Password for $fullname:"
+ { send "$newpw\n" }
+ }
+ } $args]
+}
diff --git a/src/kadmin/v4server/unit-test/remove_changepw_perms.sh b/src/kadmin/v4server/unit-test/remove_changepw_perms.sh
new file mode 100644
index 0000000000..27d026ff32
--- /dev/null
+++ b/src/kadmin/v4server/unit-test/remove_changepw_perms.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+# tcl sucks big fat hairy rocks
+
+ed /krb5/ovsec_adm.acl <<EOF >/dev/null 2>&1
+g/changepw\/kerberos/s/^/#/
+w
+q
+EOF
diff --git a/src/kadmin/v4server/unit-test/v4server.0/setup-srvtab.exp b/src/kadmin/v4server/unit-test/v4server.0/setup-srvtab.exp
new file mode 100644
index 0000000000..3c8e181b2c
--- /dev/null
+++ b/src/kadmin/v4server/unit-test/v4server.0/setup-srvtab.exp
@@ -0,0 +1,11 @@
+load_lib "helpers.exp"
+
+set timeout 10
+
+exp_prog "setup" $ovsec_edit_keytab \
+ "-k /krb5/ovsec_adm.srvtab -a -c -p admin changepw/kerberos" \
+ 0 {
+ "Enter password:" { send "admin\n" }
+} {
+ -re "Entry for principal changepw/kerberos .* added to keytab" {}
+}
diff --git a/src/kadmin/v4server/unit-test/v4server.1/access.exp b/src/kadmin/v4server/unit-test/v4server.1/access.exp
new file mode 100644
index 0000000000..4d30fc9c73
--- /dev/null
+++ b/src/kadmin/v4server/unit-test/v4server.1/access.exp
@@ -0,0 +1,88 @@
+load_lib "helpers.exp"
+
+set timeout 30
+
+# Setup: make sure the principals we will use have V4 salt
+fix_salt "A.setup" testuser notathena notathena
+unexpire "A.setup" testuser
+unexpire "A.setup" changepw/kerberos
+
+proc kill_admin_server {} {
+ global env kill getpid
+
+ set pid [exec $getpid kadmind]
+ if {$pid != ""} {
+ exec $kill $pid
+ }
+}
+
+proc start_admin_server {} {
+ global ovsec_adm_server sleep
+
+ set max_tries 60
+
+ for {set num_tries 0} {$num_tries <= $max_tries} {incr num_tries} {
+ if {$num_tries} {
+ exec $sleep 5
+ verbose "$ovsec_adm_server couldn't bind; retrying ($num_tries so far)"
+ }
+ if {[catch "exec $ovsec_adm_server" msg]} {
+ if {[regexp {Address already in use} $msg]} {
+ continue
+ }
+ fail "starting $ovsec_adm_server: $msg"
+ }
+ return
+ }
+ fail "starting $ovsec_adm_server: $msg"
+}
+
+proc remove_changepw_perms {} {
+ global remove_changepw_perms
+
+ exec $remove_changepw_perms
+}
+
+proc set_changepw_perms { perms } {
+ remove_changepw_perms
+
+ exec echo "changepw/kerberos@SECURE-TEST.OV.COM $perms" \
+ >> /krb5/ovsec_adm.acl
+}
+
+# start off with a dead admin server
+kill_admin_server
+
+set_changepw_perms "i"
+start_admin_server
+server_start A.1 "-n" 1 {
+ "KADM Server starting in the OVSEC_KADM mode" {}
+}
+kpasswd_v4 A.1 testuser 2 notathena foobar {
+ "Operation requires ``change-password'' privilege" {}
+} {
+ "$kpasswd_v4: Insufficient access to perform requested operation while attempting to change password." {}
+} {
+ "Password NOT changed." {}
+}
+server_exit A.1 -1
+kill_admin_server
+
+set_changepw_perms "c"
+start_admin_server
+server_start A.2 "-n" 1 {
+ "KADM Server starting in the OVSEC_KADM mode" {}
+}
+kpasswd_v4 A.2 testuser 2 notathena foobar {
+ "Operation requires ``get'' privilege" {}
+} {
+ "$kpasswd_v4: Insufficient access to perform requested operation while attempting to change password." {}
+} {
+ "Password NOT changed." {}
+}
+server_exit A.2 -1
+kill_admin_server
+
+set_changepw_perms "ci"
+
+start_admin_server
diff --git a/src/kadmin/v4server/unit-test/v4server.1/change-password.exp b/src/kadmin/v4server/unit-test/v4server.1/change-password.exp
new file mode 100644
index 0000000000..62b9ec30a8
--- /dev/null
+++ b/src/kadmin/v4server/unit-test/v4server.1/change-password.exp
@@ -0,0 +1,59 @@
+load_lib "helpers.exp"
+
+set timeout 30
+
+spawn stty -a
+expect { eof {} }
+wait
+
+# Setup: make sure the principals we will use have V4 salt
+fix_salt "CPW.setup" testuser notathena notathena
+fix_salt "CPW.setup" pol1 pol111111 pol111111
+fix_salt "CPW.setup" pol2 pol222222 pol222222
+unexpire "CPW.setup" testuser
+unexpire "CPW.setup" pol1
+unexpire "CPW.setup" pol2
+unexpire "CPW.setup" changepw/kerberos
+
+server_start "CPW.all" "-n" 1 {
+ "KADM Server starting in the OVSEC_KADM mode" {}
+}
+
+kpasswd_v4 CPW.1 testuser 0 notathena foobar { "Password changed." {} }
+kpasswd_v4 CPW.1 testuser 0 foobar notathena { "Password changed." {} }
+
+kpasswd_v4 CPW.3 pol1 -1 pol111111 foo {
+ "New password is too short." {}
+} {
+ "$kpasswd_v4: Insecure password rejected while attempting to change password." { send "\003\n"; close; break }
+}
+
+kpasswd_v4 CPW.4 pol1 -1 pol111111 foooooooo {
+ "New password does not have enough character classes." {}
+} {
+ "$kpasswd_v4: Insecure password rejected while attempting to change password." { send "\003\n"; close; break }
+}
+
+kpasswd_v4 CPW.5 pol1 -1 pol111111 Abyssinia {
+ "New password was found in a dictionary" {}
+} {
+ "$kpasswd_v4: Insecure password rejected while attempting to change password." { send "\003\n"; close; break }
+}
+
+kpasswd_v4 CPW.6.setup pol1 0 pol111111 polAAAAAA { "Password changed." {} }
+kpasswd_v4 CPW.6 pol1 -1 polAAAAAA pol111111 {
+ "New password was used previously." {}
+} {
+ "$kpasswd_v4: Insecure password rejected while attempting to change password." { send "\003\n"; close; break }
+}
+
+# this relies on the fact that kdb5_edit resets last_pwd_change, which
+# it appears to
+kpasswd_v4 CPW.7.setup pol2 0 pol222222 polBBBBBB { "Password changed." {} }
+kpasswd_v4 CPW.7 pol2 -1 polBBBBBB pol222222 {
+ "Password cannot be changed because it was changed too recently." {}
+} {
+ "$kpasswd_v4: Insecure password rejected while attempting to change password." { send "\003\n"; close; break }
+}
+
+server_exit "CPW.all" -1
diff --git a/src/kadmin/v4server/unit-test/v4server.1/usage.exp b/src/kadmin/v4server/unit-test/v4server.1/usage.exp
new file mode 100644
index 0000000000..4d292067a1
--- /dev/null
+++ b/src/kadmin/v4server/unit-test/v4server.1/usage.exp
@@ -0,0 +1,26 @@
+load_lib "helpers.exp"
+
+set timeout 10
+
+server_start "U.1: -h" "-h" 0 {
+ -re {Usage: .*} {}
+} {
+ eof {}
+}
+server_exit "U.1: -h" 255
+
+server_start "U.4: -n" "-n" 1 {
+ "Enter KDC database master key:" {
+ myfail "unexpected password prompt"
+ }
+ "KADM Server starting in the OVSEC_KADM mode" {}
+}
+
+server_exit "U.4: -n" -1
+
+server_start "U.5: no -n" "" 1 {
+ "KADM Server starting in the OVSEC_KADM mode" {}
+} {
+ "Enter KDC database master key:" { send "mrroot\n" }
+}
+server_exit "U.5: no -n" -1
diff --git a/src/kdc/ChangeLog b/src/kdc/ChangeLog
index 94090314e0..eca2edc699 100644
--- a/src/kdc/ChangeLog
+++ b/src/kdc/ChangeLog
@@ -7,6 +7,10 @@ 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>
diff --git a/src/kdc/configure.in b/src/kdc/configure.in
index 1e4211d893..163060e723 100644
--- a/src/kdc/configure.in
+++ b/src/kdc/configure.in
@@ -31,7 +31,7 @@ if test "$withval" = yes; then
AC_DEFINE(KRBCONF_KDC_MODIFIES_KDB)
fi
dnl
-USE_KADM_LIBRARY
+USE_KADMSRV_LIBRARY
USE_KDB5_LIBRARY
USE_KRB4_LIBRARY
KRB5_LIBRARIES
diff --git a/src/krb524/ChangeLog b/src/krb524/ChangeLog
index 999353451d..f8304f252f 100644
--- a/src/krb524/ChangeLog
+++ b/src/krb524/ChangeLog
@@ -1,3 +1,11 @@
+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
diff --git a/src/krb524/configure.in b/src/krb524/configure.in
index 1f456b3b68..fe92f9bcaa 100644
--- a/src/krb524/configure.in
+++ b/src/krb524/configure.in
@@ -4,9 +4,13 @@ AC_PROG_ARCHIVE
AC_PROG_ARCHIVE_ADD
AC_PROG_RANLIB
AC_PROG_INSTALL
-AC_TYPE_SIGNAL
AC_PROG_AWK
-USE_KADM_LIBRARY
+AC_TYPE_SIGNAL
+USE_KADMSRV_LIBRARY
+USE_GSSRPC_LIBRARY
+USE_GSSAPI_LIBRARY
+USE_DYN_LIBRARY
+USE_DB_LIBRARY
USE_KDB5_LIBRARY
USE_KRB4_LIBRARY
KRB5_LIBRARIES
diff --git a/src/krb524/krb524d.c b/src/krb524/krb524d.c
index 1a9dbabcac..c765ab7ad2 100644
--- a/src/krb524/krb524d.c
+++ b/src/krb524/krb524d.c
@@ -20,8 +20,9 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-#include "k5-int.h"
-#include "com_err.h"
+#include <krb5.h>
+#include <kadm5/admin.h>
+#include <com_err.h>
#include <stdio.h>
#ifdef HAVE_SYS_SELECT_H
@@ -36,7 +37,6 @@
#include <netinet/in.h>
#include <netdb.h>
-#include "adm.h"
#include <krb.h>
#include "krb524.h"
@@ -47,16 +47,12 @@
char *whoami;
int signalled = 0;
static int debug = 0;
+void *handle;
-int use_keytab;
+int use_keytab, use_master;
char *keytab = NULL;
krb5_keytab kt;
-int use_master;
-krb5_principal master_princ;
-krb5_encrypt_block master_encblock;
-krb5_keyblock master_keyblock;
-
void init_keytab(), init_master(), cleanup_and_exit();
krb5_error_code do_connection(), lookup_service_key(), kdc_get_server_key();
@@ -73,6 +69,8 @@ RETSIGTYPE request_exit(signo)
signalled = 1;
}
+#if 0
+/* this is in the kadm5 library */
int krb5_free_keyblock_contents(context, key)
krb5_context context;
krb5_keyblock *key;
@@ -81,6 +79,7 @@ int krb5_free_keyblock_contents(context, key)
krb5_xfree(key->contents);
return 0;
}
+#endif
int main(argc, argv)
int argc;
@@ -92,8 +91,7 @@ int main(argc, argv)
int ret, s;
fd_set rfds;
krb5_context context;
- krb5_realm_params *rparams;
- char *realm = 0;
+
krb5_init_context(&context);
krb524_init_ets(context);
@@ -119,16 +117,12 @@ int main(argc, argv)
signal(SIGINT, request_exit);
signal(SIGHUP, request_exit);
signal(SIGTERM, request_exit);
- if (!realm&&(ret = krb5_get_default_realm(context, &realm)))
- {
-com_err(whoami, ret, "Getting default realm");
-exit(1);
-}
if (use_keytab)
init_keytab(context);
if (use_master)
- init_master(context);
+ /* someday maybe there will be some config param options */
+ init_master(context, NULL);
memset((char *) &saddr, 0, sizeof(struct sockaddr_in));
saddr.sin_family = AF_INET;
@@ -161,7 +155,7 @@ exit(1);
cleanup_and_exit(0, context);
else if (ret == 0) {
if (use_master) {
- ret = krb5_db_fini(context);
+ ret = kadm5_flush(handle);
if (ret && ret != KRB5_KDB_DBNOTINITED) {
com_err(whoami, ret, "closing kerberos database");
cleanup_and_exit(1, context);
@@ -188,11 +182,8 @@ void cleanup_and_exit(ret, context)
krb5_context context;
{
if (use_master) {
- krb5_finish_key(context, &master_encblock);
- memset((char *)&master_encblock, 0, sizeof(master_encblock));
- (void) krb5_db_fini(context);
+ (void) kadm5_destroy(handle);
}
- if (use_master) krb5_free_principal(context, master_princ);
if (use_keytab) krb5_kt_close(context, kt);
krb5_free_context(context);
exit(ret);
@@ -218,83 +209,20 @@ void init_keytab(context)
use_keytab = 1; /* now safe to close keytab */
}
-void init_master(context)
+void init_master(context, params)
krb5_context context;
+ kadm5_config_params *params;
{
int ret;
- krb5_realm_params *rparams;
- char *realm = 0;
- char *key_name =0, *dbname = 0;
- char *stash_file = 0;
use_master = 0;
- /* Use the stashed enctype */
- master_keyblock.enctype = ENCTYPE_UNKNOWN;
-
- if (!realm&&(ret = krb5_get_default_realm(context, &realm))) {
- com_err(whoami, ret, "getting default realm");
+ if (ret = kadm5_init(whoami, NULL, KADM5_ADMIN_SERVICE, params,
+ KADM5_STRUCT_VERSION, KADM5_API_VERSION_2,
+ &handle)) {
+ com_err(whoami, ret, "initializing kadm5 library");
cleanup_and_exit(1, context);
}
- if ((ret = krb5_read_realm_params(context,
- realm,
- (char *) NULL, (char *) NULL,
- &rparams))) {
- com_err(whoami, ret, "Reading KDC profile");
-krb5_xfree(realm);
- cleanup_and_exit(1,context);
- }
-
- /* Get the value for the database */
- if (rparams->realm_dbname && !dbname)
- dbname = strdup(rparams->realm_dbname);
-
- /* Get the value for the master key name */
- if (rparams->realm_mkey_name && !key_name)
- key_name = strdup(rparams->realm_mkey_name);
-
- /* Get the value for the master key type */
- if (rparams->realm_enctype_valid )
- master_keyblock.enctype = rparams->realm_enctype;
-
- /* Get the value for the stashfile */
- if (rparams->realm_stash_file)
- stash_file = strdup(rparams->realm_stash_file);
-
- if ((ret = krb5_db_set_name(context, dbname))) {
- com_err(whoami, ret, "Setting database name");
- cleanup_and_exit(1,context);
- }
-
- if ((ret = krb5_db_setup_mkey_name(context, key_name, realm, (char **) 0,
- &master_princ))) {
- free(realm);
- com_err(whoami, ret, "while setting up master key name");
- cleanup_and_exit(1, context);
- } else {
- free(realm);
- }
-
-
- if ((ret = krb5_db_fetch_mkey(context, master_princ, &master_encblock,
- FALSE, /* non-manual type-in */
- FALSE, /* irrelevant, given prev. arg */
- stash_file,
- 0, &master_keyblock))) {
- com_err(whoami, ret, "while fetching master key");
- cleanup_and_exit(1, context);
- }
-
- if ((ret = krb5_db_init(context))) {
- com_err(whoami, ret, "while initializing master database");
- cleanup_and_exit(1, context);
- }
- if ((ret = krb5_process_key(context, &master_encblock,
- &master_keyblock))) {
- krb5_db_fini(context);
- com_err(whoami, ret, "while processing master key");
- cleanup_and_exit(1, context);
- }
- use_master = 1; /* now safe to finish master key */
+ use_master = 1; /* now safe to close kadm5 */
}
krb5_error_code do_connection(s, context)
@@ -434,14 +362,11 @@ krb5_error_code lookup_service_key(context, p, ktype, key)
memcpy(key, (char *) &entry.key, sizeof(krb5_keyblock));
return 0;
} else if (use_master) {
- if ((ret = krb5_db_init(context)))
- return ret;
return kdc_get_server_key(context, p, key, NULL, ktype);
}
return 0;
}
-/* taken from kdc/kdc_util.c, and modified somewhat */
krb5_error_code kdc_get_server_key(context, service, key, kvno, ktype)
krb5_context context;
krb5_principal service;
@@ -450,54 +375,36 @@ krb5_error_code kdc_get_server_key(context, service, key, kvno, ktype)
krb5_enctype ktype;
{
krb5_error_code ret;
- int nprincs;
- krb5_db_entry server;
- krb5_boolean more;
- int i, vno, ok_key;
- krb5_key_data *pkey;
- nprincs = 1;
- if ((ret = krb5_db_get_principal(context, service, &server,
- &nprincs, &more)))
- return(ret);
-
- if (more) {
- krb5_db_free_principal(context, &server, nprincs);
- return(KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE);
- } else if (nprincs != 1) {
- krb5_db_free_principal(context, &server, nprincs);
- return(KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN);
- }
-/* We use krb5_dbe_find_enctype 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.*/
+ kadm5_principal_ent_rec server;
- if (krb5_dbe_find_enctype(context,
- &server,
- ktype,
- (ktype == ENCTYPE_DES_CBC_CRC)?
- KRB5_KDB_SALTTYPE_V4:-1,
- -1,
- &pkey) &&
- krb5_dbe_find_enctype(context,
- &server,
- ktype,
- -1,
- -1,
- &pkey))
- {
- krb5_db_free_principal(context, &server, nprincs);
- return (KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN);
- }
-if (kvno)
- *kvno = pkey->key_data_kvno;
- ret = krb5_dbekd_decrypt_key_data(context, &master_encblock,
- pkey, key, NULL);
- krb5_db_free_principal(context, &server, nprincs);
-
-
+ if (ret = kadm5_get_principal(handle, service, &server,
+ KADM5_KEY_DATA))
+ return ret;
+
+ /*
+ * 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,
+ -1,
+ key, NULL, kvno)) &&
+ (ret = kadm5_decrypt_key(handle,
+ &server,
+ ktype,
+ -1,
+ -1,
+ key, NULL, kvno))) {
+ kadm5_free_principal_ent(handle, &server);
+ return (KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN);
+ }
+ kadm5_free_principal_ent(handle, &server);
return ret;
}
-
diff --git a/src/lib/ChangeLog b/src/lib/ChangeLog
index 210d8cf517..c7e7fb6b1a 100644
--- a/src/lib/ChangeLog
+++ b/src/lib/ChangeLog
@@ -12,6 +12,10 @@ Wed Jul 10 20:32:22 1996 Theodore Y. Ts'o <tytso@mit.edu>
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
diff --git a/src/lib/configure.in b/src/lib/configure.in
index aebd96c6a9..80c359eb35 100644
--- a/src/lib/configure.in
+++ b/src/lib/configure.in
@@ -7,7 +7,7 @@ else
AC_MSG_RESULT(skipping Kerberos 4 libraries)
krb4=
fi
-CONFIG_DIRS(crypto krb5 des425 $krb4 krb5util kdb gssapi kadm)
+CONFIG_DIRS(crypto krb5 des425 $krb4 krb5util kdb gssapi rpc kadm5)
AC_PROG_ARCHIVE
AC_PROG_RANLIB
DO_SUBDIRS
diff --git a/src/lib/crypto/des/ChangeLog b/src/lib/crypto/des/ChangeLog
index f8637a6e79..c6f7072903 100644
--- a/src/lib/crypto/des/ChangeLog
+++ b/src/lib/crypto/des/ChangeLog
@@ -1,3 +1,4 @@
+<<<<<<< ChangeLog
Sat Jun 15 03:51:19 1996 Ezra Peisach <epeisach@kangaroo.mit.edu>
* Makefile.in (clean): Add space before \
@@ -66,6 +67,11 @@ Thu May 2 18:29:01 1996 Richard Basch <basch@lehman.com>
[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
diff --git a/src/lib/crypto/des/cbc_cksum.c b/src/lib/crypto/des/cbc_cksum.c
index 9c98263a2a..c4fb8c0860 100644
--- a/src/lib/crypto/des/cbc_cksum.c
+++ b/src/lib/crypto/des/cbc_cksum.c
@@ -86,7 +86,6 @@ mit_des_cbc_checksum(in, in_length, key, key_size, cksum)
cksum->checksum_type = CKSUMTYPE_DESCBC;
cksum->length = sizeof(mit_des_cblock);
-
mit_des_cbc_cksum(in, cksum->contents, in_length, schedule, key);
cleanup();
diff --git a/src/lib/gssapi/ChangeLog b/src/lib/gssapi/ChangeLog
index 0ad7c89bd8..036bd46930 100644
--- a/src/lib/gssapi/ChangeLog
+++ b/src/lib/gssapi/ChangeLog
@@ -12,6 +12,11 @@ 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
diff --git a/src/lib/gssapi/Makefile.in b/src/lib/gssapi/Makefile.in
index c27788dc2f..b874a951c5 100644
--- a/src/lib/gssapi/Makefile.in
+++ b/src/lib/gssapi/Makefile.in
@@ -10,8 +10,8 @@ KRB5_VER=@KRB5_SH_VERS@
DEPLIBS=$(TOPLIBD)/libcrypto.$(SHEXT).$(CRYPTO_VER) \
$(TOPLIBD)/libcom_err.$(SHEXT).$(COMERR_VER) \
$(TOPLIBD)/libkrb5.$(SHEXT).$(KRB5_VER)
-LIB_SUBDIRS= generic krb5 mechglue
-LIBDONE= generic/DONE krb5/DONE mechglue/DONE
+LIB_SUBDIRS= generic krb5
+LIBDONE= generic/DONE krb5/DONE # mechglue/DONE
LIBUPDATE= $(BUILDTOP)/util/libupdate
SHLIB_LIBS=-lkrb5 -lcrypto -lcom_err
@@ -51,9 +51,9 @@ all-windows::
cd ..\krb5
@echo Making in gssapi\krb5
-$(MAKE) -$(MFLAGS)
- cd ..\mechglue
- @echo Making in gssapi\mechglue
- -$(MAKE) -$(MFLAGS)
+# cd ..\mechglue
+# @echo Making in gssapi\mechglue
+# -$(MAKE) -$(MFLAGS)
cd ..
clean-windows::
@@ -63,9 +63,9 @@ clean-windows::
cd ..\krb5
@echo Making clean in gssapi\krb5
-$(MAKE) -$(MFLAGS) clean
- cd ..\mechglue
- @echo Making clean in gssapi\mechglue
- -$(MAKE) -$(MFLAGS) clean
+# cd ..\mechglue
+# @echo Making clean in gssapi\mechglue
+# -$(MAKE) -$(MFLAGS) clean
cd ..
@echo Making clean in gssapi
diff --git a/src/lib/gssapi/configure.in b/src/lib/gssapi/configure.in
index ee150e11f4..164582c647 100644
--- a/src/lib/gssapi/configure.in
+++ b/src/lib/gssapi/configure.in
@@ -1,6 +1,7 @@
AC_INIT(configure.in)
CONFIG_RULES
-CONFIG_DIRS(generic krb5 mechglue)
+CONFIG_DIRS(generic krb5)
+dnl CONFIG_DIRS(generic krb5 mechglue)
AC_PROG_ARCHIVE
AC_PROG_ARCHIVE_ADD
AC_PROG_RANLIB
diff --git a/src/lib/gssapi/generic/ChangeLog b/src/lib/gssapi/generic/ChangeLog
index d434599140..a3b2a14110 100644
--- a/src/lib/gssapi/generic/ChangeLog
+++ b/src/lib/gssapi/generic/ChangeLog
@@ -28,6 +28,26 @@ Wed Jun 12 00:46:41 1996 Theodore Ts'o <tytso@rsts-11.mit.edu>
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
diff --git a/src/lib/gssapi/generic/Makefile.in b/src/lib/gssapi/generic/Makefile.in
index 9c90244f24..c9e940962a 100644
--- a/src/lib/gssapi/generic/Makefile.in
+++ b/src/lib/gssapi/generic/Makefile.in
@@ -39,28 +39,40 @@ gssapi_err_generic.c: gssapi_err_generic.et
#endif
SRCS = \
- $(srcdir)/disp_major_status.c \
$(srcdir)/disp_com_err_status.c \
+ $(srcdir)/disp_major_status.c \
+ $(srcdir)/gssapi_generic.c \
+ $(srcdir)/oid_ops.c \
+ $(srcdir)/release_buffer.c \
+ $(srcdir)/release_oid_set.c \
$(srcdir)/util_buffer.c \
$(srcdir)/util_canonhost.c \
$(srcdir)/util_dup.c \
$(srcdir)/util_oid.c \
+ $(srcdir)/util_ordering.c \
+ $(srcdir)/util_set.c \
$(srcdir)/util_token.c \
- $(srcdir)/utl_nohash_validate.c \
+ $(srcdir)/util_validate.c \
gssapi_err_generic.c
OBJS = \
- disp_major_status.$(OBJEXT) \
disp_com_err_status.$(OBJEXT) \
+ disp_major_status.$(OBJEXT) \
+ gssapi_generic.$(OBJEXT) \
+ oid_ops.$(OBJEXT) \
+ release_buffer.$(OBJEXT) \
+ release_oid_set.$(OBJEXT) \
util_buffer.$(OBJEXT) \
util_canonhost.$(OBJEXT) \
util_dup.$(OBJEXT) \
util_oid.$(OBJEXT) \
+ util_ordering.$(OBJEXT) \
+ util_set.$(OBJEXT) \
util_token.$(OBJEXT) \
- utl_nohash_validate.$(OBJEXT) \
+ util_validate.$(OBJEXT) \
gssapi_err_generic.$(OBJEXT)
-EHDRDIR= $(BUILDTOP)$(S)include$(S)gssapi
+EHDRDIR= $(BUILDTOP)/include/gssapi
EXPORTED_HEADERS= gssapi.h gssapi_generic.h
HDRS= $(ETHDRS)
@@ -89,8 +101,8 @@ clean-windows::
# 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 ; \
+ do $(INSTALL_DATA) $(srcdir)/$$f \
+ $(DESTDIR)$(KRB5_INCDIR)/gssapi/$$f ; \
done
depend:: $(ETSRCS)
diff --git a/src/lib/gssapi/generic/disp_com_err_status.c b/src/lib/gssapi/generic/disp_com_err_status.c
index 79b5fbbe2e..c4db91375c 100644
--- a/src/lib/gssapi/generic/disp_com_err_status.c
+++ b/src/lib/gssapi/generic/disp_com_err_status.c
@@ -20,6 +20,10 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
+/*
+ * $Id$
+ */
+
#include "gssapiP_generic.h"
#include "com_err.h"
diff --git a/src/lib/gssapi/generic/disp_major_status.c b/src/lib/gssapi/generic/disp_major_status.c
index ad0b17f203..4dd91d25fd 100644
--- a/src/lib/gssapi/generic/disp_major_status.c
+++ b/src/lib/gssapi/generic/disp_major_status.c
@@ -23,6 +23,10 @@
#include "gssapiP_generic.h"
#include <string.h>
+/*
+ * $Id$
+ */
+
/* This code has knowledge of the min and max errors of each type
within the gssapi major status */
diff --git a/src/lib/gssapi/generic/gssapi.h b/src/lib/gssapi/generic/gssapi.h
index 2b2e6002bf..28cc4ca417 100644
--- a/src/lib/gssapi/generic/gssapi.h
+++ b/src/lib/gssapi/generic/gssapi.h
@@ -131,14 +131,6 @@ typedef unsigned int uid_t;
#endif
#endif
-#ifndef NPROTOTYPE
-#if defined(__ultrix) && !defined (__GNUC__)
-#define NPROTOTYPE(x) ()
-#else
-#define NPROTOTYPE(x) PROTOTYPE(x)
-#endif
-#endif
-
/*
* First, include stddef.h to get size_t defined.
*/
@@ -161,8 +153,13 @@ typedef unsigned int uid_t;
#endif /* HAVE_XOM_H */
/*
+ * $Id$
+ */
+
+/*
* First, define the three platform-dependent pointer types.
*/
+
typedef void FAR * gss_name_t;
typedef void FAR * gss_cred_id_t;
typedef void FAR * gss_ctx_id_t;
@@ -305,7 +302,7 @@ typedef int gss_cred_usage_t;
* Expiration time of 2^32-1 seconds means infinite lifetime for a
* credential or security context
*/
-#define GSS_C_INDEFINITE 0xffffffffl
+#define GSS_C_INDEFINITE ((OM_uint32) 0xfffffffful)
/* Major status codes */
@@ -318,9 +315,9 @@ typedef int gss_cred_usage_t;
#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 0377l
-#define GSS_C_ROUTINE_ERROR_MASK 0377l
-#define GSS_C_SUPPLEMENTARY_MASK 0177777l
+#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
@@ -345,43 +342,51 @@ typedef int gss_cred_usage_t;
* Calling errors:
*/
#define GSS_S_CALL_INACCESSIBLE_READ \
- (1l << GSS_C_CALLING_ERROR_OFFSET)
+ (((OM_uint32) 1ul) << GSS_C_CALLING_ERROR_OFFSET)
#define GSS_S_CALL_INACCESSIBLE_WRITE \
- (2l << GSS_C_CALLING_ERROR_OFFSET)
+ (((OM_uint32) 2ul) << GSS_C_CALLING_ERROR_OFFSET)
#define GSS_S_CALL_BAD_STRUCTURE \
- (3l << GSS_C_CALLING_ERROR_OFFSET)
+ (((OM_uint32) 3ul) << GSS_C_CALLING_ERROR_OFFSET)
/*
* Routine errors:
*/
-#define GSS_S_BAD_MECH (1l << GSS_C_ROUTINE_ERROR_OFFSET)
-#define GSS_S_BAD_NAME (2l << GSS_C_ROUTINE_ERROR_OFFSET)
-#define GSS_S_BAD_NAMETYPE (3l << GSS_C_ROUTINE_ERROR_OFFSET)
-#define GSS_S_BAD_BINDINGS (4l << GSS_C_ROUTINE_ERROR_OFFSET)
-#define GSS_S_BAD_STATUS (5l << GSS_C_ROUTINE_ERROR_OFFSET)
-#define GSS_S_BAD_SIG (6l << GSS_C_ROUTINE_ERROR_OFFSET)
-#define GSS_S_NO_CRED (7l << GSS_C_ROUTINE_ERROR_OFFSET)
-#define GSS_S_NO_CONTEXT (8l << GSS_C_ROUTINE_ERROR_OFFSET)
-#define GSS_S_DEFECTIVE_TOKEN (9l << GSS_C_ROUTINE_ERROR_OFFSET)
-#define GSS_S_DEFECTIVE_CREDENTIAL (10l << GSS_C_ROUTINE_ERROR_OFFSET)
-#define GSS_S_CREDENTIALS_EXPIRED (11l << GSS_C_ROUTINE_ERROR_OFFSET)
-#define GSS_S_CONTEXT_EXPIRED (12l << GSS_C_ROUTINE_ERROR_OFFSET)
-#define GSS_S_FAILURE (13l << GSS_C_ROUTINE_ERROR_OFFSET)
-#define GSS_S_BAD_QOP (14l << GSS_C_ROUTINE_ERROR_OFFSET)
-#define GSS_S_UNAUTHORIZED (15l << GSS_C_ROUTINE_ERROR_OFFSET)
-#define GSS_S_UNAVAILABLE (16l << GSS_C_ROUTINE_ERROR_OFFSET)
+#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)
/*
* XXX new functions. Check to get official error number assigments?
*/
-#define GSS_S_DUPLICATE_ELEMENT (17l << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_DUPLICATE_ELEMENT \
+ (((OM_uint32) 17ul) << GSS_C_ROUTINE_ERROR_OFFSET)
/*
* Supplementary info bits:
*/
-#define GSS_S_CONTINUE_NEEDED (1l << (GSS_C_SUPPLEMENTARY_OFFSET + 0))
-#define GSS_S_DUPLICATE_TOKEN (1l << (GSS_C_SUPPLEMENTARY_OFFSET + 1))
-#define GSS_S_OLD_TOKEN (1l << (GSS_C_SUPPLEMENTARY_OFFSET + 2))
-#define GSS_S_UNSEQ_TOKEN (1l << (GSS_C_SUPPLEMENTARY_OFFSET + 3))
+#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))
+/*
+ * XXX not in the cbindings yet. remove this comment when it is
+ */
+#define GSS_S_GAP_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 4))
/*
diff --git a/src/lib/gssapi/generic/gssapiP_generic.h b/src/lib/gssapi/generic/gssapiP_generic.h
index a882f61392..e0bb28d447 100644
--- a/src/lib/gssapi/generic/gssapiP_generic.h
+++ b/src/lib/gssapi/generic/gssapiP_generic.h
@@ -23,7 +23,10 @@
#ifndef _GSSAPIP_GENERIC_H_
#define _GSSAPIP_GENERIC_H_
-#include "k5-int.h"
+/*
+ * $Id$
+ */
+
#include "gssapi.h"
#include "gssapi_err_generic.h"
@@ -86,6 +89,14 @@
/** helper functions **/
+typedef struct _g_set *g_set;
+
+int g_set_init PROTOTYPE((g_set *s));
+int g_set_destroy PROTOTYPE((g_set *s));
+int g_set_entry_add PROTOTYPE((g_set *s, void *key, void *value));
+int g_set_entry_delete PROTOTYPE((g_set *s, void *key));
+int g_set_entry_get PROTOTYPE((g_set *s, void *key, void **value));
+
int g_save_name PROTOTYPE((void **vdb, gss_name_t *name));
int g_save_cred_id PROTOTYPE((void **vdb, gss_cred_id_t *cred));
int g_save_ctx_id PROTOTYPE((void **vdb, gss_ctx_id_t *ctx));
@@ -119,8 +130,64 @@ OM_uint32 g_display_com_err_status PROTOTYPE((OM_uint32 *minor_status,
OM_uint32 status_value,
gss_buffer_t status_string));
-char * g_canonicalize_host PROTOTYPE((char *hostname));
-
-char * g_strdup PROTOTYPE((char *str));
+OM_uint32 g_order_init PROTOTYPE((void **queue, unsigned int seqnum,
+ int do_replay, int do_sequence));
+
+OM_uint32 g_order_check PROTOTYPE((void **queue, unsigned int seqnum));
+
+void g_order_free PROTOTYPE((void **queue));
+
+char *g_canonicalize_host PROTOTYPE((char *hostname));
+char *g_local_host_name PROTOTYPE((void));
+
+char *g_strdup PROTOTYPE((char *str));
+
+/** declarations of internal name mechanism functions **/
+
+OM_uint32 generic_gss_release_buffer
+PROTOTYPE((OM_uint32*, /* minor_status */
+ gss_buffer_t /* buffer */
+ ));
+
+OM_uint32 generic_gss_release_oid_set
+PROTOTYPE((OM_uint32*, /* minor_status */
+ gss_OID_set* /* set */
+ ));
+
+OM_uint32 generic_gss_copy_oid
+PROTOTYPE( (OM_uint32 *, /* minor_status */
+ gss_OID, /* oid */
+ gss_OID * /* new_oid */
+ ));
+
+OM_uint32 generic_gss_create_empty_oid_set
+PROTOTYPE( (OM_uint32 *, /* minor_status */
+ gss_OID_set * /* oid_set */
+ ));
+
+OM_uint32 generic_gss_add_oid_set_member
+PROTOTYPE( (OM_uint32 *, /* minor_status */
+ gss_OID, /* member_oid */
+ gss_OID_set * /* oid_set */
+ ));
+
+OM_uint32 generic_gss_test_oid_set_member
+PROTOTYPE( (OM_uint32 *, /* minor_status */
+ gss_OID, /* member */
+ gss_OID_set, /* set */
+ int * /* present */
+ ));
+
+OM_uint32 generic_gss_oid_to_str
+PROTOTYPE( (OM_uint32 *, /* minor_status */
+ gss_OID, /* oid */
+ gss_buffer_t /* oid_str */
+ ));
+
+OM_uint32 generic_gss_str_to_oid
+PROTOTYPE( (OM_uint32 *, /* minor_status */
+ gss_buffer_t, /* oid_str */
+ gss_OID * /* oid */
+ ));
#endif /* _GSSAPIP_GENERIC_H_ */
diff --git a/src/lib/gssapi/generic/gssapi_err_generic.et b/src/lib/gssapi/generic/gssapi_err_generic.et
index 91d958d125..ddeed4227e 100644
--- a/src/lib/gssapi/generic/gssapi_err_generic.et
+++ b/src/lib/gssapi/generic/gssapi_err_generic.et
@@ -20,6 +20,10 @@
# PERFORMANCE OF THIS SOFTWARE.
#
+#
+# $Id$
+#
+
error_table ggss
error_code G_BAD_SERVICE_NAME, "No @ in SERVICE-NAME name string"
@@ -31,5 +35,9 @@ 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"
end
diff --git a/src/lib/gssapi/generic/gssapi_generic.c b/src/lib/gssapi/generic/gssapi_generic.c
new file mode 100644
index 0000000000..7072329b75
--- /dev/null
+++ b/src/lib/gssapi/generic/gssapi_generic.c
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+/*
+ * 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 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"},
+};
+
+gss_OID gss_nt_user_name = oids+0;
+gss_OID gss_nt_machine_uid_name = oids+1;
+gss_OID gss_nt_string_uid_name = oids+2;
+gss_OID gss_nt_service_name = oids+3;
diff --git a/src/lib/gssapi/generic/gssapi_generic.h b/src/lib/gssapi/generic/gssapi_generic.h
index fe22827967..88c0547880 100644
--- a/src/lib/gssapi/generic/gssapi_generic.h
+++ b/src/lib/gssapi/generic/gssapi_generic.h
@@ -23,6 +23,10 @@
#ifndef _GSSAPI_GENERIC_H_
#define _GSSAPI_GENERIC_H_
+/*
+ * $Id$
+ */
+
#if defined(__MWERKS__) || defined(applec) || defined(THINK_C)
#include <gssapi.h>
#else
diff --git a/src/lib/gssapi/generic/oid_ops.c b/src/lib/gssapi/generic/oid_ops.c
new file mode 100644
index 0000000000..38d73f429e
--- /dev/null
+++ b/src/lib/gssapi/generic/oid_ops.c
@@ -0,0 +1,385 @@
+/*
+ * 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. M.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>
+
+#if 0
+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)) {
+ free((*oid)->elements);
+ free(*oid);
+ }
+ *oid = GSS_C_NO_OID;
+ return(GSS_S_COMPLETE);
+}
+#endif
+
+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 index;
+ unsigned char *op;
+
+ 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++;
+ nbytes++;
+ while (isdigit(*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(*bp))
+ bp++;
+ while ((bp < &cp[oid_str->length]) && isspace(*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(*bp))
+ bp++;
+ while (isspace(*bp))
+ bp++;
+ onumbuf = 40*numbuf;
+ sscanf(bp, "%ld", &numbuf);
+ onumbuf += numbuf;
+ *op = (unsigned char) onumbuf;
+ op++;
+ while (isdigit(*bp))
+ bp++;
+ while (isspace(*bp))
+ bp++;
+ while (isdigit(*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;
+ 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++;
+ }
+ *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/src/lib/gssapi/generic/release_buffer.c b/src/lib/gssapi/generic/release_buffer.c
new file mode 100644
index 0000000000..d367ef31ec
--- /dev/null
+++ b/src/lib/gssapi/generic/release_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 "gssapiP_generic.h"
+
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+OM_uint32 INTERFACE
+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->length) &&
+ (buffer->value)) {
+ free(buffer->value);
+ buffer->length = 0;
+ buffer->value = NULL;
+ }
+
+ return (GSS_S_COMPLETE);
+}
diff --git a/src/lib/gssapi/generic/release_oid_set.c b/src/lib/gssapi/generic/release_oid_set.c
new file mode 100644
index 0000000000..01e814bcb4
--- /dev/null
+++ b/src/lib/gssapi/generic/release_oid_set.c
@@ -0,0 +1,62 @@
+/* #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 INTERFACE
+generic_gss_release_oid_set (minor_status,
+ set)
+ OM_uint32 * minor_status;
+ gss_OID_set * set;
+{
+ size_t i;
+ 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 (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/src/lib/gssapi/generic/util_buffer.c b/src/lib/gssapi/generic/util_buffer.c
index cf144495f8..e715834d92 100644
--- a/src/lib/gssapi/generic/util_buffer.c
+++ b/src/lib/gssapi/generic/util_buffer.c
@@ -20,6 +20,10 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
+/*
+ * $Id$
+ */
+
#include "gssapiP_generic.h"
#include <string.h>
diff --git a/src/lib/gssapi/generic/util_canonhost.c b/src/lib/gssapi/generic/util_canonhost.c
index 896b950b15..900834f40d 100644
--- a/src/lib/gssapi/generic/util_canonhost.c
+++ b/src/lib/gssapi/generic/util_canonhost.c
@@ -20,10 +20,16 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
+/*
+ * $Id$
+ */
+
/* This file could be OS specific */
-#define NEED_SOCKETS
+
#include "gssapiP_generic.h"
+#include "port-sockets.h"
+
#ifndef _MACINTOSH
#include <sys/types.h>
#endif
@@ -41,7 +47,7 @@ g_canonicalize_host(hostname)
if ((hent = gethostbyname(hostname)) == NULL)
return(NULL);
- if (! (haddr = xmalloc(hent->h_length))) {
+ if (! (haddr = (char *) xmalloc(hent->h_length))) {
return(NULL);
}
@@ -53,7 +59,7 @@ g_canonicalize_host(hostname)
xfree(haddr);
- if ((canon = xmalloc(strlen(hent->h_name)+1)) == NULL)
+ if ((canon = (char *) xmalloc(strlen(hent->h_name)+1)) == NULL)
return(NULL);
strcpy(canon, hent->h_name);
diff --git a/src/lib/gssapi/generic/util_dup.c b/src/lib/gssapi/generic/util_dup.c
index 6b19092db8..d601ceef2f 100644
--- a/src/lib/gssapi/generic/util_dup.c
+++ b/src/lib/gssapi/generic/util_dup.c
@@ -20,6 +20,10 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
+/*
+ * $Id$
+ */
+
#include "gssapiP_generic.h"
#include <string.h>
diff --git a/src/lib/gssapi/generic/util_oid.c b/src/lib/gssapi/generic/util_oid.c
index 91bb544ede..8843a7ff6a 100644
--- a/src/lib/gssapi/generic/util_oid.c
+++ b/src/lib/gssapi/generic/util_oid.c
@@ -22,6 +22,10 @@
#include "gssapiP_generic.h"
+/*
+ * $Id$
+ */
+
int
g_copy_OID_set(in, out)
const gss_OID_set_desc * const in;
diff --git a/src/lib/gssapi/generic/util_token.c b/src/lib/gssapi/generic/util_token.c
index e440d907a3..027d2a765f 100644
--- a/src/lib/gssapi/generic/util_token.c
+++ b/src/lib/gssapi/generic/util_token.c
@@ -23,11 +23,9 @@
#include "gssapiP_generic.h"
#include <memory.h>
-#if (SIZEOF_INT == 2)
-#define VALID_INT_BITS 0x7fff
-#elif (SIZEOF_INT == 4)
-#define VALID_INT_BITS 0x7fffffff
-#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
@@ -153,58 +151,68 @@ void g_make_token_header(mech, body_size, buf, tok_type)
*(*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 */
-
-int g_verify_token_header(mech, body_size, buf, tok_type, toksize)
+/*
+ * 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.
+ */
+int g_verify_token_header(mech, body_size, buf_in, tok_type, toksize)
gss_OID mech;
int *body_size;
- unsigned char **buf;
+ unsigned char **buf_in;
int tok_type;
int toksize;
{
+ char *buf = *buf_in;
int seqsize;
gss_OID_desc toid;
+ int ret = 0;
if ((toksize-=1) < 0)
- return(0);
- if (*(*buf)++ != 0x60)
- return(0);
+ return(G_BAD_TOK_HEADER);
+ if (*buf++ != 0x60)
+ return(G_BAD_TOK_HEADER);
- if ((seqsize = der_read_length(buf, &toksize)) < 0)
- return(0);
+ if ((seqsize = der_read_length(&buf, &toksize)) < 0)
+ return(G_BAD_TOK_HEADER);
if (seqsize != toksize)
- return(0);
+ return(G_BAD_TOK_HEADER);
if ((toksize-=1) < 0)
- return(0);
- if (*(*buf)++ != 0x06)
- return(0);
+ return(G_BAD_TOK_HEADER);
+ if (*buf++ != 0x06)
+ return(G_BAD_TOK_HEADER);
if ((toksize-=1) < 0)
- return(0);
- toid.length = *(*buf)++;
-
- if ((toid.length & VALID_INT_BITS) != toid.length) /* Overflow??? */
- return(0);
- if ((toksize-= (int) toid.length) < 0)
- return(0);
- toid.elements = *buf;
- (*buf)+=toid.length;
-
- if (! g_OID_equal(&toid, mech))
- return(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))
+ ret = G_WRONG_MECH;
+ /* G_WRONG_MECH is not returned immediately because it's more important
+ to return G_BAD_TOK_HEADER if the token header is in fact bad */
+
if ((toksize-=2) < 0)
- return(0);
+ return(G_BAD_TOK_HEADER);
- if ((*(*buf)++ != ((tok_type>>8)&0xff)) ||
- (*(*buf)++ != (tok_type&0xff)))
- return(0);
+ if ((*buf++ != ((tok_type>>8)&0xff)) ||
+ (*buf++ != (tok_type&0xff)))
+ return(G_BAD_TOK_HEADER);
- *body_size = toksize;
+ if (!ret) {
+ *buf_in = buf;
+ *body_size = toksize;
+ }
- return(1);
+ return(ret);
}
diff --git a/src/lib/gssapi/generic/util_validate.c b/src/lib/gssapi/generic/util_validate.c
index 72631341ba..63f5528598 100644
--- a/src/lib/gssapi/generic/util_validate.c
+++ b/src/lib/gssapi/generic/util_validate.c
@@ -21,6 +21,10 @@
*/
/*
+ * $Id$
+ */
+
+/*
* functions to validate name, credential, and context handles
*/
@@ -30,24 +34,31 @@
#include <sys/file.h>
#include <fcntl.h>
#include <limits.h>
+#ifdef HAVE_BSD_DB
#include <db.h>
-#define V_NAME 1
-#define V_CRED_ID 2
-#define V_CTX_ID 3
+static const int one = 1;
+static const DBT dbtone = { (void *) &one, sizeof(one) };
typedef struct _vkey {
int type;
void *ptr;
} vkey;
+#endif
-static const int one = 1;
-static const DBT dbtone = { (void *) &one, sizeof(one) };
+#define V_NAME 1
+#define V_CRED_ID 2
+#define V_CTX_ID 3
/* All these functions return 0 on failure, and non-zero on success */
-static int g_save(DB **vdb, int type, void *ptr)
+static int g_save(db, type, ptr)
+ void **db;
+ int type;
+ void *ptr;
{
+#ifdef HAVE_BSD_DB
+ DB **vdb = (DB **) db;
vkey vk;
DBT key;
@@ -61,10 +72,24 @@ static int g_save(DB **vdb, int type, void *ptr)
key.size = sizeof(vk);
return((*((*vdb)->put))(*vdb, &key, &dbtone, 0) == 0);
+#else
+ g_set *gs = (g_set *) db;
+
+ if (!*gs)
+ if (g_set_init(gs))
+ return(0);
+
+ return(g_set_entry_add(gs, ptr, (void *) type) == 0);
+#endif
}
-static int g_validate(DB **vdb, int type, void *ptr)
+static int g_validate(db, type, ptr)
+ void **db;
+ int type;
+ void *ptr;
{
+#ifdef HAVE_BSD_DB
+ DB **vdb = (DB **) db;
vkey vk;
DBT key, value;
@@ -82,10 +107,27 @@ static int g_validate(DB **vdb, int type, void *ptr)
return((value.size == sizeof(one)) &&
(*((int *) value.data) == one));
+#else
+ g_set *gs = (g_set *) db;
+ void *value;
+
+ if (!*gs)
+ return(0);
+
+ if (g_set_entry_get(gs, ptr, (void **) &value))
+ return(0);
+
+ return(((int) value) == type);
+#endif
}
-static int g_delete(DB **vdb, int type, void *ptr)
+static int g_delete(db, type, ptr)
+ void **db;
+ int type;
+ void *ptr;
{
+#ifdef HAVE_BSD_DB
+ DB **vdb = (DB **) db;
vkey vk;
DBT key;
@@ -99,52 +141,81 @@ static int g_delete(DB **vdb, int type, void *ptr)
key.size = sizeof(vk);
return((*((*vdb)->del))(*vdb, &key, 0) == 0);
+#else
+ g_set *gs = (g_set *) db;
+
+ if (!*gs)
+ return(0);
+
+ if (g_set_entry_delete(gs, ptr))
+ return(0);
+
+ return(1);
+#endif
}
/* functions for each type */
/* save */
-int g_save_name(void **vdb, gss_name_t *name)
+int g_save_name(vdb, name)
+ void **vdb;
+ gss_name_t *name;
{
- return(g_save((DB **) vdb, V_NAME, (void *) name));
+ return(g_save(vdb, V_NAME, (void *) name));
}
-int g_save_cred_id(void **vdb, gss_cred_id_t *cred)
+int g_save_cred_id(vdb, cred)
+ void **vdb;
+ gss_cred_id_t *cred;
{
- return(g_save((DB **) vdb, V_CRED_ID, (void *) cred));
+ return(g_save(vdb, V_CRED_ID, (void *) cred));
}
-int g_save_ctx_id(void **vdb, gss_ctx_id_t *ctx)
+int g_save_ctx_id(vdb, ctx)
+ void **vdb;
+ gss_ctx_id_t *ctx;
{
- return(g_save((DB **) vdb, V_CTX_ID, (void *) ctx));
+ return(g_save(vdb, V_CTX_ID, (void *) ctx));
}
/* validate */
-int g_validate_name(void **vdb, gss_name_t *name)
+int g_validate_name(vdb, name)
+ void **vdb;
+ gss_name_t *name;
{
- return(g_validate((DB **) vdb, V_NAME, (void *) name));
+ return(g_validate(vdb, V_NAME, (void *) name));
}
-int g_validate_cred_id(void **vdb, gss_cred_id_t *cred)
+int g_validate_cred_id(vdb, cred)
+ void **vdb;
+ gss_cred_id_t *cred;
{
- return(g_validate((DB **) vdb, V_CRED_ID, (void *) cred));
+ return(g_validate(vdb, V_CRED_ID, (void *) cred));
}
-int g_validate_ctx_id(void **vdb, gss_ctx_id_t *ctx)
+int g_validate_ctx_id(vdb, ctx)
+ void **vdb;
+ gss_ctx_id_t *ctx;
{
- return(g_validate((DB **) vdb, V_CTX_ID, (void *) ctx));
+ return(g_validate(vdb, V_CTX_ID, (void *) ctx));
}
/* delete */
-int g_delete_name(void **vdb, gss_name_t *name)
+int g_delete_name(vdb, name)
+ void **vdb;
+ gss_name_t *name;
{
- return(g_delete((DB **) vdb, V_NAME, (void *) name));
+ return(g_delete(vdb, V_NAME, (void *) name));
}
-int g_delete_cred_id(void **vdb, gss_cred_id_t *cred)
+int g_delete_cred_id(vdb, cred)
+ void **vdb;
+ gss_cred_id_t *cred;
{
- return(g_delete((DB **) vdb, V_CRED_ID, (void *) cred));
+ return(g_delete(vdb, V_CRED_ID, (void *) cred));
}
-int g_delete_ctx_id(void **vdb, gss_ctx_id_t *ctx)
+int g_delete_ctx_id(vdb, ctx)
+ void **vdb;
+ gss_ctx_id_t *ctx;
{
- return(g_delete((DB **) vdb, V_CTX_ID, (void *) ctx));
+ return(g_delete(vdb, V_CTX_ID, (void *) ctx));
}
diff --git a/src/lib/gssapi/krb5/ChangeLog b/src/lib/gssapi/krb5/ChangeLog
index 73a09c111e..a996733e68 100644
--- a/src/lib/gssapi/krb5/ChangeLog
+++ b/src/lib/gssapi/krb5/ChangeLog
@@ -1,3 +1,43 @@
+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
@@ -29,6 +69,63 @@ Tue May 14 04:42:11 1996 Theodore Y. Ts'o <tytso@mit.edu>
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:
diff --git a/src/lib/gssapi/krb5/Makefile.in b/src/lib/gssapi/krb5/Makefile.in
index d5061fa149..4a18efeea2 100644
--- a/src/lib/gssapi/krb5/Makefile.in
+++ b/src/lib/gssapi/krb5/Makefile.in
@@ -1,4 +1,4 @@
-CFLAGS = $(CCOPTS) $(DEFS) -I. -I$(srcdir) -I../generic -I$(srcdir)/../generic -I$(srcdir)/../../crypto/md5 -DUSE_AUTOCONF_H
+CFLAGS = $(CCOPTS) $(DEFS) -I. -I$(srcdir) -I../generic -I$(srcdir)/../generic -DUSE_AUTOCONF_H
##DOSBUILDTOP = ..\..\..
##DOSLIBNAME=..\gssapi.$(LIBEXT)
@@ -50,12 +50,10 @@ SRCS = \
$(srcdir)/inq_names.c \
$(srcdir)/k5seal.c \
$(srcdir)/k5unseal.c \
- $(srcdir)/k5mech.c \
- $(srcdir)/pname_to_uid.c \
+ $(srcdir)/krb5_gss_glue.c \
$(srcdir)/process_context_token.c \
$(srcdir)/rel_cred.c \
$(srcdir)/rel_name.c \
- $(srcdir)/rel_oid.c \
$(srcdir)/seal.c \
$(srcdir)/ser_sctx.c \
$(srcdir)/sign.c \
@@ -65,8 +63,13 @@ SRCS = \
$(srcdir)/util_seed.c \
$(srcdir)/util_seqnum.c \
$(srcdir)/verify.c \
+ $(srcdir)/wrap_size_limit.c \
gssapi_err_krb5.c
+# $(srcdir)/pname_to_uid.c \
+# $(srcdir)/k5mech.c \
+# $(srcdir)/rel_oid.c
+
OBJS = \
accept_sec_context.$(OBJEXT) \
acquire_cred.$(OBJEXT) \
@@ -87,12 +90,10 @@ OBJS = \
inq_names.$(OBJEXT) \
k5seal.$(OBJEXT) \
k5unseal.$(OBJEXT) \
- k5mech.$(OBJEXT) \
- pname_to_uid.$(OBJEXT) \
+ krb5_gss_glue.$(OBJEXT) \
process_context_token.$(OBJEXT) \
rel_cred.$(OBJEXT) \
rel_name.$(OBJEXT) \
- rel_oid.$(OBJEXT) \
seal.$(OBJEXT) \
ser_sctx.$(OBJEXT) \
sign.$(OBJEXT) \
@@ -102,15 +103,23 @@ OBJS = \
util_seed.$(OBJEXT) \
util_seqnum.$(OBJEXT) \
verify.$(OBJEXT) \
+ wrap_size_limit.$(OBJEXT) \
gssapi_err_krb5.$(OBJEXT)
+# k5mech.$(OBJEXT) \
+# pname_to_uid.$(OBJEXT) \
+# rel_oid.$(OBJEXT)
+
HDRS= $(ETHDRS)
EHDRDIR=$(TOP)/include/gssapi
+EXPORTED_HEADERS= gssapi_krb5.h
all-unix:: $(SRCS) $(HDRS) includes $(OBJS)
all-mac:: $(SRCS) $(HDRS) includes $(OBJS)
all-windows:: $(SRCS) $(HDRS) includes $(OBJS)
+ if not exist $(EHDRDIR)\nul mkdir $(EHDRDIR)
+ copy gssapi_krb5.h $(EHDRDIR)
clean-unix::
$(RM) $(ETHDRS) $(ETSRCS) shared/*
@@ -119,6 +128,14 @@ clean-mac::
$(RM) $(ETHDRS) $(ETSRCS) shared/*
clean-windows::
+ $(RM) $(EHDRDIR)\gssapi_krb5.h
+ if exist $(EHDRDIR)\nul rmdir $(EHDRDIR)
+
+install::
+ @set -x; for f in $(EXPORTED_HEADERS) ; \
+ do $(INSTALL_DATA) $(srcdir)/$$f \
+ $(DESTDIR)$(KRB5_INCDIR)/gssapi/$$f ; \
+ done
depend:: $(ETSRCS)
diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c
index 79d41b71da..09ed412472 100644
--- a/src/lib/gssapi/krb5/accept_sec_context.c
+++ b/src/lib/gssapi/krb5/accept_sec_context.c
@@ -21,9 +21,40 @@
*/
#include "gssapiP_krb5.h"
-#include "rsa-md5.h"
#include <memory.h>
+/*
+ * $Id$
+ */
+
+#if 0
+
+/* XXXX This widen/narrow stuff is bletcherous, but it seems to be
+ necessary. Perhaps there is a "better" way, but I don't know what it
+ is */
+
+#include <krb5/widen.h>
+static krb5_error_code
+rd_req_keyproc(krb5_pointer keyprocarg, krb5_principal server,
+ krb5_kvno kvno, krb5_keyblock **keyblock)
+#include <krb5/narrow.h>
+{
+ krb5_error_code code;
+ krb5_keytab_entry ktentry;
+
+ if (code = krb5_kt_get_entry((krb5_keytab) keyprocarg, server, kvno,
+ &ktentry))
+ return(code);
+
+ code = krb5_copy_keyblock(&ktentry.key, keyblock);
+
+ (void) krb5_kt_free_entry(&ktentry);
+
+ return(code);
+}
+
+#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)
@@ -56,12 +87,11 @@ cleanup:
}
OM_uint32
-krb5_gss_accept_sec_context(ct, minor_status, context_handle,
+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)
- void *ct;
OM_uint32 *minor_status;
gss_ctx_id_t *context_handle;
gss_cred_id_t verifier_cred_handle;
@@ -74,7 +104,7 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle,
OM_uint32 *time_rec;
gss_cred_id_t *delegated_cred_handle;
{
- krb5_context context = ct;
+ krb5_context context;
unsigned char *ptr, *ptr2;
char *sptr;
long tmp;
@@ -89,14 +119,20 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle,
krb5_principal name;
int gss_flags;
krb5_gss_ctx_id_rec *ctx;
+ krb5_enctype enctype;
krb5_timestamp now;
gss_buffer_desc token;
+ int err;
krb5_auth_context auth_context = NULL;
krb5_ticket * ticket = NULL;
int option_id;
krb5_data option;
krb5_auth_context auth_context_cred = NULL;
+ const gss_OID_desc *mech_used = NULL;
+
+ if (GSS_ERROR(kg_get_context(minor_status, &context)))
+ return(GSS_S_FAILURE);
/* set up returns to be freeable */
@@ -141,14 +177,43 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle,
return(GSS_S_NO_CRED);
}
- /* verify the token's integrity, and leave the token in ap_req */
+ /* 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 (! g_verify_token_header((gss_OID) gss_mech_krb5, &(ap_req.length),
- &ptr, KG_TOK_CTX_AP_REQ, input_token->length)) {
- *minor_status = 0;
- return(GSS_S_DEFECTIVE_TOKEN);
+ if (err = g_verify_token_header((gss_OID) gss_mech_krb5, &(ap_req.length),
+ &ptr, KG_TOK_CTX_AP_REQ,
+ input_token->length)) {
+ /*
+ * 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.
+ */
+ if (err != G_WRONG_MECH ||
+ (err = g_verify_token_header((gss_OID) gss_mech_krb5_old,
+ &(ap_req.length),
+ &ptr, KG_TOK_CTX_AP_REQ,
+ input_token->length))) {
+ *minor_status = err;
+ return(GSS_S_DEFECTIVE_TOKEN);
+ } else {
+ if (! cred->prerfc_mech) {
+ *minor_status = G_WRONG_MECH;
+ return(GSS_S_DEFECTIVE_TOKEN);
+ }
+
+ mech_used = gss_mech_krb5_old;
+ }
+ } else {
+ if (! cred->rfc_mech) {
+ *minor_status = G_WRONG_MECH;
+ return(GSS_S_DEFECTIVE_TOKEN);
+ }
+
+ mech_used = gss_mech_krb5;
}
sptr = (char *) ptr;
@@ -180,6 +245,17 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle,
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)) {
+ krb5_free_tkt_authent(authdat);
+ *minor_status = KG_NO_SUBKEY;
+ return(GSS_S_FAILURE);
+ }
+#endif
+
/* verify that the checksum is correct */
/*
@@ -210,13 +286,13 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle,
TREAD_INT(ptr, tmp, bigend);
- if (tmp != RSA_MD5_CKSUM_LENGTH) {
+ if (tmp != krb5_checksum_size(context, CKSUMTYPE_RSA_MD5)) {
ptr = (unsigned char *) authdat->checksum->contents;
bigend = 1;
TREAD_INT(ptr, tmp, bigend);
- if (tmp != RSA_MD5_CKSUM_LENGTH) {
+ if (tmp != krb5_checksum_size(context, CKSUMTYPE_RSA_MD5)) {
xfree(md5.contents);
krb5_free_authenticator(context, authdat);
*minor_status = KG_BAD_LENGTH;
@@ -226,7 +302,7 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle,
/* at this point, bigend is set according to the initiator's byte order */
- if ((code = kg_checksum_channel_bindings(input_chan_bindings, &md5,
+ if ((code = kg_checksum_channel_bindings(context, input_chan_bindings, &md5,
bigend))) {
krb5_free_authenticator(context, authdat);
*minor_status = code;
@@ -289,21 +365,13 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle,
break;
- default :
+ /* default: */
+ /* unknown options aren't an error */
- /* any other options are unrecognized. return
- generic GSS_C_FAILURE error with a minor status
- of KRB5_PARSE_MALFORMED (XXX this is probably
- not the right error, since it is used for
- string parsing errors not token parsing errors.) */
-
- *minor_status = KRB5_PARSE_MALFORMED;
- return(GSS_S_FAILURE);
} /* switch */
} /* while */
} /* if */
-
/* create the ctx struct and start filling it in */
if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec)))
@@ -313,6 +381,7 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle,
}
memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
+ ctx->mech_used = mech_used;
ctx->auth_context = auth_context;
ctx->initiate = 0;
ctx->gss_flags = GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG |
@@ -345,20 +414,42 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle,
return(GSS_S_FAILURE);
}
+ switch(ctx->subkey->enctype) {
+ case ENCTYPE_DES_CBC_MD5:
+ case ENCTYPE_DES_CBC_CRC:
+ enctype = ENCTYPE_DES_CBC_RAW;
+ ctx->signalg = 0;
+ ctx->cksum_size = 8;
+ ctx->sealalg = 0;
+ break;
+#if 0
+ case ENCTYPE_DES3_CBC_MD5:
+ enctype = ENCTYPE_DES3_CBC_RAW;
+ ctx->signalg = 3;
+ ctx->cksum_size = 16;
+ ctx->sealalg = 1;
+ break;
+#endif
+ default:
+ return GSS_S_FAILURE;
+ }
+
/* fill in the encryption descriptors */
- krb5_use_enctype(context, &ctx->enc.eblock, ENCTYPE_DES_CBC_RAW);
+ krb5_use_enctype(context, &ctx->enc.eblock, enctype);
ctx->enc.processed = 0;
- if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc.key)))
+
+ if (code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc.key))
return(code);
for (i=0; i<ctx->enc.key->length; i++)
/*SUPPRESS 113*/
ctx->enc.key->contents[i] ^= 0xf0;
- krb5_use_enctype(context, &ctx->seq.eblock, ENCTYPE_DES_CBC_RAW);
+ krb5_use_enctype(context, &ctx->seq.eblock, enctype);
ctx->seq.processed = 0;
if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->seq.key)))
return(code);
+
ctx->endtime = ticket->enc_part2->times.endtime;
ctx->flags = ticket->enc_part2->flags;
@@ -366,6 +457,10 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle,
krb5_auth_con_getremoteseqnumber(context, auth_context, &ctx->seq_recv);
+ g_order_init(&(ctx->seqstate), ctx->seq_recv,
+ gss_flags & GSS_C_REPLAY_FLAG,
+ gss_flags & GSS_C_SEQUENCE_FLAG);
+
/* at this point, the entire context structure is filled in,
so it can be released. */
@@ -375,23 +470,23 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle,
krb5_data ap_rep;
unsigned char * ptr;
if ((code = krb5_mk_rep(context, auth_context, &ap_rep))) {
- (void)krb5_gss_delete_sec_context(context, minor_status,
+ (void)krb5_gss_delete_sec_context(minor_status,
(gss_ctx_id_t *) &ctx, NULL);
*minor_status = code;
return(GSS_S_FAILURE);
}
krb5_auth_con_getlocalseqnumber(context, auth_context, &ctx->seq_send);
- token.length = g_token_size((gss_OID) gss_mech_krb5, ap_rep.length);
+ token.length = g_token_size((gss_OID) mech_used, ap_rep.length);
if ((token.value = (unsigned char *) xmalloc(token.length)) == NULL) {
- (void)krb5_gss_delete_sec_context(context, minor_status,
+ (void)krb5_gss_delete_sec_context(minor_status,
(gss_ctx_id_t *) &ctx, NULL);
- *minor_status = code;
+ *minor_status = ENOMEM;
return(GSS_S_FAILURE);
}
ptr = token.value;
- g_make_token_header((gss_OID) gss_mech_krb5, ap_rep.length,
- &ptr, KG_TOK_CTX_AP_REP);
+ g_make_token_header((gss_OID) mech_used, ap_rep.length,
+ &ptr, KG_TOK_CTX_AP_REP);
TWRITE_STR(ptr, ap_rep.data, ap_rep.length);
xfree(ap_rep.data);
@@ -410,7 +505,7 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle,
if ((code = krb5_copy_principal(context, ctx->there, &name))) {
if (token.value)
xfree(token.value);
- (void)krb5_gss_delete_sec_context(context, minor_status,
+ (void)krb5_gss_delete_sec_context(minor_status,
(gss_ctx_id_t *) &ctx, NULL);
*minor_status = code;
return(GSS_S_FAILURE);
@@ -418,14 +513,14 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle,
}
if (mech_type)
- *mech_type = (gss_OID) gss_mech_krb5;
+ *mech_type = (gss_OID) mech_used;
if (time_rec) {
if ((code = krb5_timeofday(context, &now))) {
if (src_name)
krb5_free_principal(context, name);
xfree(token.value);
- (void)krb5_gss_delete_sec_context(context, minor_status,
+ (void)krb5_gss_delete_sec_context(minor_status,
(gss_ctx_id_t *) &ctx, NULL);
*minor_status = code;
return(GSS_S_FAILURE);
@@ -434,7 +529,7 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle,
}
if (ret_flags)
- *ret_flags = ctx->gss_flags;
+ *ret_flags = KG_IMPLFLAGS(gss_flags);
ctx->established = 1;
@@ -445,7 +540,7 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle,
krb5_free_principal(context, name);
if (token.value)
xfree(token.value);
- (void)krb5_gss_delete_sec_context(context, minor_status,
+ (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);
@@ -460,7 +555,7 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle,
}
if (token.value)
xfree(token.value);
- (void)krb5_gss_delete_sec_context(context, minor_status,
+ (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);
diff --git a/src/lib/gssapi/krb5/acquire_cred.c b/src/lib/gssapi/krb5/acquire_cred.c
index 526e6dddb7..b2d6ce1116 100644
--- a/src/lib/gssapi/krb5/acquire_cred.c
+++ b/src/lib/gssapi/krb5/acquire_cred.c
@@ -27,6 +27,10 @@
#include <strings.h>
#endif
+/*
+ * $Id$
+ */
+
/* 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
@@ -35,14 +39,13 @@
*/
static OM_uint32
-acquire_accept_cred(ctx, minor_status, desired_name, output_princ, cred)
- void *ctx;
+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_context context = ctx;
krb5_error_code code;
krb5_principal princ;
krb5_keytab kt;
@@ -65,6 +68,7 @@ acquire_accept_cred(ctx, minor_status, desired_name, output_princ, cred)
if (desired_name == (gss_name_t) NULL) {
if (code = krb5_sname_to_principal(context, NULL, NULL, KRB5_NT_SRV_HST,
&princ)) {
+ (void) krb5_kt_close(context, kt);
*minor_status = code;
return(GSS_S_FAILURE);
}
@@ -76,6 +80,7 @@ acquire_accept_cred(ctx, minor_status, desired_name, output_princ, cred)
/* iterate over the keytab searching for the principal */
if (code = krb5_kt_start_seq_get(context, kt, &cur)) {
+ (void) krb5_kt_close(context, kt);
*minor_status = code;
return(GSS_S_FAILURE);
}
@@ -92,16 +97,19 @@ acquire_accept_cred(ctx, minor_status, desired_name, output_princ, cred)
if (code == KRB5_KT_END) {
/* this means that the principal wasn't in the keytab */
(void)krb5_kt_end_seq_get(context, kt, &cur);
+ (void) krb5_kt_close(context, kt);
*minor_status = KG_KEYTAB_NOMATCH;
return(GSS_S_CRED_UNAVAIL);
} else if (code) {
/* this means some error occurred reading the keytab */
(void)krb5_kt_end_seq_get(context, kt, &cur);
+ (void) krb5_kt_close(context, kt);
*minor_status = code;
return(GSS_S_FAILURE);
} else {
/* this means that we found a matching entry */
if (code = krb5_kt_end_seq_get(context, kt, &cur)) {
+ (void) krb5_kt_close(context, kt);
*minor_status = code;
return(GSS_S_FAILURE);
}
@@ -204,7 +212,6 @@ acquire_init_cred(context, minor_status, desired_name, output_princ, cred)
if (got_endtime == 0) {
cred->tgt_expire = creds.times.endtime;
got_endtime = 1;
- *minor_status = KG_TGT_MISSING;
}
krb5_free_cred_contents(context, &creds);
}
@@ -215,6 +222,12 @@ acquire_init_cred(context, minor_status, desired_name, output_princ, cred)
(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)) {
@@ -239,10 +252,9 @@ acquire_init_cred(context, minor_status, desired_name, output_princ, cred)
/*ARGSUSED*/
OM_uint32
-krb5_gss_acquire_cred(ctx, minor_status, desired_name, time_req,
+krb5_gss_acquire_cred(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;
@@ -252,13 +264,17 @@ krb5_gss_acquire_cred(ctx, minor_status, desired_name, time_req,
gss_OID_set *actual_mechs;
OM_uint32 *time_rec;
{
- krb5_context context = ctx;
+ krb5_context context;
size_t i;
krb5_gss_cred_id_t cred;
- gss_OID_set mechs;
+ gss_OID_set valid_mechs, ret_mechs;
+ int req_old, req_new;
OM_uint32 ret;
krb5_error_code code;
+ if (GSS_ERROR(kg_get_context(minor_status, &context)))
+ return(GSS_S_FAILURE);
+
/* make sure all outputs are valid */
*output_cred_handle = NULL;
@@ -279,11 +295,26 @@ krb5_gss_acquire_cred(ctx, minor_status, desired_name, time_req,
/* verify that the requested mechanism set is the default, or
contains krb5 */
- if (desired_mechs != GSS_C_NULL_OID_SET) {
- for (i=0; i<desired_mechs->count; i++)
+ if (desired_mechs == GSS_C_NULL_OID_SET) {
+ valid_mechs = gss_mech_set_krb5_both;
+ } 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])))
- break;
- if (i == desired_mechs->count) {
+ req_new++;
+ }
+
+ if (req_old && req_new) {
+ valid_mechs = gss_mech_set_krb5_both;
+ } else if (req_old) {
+ valid_mechs = gss_mech_set_krb5_old;
+ } else if (req_new) {
+ valid_mechs = gss_mech_set_krb5;
+ } else {
*minor_status = 0;
return(GSS_S_BAD_MECH);
}
@@ -300,6 +331,9 @@ krb5_gss_acquire_cred(ctx, minor_status, desired_name, time_req,
cred->usage = cred_usage;
cred->princ = NULL;
+ cred->actual_mechs = valid_mechs;
+ cred->prerfc_mech = req_old;
+ cred->rfc_mech = req_new;
cred->keytab = NULL;
cred->ccache = NULL;
@@ -390,7 +424,7 @@ krb5_gss_acquire_cred(ctx, minor_status, desired_name, time_req,
/* create mechs */
if (actual_mechs) {
- if (! g_copy_OID_set(gss_mech_set_krb5, &mechs)) {
+ if (! g_copy_OID_set(cred->actual_mechs, &ret_mechs)) {
if (cred->ccache)
(void)krb5_cc_close(context, cred->ccache);
if (cred->keytab)
@@ -406,8 +440,8 @@ krb5_gss_acquire_cred(ctx, minor_status, desired_name, time_req,
/* intern the credential handle */
if (! kg_save_cred_id((gss_cred_id_t) cred)) {
- free(mechs->elements);
- free(mechs);
+ free(ret_mechs->elements);
+ free(ret_mechs);
if (cred->ccache)
(void)krb5_cc_close(context, cred->ccache);
if (cred->keytab)
@@ -424,19 +458,18 @@ krb5_gss_acquire_cred(ctx, minor_status, desired_name, time_req,
*minor_status = 0;
*output_cred_handle = (gss_cred_id_t) cred;
if (actual_mechs)
- *actual_mechs = mechs;
+ *actual_mechs = ret_mechs;
return(GSS_S_COMPLETE);
}
/* V2 interface */
OM_uint32
-krb5_gss_add_cred(ctx, minor_status, input_cred_handle,
+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)
- void *ctx;
OM_uint32 *minor_status;
gss_cred_id_t input_cred_handle;
gss_name_t desired_name;
@@ -449,12 +482,19 @@ krb5_gss_add_cred(ctx, minor_status, input_cred_handle,
OM_uint32 *initiator_time_rec;
OM_uint32 *acceptor_time_rec;
{
- krb5_context context = ctx;
/*
- * This does not apply to our single-mechanism implementation. Until we
- * come up with a better error code, return failure.
+ * This does not apply to our single-mechanism implementation. Decide
+ * if the correct error is BAD_MECH or DUPLICATE_ELEMENT.
*/
+
+ /* verify that the requested mechanism is the default, or
+ is krb5 */
+
+ if ((desired_mech != GSS_C_NULL_OID) &&
+ (g_OID_equal(desired_mech, gss_mech_krb5)))
+ return(GSS_S_BAD_MECH);
+
*minor_status = 0;
- return(GSS_S_FAILURE);
+ return(GSS_S_DUPLICATE_ELEMENT);
}
diff --git a/src/lib/gssapi/krb5/compare_name.c b/src/lib/gssapi/krb5/compare_name.c
index 19b94f452d..75a534220d 100644
--- a/src/lib/gssapi/krb5/compare_name.c
+++ b/src/lib/gssapi/krb5/compare_name.c
@@ -20,17 +20,24 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
+/*
+ * $Id$
+ */
+
#include "gssapiP_krb5.h"
OM_uint32
-krb5_gss_compare_name(ctx, minor_status, name1, name2, name_equal)
- void *ctx;
+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 = ctx;
+ krb5_context context;
+
+ if (GSS_ERROR(kg_get_context(minor_status, &context)))
+ return(GSS_S_FAILURE);
+
if (! kg_validate_name(name1)) {
*minor_status = (OM_uint32) G_VALIDATE_FAILED;
return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME);
diff --git a/src/lib/gssapi/krb5/configure.in b/src/lib/gssapi/krb5/configure.in
index d5fc0695f3..a055318932 100644
--- a/src/lib/gssapi/krb5/configure.in
+++ b/src/lib/gssapi/krb5/configure.in
@@ -4,4 +4,5 @@ AC_PROG_AWK
AC_CHECK_HEADERS(stdlib.h)
V5_SHARED_LIB_OBJS
SubdirLibraryRule([${OBJS}])
+CopySrcHeader(gssapi_krb5.h,[$](BUILDTOP)/include/gssapi)
V5_AC_OUTPUT_MAKEFILE
diff --git a/src/lib/gssapi/krb5/context_time.c b/src/lib/gssapi/krb5/context_time.c
index 3bc42e603d..76f1489b77 100644
--- a/src/lib/gssapi/krb5/context_time.c
+++ b/src/lib/gssapi/krb5/context_time.c
@@ -22,19 +22,25 @@
#include "gssapiP_krb5.h"
+/*
+ * $Id$
+ */
+
OM_uint32
-krb5_gss_context_time(ct, minor_status, context_handle, time_rec)
- void *ct;
+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_context context = ct;
+ krb5_context context;
krb5_error_code code;
krb5_gss_ctx_id_rec *ctx;
krb5_timestamp now;
krb5_deltat lifetime;
+ if (GSS_ERROR(kg_get_context(minor_status, &context)))
+ return(GSS_S_FAILURE);
+
/* validate the context handle */
if (! kg_validate_ctx_id(context_handle)) {
*minor_status = (OM_uint32) G_VALIDATE_FAILED;
diff --git a/src/lib/gssapi/krb5/delete_sec_context.c b/src/lib/gssapi/krb5/delete_sec_context.c
index fded9afa8a..5b5ff74fa6 100644
--- a/src/lib/gssapi/krb5/delete_sec_context.c
+++ b/src/lib/gssapi/krb5/delete_sec_context.c
@@ -22,16 +22,22 @@
#include "gssapiP_krb5.h"
+/*
+ * $Id$
+ */
+
OM_uint32
-krb5_gss_delete_sec_context(ct, minor_status, context_handle, output_token)
- void *ct;
+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 = ct;
+ krb5_context context;
krb5_gss_ctx_id_rec *ctx;
+ if (GSS_ERROR(kg_get_context(minor_status, &context)))
+ return(GSS_S_FAILURE);
+
if (output_token) {
output_token->length = 0;
output_token->value = NULL;
@@ -71,6 +77,9 @@ krb5_gss_delete_sec_context(ct, minor_status, context_handle, output_token)
ctx = (gss_ctx_id_t) *context_handle;
+ if (ctx->seqstate)
+ g_order_free(&(ctx->seqstate));
+
if (ctx->enc.processed)
krb5_finish_key(context, &ctx->enc.eblock);
krb5_free_keyblock(context, ctx->enc.key);
@@ -86,6 +95,8 @@ krb5_gss_delete_sec_context(ct, minor_status, context_handle, output_token)
if (ctx->auth_context)
krb5_auth_con_free(context, ctx->auth_context);
+ /* Zero out context */
+ memset(ctx, 0, sizeof(*ctx));
xfree(ctx);
/* zero the handle itself */
diff --git a/src/lib/gssapi/krb5/disp_name.c b/src/lib/gssapi/krb5/disp_name.c
index a9cbcae066..77f520035f 100644
--- a/src/lib/gssapi/krb5/disp_name.c
+++ b/src/lib/gssapi/krb5/disp_name.c
@@ -23,18 +23,20 @@
#include "gssapiP_krb5.h"
OM_uint32
-krb5_gss_display_name(ctx, minor_status, input_name, output_name_buffer,
+krb5_gss_display_name(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;
{
- krb5_context context = ctx;
+ krb5_context context;
krb5_error_code code;
char *str;
+ if (GSS_ERROR(kg_get_context(minor_status, &context)))
+ return(GSS_S_FAILURE);
+
output_name_buffer->length = 0;
output_name_buffer->value = NULL;
diff --git a/src/lib/gssapi/krb5/disp_status.c b/src/lib/gssapi/krb5/disp_status.c
index 326d3fc7c8..143f7a6245 100644
--- a/src/lib/gssapi/krb5/disp_status.c
+++ b/src/lib/gssapi/krb5/disp_status.c
@@ -32,9 +32,8 @@ static int init_et = 0;
/**/
OM_uint32
-krb5_gss_display_status(ctx, minor_status, status_value, status_type,
+krb5_gss_display_status(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;
@@ -42,10 +41,13 @@ krb5_gss_display_status(ctx, minor_status, status_value, status_type,
OM_uint32 *message_context;
gss_buffer_t status_string;
{
- krb5_context context = ctx;
+ krb5_context context;
status_string->length = 0;
status_string->value = NULL;
+ if (GSS_ERROR(kg_get_context(minor_status, &context)))
+ return(GSS_S_FAILURE);
+
if ((mech_type != GSS_C_NULL_OID) &&
(! g_OID_equal(gss_mech_krb5, mech_type))) {
*minor_status = 0;
diff --git a/src/lib/gssapi/krb5/export_sec_context.c b/src/lib/gssapi/krb5/export_sec_context.c
index 180cc2ef59..fba8a684ba 100644
--- a/src/lib/gssapi/krb5/export_sec_context.c
+++ b/src/lib/gssapi/krb5/export_sec_context.c
@@ -28,20 +28,21 @@
#include "gssapiP_krb5.h"
OM_uint32
-krb5_gss_export_sec_context(ct,
- minor_status, context_handle, interprocess_token)
- void *ct;
+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 ser_ctx = ct;
+ krb5_context context;
krb5_error_code kret;
OM_uint32 retval;
size_t bufsize, blen;
- krb5_gss_ctx_id_t *ctx;
+ krb5_gss_ctx_id_t ctx;
krb5_octet *obuffer, *obp;
+ if (GSS_ERROR(kg_get_context(minor_status, &context)))
+ return(GSS_S_FAILURE);
+
/* Assume a tragic failure */
obuffer = (krb5_octet *) NULL;
retval = GSS_S_FAILURE;
@@ -53,12 +54,12 @@ krb5_gss_export_sec_context(ct,
goto error_out;
}
- ctx = (krb5_gss_ctx_id_t *) *context_handle;
+ ctx = (krb5_gss_ctx_id_t) *context_handle;
/* Determine size needed for externalization of context */
bufsize = 0;
- if ((kret = krb5_size_opaque(ser_ctx, KG_CONTEXT, (krb5_pointer) ctx,
- &bufsize)))
+ if ((kret = kg_ctx_size(context, (krb5_pointer) ctx,
+ &bufsize)))
goto error_out;
/* Allocate the buffer */
@@ -70,8 +71,8 @@ krb5_gss_export_sec_context(ct,
obp = obuffer;
blen = bufsize;
/* Externalize the context */
- if ((kret = krb5_externalize_opaque(ser_ctx, KG_CONTEXT,
- (krb5_pointer)ctx, &obp, &blen)))
+ if ((kret = kg_ctx_externalize(context,
+ (krb5_pointer) ctx, &obp, &blen)))
goto error_out;
/* Success! Return the buffer */
@@ -81,23 +82,7 @@ krb5_gss_export_sec_context(ct,
retval = GSS_S_COMPLETE;
/* Now, clean up the context state */
- (void) kg_delete_ctx_id((gss_ctx_id_t) ctx);
- if (ctx->enc.processed)
- krb5_finish_key(ser_ctx, &ctx->enc.eblock);
- krb5_free_keyblock(ser_ctx, ctx->enc.key);
- if (ctx->seq.processed)
- krb5_finish_key(ser_ctx, &ctx->seq.eblock);
- krb5_free_keyblock(ser_ctx, ctx->seq.key);
- krb5_free_principal(ser_ctx, ctx->here);
- krb5_free_principal(ser_ctx, ctx->there);
- krb5_free_keyblock(ser_ctx, ctx->subkey);
-
- if (ctx->auth_context)
- krb5_auth_con_free(ser_ctx, ctx->auth_context);
-
- /* Zero out context */
- memset(ctx, 0, sizeof(*ctx));
- xfree(ctx);
+ (void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL);
*context_handle = GSS_C_NO_CONTEXT;
return (GSS_S_COMPLETE);
diff --git a/src/lib/gssapi/krb5/get_tkt_flags.c b/src/lib/gssapi/krb5/get_tkt_flags.c
index 2e73cacfee..5dd91064f7 100644
--- a/src/lib/gssapi/krb5/get_tkt_flags.c
+++ b/src/lib/gssapi/krb5/get_tkt_flags.c
@@ -22,6 +22,10 @@
#include "gssapiP_krb5.h"
+/*
+ * $Id$
+ */
+
OM_uint32
gss_krb5_get_tkt_flags(minor_status, context_handle, ticket_flags)
OM_uint32 *minor_status;
diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h
index 53c4f46918..7ccc4b8288 100644
--- a/src/lib/gssapi/krb5/gssapiP_krb5.h
+++ b/src/lib/gssapi/krb5/gssapiP_krb5.h
@@ -23,7 +23,11 @@
#ifndef _GSSAPIP_KRB5_H_
#define _GSSAPIP_KRB5_H_
-#include "k5-int.h"
+/*
+ * $Id$
+ */
+
+#include <krb5.h>
#include <memory.h>
/* work around sunos braindamage */
@@ -34,12 +38,15 @@
#undef minor
#endif
-/* this must be after "krb5.h", since krb5 #defines xfree(), too */
#ifndef _MACINTOSH
#include "../generic/gssapiP_generic.h"
#else
#include "gssapiP_generic.h"
#endif
+
+/* The include of gssapi_krb5.h will dtrt with the above #defines in
+ * effect.
+ */
#include "gssapi_krb5.h"
#include "gssapi_err_krb5.h"
@@ -56,6 +63,10 @@
#define KG_TOK_WRAP_MSG 0x0201
#define KG_TOK_DEL_CTX 0x0102
+#define KG_IMPLFLAGS(x) (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG | \
+ ((x) & (GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | \
+ GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG)))
+
#define KRB5_GSS_FOR_CREDS_OPTION 1
/** internal types **/
@@ -66,6 +77,9 @@ typedef struct _krb5_gss_cred_id_rec {
/* name/type of credential */
gss_cred_usage_t usage;
krb5_principal princ; /* this is not interned as a gss_name_t */
+ const gss_OID_set_desc *actual_mechs;
+ int prerfc_mech; /* these are a cache of the set above */
+ int rfc_mech;
/* keytab (accept) data */
krb5_keytab keytab;
@@ -89,21 +103,24 @@ typedef struct _krb5_gss_ctx_id_rec {
krb5_principal here;
krb5_principal there;
krb5_keyblock *subkey;
+ int signalg;
+ int cksum_size;
+ int sealalg;
krb5_gss_enc_desc enc;
krb5_gss_enc_desc seq;
krb5_timestamp endtime;
krb5_flags flags;
krb5_int32 seq_send;
krb5_int32 seq_recv;
+ void *seqstate;
int established;
int big_endian;
krb5_auth_context auth_context;
-} krb5_gss_ctx_id_rec, krb5_gss_ctx_id_t;
+ const gss_OID_desc *mech_used;
+} krb5_gss_ctx_id_rec, *krb5_gss_ctx_id_t;
extern void *kg_vdb;
-extern krb5_context kg_context;
-
/* helper macros */
#define kg_save_name(name) g_save_name(&kg_vdb,name)
@@ -127,16 +144,23 @@ OM_uint32 kg_get_defcred
OM_uint32 kg_release_defcred PROTOTYPE((OM_uint32 *minor_status));
krb5_error_code kg_checksum_channel_bindings
- PROTOTYPE((gss_channel_bindings_t cb,
+ PROTOTYPE((krb5_context context, gss_channel_bindings_t cb,
krb5_checksum *cksum,
int bigend));
-krb5_error_code kg_make_seq_num PROTOTYPE((krb5_gss_enc_desc *ed,
+krb5_error_code kg_make_seq_num PROTOTYPE((krb5_context context,
+ krb5_gss_enc_desc *ed,
int direction, krb5_int32 seqnum, unsigned char *cksum,
unsigned char *buf));
-krb5_error_code kg_make_seed PROTOTYPE((krb5_keyblock *key,
- unsigned char *seed));
+krb5_error_code kg_get_seq_num PROTOTYPE((krb5_context context,
+ krb5_gss_enc_desc *ed,
+ unsigned char *cksum, unsigned char *buf, int *direction,
+ krb5_int32 *seqnum));
+
+krb5_error_code kg_make_seed PROTOTYPE((krb5_context context,
+ krb5_keyblock *key,
+ unsigned char *seed));
int kg_confounder_size PROTOTYPE((krb5_gss_enc_desc *ed));
@@ -145,10 +169,12 @@ krb5_error_code kg_make_confounder PROTOTYPE((krb5_gss_enc_desc *ed,
int kg_encrypt_size PROTOTYPE((krb5_gss_enc_desc *ed, int n));
-krb5_error_code kg_encrypt PROTOTYPE((krb5_gss_enc_desc *ed,
+krb5_error_code kg_encrypt PROTOTYPE((krb5_context context,
+ krb5_gss_enc_desc *ed,
krb5_pointer iv, krb5_pointer in, krb5_pointer out, int length));
-krb5_error_code kg_decrypt PROTOTYPE((krb5_gss_enc_desc *ed,
+krb5_error_code kg_decrypt PROTOTYPE((krb5_context context,
+ krb5_gss_enc_desc *ed,
krb5_pointer iv, krb5_pointer in, krb5_pointer out, int length));
OM_uint32 kg_seal PROTOTYPE((krb5_context context,
@@ -178,14 +204,27 @@ OM_uint32 kg_seal_size PROTOTYPE((krb5_context context,
OM_uint32 output_size,
OM_uint32 *input_size));
-krb5_error_code
-kg_ser_context_init PROTOTYPE((krb5_context));
+krb5_error_code kg_ctx_size PROTOTYPE((krb5_context kcontext,
+ krb5_pointer arg,
+ size_t *sizep));
+
+krb5_error_code kg_ctx_externalize PROTOTYPE((krb5_context kcontext,
+ krb5_pointer arg,
+ krb5_octet **buffer,
+ size_t *lenremain));
+
+krb5_error_code kg_ctx_internalize PROTOTYPE((krb5_context kcontext,
+ krb5_pointer *argp,
+ krb5_octet **buffer,
+ size_t *lenremain));
+OM_uint32 kg_get_context PROTOTYPE((OM_uint32 *minor_status,
+ krb5_context *context));
+
/** declarations of internal name mechanism functions **/
OM_uint32 krb5_gss_acquire_cred
-PROTOTYPE( (void *,
- OM_uint32*, /* minor_status */
+PROTOTYPE( (OM_uint32*, /* minor_status */
gss_name_t, /* desired_name */
OM_uint32, /* time_req */
gss_OID_set, /* desired_mechs */
@@ -196,14 +235,12 @@ PROTOTYPE( (void *,
));
OM_uint32 krb5_gss_release_cred
-PROTOTYPE( (void *,
- OM_uint32*, /* minor_status */
+PROTOTYPE( (OM_uint32*, /* minor_status */
gss_cred_id_t* /* cred_handle */
));
OM_uint32 krb5_gss_init_sec_context
-PROTOTYPE( (void *,
- OM_uint32*, /* minor_status */
+PROTOTYPE( (OM_uint32*, /* minor_status */
gss_cred_id_t, /* claimant_cred_handle */
gss_ctx_id_t*, /* context_handle */
gss_name_t, /* target_name */
@@ -220,8 +257,7 @@ PROTOTYPE( (void *,
));
OM_uint32 krb5_gss_accept_sec_context
-PROTOTYPE( (void *,
- OM_uint32*, /* minor_status */
+PROTOTYPE( (OM_uint32*, /* minor_status */
gss_ctx_id_t*, /* context_handle */
gss_cred_id_t, /* verifier_cred_handle */
gss_buffer_t, /* input_token_buffer */
@@ -236,29 +272,25 @@ PROTOTYPE( (void *,
));
OM_uint32 krb5_gss_process_context_token
-PROTOTYPE( (void *,
- OM_uint32*, /* minor_status */
+PROTOTYPE( (OM_uint32*, /* minor_status */
gss_ctx_id_t, /* context_handle */
gss_buffer_t /* token_buffer */
));
OM_uint32 krb5_gss_delete_sec_context
-PROTOTYPE( (void *,
- OM_uint32*, /* minor_status */
+PROTOTYPE( (OM_uint32*, /* minor_status */
gss_ctx_id_t*, /* context_handle */
gss_buffer_t /* output_token */
));
OM_uint32 krb5_gss_context_time
-PROTOTYPE( (void *,
- OM_uint32*, /* minor_status */
+PROTOTYPE( (OM_uint32*, /* minor_status */
gss_ctx_id_t, /* context_handle */
OM_uint32* /* time_rec */
));
OM_uint32 krb5_gss_sign
-PROTOTYPE( (void *,
- OM_uint32*, /* minor_status */
+PROTOTYPE( (OM_uint32*, /* minor_status */
gss_ctx_id_t, /* context_handle */
int, /* qop_req */
gss_buffer_t, /* message_buffer */
@@ -266,8 +298,7 @@ PROTOTYPE( (void *,
));
OM_uint32 krb5_gss_verify
-PROTOTYPE( (void *,
- OM_uint32*, /* minor_status */
+PROTOTYPE( (OM_uint32*, /* minor_status */
gss_ctx_id_t, /* context_handle */
gss_buffer_t, /* message_buffer */
gss_buffer_t, /* token_buffer */
@@ -275,8 +306,7 @@ PROTOTYPE( (void *,
));
OM_uint32 krb5_gss_seal
-PROTOTYPE( (void *,
- OM_uint32*, /* minor_status */
+PROTOTYPE( (OM_uint32*, /* minor_status */
gss_ctx_id_t, /* context_handle */
int, /* conf_req_flag */
int, /* qop_req */
@@ -286,8 +316,7 @@ PROTOTYPE( (void *,
));
OM_uint32 krb5_gss_unseal
-PROTOTYPE( (void *,
- OM_uint32*, /* minor_status */
+PROTOTYPE( (OM_uint32*, /* minor_status */
gss_ctx_id_t, /* context_handle */
gss_buffer_t, /* input_message_buffer */
gss_buffer_t, /* output_message_buffer */
@@ -296,8 +325,7 @@ PROTOTYPE( (void *,
));
OM_uint32 krb5_gss_display_status
-PROTOTYPE( (void *,
- OM_uint32*, /* minor_status */
+PROTOTYPE( (OM_uint32*, /* minor_status */
OM_uint32, /* status_value */
int, /* status_type */
gss_OID, /* mech_type */
@@ -306,44 +334,38 @@ PROTOTYPE( (void *,
));
OM_uint32 krb5_gss_indicate_mechs
-PROTOTYPE( (void *,
- OM_uint32*, /* minor_status */
+PROTOTYPE( (OM_uint32*, /* minor_status */
gss_OID_set* /* mech_set */
));
OM_uint32 krb5_gss_compare_name
-PROTOTYPE( (void *,
- OM_uint32*, /* minor_status */
+PROTOTYPE( (OM_uint32*, /* minor_status */
gss_name_t, /* name1 */
gss_name_t, /* name2 */
int* /* name_equal */
));
OM_uint32 krb5_gss_display_name
-PROTOTYPE( (void *,
- OM_uint32*, /* minor_status */
+PROTOTYPE( (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
-PROTOTYPE( (void *,
- OM_uint32*, /* minor_status */
+PROTOTYPE( (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
-PROTOTYPE( (void *,
- OM_uint32*, /* minor_status */
+PROTOTYPE( (OM_uint32*, /* minor_status */
gss_name_t* /* input_name */
));
OM_uint32 krb5_gss_inquire_cred
-PROTOTYPE( (void *,
- OM_uint32 *, /* minor_status */
+PROTOTYPE( (OM_uint32 *, /* minor_status */
gss_cred_id_t, /* cred_handle */
gss_name_t *, /* name */
OM_uint32 *, /* lifetime */
@@ -352,8 +374,7 @@ PROTOTYPE( (void *,
));
OM_uint32 krb5_gss_inquire_context
-PROTOTYPE( (void *,
- OM_uint32*, /* minor_status */
+PROTOTYPE( (OM_uint32*, /* minor_status */
gss_ctx_id_t, /* context_handle */
gss_name_t*, /* initiator_name */
gss_name_t*, /* acceptor_name */
@@ -366,8 +387,7 @@ PROTOTYPE( (void *,
/* New V2 entry points */
OM_uint32 krb5_gss_get_mic
-PROTOTYPE( (void *,
- OM_uint32 *, /* minor_status */
+PROTOTYPE( (OM_uint32 *, /* minor_status */
gss_ctx_id_t, /* context_handle */
gss_qop_t, /* qop_req */
gss_buffer_t, /* message_buffer */
@@ -375,8 +395,7 @@ PROTOTYPE( (void *,
));
OM_uint32 krb5_gss_verify_mic
-PROTOTYPE( (void *,
- OM_uint32 *, /* minor_status */
+PROTOTYPE( (OM_uint32 *, /* minor_status */
gss_ctx_id_t, /* context_handle */
gss_buffer_t, /* message_buffer */
gss_buffer_t, /* message_token */
@@ -384,8 +403,7 @@ PROTOTYPE( (void *,
));
OM_uint32 krb5_gss_wrap
-PROTOTYPE( (void *,
- OM_uint32 *, /* minor_status */
+PROTOTYPE( (OM_uint32 *, /* minor_status */
gss_ctx_id_t, /* context_handle */
int, /* conf_req_flag */
gss_qop_t, /* qop_req */
@@ -395,8 +413,7 @@ PROTOTYPE( (void *,
));
OM_uint32 krb5_gss_unwrap
-PROTOTYPE( (void *,
- OM_uint32 *, /* minor_status */
+PROTOTYPE( (OM_uint32 *, /* minor_status */
gss_ctx_id_t, /* context_handle */
gss_buffer_t, /* input_message_buffer */
gss_buffer_t, /* output_message_buffer */
@@ -405,8 +422,7 @@ PROTOTYPE( (void *,
));
OM_uint32 krb5_gss_wrap_size_limit
-PROTOTYPE( (void *,
- OM_uint32 *, /* minor_status */
+PROTOTYPE( (OM_uint32 *, /* minor_status */
gss_ctx_id_t, /* context_handle */
int, /* conf_req_flag */
gss_qop_t, /* qop_req */
@@ -415,24 +431,21 @@ PROTOTYPE( (void *,
));
OM_uint32 krb5_gss_import_name_object
-PROTOTYPE( (krb5_context,
- OM_uint32 *, /* minor_status */
+PROTOTYPE( (OM_uint32 *, /* minor_status */
void *, /* input_name */
gss_OID, /* input_name_type */
gss_name_t * /* output_name */
));
OM_uint32 krb5_gss_export_name_object
-PROTOTYPE( (krb5_context,
- OM_uint32 *, /* minor_status */
+PROTOTYPE( (OM_uint32 *, /* minor_status */
gss_name_t, /* input_name */
gss_OID, /* desired_name_type */
void * * /* output_name */
));
OM_uint32 krb5_gss_add_cred
-PROTOTYPE( (void *,
- OM_uint32 *, /* minor_status */
+PROTOTYPE( (OM_uint32 *, /* minor_status */
gss_cred_id_t, /* input_cred_handle */
gss_name_t, /* desired_name */
gss_OID, /* desired_mech */
@@ -446,8 +459,7 @@ PROTOTYPE( (void *,
));
OM_uint32 krb5_gss_inquire_cred_by_mech
-PROTOTYPE( (void *,
- OM_uint32 *, /* minor_status */
+PROTOTYPE( (OM_uint32 *, /* minor_status */
gss_cred_id_t, /* cred_handle */
gss_OID, /* mech_type */
gss_name_t *, /* name */
@@ -457,38 +469,33 @@ PROTOTYPE( (void *,
));
OM_uint32 krb5_gss_export_sec_context
-PROTOTYPE( (void *,
- OM_uint32 *, /* minor_status */
+PROTOTYPE( (OM_uint32 *, /* minor_status */
gss_ctx_id_t *, /* context_handle */
gss_buffer_t /* interprocess_token */
));
OM_uint32 krb5_gss_import_sec_context
-PROTOTYPE( (void *,
- OM_uint32 *, /* minor_status */
+PROTOTYPE( (OM_uint32 *, /* minor_status */
gss_buffer_t, /* interprocess_token */
gss_ctx_id_t * /* context_handle */
));
+#if 0
OM_uint32 krb5_gss_release_oid
PROTOTYPE( (OM_uint32 *, /* minor_status */
gss_OID * /* oid */
));
-
+#endif
OM_uint32 krb5_gss_internal_release_oid
-PROTOTYPE( (void *,
- OM_uint32 *, /* minor_status */
+PROTOTYPE( (OM_uint32 *, /* minor_status */
gss_OID * /* oid */
));
OM_uint32 krb5_gss_inquire_names_for_mech
-PROTOTYPE( (void *,
- OM_uint32 *, /* minor_status */
+PROTOTYPE( (OM_uint32 *, /* minor_status */
gss_OID, /* mechanism */
gss_OID_set * /* name_types */
));
-OM_uint32 kg_get_context();
-
#endif /* _GSSAPIP_KRB5_H_ */
diff --git a/src/lib/gssapi/krb5/gssapi_err_krb5.et b/src/lib/gssapi/krb5/gssapi_err_krb5.et
index 0f26773b19..54a126518b 100644
--- a/src/lib/gssapi/krb5/gssapi_err_krb5.et
+++ b/src/lib/gssapi/krb5/gssapi_err_krb5.et
@@ -33,4 +33,6 @@ 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"
end
diff --git a/src/lib/gssapi/krb5/gssapi_krb5.c b/src/lib/gssapi/krb5/gssapi_krb5.c
index e184557558..feec0bc712 100644
--- a/src/lib/gssapi/krb5/gssapi_krb5.c
+++ b/src/lib/gssapi/krb5/gssapi_krb5.c
@@ -20,50 +20,62 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
+/*
+ * $Id$
+ */
+
#include "gssapiP_krb5.h"
-/** exported constants defined in gssapi_krb5.h **/
+/** exported constants defined in gssapi_krb5{,_nx}.h **/
/* these are bogus, but will compile */
/*
- * The OID of the krb5 mechanism, assigned by IETF, is:
- * 1.3.5.1.5.2
+ * 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.2.1.2.1
+ * 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.2.1.2.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
+ *
*/
/*
* 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 set on all octets except
- * the last in each value's encoding.
+ * significant digit first, with the high bit (\200) set on all octets
+ * except the last in each value's encoding.
*/
static const gss_OID_desc oids[] = {
- /* this OID is from Ted. It's not official yet, but it's close. */
+ /* this is the unofficial, wrong OID */
{5, "\053\005\001\005\002"},
+ /* this is the official, rfc-specified OID */
+ {9, "\052\206\110\206\367\022\001\002\002"},
{10, "\052\206\110\206\367\022\001\002\002\001"},
{10, "\052\206\110\206\367\022\001\002\002\002"},
- {9, "\052\206\110\206\367\022\001\002\002"},
};
-const gss_OID_desc * const gss_mech_krb5 = oids+0;
+const gss_OID_desc * const gss_mech_krb5_old = oids+0;
+const gss_OID_desc * const gss_mech_krb5 = oids+1;
const gss_OID_desc * const gss_nt_krb5_name = oids+1;
-const gss_OID_desc * const gss_nt_krb5_principal = oids+2;
-const gss_OID_desc * const gss_new_mech_krb5 = oids+3;
+const gss_OID_desc * const gss_nt_krb5_principal = oids+3;
static const gss_OID_set_desc oidsets[] = {
- {1, (gss_OID) oids},
+ {1, (gss_OID) oids+0},
+ {1, (gss_OID) oids+1},
+ {2, (gss_OID) oids+0},
};
-const gss_OID_set_desc * const gss_mech_set_krb5 = oidsets+0;
-
-krb5_context kg_context;
+const gss_OID_set_desc * const gss_mech_set_krb5_old = oidsets+0;
+const gss_OID_set_desc * const gss_mech_set_krb5 = oidsets+1;
+const gss_OID_set_desc * const gss_mech_set_krb5_both = oidsets+2;
void *kg_vdb = NULL;
@@ -83,10 +95,7 @@ kg_get_defcred(minor_status, cred)
if (defcred == GSS_C_NO_CREDENTIAL) {
OM_uint32 major;
- if (!kg_context && kg_get_context())
- return GSS_S_FAILURE;
-
- if ((major = krb5_gss_acquire_cred(kg_context, minor_status,
+ if ((major = krb5_gss_acquire_cred(minor_status,
(gss_name_t) NULL, GSS_C_INDEFINITE,
GSS_C_NULL_OID_SET, GSS_C_INITIATE,
&defcred, NULL, NULL)) &&
@@ -110,19 +119,24 @@ kg_release_defcred(minor_status)
return(GSS_S_COMPLETE);
}
- if (!kg_context && kg_get_context())
- return GSS_S_FAILURE;
-
- return(krb5_gss_release_cred(kg_context, minor_status, &defcred));
+ return(krb5_gss_release_cred(minor_status, &defcred));
}
OM_uint32
-kg_get_context()
+kg_get_context(minor_status, context)
+ OM_uint32 *minor_status;
+ krb5_context *context;
{
- if (kg_context)
- return GSS_S_COMPLETE;
- if (krb5_init_context(&kg_context))
- return GSS_S_FAILURE;
- krb5_init_ets(kg_context);
- return GSS_S_COMPLETE;
+ static krb5_context kg_context = NULL;
+ krb5_error_code code;
+
+ if ((! kg_context) &&
+ (code = krb5_init_context(&kg_context))) {
+ *minor_status = (OM_uint32) code;
+ return GSS_S_FAILURE;
+ }
+
+ *context = kg_context;
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
}
diff --git a/src/lib/gssapi/krb5/gssapi_krb5.h b/src/lib/gssapi/krb5/gssapi_krb5.h
index 450081d97c..71182f22b4 100644
--- a/src/lib/gssapi/krb5/gssapi_krb5.h
+++ b/src/lib/gssapi/krb5/gssapi_krb5.h
@@ -28,10 +28,13 @@
#else
#include <gssapi_generic.h>
#endif
-#include "krb5.h"
+#include <krb5.h>
extern const gss_OID_desc * const gss_mech_krb5;
+extern const gss_OID_desc * const gss_mech_krb5_old;
extern const gss_OID_set_desc * const gss_mech_set_krb5;
+extern const gss_OID_set_desc * const gss_mech_set_krb5_old;
+extern const gss_OID_set_desc * const gss_mech_set_krb5_both;
extern const gss_OID_desc * const gss_nt_krb5_name;
extern const gss_OID_desc * const gss_nt_krb5_principal;
@@ -49,4 +52,11 @@ OM_uint32 gss_krb5_get_tkt_flags
krb5_flags *ticket_flags));
+/* this is for backward compatibility only. It is declared here for
+ completeness, but should not be used */
+
+OM_uint32 krb5_gss_set_backward_mode
+ PROTOTYPE((OM_uint32 *minor_status,
+ int mode));
+
#endif /* _GSSAPI_KRB5_H_ */
diff --git a/src/lib/gssapi/krb5/import_name.c b/src/lib/gssapi/krb5/import_name.c
index ee44132ae3..5c2c6f43a8 100644
--- a/src/lib/gssapi/krb5/import_name.c
+++ b/src/lib/gssapi/krb5/import_name.c
@@ -20,7 +20,12 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
+/*
+ * $Id$
+ */
+
#include "gssapiP_krb5.h"
+
#ifndef NO_PASSWORD
#include <pwd.h>
#endif
@@ -39,21 +44,24 @@
*/
OM_uint32
-krb5_gss_import_name(ctx, minor_status, input_name_buffer,
+krb5_gss_import_name(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;
{
- krb5_context context = ctx;
+ krb5_context context;
krb5_principal princ;
krb5_error_code code;
char *stringrep, *tmp;
#ifndef NO_PASSWORD
struct passwd *pw;
#endif
+
+ if (GSS_ERROR(kg_get_context(minor_status, &context)))
+ return(GSS_S_FAILURE);
+
/* set up default returns */
*output_name = NULL;
@@ -75,13 +83,10 @@ krb5_gss_import_name(ctx, minor_status, input_name_buffer,
tmp[input_name_buffer->length] = 0;
service = tmp;
- if ((host = strchr(tmp, '@')) == NULL) {
- xfree(tmp);
- *minor_status = (OM_uint32) G_BAD_SERVICE_NAME;
- return(GSS_S_BAD_NAME);
+ if (host = strchr(tmp, '@')) {
+ *host = '\0';
+ host++;
}
- *host = '\0';
- host++;
code = krb5_sname_to_principal(context, host, service, KRB5_NT_SRV_HST,
&princ);
diff --git a/src/lib/gssapi/krb5/import_sec_context.c b/src/lib/gssapi/krb5/import_sec_context.c
index d802ecdd00..c1d1bfa72a 100644
--- a/src/lib/gssapi/krb5/import_sec_context.c
+++ b/src/lib/gssapi/krb5/import_sec_context.c
@@ -28,59 +28,46 @@
#include "gssapiP_krb5.h"
OM_uint32
-krb5_gss_import_sec_context(ct,
- minor_status, interprocess_token, context_handle)
- void *ct;
+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 ser_ctx = ct;
+ krb5_context context;
krb5_error_code kret = 0;
OM_uint32 retval;
size_t blen;
- krb5_gss_ctx_id_t *ctx;
+ krb5_gss_ctx_id_t ctx;
krb5_octet *ibp;
+ if (GSS_ERROR(kg_get_context(minor_status, &context)))
+ return(GSS_S_FAILURE);
+
/* Assume a tragic failure */
- ctx = (krb5_gss_ctx_id_t *) NULL;
+ ctx = (krb5_gss_ctx_id_t) NULL;
retval = GSS_S_FAILURE;
*minor_status = 0;
/* Internalize the context */
ibp = (krb5_octet *) interprocess_token->value;
blen = (size_t) interprocess_token->length;
- if ((kret = krb5_internalize_opaque(ser_ctx, KG_CONTEXT,
- (krb5_pointer *) &ctx,
- &ibp, &blen)))
- goto error_out;
-
+ if ((kret = kg_ctx_internalize(context,
+ (krb5_pointer *) &ctx,
+ &ibp, &blen))) {
+ *minor_status = (OM_uint32) kret;
+ return(GSS_S_FAILURE);
+ }
- /* Make sure that everything is cool. */
- if (!kg_validate_ctx_id((gss_ctx_id_t) ctx))
- goto error_out;
+ /* 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);
+ }
*context_handle = (gss_ctx_id_t) ctx;
+ *minor_status = 0;
return (GSS_S_COMPLETE);
-
-error_out:
- if (ctx) {
- (void) kg_delete_ctx_id((gss_ctx_id_t) ctx);
- if (ctx->enc.processed)
- krb5_finish_key(ser_ctx, &ctx->enc.eblock);
- krb5_free_keyblock(ser_ctx, ctx->enc.key);
- if (ctx->seq.processed)
- krb5_finish_key(ser_ctx, &ctx->seq.eblock);
- krb5_free_principal(ser_ctx, ctx->here);
- krb5_free_principal(ser_ctx, ctx->there);
- krb5_free_keyblock(ser_ctx, ctx->subkey);
-
- /* Zero out context */
- memset(ctx, 0, sizeof(*ctx));
- xfree(ctx);
- }
- if (*minor_status == 0)
- *minor_status = (OM_uint32) kret;
- return(retval);
}
diff --git a/src/lib/gssapi/krb5/indicate_mechs.c b/src/lib/gssapi/krb5/indicate_mechs.c
index 0f78de2199..bc53b4434d 100644
--- a/src/lib/gssapi/krb5/indicate_mechs.c
+++ b/src/lib/gssapi/krb5/indicate_mechs.c
@@ -20,11 +20,14 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
+/*
+ * $Id$
+ */
+
#include "gssapiP_krb5.h"
OM_uint32
-krb5_gss_indicate_mechs(ctx, minor_status, mech_set)
- void *ctx;
+krb5_gss_indicate_mechs(minor_status, mech_set)
OM_uint32 *minor_status;
gss_OID_set *mech_set;
{
diff --git a/src/lib/gssapi/krb5/init_sec_context.c b/src/lib/gssapi/krb5/init_sec_context.c
index 2b671680ae..686384216a 100644
--- a/src/lib/gssapi/krb5/init_sec_context.c
+++ b/src/lib/gssapi/krb5/init_sec_context.c
@@ -22,22 +22,25 @@
#include "gssapiP_krb5.h"
#include <memory.h>
-#include "k5-int.h"
+
+/*
+ * $Id$
+ */
static krb5_error_code
-make_ap_req(ctx, auth_context, cred, server, endtime, chan_bindings,
- do_mutual, flags, token)
- void *ctx;
+make_ap_req(context, auth_context, cred, server, endtime, chan_bindings,
+ req_flags, flags, mech_type, token)
+ krb5_context context;
krb5_auth_context * auth_context;
krb5_gss_cred_id_t cred;
krb5_principal server;
krb5_timestamp *endtime;
gss_channel_bindings_t chan_bindings;
- OM_uint32 do_mutual;
+ OM_uint32 req_flags;
krb5_flags *flags;
+ gss_OID mech_type;
gss_buffer_t token;
{
- krb5_context context = ctx;
krb5_flags mk_req_flags = 0;
krb5_error_code code;
krb5_data checksum_data;
@@ -46,19 +49,19 @@ make_ap_req(ctx, auth_context, cred, server, endtime, chan_bindings,
krb5_data ap_req;
unsigned char *ptr;
krb5_data credmsg;
- unsigned char ckbuf[24]; /* see the token formats doc */
unsigned char *t;
int tlen;
krb5_int32 con_flags;
ap_req.data = 0;
checksum_data.data = 0;
+ credmsg.data = 0;
/* build the checksum buffer */
/* compute the hash of the channel bindings */
- if ((code = kg_checksum_channel_bindings(chan_bindings, &md5, 0)))
+ if ((code = kg_checksum_channel_bindings(context, chan_bindings, &md5, 0)))
return(code);
/* get an auth_context structure and fill in checksum type */
@@ -92,25 +95,31 @@ make_ap_req(ctx, auth_context, cred, server, endtime, chan_bindings,
return(KRB5KRB_ERR_FIELD_TOOLONG);
}
- /* now allocate a buffer to hold the checksum data and KRB_CRED msg
- and write it */
+ checksum_data.length = 28+credmsg.length;
+ } else {
+ checksum_data.length = 24;
+ }
+
+ /* now allocate a buffer to hold the checksum data and
+ (maybe) KRB_CRED msg */
- if ((ptr = (unsigned char *) xmalloc(credmsg.length+28)) == NULL) {
+ if ((checksum_data.data =
+ (char *) xmalloc(checksum_data.length)) == NULL) {
+ if (credmsg.data)
krb5_xfree(credmsg.data);
- return(ENOMEM);
- }
+ return(ENOMEM);
+ }
- checksum_data.data = (char *) ptr;
- checksum_data.length = credmsg.length+28;
+ ptr = checksum_data.data;
- TWRITE_INT(ptr, md5.length, 0);
- TWRITE_STR(ptr, (unsigned char *) md5.contents, md5.length);
- TWRITE_INT(ptr, do_mutual?GSS_C_MUTUAL_FLAG | GSS_C_DELEG_FLAG
- :GSS_C_DELEG_FLAG, 0);
+ TWRITE_INT(ptr, md5.length, 0);
+ TWRITE_STR(ptr, (unsigned char *) md5.contents, md5.length);
+ TWRITE_INT(ptr, KG_IMPLFLAGS(req_flags), 0);
- /* done with this, free it */
- xfree(md5.contents);
+ /* done with this, free it */
+ xfree(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);
@@ -118,20 +127,6 @@ make_ap_req(ctx, auth_context, cred, server, endtime, chan_bindings,
/* free credmsg data */
krb5_xfree(credmsg.data);
-
- } else {
-
- ptr = ckbuf;
-
- TWRITE_INT(ptr, md5.length, 0);
- TWRITE_STR(ptr, (unsigned char *) md5.contents, md5.length);
- TWRITE_INT(ptr, do_mutual?GSS_C_MUTUAL_FLAG:0, 0);
-
- /* done with this, free it */
- xfree(md5.contents);
-
- checksum_data.data = (char *) ckbuf;
- checksum_data.length = sizeof(ckbuf);
}
/* fill in the necessary fields in creds */
@@ -142,7 +137,7 @@ make_ap_req(ctx, auth_context, cred, server, endtime, chan_bindings,
goto cleanup;
in_creds.times.endtime = *endtime;
- in_creds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
+
/*
* Get the credential..., I don't know in 0 is a good value for the
* kdcoptions
@@ -155,7 +150,7 @@ make_ap_req(ctx, auth_context, cred, server, endtime, chan_bindings,
mk_req_flags = AP_OPTS_USE_SUBKEY;
- if (do_mutual)
+ if (req_flags & GSS_C_MUTUAL_FLAG)
mk_req_flags |= AP_OPTS_MUTUAL_REQUIRED;
if ((code = krb5_mk_req_extended(context, auth_context, mk_req_flags,
@@ -169,7 +164,7 @@ make_ap_req(ctx, auth_context, cred, server, endtime, chan_bindings,
/* build up the token */
/* allocate space for the token */
- tlen = g_token_size((gss_OID) gss_mech_krb5, ap_req.length);
+ tlen = g_token_size((gss_OID) mech_type, ap_req.length);
if ((t = (unsigned char *) xmalloc(tlen)) == NULL) {
code = ENOMEM;
@@ -180,38 +175,38 @@ make_ap_req(ctx, auth_context, cred, server, endtime, chan_bindings,
ptr = t;
- g_make_token_header((gss_OID) gss_mech_krb5, ap_req.length,
+ 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.data && checksum_data.data != (char *) ckbuf)
- free(checksum_data.data);
- krb5_free_cred_contents(context, &in_creds);
- if (out_creds)
- krb5_free_creds(context, out_creds);
- if (ap_req.data)
- xfree(ap_req.data);
- if (code)
- krb5_auth_con_free(context, *auth_context);
-
- return (code);
+ if (checksum_data.data)
+ free(checksum_data.data);
+ krb5_free_cred_contents(context, &in_creds);
+ if (out_creds)
+ krb5_free_creds(context, out_creds);
+ if (ap_req.data)
+ xfree(ap_req.data);
+ if (code)
+ krb5_auth_con_free(context, *auth_context);
+
+ return (code);
}
OM_uint32
-krb5_gss_init_sec_context(ct, 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 *ct;
+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;
@@ -226,28 +221,25 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle,
OM_uint32 *ret_flags;
OM_uint32 *time_rec;
{
- krb5_context context = ct;
- krb5_gss_cred_id_t cred;
- krb5_error_code code;
- krb5_gss_ctx_id_rec *ctx;
- krb5_timestamp now;
- gss_buffer_desc token;
- int i;
+ krb5_context context;
+ krb5_gss_cred_id_t cred;
+ krb5_error_code code;
+ krb5_gss_ctx_id_rec *ctx;
+ krb5_timestamp now;
+ krb5_enctype enctype;
+ gss_buffer_desc token;
+ int i;
+ int err;
+
+ if (GSS_ERROR(kg_get_context(minor_status, &context)))
+ return(GSS_S_FAILURE);
/* set up return values so they can be "freed" successfully */
output_token->length = 0;
output_token->value = NULL;
if (actual_mech_type)
- *actual_mech_type = (gss_OID) gss_mech_krb5;
-
- /* verify the mech_type */
-
- if ((mech_type != GSS_C_NULL_OID) &&
- (! g_OID_equal(mech_type, gss_mech_krb5))) {
- *minor_status = 0;
- return(GSS_S_BAD_MECH);
- }
+ *actual_mech_type = NULL;
/* verify the credential, or use the default */
/*SUPPRESS 29*/
@@ -267,6 +259,17 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle,
cred = (krb5_gss_cred_id_t) claimant_cred_handle;
+ /* verify the mech_type */
+
+ if (mech_type == GSS_C_NULL_OID) {
+ mech_type = cred->rfc_mech?gss_mech_krb5:gss_mech_krb5_old;
+ } else if ((g_OID_equal(mech_type, gss_mech_krb5) && !cred->rfc_mech) ||
+ (g_OID_equal(mech_type, gss_mech_krb5_old) &&
+ !cred->prerfc_mech)) {
+ *minor_status = 0;
+ return(GSS_S_BAD_MECH);
+ }
+
/* verify that the target_name is valid and usable */
if (! kg_validate_name(target_name)) {
@@ -303,6 +306,7 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle,
/* fill in the ctx */
memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
+ ctx->mech_used = mech_type;
ctx->auth_context = NULL;
ctx->initiate = 1;
ctx->gss_flags = ((req_flags & (GSS_C_MUTUAL_FLAG | GSS_C_DELEG_FLAG)) |
@@ -310,6 +314,7 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle,
ctx->flags = req_flags & GSS_C_DELEG_FLAG;
ctx->seed_init = 0;
ctx->big_endian = 0; /* all initiators do little-endian, as per spec */
+ ctx->seqstate = 0;
if (time_req == 0 || time_req == GSS_C_INDEFINITE) {
ctx->endtime = 0;
@@ -338,8 +343,7 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle,
if ((code = make_ap_req(context, &(ctx->auth_context), cred,
ctx->there, &ctx->endtime, input_chan_bindings,
- ctx->gss_flags & GSS_C_MUTUAL_FLAG, &ctx->flags,
- &token))) {
+ req_flags, &ctx->flags, mech_type, &token))) {
krb5_free_principal(context, ctx->here);
krb5_free_principal(context, ctx->there);
xfree(ctx);
@@ -354,9 +358,29 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle,
/* fill in the encryption descriptors */
+ switch(ctx->subkey->enctype) {
+ case ENCTYPE_DES_CBC_MD5:
+ case ENCTYPE_DES_CBC_CRC:
+ enctype = ENCTYPE_DES_CBC_RAW;
+ ctx->signalg = 0;
+ ctx->cksum_size = 8;
+ ctx->sealalg = 0;
+ break;
+#if 0
+ case ENCTYPE_DES3_CBC_MD5:
+ enctype = ENCTYPE_DES3_CBC_RAW;
+ ctx->signalg = 3;
+ ctx->cksum_size = 16;
+ ctx->sealalg = 1;
+ break;
+#endif
+ default:
+ return GSS_S_FAILURE;
+ }
+
/* the encryption key is the session key XOR 0xf0f0f0f0f0f0f0f0 */
- krb5_use_enctype(context, &ctx->enc.eblock, ENCTYPE_DES_CBC_RAW);
+ krb5_use_enctype(context, &ctx->enc.eblock, enctype);
ctx->enc.processed = 0;
if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc.key)))
return(code);
@@ -364,7 +388,7 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle,
/*SUPPRESS 113*/
ctx->enc.key->contents[i] ^= 0xf0;
- krb5_use_enctype(context, &ctx->seq.eblock, ENCTYPE_DES_CBC_RAW);
+ krb5_use_enctype(context, &ctx->seq.eblock, enctype);
ctx->seq.processed = 0;
if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->seq.key)))
return(code);
@@ -390,7 +414,7 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle,
if (time_rec) {
if ((code = krb5_timeofday(context, &now))) {
xfree(token.value);
- (void)krb5_gss_delete_sec_context(context, minor_status,
+ (void)krb5_gss_delete_sec_context(minor_status,
(gss_ctx_id_t) ctx, NULL);
*minor_status = code;
return(GSS_S_FAILURE);
@@ -405,7 +429,10 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle,
*output_token = token;
if (ret_flags)
- *ret_flags = ctx->gss_flags;
+ *ret_flags = KG_IMPLFLAGS(req_flags);
+
+ if (actual_mech_type)
+ *actual_mech_type = mech_type;
/* return successfully */
@@ -415,8 +442,11 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle,
return(GSS_S_CONTINUE_NEEDED);
} else {
ctx->seq_recv = ctx->seq_send;
+ g_order_init(&(ctx->seqstate), ctx->seq_recv,
+ req_flags & GSS_C_REPLAY_FLAG,
+ req_flags & GSS_C_SEQUENCE_FLAG);
ctx->established = 1;
- return(GSS_S_COMPLETE);
+ /* fall through to GSS_S_COMPLETE */
}
} else {
unsigned char *ptr;
@@ -439,15 +469,16 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle,
if ((ctx->established) ||
(((gss_cred_id_t) cred) != claimant_cred_handle) ||
((req_flags & GSS_C_MUTUAL_FLAG) == 0)) {
- (void)krb5_gss_delete_sec_context(context, minor_status,
+ (void)krb5_gss_delete_sec_context(minor_status,
context_handle, NULL);
+ /* XXX this minor status is wrong if an arg was changed */
*minor_status = KG_CONTEXT_ESTABLISHED;
return(GSS_S_FAILURE);
}
if (! krb5_principal_compare(context, ctx->there,
(krb5_principal) target_name)) {
- (void)krb5_gss_delete_sec_context(context, minor_status,
+ (void)krb5_gss_delete_sec_context(minor_status,
context_handle, NULL);
*minor_status = 0;
return(GSS_S_BAD_NAME);
@@ -456,7 +487,7 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle,
/* 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(context, minor_status,
+ (void)krb5_gss_delete_sec_context(minor_status,
context_handle, NULL);
*minor_status = 0;
return(GSS_S_DEFECTIVE_TOKEN);
@@ -464,10 +495,10 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle,
ptr = (unsigned char *) input_token->value;
- if (! g_verify_token_header((gss_OID) gss_mech_krb5, &(ap_rep.length),
- &ptr, KG_TOK_CTX_AP_REP,
- input_token->length)) {
- *minor_status = 0;
+ if (err = g_verify_token_header((gss_OID) mech_type, &(ap_rep.length),
+ &ptr, KG_TOK_CTX_AP_REP,
+ input_token->length)) {
+ *minor_status = err;
return(GSS_S_DEFECTIVE_TOKEN);
}
@@ -482,9 +513,9 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle,
* To be removed in 1999 -- proven
*/
krb5_auth_con_setuseruserkey(context,ctx->auth_context,ctx->subkey);
- if ((code = krb5_rd_rep(context, ctx->auth_context, &ap_rep,
- &ap_rep_data))) {
- (void)krb5_gss_delete_sec_context(context, minor_status,
+ if ((krb5_rd_rep(context, ctx->auth_context, &ap_rep,
+ &ap_rep_data))) {
+ (void)krb5_gss_delete_sec_context(minor_status,
context_handle, NULL);
*minor_status = code;
return(GSS_S_FAILURE);
@@ -493,6 +524,9 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle,
/* store away the sequence number */
ctx->seq_recv = ap_rep_data->seq_number;
+ g_order_init(&(ctx->seqstate), ctx->seq_recv,
+ req_flags & GSS_C_REPLAY_FLAG,
+ req_flags & GSS_C_SEQUENCE_FLAG);
/* free the ap_rep_data */
krb5_free_ap_rep_enc_part(context, ap_rep_data);
@@ -504,20 +538,25 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle,
if (time_rec) {
if ((code = krb5_timeofday(context, &now))) {
- (void)krb5_gss_delete_sec_context(context, minor_status,
+ (void)krb5_gss_delete_sec_context(minor_status,
(gss_ctx_id_t) ctx, NULL);
*minor_status = code;
return(GSS_S_FAILURE);
-
}
+ *time_rec = ctx->endtime - now;
}
if (ret_flags)
- *ret_flags = GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG | GSS_C_MUTUAL_FLAG;
+ *ret_flags = KG_IMPLFLAGS(req_flags);
+
+ if (actual_mech_type)
+ *actual_mech_type = mech_type;
/* success */
*minor_status = 0;
- return(GSS_S_COMPLETE);
+ /* fall through to GSS_S_COMPLETE */
}
+
+ return(GSS_S_COMPLETE);
}
diff --git a/src/lib/gssapi/krb5/inq_context.c b/src/lib/gssapi/krb5/inq_context.c
index c8499212fb..5e57463441 100644
--- a/src/lib/gssapi/krb5/inq_context.c
+++ b/src/lib/gssapi/krb5/inq_context.c
@@ -23,10 +23,9 @@
#include "gssapiP_krb5.h"
OM_uint32
-krb5_gss_inquire_context(ct, minor_status, context_handle, initiator_name,
+krb5_gss_inquire_context(minor_status, context_handle, initiator_name,
acceptor_name, lifetime_rec, mech_type, ret_flags,
locally_initiated, open)
- void *ct;
OM_uint32 *minor_status;
gss_ctx_id_t context_handle;
gss_name_t *initiator_name;
@@ -37,13 +36,16 @@ krb5_gss_inquire_context(ct, minor_status, context_handle, initiator_name,
int *locally_initiated;
int *open;
{
- krb5_context context = ct;
+ krb5_context context;
krb5_error_code code;
krb5_gss_ctx_id_rec *ctx;
krb5_principal init, accept;
krb5_timestamp now;
krb5_deltat lifetime;
+ if (GSS_ERROR(kg_get_context(minor_status, &context)))
+ return(GSS_S_FAILURE);
+
if (initiator_name)
*initiator_name = (gss_name_t) NULL;
if (acceptor_name)
@@ -116,7 +118,7 @@ krb5_gss_inquire_context(ct, minor_status, context_handle, initiator_name,
*lifetime_rec = lifetime;
if (mech_type)
- *mech_type = (gss_OID) gss_mech_krb5;
+ *mech_type = (gss_OID) ctx->mech_used;
if (ret_flags)
*ret_flags = ctx->gss_flags;
diff --git a/src/lib/gssapi/krb5/inq_cred.c b/src/lib/gssapi/krb5/inq_cred.c
index e3e01bf4ec..f9811c347c 100644
--- a/src/lib/gssapi/krb5/inq_cred.c
+++ b/src/lib/gssapi/krb5/inq_cred.c
@@ -23,9 +23,8 @@
#include "gssapiP_krb5.h"
OM_uint32
-krb5_gss_inquire_cred(ctx, minor_status, cred_handle, name, lifetime_ret,
+krb5_gss_inquire_cred(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;
@@ -33,7 +32,7 @@ krb5_gss_inquire_cred(ctx, minor_status, cred_handle, name, lifetime_ret,
gss_cred_usage_t *cred_usage;
gss_OID_set *mechanisms;
{
- krb5_context context = ctx;
+ krb5_context context;
krb5_gss_cred_id_t cred;
krb5_error_code code;
krb5_timestamp now;
@@ -41,6 +40,9 @@ krb5_gss_inquire_cred(ctx, minor_status, cred_handle, name, lifetime_ret,
krb5_principal ret_name;
gss_OID_set mechs;
+ if (GSS_ERROR(kg_get_context(minor_status, &context)))
+ return(GSS_S_FAILURE);
+
if (name) *name = NULL;
if (mechanisms) *mechanisms = NULL;
@@ -82,7 +84,7 @@ krb5_gss_inquire_cred(ctx, minor_status, cred_handle, name, lifetime_ret,
}
if (mechanisms)
- if (! g_copy_OID_set(gss_mech_set_krb5, &mechs)) {
+ if (! g_copy_OID_set(cred->actual_mechs, &mechs)) {
krb5_free_principal(context, ret_name);
*minor_status = ENOMEM;
return(GSS_S_FAILURE);
@@ -113,10 +115,9 @@ krb5_gss_inquire_cred(ctx, minor_status, cred_handle, name, lifetime_ret,
/* V2 interface */
OM_uint32
-krb5_gss_inquire_cred_by_mech(ctx, minor_status, cred_handle,
+krb5_gss_inquire_cred_by_mech(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;
@@ -125,11 +126,14 @@ krb5_gss_inquire_cred_by_mech(ctx, minor_status, cred_handle,
OM_uint32 *acceptor_lifetime;
gss_cred_usage_t *cred_usage;
{
- krb5_context context = ctx;
+ krb5_context context;
krb5_gss_cred_id_t cred;
OM_uint32 lifetime;
OM_uint32 mstat;
+ if (GSS_ERROR(kg_get_context(minor_status, &context)))
+ return(GSS_S_FAILURE);
+
/*
* We only know how to handle our own creds.
*/
@@ -140,8 +144,7 @@ krb5_gss_inquire_cred_by_mech(ctx, minor_status, cred_handle,
}
cred = (krb5_gss_cred_id_t) cred_handle;
- mstat = krb5_gss_inquire_cred(context,
- minor_status,
+ mstat = krb5_gss_inquire_cred(minor_status,
cred_handle,
name,
&lifetime,
diff --git a/src/lib/gssapi/krb5/inq_names.c b/src/lib/gssapi/krb5/inq_names.c
index fe61eb01af..948346dc6c 100644
--- a/src/lib/gssapi/krb5/inq_names.c
+++ b/src/lib/gssapi/krb5/inq_names.c
@@ -28,19 +28,23 @@
#include "gssapiP_krb5.h"
OM_uint32
-krb5_gss_inquire_names_for_mech(context, minor_status, mechanism, name_types)
- void *context;
+krb5_gss_inquire_names_for_mech(minor_status, mechanism, name_types)
OM_uint32 *minor_status;
gss_OID mechanism;
gss_OID_set *name_types;
{
+ krb5_context context;
OM_uint32 major, minor;
+ if (GSS_ERROR(kg_get_context(minor_status, &context)))
+ return(GSS_S_FAILURE);
+
/*
* 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, mechanism) &&
+ !g_OID_equal(gss_mech_krb5_old, mechanism)) {
*minor_status = 0;
return(GSS_S_FAILURE);
}
diff --git a/src/lib/gssapi/krb5/k5seal.c b/src/lib/gssapi/krb5/k5seal.c
index 4e5c78bd1a..254d516807 100644
--- a/src/lib/gssapi/krb5/k5seal.c
+++ b/src/lib/gssapi/krb5/k5seal.c
@@ -21,11 +21,11 @@
*/
#include "gssapiP_krb5.h"
-#include "rsa-md5.h"
static krb5_error_code
make_seal_token(context, enc_ed, seq_ed, seqnum, direction, text, token,
- encrypt, toktype, bigend)
+ signalg, cksum_size, sealalg, encrypt, toktype,
+ bigend, oid)
krb5_context context;
krb5_gss_enc_desc *enc_ed;
krb5_gss_enc_desc *seq_ed;
@@ -33,29 +33,36 @@ make_seal_token(context, enc_ed, seq_ed, seqnum, direction, text, token,
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;
- krb5_MD5_CTX md5;
- krb5_checksum desmac;
- krb5_octet cbc_checksum[KRB5_MIT_DES_KEYSIZE];
- int tmsglen, tlen;
+ char *data_ptr;
+ krb5_checksum md5cksum;
+ krb5_checksum cksum;
+ int conflen, tmsglen, tlen;
unsigned char *t, *ptr;
/* create the token buffer */
- if ((toktype == KG_TOK_SEAL_MSG) || (toktype == KG_TOK_WRAP_MSG)) {
- if (bigend && !encrypt)
+ if (toktype == KG_TOK_SEAL_MSG) {
+ if (bigend && !encrypt) {
tmsglen = text->length;
- else
- tmsglen = (kg_confounder_size(enc_ed)+text->length+8)&(~7);
+ } else {
+ conflen = kg_confounder_size(enc_ed);
+ /* XXX knows that des block size is 8 */
+ tmsglen = (conflen+text->length+8)&(~7);
+ }
} else {
tmsglen = 0;
}
- tlen = g_token_size((gss_OID) gss_mech_krb5, 22+tmsglen);
+ tlen = g_token_size((gss_OID) oid, 14+cksum_size+tmsglen);
if ((t = (unsigned char *) xmalloc(tlen)) == NULL)
return(ENOMEM);
@@ -64,104 +71,192 @@ make_seal_token(context, enc_ed, seq_ed, seqnum, direction, text, token,
ptr = t;
- g_make_token_header((gss_OID) gss_mech_krb5, 22+tmsglen, &ptr, toktype);
+ g_make_token_header((gss_OID) oid, 14+cksum_size+tmsglen, &ptr, toktype);
- /* for now, only generate DES integrity */
+ /* 0..1 SIGN_ALG */
- ptr[0] = 0;
+ ptr[0] = signalg;
ptr[1] = 0;
+
+ /* 2..3 SEAL_ALG or Filler */
- /* SEAL_ALG, or filler */
-
- if (((toktype == KG_TOK_SEAL_MSG) ||
- (toktype == KG_TOK_WRAP_MSG)) && encrypt) {
- ptr[2] = 0;
+ if ((toktype == KG_TOK_SEAL_MSG) && encrypt) {
+ ptr[2] = sealalg;
ptr[3] = 0;
} else {
+ /* No seal */
ptr[2] = 0xff;
ptr[3] = 0xff;
}
- /* filler */
+ /* 4..5 Filler */
ptr[4] = 0xff;
ptr[5] = 0xff;
/* pad the plaintext, encrypt if needed, and stick it in the token */
- if ((toktype == KG_TOK_SEAL_MSG) || (toktype == KG_TOK_WRAP_MSG)) {
+ /* initialize the the cksum and allocate the contents buffer */
+ md5cksum.checksum_type = CKSUMTYPE_RSA_MD5;
+ md5cksum.length = krb5_checksum_size(context, CKSUMTYPE_RSA_MD5);
+ if ((md5cksum.contents = (krb5_octet *) xmalloc(md5cksum.length)) == NULL) {
+ return(ENOMEM);
+ }
+
+ if (toktype == KG_TOK_SEAL_MSG) {
unsigned char *plain;
unsigned char pad;
- if ((plain = (unsigned char *) xmalloc(tmsglen)) == NULL) {
- xfree(t);
- return(ENOMEM);
- }
+ if (!bigend || encrypt) {
+ if ((plain = (unsigned char *) xmalloc(tmsglen)) == NULL) {
+ xfree(md5cksum.contents);
+ xfree(t);
+ return(ENOMEM);
+ }
- if (code = kg_make_confounder(enc_ed, plain)) {
- xfree(plain);
- xfree(t);
- return(code);
- }
+ if (code = kg_make_confounder(enc_ed, plain)) {
+ xfree(plain);
+ xfree(md5cksum.contents);
+ xfree(t);
+ return(code);
+ }
- memcpy(plain+8, text->value, text->length);
+ memcpy(plain+conflen, text->value, text->length);
- pad = 8-(text->length%8);
+ /* XXX 8 is DES cblock size */
+ pad = 8-(text->length%8);
- memset(plain+8+text->length, pad, pad);
+ memset(plain+conflen+text->length, pad, pad);
+ } else {
+ /* plain is never used in the bigend && !encrypt case */
+ plain = NULL;
+ }
if (encrypt) {
- if (code = kg_encrypt(enc_ed, NULL, (krb5_pointer) plain,
- (krb5_pointer) (ptr+22), tmsglen)) {
- xfree(plain);
+ if (code = kg_encrypt(context, enc_ed, NULL, (krb5_pointer) plain,
+ (krb5_pointer) (ptr+cksum_size+14), tmsglen)) {
+ if (plain)
+ xfree(plain);
+ xfree(md5cksum.contents);
xfree(t);
return(code);
}
} else {
if (bigend)
- memcpy(ptr+22, text->value, text->length);
+ memcpy(ptr+14+cksum_size, text->value, text->length);
else
- memcpy(ptr+22, plain, tmsglen);
+ memcpy(ptr+14+cksum_size, plain, tmsglen);
}
/* compute the checksum */
- krb5_MD5Init(&md5);
- krb5_MD5Update(&md5, (unsigned char *) ptr-2, 8);
+ /* 8 = head of token body as specified by mech spec */
+ if (! (data_ptr =
+ (char *) xmalloc(8 + (bigend ? text->length : tmsglen)))) {
+ if (plain)
+ xfree(plain);
+ xfree(md5cksum.contents);
+ xfree(t);
+ return(ENOMEM);
+ }
+ (void) memcpy(data_ptr, ptr-2, 8);
if (bigend)
- krb5_MD5Update(&md5, text->value, text->length);
+ (void) memcpy(data_ptr+8, text->value, text->length);
else
- krb5_MD5Update(&md5, plain, tmsglen);
- krb5_MD5Final(&md5);
+ (void) memcpy(data_ptr+8, plain, tmsglen);
+ code = krb5_calculate_checksum(context, md5cksum.checksum_type, data_ptr,
+ 8 + (bigend ? text->length : tmsglen),
+ 0, 0, &md5cksum);
+ xfree(data_ptr);
+
+ if (code) {
+ if (plain)
+ xfree(plain);
+ xfree(md5cksum.contents);
+ xfree(t);
+ return(code);
+ memcpy(ptr+14+cksum_size, plain, tmsglen);
+ }
- xfree(plain);
+ if (plain)
+ xfree(plain);
} else {
/* compute the checksum */
- krb5_MD5Init(&md5);
- krb5_MD5Update(&md5, (unsigned char *) ptr-2, 8);
- krb5_MD5Update(&md5, text->value, text->length);
- krb5_MD5Final(&md5);
+ if (! (data_ptr = (char *) xmalloc(8 + text->length))) {
+ xfree(md5cksum.contents);
+ xfree(t);
+ return(ENOMEM);
+ }
+ (void) memcpy(data_ptr, ptr-2, 8);
+ (void) memcpy(data_ptr+8, text->value, text->length);
+ code = krb5_calculate_checksum(context, md5cksum.checksum_type, data_ptr,
+ 8 + text->length,
+ 0, 0, &md5cksum);
+ xfree(data_ptr);
+ if (code) {
+ xfree(md5cksum.contents);
+ xfree(t);
+ return(code);
+ }
}
- /* XXX this depends on the key being a single-des key, but that's
- all that kerberos supports right now */
-
- desmac.length = sizeof(cbc_checksum);
- desmac.contents = cbc_checksum;
- if (code = krb5_calculate_checksum(context, CKSUMTYPE_DESCBC, md5.digest, 16,
- seq_ed->key->contents,
- seq_ed->key->length,
- &desmac)) {
- xfree(t);
- return(code);
+ switch(signalg) {
+ case 0:
+ case 3:
+
+#if 0
+ /* XXX this depends on the key being a single-des key */
+
+ /* DES CBC doesn't use a zero IV like it should in some
+ krb5 implementations (beta5+). So we just do the
+ DES encryption the long way, and keep the last block
+ as the MAC */
+
+ /* initialize the the cksum and allocate the contents buffer */
+ cksum.checksum_type = CKSUMTYPE_DESCBC;
+ cksum.length = krb5_checksum_size(context, CKSUMTYPE_DESCBC);
+ if ((cksum.contents = (krb5_octet *) xmalloc(cksum.length)) == NULL)
+ return(ENOMEM);
+
+ if (code = krb5_calculate_checksum(context, cksum.checksum_type,
+ md5cksum.contents, 16,
+ seq_ed->key->contents,
+ seq_ed->key->length,
+ &cksum)) {
+ xfree(cksum.contents);
+ xfree(md5cksum.contents);
+ xfree(t);
+ return(code);
+ }
+
+ memcpy(ptr+14, cksum.contents, 8);
+
+ xfree(cksum.contents);
+#else
+ if (code = kg_encrypt(context, seq_ed,
+ (g_OID_equal(oid, gss_mech_krb5_old) ?
+ seq_ed->key->contents : NULL),
+ md5cksum.contents, md5cksum.contents, 16)) {
+ xfree(md5cksum.contents);
+ xfree(t);
+ return code;
+ }
+
+ cksum.length = cksum_size;
+ cksum.contents = md5cksum.contents + 16 - cksum.length;
+
+ memcpy(ptr+14, cksum.contents, cksum.length);
+#endif
+
+ break;
}
- memcpy(ptr+14, desmac.contents, 8);
+ xfree(md5cksum.contents);
/* create the seq_num */
- if (code = kg_make_seq_num(seq_ed, direction?0:0xff, *seqnum,
+ if (code = kg_make_seq_num(context, seq_ed, direction?0:0xff, *seqnum,
ptr+14, ptr+6)) {
xfree(t);
return(code);
@@ -227,60 +322,16 @@ kg_seal(context, minor_status, context_handle, conf_req_flag, qop_req,
if (code = make_seal_token(context, &ctx->enc, &ctx->seq,
&ctx->seq_send, ctx->initiate,
input_message_buffer, output_message_buffer,
- conf_req_flag, toktype, ctx->big_endian)) {
+ ctx->signalg, ctx->cksum_size, ctx->sealalg,
+ conf_req_flag, toktype, ctx->big_endian,
+ ctx->mech_used)) {
*minor_status = code;
return(GSS_S_FAILURE);
}
- if (((toktype == KG_TOK_SEAL_MSG) ||
- (toktype == KG_TOK_WRAP_MSG)) && conf_state) {
+ if ((toktype == KG_TOK_SEAL_MSG) && conf_state)
*conf_state = conf_req_flag;
- }
*minor_status = 0;
return((ctx->endtime < now)?GSS_S_CONTEXT_EXPIRED:GSS_S_COMPLETE);
}
-
-OM_uint32
-kg_seal_size(context, minor_status, context_handle, conf_req_flag, qop_req,
- output_size, input_size)
- krb5_context context;
- 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_gss_ctx_id_rec *ctx;
- OM_uint32 cfsize;
- OM_uint32 ohlen;
-
- /* 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);
- }
-
- /* Calculate the token size and subtract that from the output size */
- cfsize = (conf_req_flag) ? kg_confounder_size(&ctx->enc) : 0;
- ohlen = g_token_size((gss_OID) gss_mech_krb5, (unsigned int) cfsize + 22);
-
- /* Cannot have trailer length that will cause us to pad over our length */
- *input_size = (output_size - ohlen) & (~7);
- *minor_status = 0;
- return(GSS_S_COMPLETE);
-}
-
diff --git a/src/lib/gssapi/krb5/k5unseal.c b/src/lib/gssapi/krb5/k5unseal.c
index 1b4288c0cc..70d2d4d7bd 100644
--- a/src/lib/gssapi/krb5/k5unseal.c
+++ b/src/lib/gssapi/krb5/k5unseal.c
@@ -22,7 +22,10 @@
#include "gssapiP_krb5.h"
#include <memory.h>
-#include "rsa-md5.h"
+
+/*
+ * $Id$
+ */
/* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX
conf_state is only valid if SEAL.
@@ -44,19 +47,25 @@ kg_unseal(context, minor_status, context_handle, input_token_buffer,
krb5_error_code code;
int bodysize;
int tmsglen;
+ int conflen;
int signalg;
int sealalg;
gss_buffer_desc token;
unsigned char *ptr;
+ krb5_checksum cksum;
krb5_checksum desmac;
- krb5_octet cbc_checksum[KRB5_MIT_DES_KEYSIZE];
- krb5_MD5_CTX md5;
- unsigned char *cksum;
+ krb5_checksum md5cksum;
+ char *data_ptr;
krb5_timestamp now;
unsigned char *plain;
+ int cksum_len;
int plainlen;
+ int err;
+ int direction;
+ krb5_int32 seqnum;
+ OM_uint32 retval;
- if ((toktype == KG_TOK_SEAL_MSG) || (toktype == KG_TOK_WRAP_MSG)) {
+ if (toktype == KG_TOK_SEAL_MSG) {
message_buffer->length = 0;
message_buffer->value = NULL;
}
@@ -80,73 +89,109 @@ kg_unseal(context, minor_status, context_handle, input_token_buffer,
ptr = (unsigned char *) input_token_buffer->value;
- if (! g_verify_token_header((gss_OID) gss_mech_krb5, &bodysize,
- &ptr, toktype, input_token_buffer->length)) {
- *minor_status = 0;
+ if (err = g_verify_token_header((gss_OID) ctx->mech_used, &bodysize,
+ &ptr, toktype,
+ input_token_buffer->length)) {
+ *minor_status = err;
return(GSS_S_DEFECTIVE_TOKEN);
}
- if ((toktype == KG_TOK_SEAL_MSG) || (toktype == KG_TOK_WRAP_MSG))
- tmsglen = bodysize-22;
-
/* get the sign and seal algorithms */
signalg = ptr[0] + (ptr[1]<<8);
sealalg = ptr[2] + (ptr[3]<<8);
- if (((signalg != 0) && (signalg != 1)) ||
- (((toktype != KG_TOK_SEAL_MSG) &&
- (toktype != KG_TOK_WRAP_MSG)) && (sealalg != 0xffff)) ||
- (((toktype == KG_TOK_SEAL_MSG) ||
- (toktype == KG_TOK_WRAP_MSG)) &&
- ((sealalg != 0xffff) && (sealalg != 0))) ||
- (ptr[4] != 0xff) ||
- (ptr[5] != 0xff)) {
- *minor_status = 0;
- return(GSS_S_DEFECTIVE_TOKEN);
+ /* 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 == 0) &&
+ (signalg > 1)) ||
+ ((ctx->sealalg == 1) &&
+ (signalg != 3))) {
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ switch (signalg) {
+ case 0:
+ case 1:
+ cksum_len = 8;
+ break;
+ case 3:
+ cksum_len = 16;
+ break;
+ }
+
+ if (toktype == KG_TOK_SEAL_MSG)
+ tmsglen = bodysize-(14+cksum_len);
+
/* get the token parameters */
/* decode the message, if SEAL */
- if ((toktype == KG_TOK_SEAL_MSG) || (toktype == KG_TOK_WRAP_MSG)) {
- if (sealalg == 0) {
+ if (toktype == KG_TOK_SEAL_MSG) {
+ if (sealalg != 0xffff) {
if ((plain = (unsigned char *) xmalloc(tmsglen)) == NULL) {
*minor_status = ENOMEM;
return(GSS_S_FAILURE);
}
- if (code = kg_decrypt(&ctx->enc, NULL, ptr+22, plain, tmsglen)) {
+ if (code = kg_decrypt(context, &ctx->enc, NULL,
+ ptr+14+cksum_len, plain, tmsglen)) {
xfree(plain);
*minor_status = code;
return(GSS_S_FAILURE);
}
} else {
- plain = ptr+22;
+ plain = ptr+14+cksum_len;
}
plainlen = tmsglen;
- if (sealalg && ctx->big_endian)
+ if ((sealalg == 0xffff) && ctx->big_endian) {
token.length = tmsglen;
- else
- token.length = tmsglen - 8 - plain[tmsglen-1];
+ } else {
+ conflen = kg_confounder_size(&ctx->enc);
+ token.length = tmsglen - conflen - plain[tmsglen-1];
+ }
if (token.length) {
- if ((token.value = xmalloc(token.length)) == NULL) {
- if (sealalg == 0)
+ if ((token.value = (void *) xmalloc(token.length)) == NULL) {
+ if (sealalg != 0xffff)
xfree(plain);
*minor_status = ENOMEM;
return(GSS_S_FAILURE);
}
- if (sealalg && ctx->big_endian)
+ if ((sealalg == 0xffff) && ctx->big_endian)
memcpy(token.value, plain, token.length);
else
- memcpy(token.value, plain+8, token.length);
+ memcpy(token.value, plain+conflen, token.length);
}
- } else if ((toktype == KG_TOK_SIGN_MSG) || (toktype == KG_TOK_MIC_MSG)) {
+ } else if (toktype == KG_TOK_SIGN_MSG) {
token = *message_buffer;
plain = token.value;
plainlen = token.length;
@@ -159,81 +204,184 @@ kg_unseal(context, minor_status, context_handle, input_token_buffer,
/* compute the checksum of the message */
- if (signalg == 0) {
+ /* initialize the the cksum and allocate the contents buffer */
+ md5cksum.checksum_type = CKSUMTYPE_RSA_MD5;
+ md5cksum.length = krb5_checksum_size(context, CKSUMTYPE_RSA_MD5);
+ if ((md5cksum.contents = (krb5_octet *) xmalloc(md5cksum.length)) == NULL) {
+ if (sealalg != 0xffff)
+ xfree(plain);
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+
+ switch (signalg) {
+ case 0:
+ case 3:
/* compute the checksum of the message */
- krb5_MD5Init(&md5);
- krb5_MD5Update(&md5, (unsigned char *) ptr-2, 8);
+ /* 8 = bytes of token body to be checksummed according to spec */
+
+ if (! (data_ptr = (void *)
+ xmalloc(8 + (ctx->big_endian ? token.length : plainlen)))) {
+ xfree(md5cksum.contents);
+ 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)
- krb5_MD5Update(&md5, token.value, token.length);
+ (void) memcpy(data_ptr+8, token.value, token.length);
else
- krb5_MD5Update(&md5, plain, plainlen);
- krb5_MD5Final(&md5);
-
- if (sealalg == 0)
- xfree(plain);
+ (void) memcpy(data_ptr+8, plain, plainlen);
+
+ code = krb5_calculate_checksum(context, md5cksum.checksum_type,
+ data_ptr, 8 +
+ (ctx->big_endian ? token.length :
+ plainlen), 0, 0, &md5cksum);
+ xfree(data_ptr);
+
+ if (code) {
+ xfree(md5cksum.contents);
+ if (toktype == KG_TOK_SEAL_MSG)
+ xfree(token.value);
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+#if 0
/* XXX this depends on the key being a single-des key, but that's
all that kerberos supports right now */
- desmac.length = sizeof(cbc_checksum);
- desmac.contents = cbc_checksum;
- if (code = krb5_calculate_checksum(context, CKSUMTYPE_DESCBC, md5.digest,
- 16, ctx->seq.key->contents,
+
+ /* initialize the the cksum and allocate the contents buffer */
+ cksum.checksum_type = CKSUMTYPE_DESCBC;
+ cksum.length = krb5_checksum_size(context, CKSUMTYPE_DESCBC);
+ if ((cksum.contents = (krb5_octet *) xmalloc(cksum.length)) == NULL) {
+ xfree(md5cksum.contents);
+ if (toktype == KG_TOK_SEAL_MSG)
+ xfree(token.value);
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+
+ if (code = krb5_calculate_checksum(context, cksum.checksum_type,
+ md5cksum.contents, 16,
+ ctx->seq.key->contents,
ctx->seq.key->length,
- &desmac)) {
- if ((toktype == KG_TOK_SEAL_MSG) || (toktype == KG_TOK_WRAP_MSG))
+ &cksum)) {
+ xfree(cksum.contents);
+ xfree(md5cksum.contents);
+ if (toktype == KG_TOK_SEAL_MSG)
xfree(token.value);
*minor_status = code;
return(GSS_S_FAILURE);
}
- cksum = desmac.contents;
- } else {
- if (! ctx->seed_init) {
- if (code = kg_make_seed(ctx->subkey, ctx->seed)) {
- if (sealalg == 0)
+ code = memcmp(cksum.contents, ptr+14, cksum.length);
+
+ xfree(cksum.contents);
+#else
+ if (code = kg_encrypt(context, &ctx->seq,
+ (g_OID_equal(ctx->mech_used, gss_mech_krb5_old) ?
+ ctx->seq.key->contents : NULL),
+ md5cksum.contents, md5cksum.contents, 16)) {
+ xfree(md5cksum.contents);
+ 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);
+#endif
+ break;
+
+ case 1:
+ if (!ctx->seed_init &&
+ (code = kg_make_seed(context, ctx->subkey, ctx->seed))) {
+ xfree(md5cksum.contents);
+ if (sealalg != 0xffff)
xfree(plain);
- if ((toktype == KG_TOK_SEAL_MSG) || (toktype == KG_TOK_WRAP_MSG))
+ if (toktype == KG_TOK_SEAL_MSG)
xfree(token.value);
- *minor_status = code;
- return(GSS_S_FAILURE);
- }
- ctx->seed_init = 1;
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ if (! (data_ptr = (void *)
+ xmalloc(sizeof(ctx->seed) + 8 +
+ (ctx->big_endian ? token.length : plainlen)))) {
+ xfree(md5cksum.contents);
+ if (sealalg == 0)
+ xfree(plain);
+ if (toktype == KG_TOK_SEAL_MSG)
+ xfree(token.value);
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
}
-
- krb5_MD5Init(&md5);
- krb5_MD5Update(&md5, ctx->seed, sizeof(ctx->seed));
- krb5_MD5Update(&md5, (unsigned char *) ptr-2, 8);
+ (void) memcpy(data_ptr, ptr-2, 8);
+ (void) memcpy(data_ptr+8, ctx->seed, sizeof(ctx->seed));
if (ctx->big_endian)
- krb5_MD5Update(&md5, token.value, token.length);
+ (void) memcpy(data_ptr+8+sizeof(ctx->seed),
+ token.value, token.length);
else
- krb5_MD5Update(&md5, plain, plainlen);
- krb5_MD5Final(&md5);
+ (void) memcpy(data_ptr+8+sizeof(ctx->seed),
+ plain, plainlen);
+ code = krb5_calculate_checksum(context, md5cksum.checksum_type,
+ data_ptr, 8 + sizeof(ctx->seed) +
+ (ctx->big_endian ? token.length :
+ plainlen), 0, 0, &md5cksum);
+
+ xfree(data_ptr);
+
+ if (code) {
+ xfree(md5cksum.contents);
+ if (sealalg == 0)
+ xfree(plain);
+ if (toktype == KG_TOK_SEAL_MSG)
+ xfree(token.value);
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
- if (sealalg == 0)
- xfree(plain);
+ code = memcmp(md5cksum.contents, ptr+14, 8);
- cksum = md5.digest;
+ default:
+ *minor_status = 0;
+ return(GSS_S_DEFECTIVE_TOKEN);
}
-
+
+ xfree(md5cksum.contents);
+ if (sealalg != 0xffff)
+ xfree(plain);
+
/* compare the computed checksum against the transmitted checksum */
- if (memcmp(cksum, ptr+14, 8) != 0) {
- if ((toktype == KG_TOK_SEAL_MSG) || (toktype == KG_TOK_WRAP_MSG))
+ if (code) {
+ if (toktype == KG_TOK_SEAL_MSG)
xfree(token.value);
*minor_status = 0;
return(GSS_S_BAD_SIG);
}
+
- /* XXX this is where the seq_num check would go */
-
/* it got through unscathed. Make sure the context is unexpired */
- if ((toktype == KG_TOK_SEAL_MSG) || (toktype = KG_TOK_WRAP_MSG))
+ if (toktype == KG_TOK_SEAL_MSG)
*message_buffer = token;
if (conf_state)
- *conf_state = (sealalg == 0);
+ *conf_state = (sealalg != 0xffff);
if (qop_state)
*qop_state = GSS_C_QOP_DEFAULT;
@@ -248,8 +396,28 @@ kg_unseal(context, minor_status, context_handle, input_token_buffer,
return(GSS_S_CONTEXT_EXPIRED);
}
- /* success */
+ /* do sequencing checks */
+
+ if (code = kg_get_seq_num(context, &(ctx->seq), ptr+14, ptr+6, &direction,
+ &seqnum)) {
+ if (toktype == KG_TOK_SEAL_MSG)
+ xfree(token.value);
+ *minor_status = code;
+ return(GSS_S_BAD_SIG);
+ }
+
+ 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(GSS_S_COMPLETE);
+ return(retval);
}
diff --git a/src/lib/gssapi/krb5/krb5_gss_glue.c b/src/lib/gssapi/krb5/krb5_gss_glue.c
new file mode 100644
index 0000000000..f22e9d6337
--- /dev/null
+++ b/src/lib/gssapi/krb5/krb5_gss_glue.c
@@ -0,0 +1,538 @@
+/*
+ * 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 INTERFACE
+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;
+{
+ 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));
+}
+
+OM_uint32 INTERFACE
+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;
+{
+ return(krb5_gss_acquire_cred(minor_status,
+ desired_name,
+ time_req,
+ desired_mechs,
+ cred_usage,
+ output_cred_handle,
+ actual_mechs,
+ time_rec));
+}
+
+/* V2 */
+OM_uint32 INTERFACE
+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;
+{
+ 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));
+}
+
+/* V2 */
+OM_uint32 INTERFACE
+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 INTERFACE
+gss_compare_name(minor_status, name1, name2, name_equal)
+ 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));
+}
+
+OM_uint32 INTERFACE
+gss_context_time(minor_status, context_handle, time_rec)
+ 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));
+}
+
+/* V2 */
+OM_uint32 INTERFACE
+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 INTERFACE
+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;
+{
+ return(krb5_gss_delete_sec_context(minor_status,
+ context_handle, output_token));
+}
+
+OM_uint32 INTERFACE
+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;
+{
+ return(krb5_gss_display_name(minor_status, input_name,
+ output_name_buffer, output_name_type));
+}
+
+OM_uint32 INTERFACE
+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;
+{
+ return(krb5_gss_display_status(minor_status, status_value,
+ status_type, mech_type, message_context,
+ status_string));
+}
+
+/* V2 */
+OM_uint32 INTERFACE
+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;
+{
+ return(krb5_gss_export_sec_context(minor_status,
+ context_handle,
+ interprocess_token));
+}
+
+/* V2 */
+OM_uint32 INTERFACE
+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(krb5_gss_get_mic(minor_status, context_handle,
+ qop_req, message_buffer, message_token));
+}
+
+OM_uint32 INTERFACE
+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;
+{
+ return(krb5_gss_import_name(minor_status, input_name_buffer,
+ input_name_type, output_name));
+}
+
+/* V2 */
+OM_uint32 INTERFACE
+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;
+{
+ return(krb5_gss_import_sec_context(minor_status,
+ interprocess_token,
+ context_handle));
+}
+
+OM_uint32 INTERFACE
+gss_indicate_mechs(minor_status, mech_set)
+ OM_uint32 *minor_status;
+ gss_OID_set *mech_set;
+{
+ return(krb5_gss_indicate_mechs(minor_status, mech_set));
+}
+
+OM_uint32 INTERFACE
+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;
+{
+ 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));
+}
+
+OM_uint32 INTERFACE
+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;
+{
+ return(krb5_gss_inquire_context(minor_status, context_handle,
+ initiator_name, acceptor_name, lifetime_rec,
+ mech_type, ret_flags, locally_initiated,
+ open));
+}
+
+OM_uint32 INTERFACE
+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;
+{
+ return(krb5_gss_inquire_cred(minor_status, cred_handle,
+ name, lifetime_ret, cred_usage, mechanisms));
+}
+
+/* V2 */
+OM_uint32 INTERFACE
+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;
+{
+ return(krb5_gss_inquire_cred_by_mech(minor_status, cred_handle,
+ mech_type, name, initiator_lifetime,
+ acceptor_lifetime, cred_usage));
+}
+
+/* V2 */
+OM_uint32 INTERFACE
+gss_inquire_names_for_mech(minor_status, mechanism, name_types)
+ OM_uint32 *minor_status;
+ gss_OID mechanism;
+ gss_OID_set *name_types;
+{
+ return(krb5_gss_inquire_names_for_mech(minor_status,
+ mechanism,
+ name_types));
+}
+
+/* V2 */
+OM_uint32 INTERFACE
+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 INTERFACE
+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;
+{
+ return(krb5_gss_process_context_token(minor_status,
+ context_handle, token_buffer));
+}
+
+OM_uint32 INTERFACE
+gss_release_cred(minor_status, cred_handle)
+ OM_uint32 *minor_status;
+ gss_cred_id_t *cred_handle;
+{
+ return(krb5_gss_release_cred(minor_status, cred_handle));
+}
+
+OM_uint32 INTERFACE
+gss_release_name(minor_status, input_name)
+ OM_uint32 *minor_status;
+ gss_name_t *input_name;
+{
+ return(krb5_gss_release_name(minor_status, input_name));
+}
+
+OM_uint32 INTERFACE
+gss_release_buffer(minor_status, buffer)
+ OM_uint32 *minor_status;
+ gss_buffer_t buffer;
+{
+ return(generic_gss_release_buffer(minor_status,
+ buffer));
+}
+
+#if 0
+/* V2 */
+OM_uint32 INTERFACE
+gss_release_oid(minor_status, oid)
+ OM_uint32 *minor_status;
+ gss_OID *oid;
+{
+ return(krb5_gss_release_oid(minor_status, oid));
+}
+#endif
+
+OM_uint32 INTERFACE
+gss_release_oid_set(minor_status, set)
+ OM_uint32* minor_status;
+ gss_OID_set *set;
+{
+ return(generic_gss_release_oid_set(minor_status, set));
+}
+
+/* V1 only */
+OM_uint32 INTERFACE
+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(krb5_gss_seal(minor_status, context_handle,
+ conf_req_flag, qop_req, input_message_buffer,
+ conf_state, output_message_buffer));
+}
+
+OM_uint32 INTERFACE
+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(krb5_gss_sign(minor_status, context_handle,
+ qop_req, message_buffer, message_token));
+}
+
+/* V2 */
+OM_uint32 INTERFACE
+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(krb5_gss_verify_mic(minor_status, context_handle,
+ message_buffer, token_buffer, qop_state));
+}
+
+/* V2 */
+OM_uint32 INTERFACE
+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(krb5_gss_wrap(minor_status, context_handle, conf_req_flag, qop_req,
+ input_message_buffer, conf_state,
+ output_message_buffer));
+}
+
+/* V2 */
+OM_uint32 INTERFACE
+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));
+}
+
+/* V2 */
+OM_uint32 INTERFACE
+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));
+}
+
+/* V1 only */
+OM_uint32 INTERFACE
+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(krb5_gss_unseal(minor_status, context_handle,
+ input_message_buffer, output_message_buffer,
+ conf_state, qop_state));
+}
+
+/* V2 */
+OM_uint32 INTERFACE
+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;
+{
+ return(krb5_gss_unwrap(minor_status, context_handle, input_message_buffer,
+ output_message_buffer, conf_state, qop_state));
+}
+
+/* V1 only */
+OM_uint32 INTERFACE
+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(krb5_gss_verify(minor_status,
+ context_handle,
+ message_buffer,
+ token_buffer,
+ qop_state));
+}
+
+/* V2 interface */
+OM_uint32 INTERFACE
+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;
+{
+ return(krb5_gss_wrap_size_limit(minor_status, context_handle,
+ conf_req_flag, qop_req,
+ req_output_size, max_input_size));
+}
diff --git a/src/lib/gssapi/krb5/process_context_token.c b/src/lib/gssapi/krb5/process_context_token.c
index 80affbd271..4639108d51 100644
--- a/src/lib/gssapi/krb5/process_context_token.c
+++ b/src/lib/gssapi/krb5/process_context_token.c
@@ -22,18 +22,24 @@
#include "gssapiP_krb5.h"
+/*
+ * $Id$
+ */
+
OM_uint32
-krb5_gss_process_context_token(ct, minor_status, context_handle,
+krb5_gss_process_context_token(minor_status, context_handle,
token_buffer)
- void *ct;
OM_uint32 *minor_status;
gss_ctx_id_t context_handle;
gss_buffer_t token_buffer;
{
- krb5_context context = ct;
+ krb5_context context;
krb5_gss_ctx_id_rec *ctx;
OM_uint32 majerr;
+ if (GSS_ERROR(kg_get_context(minor_status, &context)))
+ return(GSS_S_FAILURE);
+
/* validate the context handle */
if (! kg_validate_ctx_id(context_handle)) {
*minor_status = (OM_uint32) G_VALIDATE_FAILED;
@@ -56,6 +62,6 @@ krb5_gss_process_context_token(ct, minor_status, context_handle,
/* that's it. delete the context */
- return(krb5_gss_delete_sec_context(context, minor_status, &context_handle,
+ return(krb5_gss_delete_sec_context(minor_status, &context_handle,
GSS_C_NO_BUFFER));
}
diff --git a/src/lib/gssapi/krb5/rel_cred.c b/src/lib/gssapi/krb5/rel_cred.c
index 297699fe18..df301987b7 100644
--- a/src/lib/gssapi/krb5/rel_cred.c
+++ b/src/lib/gssapi/krb5/rel_cred.c
@@ -23,15 +23,17 @@
#include "gssapiP_krb5.h"
OM_uint32
-krb5_gss_release_cred(ctx, minor_status, cred_handle)
- void *ctx;
+krb5_gss_release_cred(minor_status, cred_handle)
OM_uint32 *minor_status;
gss_cred_id_t *cred_handle;
{
- krb5_context context = ctx;
+ krb5_context context;
krb5_gss_cred_id_t cred;
krb5_error_code code1, code2;
+ if (GSS_ERROR(kg_get_context(minor_status, &context)))
+ return(GSS_S_FAILURE);
+
if (*cred_handle == GSS_C_NO_CREDENTIAL)
return(kg_release_defcred(minor_status));
diff --git a/src/lib/gssapi/krb5/rel_name.c b/src/lib/gssapi/krb5/rel_name.c
index 40ff0d2d31..56f56d060d 100644
--- a/src/lib/gssapi/krb5/rel_name.c
+++ b/src/lib/gssapi/krb5/rel_name.c
@@ -23,13 +23,15 @@
#include "gssapiP_krb5.h"
OM_uint32
-krb5_gss_release_name(ctx, minor_status, input_name)
- void *ctx;
+krb5_gss_release_name(minor_status, input_name)
OM_uint32 *minor_status;
gss_name_t *input_name;
{
- krb5_context context = ctx;
+ krb5_context context;
+ if (GSS_ERROR(kg_get_context(minor_status, &context)))
+ return(GSS_S_FAILURE);
+
if (! kg_validate_name(*input_name)) {
*minor_status = (OM_uint32) G_VALIDATE_FAILED;
return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME);
diff --git a/src/lib/gssapi/krb5/rel_oid.c b/src/lib/gssapi/krb5/rel_oid.c
index 32e697acef..d5ec7bcc72 100644
--- a/src/lib/gssapi/krb5/rel_oid.c
+++ b/src/lib/gssapi/krb5/rel_oid.c
@@ -73,6 +73,7 @@ krb5_gss_internal_release_oid(ct, minor_status, oid)
*/
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 */
diff --git a/src/lib/gssapi/krb5/seal.c b/src/lib/gssapi/krb5/seal.c
index ca52a60af2..818de191f2 100644
--- a/src/lib/gssapi/krb5/seal.c
+++ b/src/lib/gssapi/krb5/seal.c
@@ -22,11 +22,14 @@
#include "gssapiP_krb5.h"
+/*
+ * $Id$
+ */
+
OM_uint32
-krb5_gss_seal(ctx, minor_status, context_handle, conf_req_flag,
+krb5_gss_seal(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;
@@ -35,7 +38,11 @@ krb5_gss_seal(ctx, minor_status, context_handle, conf_req_flag,
int *conf_state;
gss_buffer_t output_message_buffer;
{
- krb5_context context = ctx;
+ krb5_context context;
+
+ if (GSS_ERROR(kg_get_context(minor_status, &context)))
+ return(GSS_S_FAILURE);
+
return(kg_seal(context, minor_status, context_handle, conf_req_flag,
qop_req, input_message_buffer, conf_state,
output_message_buffer, KG_TOK_SEAL_MSG));
@@ -43,10 +50,9 @@ krb5_gss_seal(ctx, minor_status, context_handle, conf_req_flag,
/* V2 interface */
OM_uint32
-krb5_gss_wrap(ctx, minor_status, context_handle, conf_req_flag,
+krb5_gss_wrap(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;
@@ -55,28 +61,13 @@ krb5_gss_wrap(ctx, minor_status, context_handle, conf_req_flag,
int *conf_state;
gss_buffer_t output_message_buffer;
{
- krb5_context context = ctx;
+ krb5_context context;
+ if (GSS_ERROR(kg_get_context(minor_status, &context)))
+ return(GSS_S_FAILURE);
+
return(kg_seal(context, minor_status, context_handle, conf_req_flag,
(int) qop_req, input_message_buffer, conf_state,
output_message_buffer, KG_TOK_WRAP_MSG));
}
-/* V2 interface */
-OM_uint32
-krb5_gss_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;
-{
- krb5_context context = ctx;
-
- /* XXX - should just put this in k5seal.c */
- return(kg_seal_size(context, minor_status, context_handle, conf_req_flag,
- qop_req, req_output_size, max_input_size));
-}
diff --git a/src/lib/gssapi/krb5/ser_sctx.c b/src/lib/gssapi/krb5/ser_sctx.c
index 5acfd5c678..2a8cd0dd03 100644
--- a/src/lib/gssapi/krb5/ser_sctx.c
+++ b/src/lib/gssapi/krb5/ser_sctx.c
@@ -28,264 +28,17 @@
#include "gssapiP_krb5.h"
/*
- * This module contains routines to [de]serialize krb5_gss_cred_id_t,
+ * 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
*/
-
-/* Windows needs these prototypes since the structure they're assigned
- * into is prototyped.
- */
-static krb5_error_code kg_cred_size
- PROTOTYPE((krb5_context kcontext,
- krb5_pointer arg,
- size_t *sizep));
-
-static krb5_error_code kg_cred_externalize
- PROTOTYPE((krb5_context kcontext,
- krb5_pointer arg,
- krb5_octet **buffer,
- size_t *lenremain));
-
-static krb5_error_code kg_cred_internalize
- PROTOTYPE((krb5_context kcontext,
- krb5_pointer *argp,
- krb5_octet **buffer,
- size_t *lenremain));
-
-static krb5_error_code kg_enc_desc_size
- PROTOTYPE((krb5_context kcontext,
- krb5_pointer arg,
- size_t *sizep));
-
-static krb5_error_code kg_enc_desc_externalize
- PROTOTYPE((krb5_context kcontext,
- krb5_pointer arg,
- krb5_octet **buffer,
- size_t *lenremain));
-
-static krb5_error_code kg_enc_desc_internalize
- PROTOTYPE((krb5_context kcontext,
- krb5_pointer *argp,
- krb5_octet **buffer,
- size_t *lenremain));
-
-static krb5_error_code kg_ctx_size
- PROTOTYPE((krb5_context kcontext,
- krb5_pointer arg,
- size_t *sizep));
-
-static krb5_error_code kg_ctx_externalize
- PROTOTYPE((krb5_context kcontext,
- krb5_pointer arg,
- krb5_octet **buffer,
- size_t *lenremain));
-
-static krb5_error_code kg_ctx_internalize
- PROTOTYPE((krb5_context kcontext,
- krb5_pointer *argp,
- krb5_octet **buffer,
- size_t *lenremain));
-
-/*
- * Determine the size required for this krb5_gss_cred_id_t.
- */
-static krb5_error_code
-kg_cred_size(kcontext, arg, sizep)
- krb5_context kcontext;
- krb5_pointer arg;
- size_t *sizep;
-{
- krb5_error_code kret;
- krb5_gss_cred_id_t cred;
- size_t required;
-
- /*
- * krb5_gss_cred_id_t requires:
- * krb5_int32 for KG_CRED
- * krb5_int32 for usage.
- * krb5_int32 for tgt_expire.
- * krb5_int32 for trailer.
- */
- kret = EINVAL;
- if ((cred = (krb5_gss_cred_id_t) arg)) {
- required = 4*sizeof(krb5_int32);
- kret = 0;
- if (cred->princ)
- kret = krb5_size_opaque(kcontext,
- KV5M_PRINCIPAL,
- (krb5_pointer) cred->princ,
- &required);
- if (!kret && cred->keytab)
- kret = krb5_size_opaque(kcontext,
- KV5M_KEYTAB,
- (krb5_pointer) cred->keytab,
- &required);
-
- if (!kret && cred->ccache)
- kret = krb5_size_opaque(kcontext,
- KV5M_CCACHE,
- (krb5_pointer) cred->ccache,
- &required);
- if (!kret)
- *sizep += required;
- }
- return(kret);
-}
-
-/*
- * Externalize this krb5_gss_cred_id_t.
- */
-static krb5_error_code
-kg_cred_externalize(kcontext, arg, buffer, lenremain)
- krb5_context kcontext;
- krb5_pointer arg;
- krb5_octet **buffer;
- size_t *lenremain;
-{
- krb5_error_code kret;
- krb5_gss_cred_id_t cred;
- size_t required;
- krb5_octet *bp;
- size_t remain;
-
- required = 0;
- bp = *buffer;
- remain = *lenremain;
- kret = EINVAL;
- if ((cred = (krb5_gss_cred_id_t) arg)) {
- kret = ENOMEM;
- if (!kg_cred_size(kcontext, arg, &required) &&
- (required <= remain)) {
- /* Our identifier */
- (void) krb5_ser_pack_int32(KG_CRED, &bp, &remain);
-
- /* Now static data */
- (void) krb5_ser_pack_int32((krb5_int32) cred->usage, &bp, &remain);
- (void) krb5_ser_pack_int32((krb5_int32) cred->tgt_expire,
- &bp, &remain);
-
- /* Now pack up dynamic data */
- if (cred->princ)
- kret = krb5_externalize_opaque(kcontext,
- KV5M_PRINCIPAL,
- (krb5_pointer) cred->princ,
- &bp, &remain);
- else
- kret = 0;
-
- if (!kret && cred->keytab)
- kret = krb5_externalize_opaque(kcontext,
- KV5M_KEYTAB,
- (krb5_pointer) cred->keytab,
- &bp, &remain);
-
- if (!kret && cred->ccache)
- kret = krb5_externalize_opaque(kcontext,
- KV5M_CCACHE,
- (krb5_pointer) cred->ccache,
- &bp, &remain);
-
- if (!kret) {
- (void) krb5_ser_pack_int32(KG_CRED, &bp, &remain);
- *buffer = bp;
- *lenremain = remain;
- }
- }
- }
- return(kret);
-}
-
-/*
- * Internalize this krb5_gss_cred_id_t.
- */
-static krb5_error_code
-kg_cred_internalize(kcontext, argp, buffer, lenremain)
- krb5_context kcontext;
- krb5_pointer *argp;
- krb5_octet **buffer;
- size_t *lenremain;
-{
- krb5_error_code kret;
- krb5_gss_cred_id_t cred;
- 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 == KG_CRED) {
- kret = ENOMEM;
-
- /* Get a cred */
- if ((remain >= (2*sizeof(krb5_int32))) &&
- (cred = (krb5_gss_cred_id_t)
- xmalloc(sizeof(krb5_gss_cred_id_rec)))) {
- memset(cred, 0, sizeof(krb5_gss_cred_id_rec));
-
- /* Get the static data */
- (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
- cred->usage = (int) ibuf;
- (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
- cred->tgt_expire = (krb5_timestamp) ibuf;
-
- /* cred->princ */
- if ((kret = krb5_internalize_opaque(kcontext,
- KV5M_PRINCIPAL,
- (krb5_pointer *) &cred->princ,
- &bp, &remain))) {
- if (kret == EINVAL)
- kret = 0;
- }
-
- /* cred->keytab */
- if (!kret &&
- (kret = krb5_internalize_opaque(kcontext,
- KV5M_KEYTAB,
- (krb5_pointer *) &cred->keytab,
- &bp, &remain))) {
- if (kret == EINVAL)
- kret = 0;
- }
-
- /* cred->ccache */
- if (!kret &&
- (kret = krb5_internalize_opaque(kcontext,
- KV5M_CCACHE,
- (krb5_pointer *) &cred->ccache,
- &bp, &remain))) {
- if (kret == EINVAL)
- kret = 0;
- }
-
- /* trailer */
- if (!kret &&
- !(kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)) &&
- (ibuf == KG_CRED)) {
- *buffer = bp;
- *lenremain = remain;
- *argp = (krb5_pointer) cred;
- }
- else {
- if (!kret && (ibuf != KG_CRED))
- kret = EINVAL;
- if (cred->ccache)
- krb5_cc_close(kcontext, cred->ccache);
- if (cred->keytab)
- krb5_kt_close(kcontext, cred->keytab);
- if (cred->princ)
- krb5_free_principal(kcontext, cred->princ);
- xfree(cred);
- }
- }
- }
- return(kret);
-}
-
/*
* Determine the size required for this krb5_gss_enc_desc.
*/
@@ -332,7 +85,7 @@ kg_enc_desc_size(kcontext, arg, sizep)
}
return(kret);
}
-
+
/*
* Externalize this krb5_gss_enc_desc.
*/
@@ -387,7 +140,7 @@ kg_enc_desc_externalize(kcontext, arg, buffer, lenremain)
}
return(kret);
}
-
+
/*
* Internalize this krb5_gss_enc_desc.
*/
@@ -471,27 +224,88 @@ kg_enc_desc_internalize(kcontext, argp, buffer, lenremain)
}
return(kret);
}
-
+
+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;
+
+ (void) krb5_ser_pack_int32((krb5_int32) oid->length,
+ buffer, lenremain);
+ (void) krb5_ser_pack_bytes((krb5_octet *) oid->elements,
+ oid->length, buffer, lenremain);
+}
+
+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;
+
+ oid = (gss_OID) malloc(sizeof(gss_OID_desc));
+ if (oid == NULL)
+ return ENOMEM;
+ (void) krb5_ser_unpack_int32(&ibuf, buffer, lenremain);
+ oid->length = ibuf;
+ (void) krb5_ser_unpack_bytes((krb5_octet *) oid->elements,
+ oid->length, buffer, lenremain);
+ return 0;
+}
+
+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 = sizeof(krb5_int32);
+ required += oid->length;
+
+ kret = 0;
+
+ *sizep += required;
+ }
+
+ return(kret);
+}
+
/*
- * Determine the size required for this krb5_gss_ctx_id_t.
+ * Determine the size required for this krb5_gss_ctx_id_rec.
*/
-static krb5_error_code
+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_t *ctx;
+ krb5_gss_ctx_id_rec *ctx;
size_t required;
/*
- * krb5_gss_ctx_id_t requires:
+ * krb5_gss_ctx_id_rec requires:
* krb5_int32 for KG_CONTEXT
* krb5_int32 for initiate.
* krb5_int32 for mutual.
* krb5_int32 for seed_init.
* sizeof(seed) for seed
+ * krb5_int32 for signalg.
+ * krb5_int32 for cksum_size.
+ * krb5_int32 for sealalg.
* krb5_int32 for endtime.
* krb5_int32 for flags.
* krb5_int32 for seq_send.
@@ -501,8 +315,8 @@ kg_ctx_size(kcontext, arg, sizep)
* krb5_int32 for trailer.
*/
kret = EINVAL;
- if ((ctx = (krb5_gss_ctx_id_t *) arg)) {
- required = 11*sizeof(krb5_int32);
+ if ((ctx = (krb5_gss_ctx_id_rec *) arg)) {
+ required = 14*sizeof(krb5_int32);
required += sizeof(ctx->seed);
kret = 0;
@@ -525,33 +339,30 @@ kg_ctx_size(kcontext, arg, sizep)
&required);
if (!kret)
- kret = krb5_size_opaque(kcontext,
- KG_ENC_DESC,
+ kret = kg_enc_desc_size(kcontext,
(krb5_pointer) &ctx->enc,
&required);
if (!kret)
- kret = krb5_size_opaque(kcontext,
- KG_ENC_DESC,
+ kret = kg_enc_desc_size(kcontext,
(krb5_pointer) &ctx->seq,
&required);
- if (!kret && ctx->auth_context)
- kret = krb5_size_opaque(kcontext,
- KV5M_AUTH_CONTEXT,
- (krb5_pointer) ctx->auth_context,
- &required);
+ if (!kret)
+ kret = kg_oid_size(kcontext,
+ (krb5_pointer) ctx->mech_used,
+ &required);
if (!kret)
*sizep += required;
}
return(kret);
}
-
+
/*
- * Externalize this krb5_gss_ctx_id_t.
+ * Externalize this krb5_gss_ctx_id_ret.
*/
-static krb5_error_code
+krb5_error_code
kg_ctx_externalize(kcontext, arg, buffer, lenremain)
krb5_context kcontext;
krb5_pointer arg;
@@ -559,7 +370,7 @@ kg_ctx_externalize(kcontext, arg, buffer, lenremain)
size_t *lenremain;
{
krb5_error_code kret;
- krb5_gss_ctx_id_t *ctx;
+ krb5_gss_ctx_id_rec *ctx;
size_t required;
krb5_octet *bp;
size_t remain;
@@ -568,7 +379,7 @@ kg_ctx_externalize(kcontext, arg, buffer, lenremain)
bp = *buffer;
remain = *lenremain;
kret = EINVAL;
- if ((ctx = (krb5_gss_ctx_id_t *) arg)) {
+ if ((ctx = (krb5_gss_ctx_id_rec *) arg)) {
kret = ENOMEM;
if (!kg_ctx_size(kcontext, arg, &required) &&
(required <= remain)) {
@@ -585,6 +396,12 @@ kg_ctx_externalize(kcontext, arg, buffer, lenremain)
(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->flags,
@@ -601,6 +418,10 @@ kg_ctx_externalize(kcontext, arg, buffer, lenremain)
/* 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,
@@ -620,23 +441,15 @@ kg_ctx_externalize(kcontext, arg, buffer, lenremain)
&bp, &remain);
if (!kret)
- kret = krb5_externalize_opaque(kcontext,
- KG_ENC_DESC,
+ kret = kg_enc_desc_externalize(kcontext,
(krb5_pointer) &ctx->enc,
&bp, &remain);
if (!kret)
- kret = krb5_externalize_opaque(kcontext,
- KG_ENC_DESC,
+ kret = kg_enc_desc_externalize(kcontext,
(krb5_pointer) &ctx->seq,
&bp, &remain);
- if (!kret && ctx->auth_context)
- kret = krb5_externalize_opaque(kcontext,
- KV5M_AUTH_CONTEXT,
- (krb5_pointer)ctx->auth_context,
- &bp, &remain);
-
if (!kret) {
(void) krb5_ser_pack_int32(KG_CONTEXT, &bp, &remain);
*buffer = bp;
@@ -646,11 +459,11 @@ kg_ctx_externalize(kcontext, arg, buffer, lenremain)
}
return(kret);
}
-
+
/*
* Internalize this krb5_gss_ctx_id_t.
*/
-static krb5_error_code
+krb5_error_code
kg_ctx_internalize(kcontext, argp, buffer, lenremain)
krb5_context kcontext;
krb5_pointer *argp;
@@ -658,7 +471,7 @@ kg_ctx_internalize(kcontext, argp, buffer, lenremain)
size_t *lenremain;
{
krb5_error_code kret;
- krb5_gss_ctx_id_t *ctx;
+ krb5_gss_ctx_id_rec *ctx;
krb5_int32 ibuf;
krb5_octet *bp;
size_t remain;
@@ -675,9 +488,9 @@ kg_ctx_internalize(kcontext, argp, buffer, lenremain)
/* Get a context */
if ((remain >= ((10*sizeof(krb5_int32))+sizeof(ctx->seed))) &&
- (ctx = (krb5_gss_ctx_id_t *)
- xmalloc(sizeof(krb5_gss_ctx_id_t)))) {
- memset(ctx, 0, sizeof(krb5_gss_ctx_id_t));
+ (ctx = (krb5_gss_ctx_id_rec *)
+ xmalloc(sizeof(krb5_gss_ctx_id_rec)))) {
+ memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
/* Get static data */
(void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
@@ -690,9 +503,15 @@ kg_ctx_internalize(kcontext, argp, buffer, lenremain)
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->flags = (krb5_timestamp) ibuf;
+ ctx->flags = (krb5_flags) ibuf;
(void) krb5_ser_unpack_int32(&ctx->seq_send, &bp, &remain);
(void) krb5_ser_unpack_int32(&ctx->seq_recv, &bp, &remain);
(void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
@@ -700,6 +519,11 @@ kg_ctx_internalize(kcontext, argp, buffer, lenremain)
(void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
ctx->big_endian = (int) ibuf;
+ 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,
@@ -725,8 +549,7 @@ kg_ctx_internalize(kcontext, argp, buffer, lenremain)
kret = 0;
}
if (!kret) {
- if ((kret = krb5_internalize_opaque(kcontext,
- KG_ENC_DESC,
+ if ((kret = kg_enc_desc_internalize(kcontext,
(krb5_pointer *) &edp,
&bp, &remain))) {
if (kret == EINVAL)
@@ -738,8 +561,7 @@ kg_ctx_internalize(kcontext, argp, buffer, lenremain)
}
}
if (!kret) {
- if ((kret = krb5_internalize_opaque(kcontext,
- KG_ENC_DESC,
+ if ((kret = kg_enc_desc_internalize(kcontext,
(krb5_pointer *) &edp,
&bp, &remain))) {
if (kret == EINVAL)
@@ -750,15 +572,6 @@ kg_ctx_internalize(kcontext, argp, buffer, lenremain)
xfree(edp);
}
}
- if (!kret &&
- (kret = krb5_internalize_opaque(kcontext,
- KV5M_AUTH_CONTEXT,
- (krb5_pointer *)
- &ctx->auth_context,
- &bp, &remain))) {
- if (kret == EINVAL)
- kret = 0;
- }
/* Get trailer */
if (!kret &&
@@ -771,8 +584,6 @@ kg_ctx_internalize(kcontext, argp, buffer, lenremain)
else {
if (!kret && (ibuf != KG_CONTEXT))
kret = EINVAL;
- if (ctx->auth_context)
- krb5_auth_con_free(kcontext, ctx->auth_context);
if (ctx->seq.eblock.key)
krb5_free_keyblock(kcontext, ctx->seq.eblock.key);
if (ctx->seq.eblock.priv && ctx->seq.eblock.priv_size)
@@ -797,36 +608,3 @@ kg_ctx_internalize(kcontext, argp, buffer, lenremain)
}
return(kret);
}
-
-static const krb5_ser_entry kg_cred_ser_entry = {
- KG_CRED, /* Type */
- kg_cred_size, /* Sizer routine */
- kg_cred_externalize, /* Externalize routine */
- kg_cred_internalize /* Internalize routine */
-};
-static const krb5_ser_entry kg_enc_desc_ser_entry = {
- KG_ENC_DESC, /* Type */
- kg_enc_desc_size, /* Sizer routine */
- kg_enc_desc_externalize, /* Externalize routine */
- kg_enc_desc_internalize /* Internalize routine */
-};
-static const krb5_ser_entry kg_ctx_ser_entry = {
- KG_CONTEXT, /* Type */
- kg_ctx_size, /* Sizer routine */
- kg_ctx_externalize, /* Externalize routine */
- kg_ctx_internalize /* Internalize routine */
-};
-
-krb5_error_code
-kg_ser_context_init(kcontext)
- krb5_context kcontext;
-{
- krb5_error_code kret;
-
- kret = krb5_register_serializer(kcontext, &kg_cred_ser_entry);
- if (!kret)
- kret = krb5_register_serializer(kcontext, &kg_enc_desc_ser_entry);
- if (!kret)
- kret = krb5_register_serializer(kcontext, &kg_ctx_ser_entry);
- return(kret);
-}
diff --git a/src/lib/gssapi/krb5/sign.c b/src/lib/gssapi/krb5/sign.c
index c3b6ebf4b4..0177f40d48 100644
--- a/src/lib/gssapi/krb5/sign.c
+++ b/src/lib/gssapi/krb5/sign.c
@@ -22,19 +22,25 @@
#include "gssapiP_krb5.h"
+/*
+ * $Id$
+ */
+
OM_uint32
-krb5_gss_sign(ctx, minor_status, context_handle,
+krb5_gss_sign(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;
{
- krb5_context context = ctx;
+ krb5_context context;
+ if (GSS_ERROR(kg_get_context(minor_status, &context)))
+ return(GSS_S_FAILURE);
+
return(kg_seal(context, minor_status, context_handle, 0,
qop_req, message_buffer, NULL,
message_token, KG_TOK_SIGN_MSG));
@@ -42,17 +48,19 @@ krb5_gss_sign(ctx, minor_status, context_handle,
/* V2 interface */
OM_uint32
-krb5_gss_get_mic(ctx, minor_status, context_handle, qop_req,
+krb5_gss_get_mic(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;
{
- krb5_context context = ctx;
+ krb5_context context;
+ if (GSS_ERROR(kg_get_context(minor_status, &context)))
+ return(GSS_S_FAILURE);
+
return(kg_seal(context, minor_status, context_handle, 0,
(int) qop_req, message_buffer, NULL,
message_token, KG_TOK_MIC_MSG));
diff --git a/src/lib/gssapi/krb5/unseal.c b/src/lib/gssapi/krb5/unseal.c
index da71fa4f4c..546521e1bf 100644
--- a/src/lib/gssapi/krb5/unseal.c
+++ b/src/lib/gssapi/krb5/unseal.c
@@ -22,11 +22,14 @@
#include "gssapiP_krb5.h"
+/*
+ * $Id$
+ */
+
OM_uint32
-krb5_gss_unseal(ctx, minor_status, context_handle,
+krb5_gss_unseal(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;
@@ -34,7 +37,11 @@ krb5_gss_unseal(ctx, minor_status, context_handle,
int *conf_state;
int *qop_state;
{
- krb5_context context = ctx;
+ krb5_context context;
+
+ if (GSS_ERROR(kg_get_context(minor_status, &context)))
+ return(GSS_S_FAILURE);
+
return(kg_unseal(context, minor_status, context_handle,
input_message_buffer, output_message_buffer,
conf_state, qop_state, KG_TOK_SEAL_MSG));
@@ -42,10 +49,9 @@ krb5_gss_unseal(ctx, minor_status, context_handle,
/* V2 interface */
OM_uint32
-krb5_gss_unwrap(ctx, minor_status, context_handle,
+krb5_gss_unwrap(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;
@@ -53,10 +59,13 @@ krb5_gss_unwrap(ctx, minor_status, context_handle,
int *conf_state;
gss_qop_t *qop_state;
{
- krb5_context context = ctx;
+ krb5_context context;
OM_uint32 rstat;
int qstate;
+ if (GSS_ERROR(kg_get_context(minor_status, &context)))
+ return(GSS_S_FAILURE);
+
rstat = kg_unseal(context, minor_status, context_handle,
input_message_buffer, output_message_buffer,
conf_state, &qstate, KG_TOK_WRAP_MSG);
diff --git a/src/lib/gssapi/krb5/util_cksum.c b/src/lib/gssapi/krb5/util_cksum.c
index 0b46d0e5e7..ee3e1aafa0 100644
--- a/src/lib/gssapi/krb5/util_cksum.c
+++ b/src/lib/gssapi/krb5/util_cksum.c
@@ -20,11 +20,16 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
+/*
+ * $Id$
+ */
+
#include "gssapiP_krb5.h"
#include <memory.h>
krb5_error_code
-kg_checksum_channel_bindings(cb, cksum, bigend)
+kg_checksum_channel_bindings(context, cb, cksum, bigend)
+ krb5_context context;
gss_channel_bindings_t cb;
krb5_checksum *cksum;
int bigend;
@@ -33,20 +38,18 @@ kg_checksum_channel_bindings(cb, cksum, bigend)
char *buf, *ptr;
krb5_error_code code;
- if (!kg_context && (code=kg_get_context()))
- return code;
-
+ /* initialize the the cksum and allocate the contents buffer */
+ cksum->checksum_type = CKSUMTYPE_RSA_MD5;
+ cksum->length = krb5_checksum_size(context, CKSUMTYPE_RSA_MD5);
+ if ((cksum->contents = (krb5_octet *) xmalloc(cksum->length)) == NULL) {
+ free(buf);
+ return(ENOMEM);
+ }
+
/* generate a buffer full of zeros if no cb specified */
if (cb == GSS_C_NO_CHANNEL_BINDINGS) {
- /* allocate the cksum contents buffer */
- if ((cksum->contents = (krb5_octet *)
- xmalloc(krb5_checksum_size(context, CKSUMTYPE_RSA_MD5))) == NULL)
- return(ENOMEM);
-
- cksum->checksum_type = CKSUMTYPE_RSA_MD5;
- memset(cksum->contents, '\0',
- (cksum->length = krb5_checksum_size(kg_context, CKSUMTYPE_RSA_MD5)));
+ memset(cksum->contents, '\0', cksum->length);
return(0);
}
@@ -60,13 +63,6 @@ kg_checksum_channel_bindings(cb, cksum, bigend)
if ((buf = (char *) xmalloc(len)) == NULL)
return(ENOMEM);
- /* allocate the cksum contents buffer */
- cksum->length = krb5_checksum_size(context, CKSUMTYPE_RSA_MD5);
- if ((cksum->contents = (krb5_octet *) xmalloc(cksum->length)) == NULL) {
- free(buf);
- return(ENOMEM);
- }
-
/* helper macros. This code currently depends on a long being 32
bits, and htonl dtrt. */
@@ -80,7 +76,7 @@ kg_checksum_channel_bindings(cb, cksum, bigend)
/* checksum the data */
- if (code = krb5_calculate_checksum(kg_context, CKSUMTYPE_RSA_MD5,
+ if (code = krb5_calculate_checksum(context, CKSUMTYPE_RSA_MD5,
buf, len, NULL, 0, cksum)) {
xfree(cksum->contents);
xfree(buf);
diff --git a/src/lib/gssapi/krb5/util_crypt.c b/src/lib/gssapi/krb5/util_crypt.c
index 89028270e3..bf49de41da 100644
--- a/src/lib/gssapi/krb5/util_crypt.c
+++ b/src/lib/gssapi/krb5/util_crypt.c
@@ -23,6 +23,10 @@
#include "gssapiP_krb5.h"
#include <memory.h>
+/*
+ * $Id$
+ */
+
static unsigned char zeros[8] = {0,0,0,0,0,0,0,0};
int
@@ -39,7 +43,7 @@ kg_make_confounder(ed, buf)
krb5_gss_enc_desc *ed;
unsigned char *buf;
{
- return(krb5_random_confounder( ed->eblock.crypto_entry->block_length, buf));
+ return(krb5_random_confounder(ed->eblock.crypto_entry->block_length, buf));
}
int
@@ -51,7 +55,8 @@ kg_encrypt_size(ed, n)
}
krb5_error_code
-kg_encrypt(ed, iv, in, out, length)
+kg_encrypt(context, ed, iv, in, out, length)
+ krb5_context context;
krb5_gss_enc_desc *ed;
krb5_pointer iv;
krb5_pointer in;
@@ -59,18 +64,29 @@ kg_encrypt(ed, iv, in, out, length)
int length;
{
krb5_error_code code;
+ krb5_pointer tmp;
- if (!kg_context && (code=kg_get_context()))
- return code;
-
if (! ed->processed) {
- if (code = krb5_process_key(kg_context, &ed->eblock, ed->key))
+ if (code = krb5_process_key(context, &ed->eblock, ed->key))
return(code);
ed->processed = 1;
}
- if (code = krb5_encrypt(kg_context, in, out, length, &ed->eblock,
- iv?iv:(krb5_pointer)zeros))
+ /* this is lame. the krb5 encryption interfaces no longer allow
+ you to encrypt in place. perhaps this should be fixed, but
+ dealing here is easier for now --marc */
+
+ if ((tmp = (krb5_pointer) xmalloc(length)) == NULL)
+ return(ENOMEM);
+
+ memcpy(tmp, in, length);
+
+ code = krb5_encrypt(context, tmp, out, length, &ed->eblock,
+ iv?iv:(krb5_pointer)zeros);
+
+ xfree(tmp);
+
+ if (code)
return(code);
return(0);
@@ -79,7 +95,8 @@ kg_encrypt(ed, iv, in, out, length)
/* length is the length of the cleartext. */
krb5_error_code
-kg_decrypt(ed, iv, in, out, length)
+kg_decrypt(context, ed, iv, in, out, length)
+ krb5_context context;
krb5_gss_enc_desc *ed;
krb5_pointer iv;
krb5_pointer in;
@@ -90,11 +107,8 @@ kg_decrypt(ed, iv, in, out, length)
int elen;
char *buf;
- if (!kg_context && (code=kg_get_context()))
- return code;
-
if (! ed->processed) {
- if (code = krb5_process_key(kg_context, &ed->eblock, ed->key))
+ if (code = krb5_process_key(context, &ed->eblock, ed->key))
return(code);
ed->processed = 1;
}
@@ -103,7 +117,7 @@ kg_decrypt(ed, iv, in, out, length)
if ((buf = (char *) xmalloc(elen)) == NULL)
return(ENOMEM);
- if (code = krb5_decrypt(kg_context, in, buf, elen, &ed->eblock,
+ if (code = krb5_decrypt(context, in, buf, elen, &ed->eblock,
iv?iv:(krb5_pointer)zeros)) {
xfree(buf);
return(code);
diff --git a/src/lib/gssapi/krb5/util_seed.c b/src/lib/gssapi/krb5/util_seed.c
index ed60922d51..14f3652452 100644
--- a/src/lib/gssapi/krb5/util_seed.c
+++ b/src/lib/gssapi/krb5/util_seed.c
@@ -23,10 +23,15 @@
#include "gssapiP_krb5.h"
#include <memory.h>
+/*
+ * $Id$
+ */
+
static 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(key, seed)
+kg_make_seed(context, key, seed)
+ krb5_context context;
krb5_keyblock *key;
unsigned char *seed;
{
@@ -34,10 +39,7 @@ kg_make_seed(key, seed)
krb5_gss_enc_desc ed;
int i;
- if (!kg_context && (code=kg_get_context()))
- return code;
-
- if (code = krb5_copy_keyblock(kg_context, key, &ed.key))
+ if (code = krb5_copy_keyblock(context, key, &ed.key))
return(code);
/* reverse the key bytes, as per spec */
@@ -45,13 +47,13 @@ kg_make_seed(key, seed)
for (i=0; i<ed.key->length; i++)
ed.key->contents[i] = key->contents[key->length - 1 - i];
- krb5_use_enctype(kg_context, &ed.eblock, ENCTYPE_DES_CBC_RAW);
+ krb5_use_enctype(context, &ed.eblock, ENCTYPE_DES_CBC_RAW);
ed.processed = 0;
- code = kg_encrypt(&ed, NULL, zeros, seed, 16);
+ code = kg_encrypt(context, &ed, NULL, zeros, seed, 16);
- krb5_finish_key(kg_context, &ed.eblock);
- krb5_free_keyblock(kg_context, ed.key);
+ krb5_finish_key(context, &ed.eblock);
+ krb5_free_keyblock(context, ed.key);
return(code);
}
diff --git a/src/lib/gssapi/krb5/util_seqnum.c b/src/lib/gssapi/krb5/util_seqnum.c
index 67bcda6db1..ed9293f778 100644
--- a/src/lib/gssapi/krb5/util_seqnum.c
+++ b/src/lib/gssapi/krb5/util_seqnum.c
@@ -22,8 +22,13 @@
#include "gssapiP_krb5.h"
+/*
+ * $Id$
+ */
+
krb5_error_code
-kg_make_seq_num(ed, direction, seqnum, cksum, buf)
+kg_make_seq_num(context, ed, direction, seqnum, cksum, buf)
+ krb5_context context;
krb5_gss_enc_desc *ed;
int direction;
krb5_int32 seqnum;
@@ -42,5 +47,34 @@ kg_make_seq_num(ed, direction, seqnum, cksum, buf)
plain[6] = direction;
plain[7] = direction;
- return(kg_encrypt(ed, cksum, plain, buf, 8));
+ return(kg_encrypt(context, ed, cksum, plain, buf, 8));
+}
+
+krb5_error_code kg_get_seq_num(context, ed, cksum, buf, direction, seqnum)
+ krb5_context context;
+ krb5_gss_enc_desc *ed;
+ unsigned char *cksum;
+ unsigned char *buf;
+ int *direction;
+ krb5_int32 *seqnum;
+{
+ krb5_error_code code;
+ unsigned char plain[8];
+
+ if (code = kg_decrypt(context, ed, cksum, buf, plain, 8))
+ 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];
+
+ *seqnum = ((plain[0]) |
+ (plain[1]<<8) |
+ (plain[2]<<16) |
+ (plain[3]<<24));
+
+ return(0);
}
diff --git a/src/lib/gssapi/krb5/verify.c b/src/lib/gssapi/krb5/verify.c
index 33ee8fb8c2..0e73056404 100644
--- a/src/lib/gssapi/krb5/verify.c
+++ b/src/lib/gssapi/krb5/verify.c
@@ -22,39 +22,50 @@
#include "gssapiP_krb5.h"
+/*
+ * $Id$
+ */
+
OM_uint32
-krb5_gss_verify(ctx, minor_status, context_handle,
+krb5_gss_verify(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;
{
- krb5_context context = ctx;
- return(kg_unseal(context, minor_status, context_handle,
- token_buffer, message_buffer,
- NULL, qop_state, KG_TOK_SIGN_MSG));
+ krb5_context context;
+
+ if (GSS_ERROR(kg_get_context(minor_status, &context)))
+ return(GSS_S_FAILURE);
+
+
+ return(kg_unseal(context, minor_status, context_handle,
+ token_buffer, message_buffer,
+ NULL, qop_state, KG_TOK_SIGN_MSG));
}
/* V2 interface */
OM_uint32
-krb5_gss_verify_mic(ctx, minor_status, context_handle,
+krb5_gss_verify_mic(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;
{
- krb5_context context = ctx;
+ krb5_context context;
OM_uint32 rstat;
int qstate;
+ if (GSS_ERROR(kg_get_context(minor_status, &context)))
+ return(GSS_S_FAILURE);
+
+
rstat = kg_unseal(context, minor_status, context_handle,
token_buffer, message_buffer,
NULL, &qstate, KG_TOK_MIC_MSG);
diff --git a/src/lib/gssapi/krb5/wrap_size_limit.c b/src/lib/gssapi/krb5/wrap_size_limit.c
new file mode 100644
index 0000000000..8c47d0fa67
--- /dev/null
+++ b/src/lib/gssapi/krb5/wrap_size_limit.c
@@ -0,0 +1,75 @@
+/*
+ * 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$
+ */
+
+/* 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_context context;
+ krb5_gss_ctx_id_rec *ctx;
+ OM_uint32 cfsize;
+ OM_uint32 ohlen;
+
+ if (GSS_ERROR(kg_get_context(minor_status, &context)))
+ return(GSS_S_FAILURE);
+
+ /* 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);
+ }
+
+ /* Calculate the token size and subtract that from the output size */
+ cfsize = (conf_req_flag) ? kg_confounder_size(&ctx->enc) : 0;
+ ohlen = g_token_size((gss_OID) ctx->mech_used,
+ (unsigned int) cfsize + ctx->cksum_size + 14);
+
+ /* Cannot have trailer length that will cause us to pad over our length */
+ *max_input_size = (req_output_size - ohlen) & (~7);
+ *minor_status = 0;
+ return(GSS_S_COMPLETE);
+}
diff --git a/src/lib/gssapi/mechglue/mglueP.h b/src/lib/gssapi/mechglue/mglueP.h
index e82cfbba0a..22b8c5bdb7 100644
--- a/src/lib/gssapi/mechglue/mglueP.h
+++ b/src/lib/gssapi/mechglue/mglueP.h
@@ -74,6 +74,17 @@ typedef struct gss_union_cred_t {
/* define one of these and provide a function to return */
/* it to initialize the GSSAPI library */
+/* ultrix cc doesn't understand prototypes in structures.
+ we could autoconf test for this --marc */
+
+#ifndef NPROTOTYPE
+#if defined(__ultrix) && !defined (__GNUC__)
+#define NPROTOTYPE(x) ()
+#else
+#define NPROTOTYPE(x) PROTOTYPE(x)
+#endif
+#endif
+
/*
* This is the definition of the mechs_array struct, which is used to
* define the mechs array table. This table is used to indirectly
diff --git a/src/lib/kadm/ChangeLog b/src/lib/kadm/ChangeLog
index 6e9e4d64ee..ac07e19810 100644
--- a/src/lib/kadm/ChangeLog
+++ b/src/lib/kadm/ChangeLog
@@ -13,6 +13,11 @@ Tue May 21 20:51:06 1996 Sam Hartman <hartmans@mit.edu>
* Makefile.in (check-unix): Use KRB5_RUN_FLAGS
+Sun May 12 00:46:57 1996 Marc Horowitz <marc@mit.edu>
+
+ * alt_prof.c (krb5_read_realm_params): added "acl_file" variable
+ for the admin server.
+
Wed Mar 13 17:37:00 1996 Ken Raeburn <raeburn@cygnus.com>
* configure.in: Use AC_HEADER_STDARG.
diff --git a/src/lib/kadm/alt_prof.c b/src/lib/kadm/alt_prof.c
index d4512c41c7..9556ac4503 100644
--- a/src/lib/kadm/alt_prof.c
+++ b/src/lib/kadm/alt_prof.c
@@ -305,6 +305,11 @@ krb5_read_realm_params(kcontext, realm, kdcprofile, kdcenv, rparamp)
if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue))
rparams->realm_kdc_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)) {
diff --git a/src/lib/kadm5/ChangeLog b/src/lib/kadm5/ChangeLog
new file mode 100644
index 0000000000..a10d351d16
--- /dev/null
+++ b/src/lib/kadm5/ChangeLog
@@ -0,0 +1,81 @@
+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/src/lib/kadm5/Makefile.in b/src/lib/kadm5/Makefile.in
new file mode 100644
index 0000000000..ef500d3f26
--- /dev/null
+++ b/src/lib/kadm5/Makefile.in
@@ -0,0 +1,165 @@
+CFLAGS = $(CCOPTS) $(DEFS)
+
+##DOSBUILDTOP = ..\..
+##DOSLIBNAME=libkadm5srv.lib
+
+.c.o:
+ $(CC) $(CFLAGS) -c $(srcdir)/$*.c
+@SHARED_RULE@
+
+kadm_err.$(OBJEXT): kadm_err.c
+ $(CC) $(CFLAGS) -c $*.c
+@SHARED_RULE_LOCAL@
+
+adb_err.$(OBJEXT): adb_err.c
+ $(CC) $(CFLAGS) -c $*.c
+@SHARED_RULE_LOCAL@
+
+chpass_util_strings.$(OBJEXT): chpass_util_strings.c
+ $(CC) $(CFLAGS) -c $*.c
+@SHARED_RULE_LOCAL@
+
+kadm_err.c kadm_err.h: $(srcdir)/kadm_err.et
+adb_err.c adb_err.h: $(srcdir)/adb_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) adb_err.c adb_err.h adb_err.o
+ $(RM) chpass_util_strings.c chpass_util_strings.h chpass_util_strings.o
+
+GENSRCS = kadm_err.c \
+ adb_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 \
+
+SRVSRCS = $(GENSRCS) \
+ $(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 \
+ $(srcdir)/adb_policy.c \
+ $(srcdir)/adb_free.c \
+ $(srcdir)/adb_openclose.c
+
+CLNTSRCS = $(GENSRCS) \
+ $(srcdir)/clnt_policy.c \
+ $(srcdir)/client_rpc.c \
+ $(srcdir)/client_principal.c \
+ $(srcdir)/client_init.c \
+ $(srcdir)/clnt_privs.c \
+ $(srcdir)/clnt_chpass_util.c
+
+GENOBJS = kadm_err.$(OBJEXT) \
+ adb_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) \
+
+SRVOBJS = $(GENOBJS) \
+ 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) \
+ adb_policy.$(OBJEXT) \
+ adb_free.$(OBJEXT) \
+ adb_openclose.$(OBJEXT)
+
+CLNTOBJS = $(GENOBJS) @LIBOBJS@ \
+ clnt_policy.$(OBJEXT) \
+ client_rpc.$(OBJEXT) \
+ client_principal.$(OBJEXT) \
+ client_init.$(OBJEXT) \
+ clnt_privs.$(OBJEXT) \
+ clnt_chpass_util.$(OBJEXT)
+
+#
+# Depends on libkdb5, libkrb5, libcrypto, libcom_err, libdyn
+#
+KDB5_VER=@KDB5_SH_VERS@
+KRB5_VER=@KRB5_SH_VERS@
+CRYPTO_VER=@CRYPTO_SH_VERS@
+COMERR_VER=@COMERR_SH_VERS@
+DYN_VER=@DYN_SH_VERS@
+DEPLIBS=$(TOPLIBD)/libkdb5.$(SHEXT).$(KDB5_VER) \
+ $(TOPLIBD)/libkrb5.$(SHEXT).$(KRB5_VER) \
+ $(TOPLIBD)/libcrypto.$(SHEXT).$(CRYPTO_VER) \
+ $(TOPLIBD)/libcom_err.$(SHEXT).$(COMERR_VER) \
+ $(TOPLIBD)/libdyn.$(SHEXT).$(DYN_VER)
+
+SHLIB_LIBS=-lkdb5 -lkrb5 -lcrypto -lcom_err -ldyn
+SHLIB_LDFLAGS= $(LDFLAGS) @SHLIB_RPATH_DIRS@
+SHLIB_LIBDIRS= @SHLIB_LIBDIRS@
+
+all-unix:: shared includes $(OBJS)
+all-mac:: $(OBJS)
+all-windows:: $(OBJS)
+
+# don't think about this very hard. when the build system goes away,
+# so will this.
+LIBDONE = srv/DONE clnt/DONE
+LIB_SUBDIRS=
+shared:
+ -mkdir shared srv clnt
+ ln -s ../shared srv/shared
+ ln -s ../shared clnt/shared
+
+srv/DONE: $(SRVOBJS)
+ $(RM) srv/DONE
+ echo $(SRVOBJS) > srv/DONE
+
+clnt/DONE: $(CLNTOBJS)
+ $(RM) clnt/DONE
+ echo $(CLNTOBJS) > clnt/DONE
+
+check-windows::
+
+clean-unix::
+ $(RM) shared/* srv/* clnt/*
+ -rmdir shared srv clnt
+
+clean-mac::
+clean-windows::
+
+libkadm5srv.a: $(SRVOBJS)
+ $(RM) $@
+ $(ARADD) $@ $(SRVOBJS)
+ $(RANLIB) $@
+
+libkadm5clnt.a: $(CLNTOBJS)
+ $(RM) $@
+ $(ARADD) $@ $(CLNTOBJS)
+ $(RANLIB) $@
+
+install:: libkadm5srv.a libkadm5clnt.a
+ $(INSTALL_DATA) libkadm5srv.a $(DESTDIR)$(KRB5_LIBDIR)/libkadm5srv.a
+ $(RANLIB) $(DESTDIR)$(KRB5_LIBDIR)/libkadm5srv.a
+ $(INSTALL_DATA) libkadm5clnt.a $(DESTDIR)$(KRB5_LIBDIR)/libkadm5clnt.a
+ $(RANLIB) $(DESTDIR)$(KRB5_LIBDIR)/libkadm5clnt.a
+
+clean::
+ $(RM) libkadm5srv.a libkadm5srv.bak DONESRV
+ $(RM) libkadm5clnt.a libkadm5clnt.bak DONECLNT
diff --git a/src/lib/kadm5/Makefile.ov b/src/lib/kadm5/Makefile.ov
new file mode 100644
index 0000000000..6b078f7776
--- /dev/null
+++ b/src/lib/kadm5/Makefile.ov
@@ -0,0 +1,61 @@
+TOP = ../../kadmin
+include $(TOP)/config.mk/template
+
+# All but D_REGEXP_TYPE are needed only for logger.c
+CFLAGS += $(D_REGEXP_TYPE) $(D_HAVE_SYSLOG_H) $(D_HAVE_STDARG_H) \
+ $(D_HAVE_SYSLOG) $(D_HAVE_VSPRINTF) $(D_HAVE_OPENLOG) \
+ $(D_HAVE_CLOSELOG) $(D_HAVE_STRFTIME)
+
+ifdef D_NO_SETENV
+SETENVC = setenv.c
+SETENVO = setenv.o
+endif
+
+SUBDIRS = unit-test
+
+COMMON_SRCS := kadm_err.c adb_err.c chpass_util_strings.c ovsec_glue.c \
+ misc_free.c kadm_rpc_xdr.c chpass_util.c alt_prof.c str_conv.c \
+ logger.c $(SETENVC)
+COMMON_OBJS := kadm_err.o adb_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 $(SETENVO)
+
+SERVER_SRCS := svr_policy.c svr_principal.c server_kdb.c server_misc.c \
+ server_init.c server_dict.c server_acl.c svr_iters.c \
+ svr_chpass_util.c
+SERVER_OBJS := svr_policy.o svr_principal.o server_kdb.o server_misc.o \
+ server_init.o server_dict.o server_acl.o svr_iters.o \
+ svr_chpass_util.o
+DB_SRCS := adb_xdr.c adb_policy.c adb_free.c adb_openclose.c
+DB_OBJS := adb_xdr.o adb_policy.o adb_free.o adb_openclose.o
+
+CLIENT_SRCS := clnt_policy.c client_rpc.c client_principal.c \
+ client_init.c clnt_privs.c clnt_chpass_util.c
+CLIENT_OBJS := clnt_policy.o client_rpc.o client_principal.o \
+ client_init.o clnt_privs.o clnt_chpass_util.o
+
+HDRS := kadm_rpc.h admin.h admin_xdr.h adb.h admin_internal.h \
+ server_internal.h server_acl.h
+HDRS_DIR := kadm5
+ETABLES := chpass_util_strings.et kadm_err.et adb_err.et
+
+SRCS := $(COMMON_SRCS) $(SERVER_SRCS) $(DB_SRCS)
+OBJS := $(COMMON_OBJS) $(SERVER_OBJS) $(DB_OBJS)
+LIB := libkadm5srv.a
+
+expand StageLibrary
+expand Depend
+
+SRCS = $(COMMON_SRCS) $(CLIENT_SRCS)
+OBJS = $(COMMON_OBJS) $(CLIENT_OBJS)
+LIB = libkadm5clnt.a
+
+expand StageLibrary
+expand Depend
+
+expand SubdirTarget
+expand StageIncludes
+expand StageErrorTables
+
+# Not sure if/why this is needed...
+chpass_util.c: chpass_util_strings.h
diff --git a/src/lib/kadm5/adb.h b/src/lib/kadm5/adb.h
new file mode 100644
index 0000000000..b73553575a
--- /dev/null
+++ b/src/lib/kadm5/adb.h
@@ -0,0 +1,141 @@
+/*
+ * Data Types for policys, and principal information that
+ * exist 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 <rpc/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;
+ char *filename;
+ osa_adb_lock_t lock;
+} 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;
+ rpc_u_int32 pw_min_life;
+ rpc_u_int32 pw_max_life;
+ rpc_u_int32 pw_min_length;
+ rpc_u_int32 pw_min_classes;
+ rpc_u_int32 pw_history_num;
+ rpc_u_int32 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);
+
+/*
+ * 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_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/src/lib/kadm5/adb_err.et b/src/lib/kadm5/adb_err.et
new file mode 100644
index 0000000000..3948025719
--- /dev/null
+++ b/src/lib/kadm5/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/src/lib/kadm5/adb_free.c b/src/lib/kadm5/adb_free.c
new file mode 100644
index 0000000000..4c6f8a66de
--- /dev/null
+++ b/src/lib/kadm5/adb_free.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ *
+ * $Log$
+ * Revision 1.8 1996/07/22 20:35:16 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.7.4.1 1996/07/18 03:08:07 marc
+ * merged in changes from OV_9510_BP to OV_9510_FINAL1
+ *
+ * Revision 1.7.2.1 1996/06/20 02:16:25 marc
+ * File added to the repository on a branch
+ *
+ * Revision 1.7 1996/05/12 06:21:57 marc
+ * don't use <absolute paths> for "internal header files"
+ *
+ * Revision 1.6 1993/12/13 21:15:56 shanzer
+ * fixed memory leak
+ * .,
+ *
+ * Revision 1.5 1993/12/06 22:20:37 marc
+ * fixup free functions to use xdr to free the underlying struct
+ *
+ * Revision 1.4 1993/11/15 00:29:46 shanzer
+ * check to make sure pointers are somewhat vaid before freeing.
+ *
+ * Revision 1.3 1993/11/09 04:02:24 shanzer
+ * added some includefiles
+ * changed bzero to memset
+ *
+ * Revision 1.2 1993/11/04 01:54:24 shanzer
+ * added rcs header ..
+ *
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include "adb.h"
+#include <memory.h>
+#include <malloc.h>
+
+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);
+}
+
+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/src/lib/kadm5/adb_openclose.c b/src/lib/kadm5/adb_openclose.c
new file mode 100644
index 0000000000..627a6b4104
--- /dev/null
+++ b/src/lib/kadm5/adb_openclose.c
@@ -0,0 +1,338 @@
+/*
+ * 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 "adb.h"
+#include <stdlib.h>
+
+#define MAX_LOCK_TRIES 5
+
+struct _locklist {
+ osa_adb_lock_ent lockinfo;
+ struct _locklist *next;
+};
+
+osa_adb_ret_t osa_adb_create_db(char *filename, char *lockfilename,
+ int magic)
+{
+ FILE *lf;
+ DB *db;
+ HASHINFO info;
+
+ lf = fopen(lockfilename, "w+");
+ if (lf == NULL)
+ return errno;
+ (void) fclose(lf);
+
+ memset(&info, 0, sizeof(info));
+ info.hash = NULL;
+ info.bsize = 256;
+ info.ffactor = 8;
+ info.nelem = 25000;
+ info.lorder = 0;
+ db = dbopen(filename, O_RDWR | O_CREAT | O_EXCL, 0600, DB_HASH, &info);
+ if (db == NULL)
+ return errno;
+ if (db->close(db) < 0)
+ return errno;
+ return OSA_ADB_OK;
+}
+
+osa_adb_ret_t 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;
+}
+
+osa_adb_ret_t 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;
+
+ /*
+ * 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((osa_adb_ret_t) 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->filename = strdup(filename);
+ db->magic = magic;
+
+ *dbp = db;
+
+ return OSA_ADB_OK;
+}
+
+osa_adb_ret_t 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.
+ */
+ (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;
+}
+
+osa_adb_ret_t osa_adb_get_lock(osa_adb_db_t db, int mode)
+{
+ int tries, gotlock, perm, krb5_mode, ret;
+
+ 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 OSA_ADB_PERMANENT:
+ perm = 1;
+ case OSA_ADB_EXCLUSIVE:
+ krb5_mode = KRB5_LOCKMODE_EXCLUSIVE;
+ break;
+ case OSA_ADB_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 == OSA_ADB_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) {
+ int ret;
+
+ /* 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;
+}
+
+osa_adb_ret_t osa_adb_release_lock(osa_adb_db_t db)
+{
+ int ret;
+
+ if (!db->lock->lockcnt) /* lock already unlocked */
+ return OSA_ADB_NOTLOCKED;
+
+ if (--db->lock->lockcnt == 0) {
+ if (db->lock->lockmode == OSA_ADB_PERMANENT) {
+ /* now we need to create the file since it does not exist */
+ if ((db->lock->lockfile = fopen(db->lock->filename,
+ "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;
+}
+
+osa_adb_ret_t 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;
+
+ db->db = dbopen(db->filename, O_RDWR, 0600, DB_HASH, &db->info);
+ if (db->db == NULL) {
+ (void) osa_adb_release_lock(db);
+ if(errno == EINVAL)
+ return OSA_ADB_BAD_DB;
+ return errno;
+ }
+ return OSA_ADB_OK;
+}
+
+osa_adb_ret_t osa_adb_close_and_unlock(osa_adb_princ_t db)
+{
+ int ret;
+
+ if(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/src/lib/kadm5/adb_policy.c b/src/lib/kadm5/adb_policy.c
new file mode 100644
index 0000000000..ff0117bac8
--- /dev/null
+++ b/src/lib/kadm5/adb_policy.c
@@ -0,0 +1,401 @@
+/*
+ * 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 "adb.h"
+#include <stdlib.h>
+#include <malloc.h>
+#include <string.h>
+
+extern int errno;
+
+#define OPENLOCK(db, mode) \
+{ \
+ int ret; \
+ if (db == NULL) \
+ return EINVAL; \
+ else if (db->magic != OSA_ADB_POLICY_DB_MAGIC) \
+ return OSA_ADB_DBINIT; \
+ else if ((ret = osa_adb_open_and_lock(db, mode)) != OSA_ADB_OK) \
+ return ret; \
+ }
+
+#define CLOSELOCK(db) \
+{ \
+ int ret; \
+ if ((ret = osa_adb_close_and_unlock(db)) != OSA_ADB_OK) \
+ return ret; \
+}
+
+osa_adb_ret_t osa_adb_create_policy_db(kadm5_config_params *params)
+{
+ return osa_adb_create_db(params->admin_dbname,
+ params->admin_lockfile,
+ OSA_ADB_POLICY_DB_MAGIC);
+}
+
+osa_adb_ret_t osa_adb_destroy_policy_db(kadm5_config_params *params)
+{
+ return osa_adb_destroy_db(params->admin_dbname,
+ params->admin_lockfile,
+ OSA_ADB_POLICY_DB_MAGIC);
+}
+
+osa_adb_ret_t osa_adb_open_policy(osa_adb_princ_t *dbp,
+ kadm5_config_params *rparams)
+{
+ return osa_adb_init_db(dbp, rparams->admin_dbname,
+ rparams->admin_lockfile,
+ OSA_ADB_POLICY_DB_MAGIC);
+}
+
+osa_adb_ret_t osa_adb_close_policy(osa_adb_princ_t db)
+{
+ return osa_adb_fini_db(db, OSA_ADB_POLICY_DB_MAGIC);
+}
+
+/*
+ * 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 sucsess, else error code.
+ *
+ * Requires:
+ * entry have a valid name.
+ *
+ * Effects:
+ * creates the entry in the db
+ *
+ * Modifies:
+ * the policy db.
+ *
+ */
+osa_adb_ret_t
+osa_adb_create_policy(osa_adb_policy_t db, osa_policy_ent_t entry)
+{
+ DBT dbkey;
+ DBT dbdata;
+ XDR xdrs;
+ int ret;
+
+ OPENLOCK(db, OSA_ADB_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 sucsess, or error code.
+ *
+ * Requires:
+ * db being valid.
+ * name being non-null.
+ * Effects:
+ * deletes policy from db.
+ *
+ * Modifies:
+ * policy db.
+ *
+ */
+osa_adb_ret_t
+osa_adb_destroy_policy(osa_adb_policy_t db, kadm5_policy_t name)
+{
+ DBT dbkey;
+ int status, ret;
+
+ OPENLOCK(db, OSA_ADB_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
+ * <return value> 0 on sucsess, error code on failure.
+ *
+ * Requires:
+ * Effects:
+ * Modifies:
+ */
+osa_adb_ret_t
+osa_adb_get_policy(osa_adb_policy_t db, kadm5_policy_t name,
+ osa_policy_ent_t *entry)
+{
+ DBT dbkey;
+ DBT dbdata;
+ XDR xdrs;
+ int ret;
+ char *aligned_data;
+
+ OPENLOCK(db, OSA_ADB_SHARED);
+
+ 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 = OSA_ADB_NOENT;
+ 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 sucsess error code on failure.
+ *
+ * Requires:
+ * [requires]
+ *
+ * Effects:
+ * [effects]
+ *
+ * Modifies:
+ * [modifies]
+ *
+ */
+osa_adb_ret_t
+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, OSA_ADB_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 sucsess error code on failure
+ *
+ * Requires:
+ * Effects:
+ * Modifies:
+ */
+osa_adb_ret_t
+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, OSA_ADB_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;
+}
diff --git a/src/lib/kadm5/adb_principal.c b/src/lib/kadm5/adb_principal.c
new file mode 100644
index 0000000000..8ee9aab30c
--- /dev/null
+++ b/src/lib/kadm5/adb_principal.c
@@ -0,0 +1,408 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ *
+ * $Log$
+ * Revision 1.24 1996/07/22 20:35:23 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.23.4.1 1996/07/18 03:08:17 marc
+ * merged in changes from OV_9510_BP to OV_9510_FINAL1
+ *
+ * Revision 1.23.2.1 1996/06/20 02:16:30 marc
+ * File added to the repository on a branch
+ *
+ * Revision 1.23 1996/05/16 21:44:35 bjaspan
+ * this file is no longer used, #if the whole thing out
+ *
+ * Revision 1.22 1996/05/08 20:51:44 bjaspan
+ * marc's changes
+ *
+ * Revision 1.21 1995/08/24 20:23:43 bjaspan
+ * marc is a bonehead
+ *
+ * Revision 1.20 1995/08/23 19:16:02 marc
+ * check for db == NULL in OPENLOCK()
+ *
+ * Revision 1.19 1995/08/08 18:31:30 bjaspan
+ * [secure/3394] first cut at admin db locking support
+ *
+ * Revision 1.18 1995/08/02 15:26:57 bjaspan
+ * check db==NULL in iter
+ *
+ * Revision 1.17 1994/05/09 17:52:36 shanzer
+ * fixed some include files
+ *
+ * Revision 1.16 1994/03/17 01:25:58 shanzer
+ * include fcntl.h
+ *
+ * Revision 1.15 1993/12/17 18:54:06 jik
+ * [secure-admin/1040]
+ *
+ * open_princ should return errno, rather than BAD_DB, if errno is
+ * something other than BAD_DB.
+ *
+ * Revision 1.14 1993/12/13 18:55:58 marc
+ * remove bogus free()'s
+ *
+ * Revision 1.13 1993/12/08 22:29:27 marc
+ * fixed another xdrmem alignment thing]
+ *
+ * Revision 1.12 1993/12/06 22:22:22 bjaspan
+ * fix alignment and free-memory-read bugs
+ *
+ * Revision 1.11 1993/12/05 04:15:16 shanzer
+ * removed data size hack.
+ *
+ * Revision 1.10 1993/11/15 00:29:24 shanzer
+ * added filenme to open
+ *
+ * Revision 1.9 1993/11/10 20:10:06 shanzer
+ * now uses xdralloc instead of xdrmem
+ *
+ * Revision 1.8 1993/11/09 21:43:24 shanzer
+ * added check to see if we overflowed our xdr buffer.
+ *
+ * Revision 1.7 1993/11/09 04:00:19 shanzer
+ * changed bzero to memset
+ *
+ * Revision 1.6 1993/11/05 23:16:21 shanzer
+ * return ENOMEM instead of ovsec_kadm_mem
+ *
+ * Revision 1.5 1993/11/05 22:17:03 shanzer
+ * added principal db interative function
+ *
+ * Revision 1.4 1993/11/04 23:20:24 shanzer
+ * made HASHINFO static.
+ *
+ * Revision 1.3 1993/11/04 01:52:30 shanzer
+ * Restructred some code .. fixed some bugs/leaks
+ *
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#if 0
+/* XXX THIS FILE IS NO LONGER USED, and should be deleted when we're done */
+
+#include <sys/file.h>
+#include <fcntl.h>
+#include "adb.h"
+#include <stdlib.h>
+#include <memory.h>
+
+#define OPENLOCK(db, mode) \
+{ \
+ int ret; \
+ if (db == NULL) \
+ return EINVAL; \
+ else if (db->magic != OSA_ADB_PRINC_DB_MAGIC) \
+ return OSA_ADB_DBINIT; \
+ else if ((ret = osa_adb_open_and_lock(db, mode)) != OSA_ADB_OK) \
+ return ret; \
+ }
+
+#define CLOSELOCK(db) \
+{ \
+ int ret; \
+ if ((ret = osa_adb_close_and_unlock(db)) != OSA_ADB_OK) \
+ return ret; \
+}
+
+osa_adb_ret_t osa_adb_open_princ(osa_adb_princ_t *dbp, char *filename)
+{
+ return osa_adb_init_db(dbp, filename, OSA_ADB_PRINC_DB_MAGIC);
+}
+
+osa_adb_ret_t osa_adb_close_princ(osa_adb_princ_t db)
+{
+ return osa_adb_fini_db(db, OSA_ADB_PRINC_DB_MAGIC);
+}
+
+osa_adb_ret_t
+osa_adb_create_princ(osa_adb_princ_t db, osa_princ_ent_t entry)
+{
+
+ DBT dbkey;
+ DBT dbdata;
+ XDR xdrs;
+ int ret;
+
+ OPENLOCK(db, OSA_ADB_EXCLUSIVE);
+
+ if(krb5_unparse_name(db->lock->context,
+ entry->name, (char **) &dbkey.data)) {
+ ret = OSA_ADB_BAD_PRINC;
+ goto error;
+ }
+ if((dbkey.size = strlen(dbkey.data)) == 0) {
+ ret = OSA_ADB_BAD_PRINC;
+ goto error;
+ }
+
+ switch(db->db->get(db->db, &dbkey, &dbdata, 0)) {
+ case 0:
+ ret = OSA_ADB_DUP;
+ goto error;
+ case 1:
+ break;
+ default:
+ ret = OSA_ADB_FAILURE;
+ goto error;
+ }
+ xdralloc_create(&xdrs, XDR_ENCODE);
+ if(!xdr_osa_princ_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;
+ else
+ ret = OSA_ADB_OK;
+ break;
+ case 1:
+ ret = OSA_ADB_DUP;
+ break;
+ default:
+ ret = OSA_ADB_FAILURE;
+ break;
+ }
+ xdralloc_release(&xdrs);
+ free(dbkey.data);
+
+error:
+ CLOSELOCK(db);
+
+ return ret;
+}
+
+osa_adb_ret_t
+osa_adb_destroy_princ(osa_adb_princ_t db, ovsec_kadm_princ_t name)
+{
+ DBT dbkey;
+ int status;
+ int ret;
+
+ OPENLOCK(db, OSA_ADB_EXCLUSIVE);
+
+ if(krb5_unparse_name(db->lock->context, name, (char **) &dbkey.data)) {
+ ret = OSA_ADB_BAD_PRINC;
+ goto error;
+ }
+ if ((dbkey.size = strlen(dbkey.data)) == 0) {
+ ret = OSA_ADB_BAD_PRINC;
+ goto error;
+ }
+ status = db->db->del(db->db, &dbkey, 0);
+ switch(status) {
+ case 1:
+ ret = OSA_ADB_NOENT;
+ break;
+ case 0:
+ if ((db->db->sync(db->db, 0)) == -1)
+ ret = OSA_ADB_FAILURE;
+ else
+ ret = OSA_ADB_OK;
+ break;
+ default:
+ ret = OSA_ADB_FAILURE;
+ break;
+ }
+ free(dbkey.data);
+
+error:
+ CLOSELOCK(db);
+
+ return ret;
+}
+
+osa_adb_ret_t
+osa_adb_get_princ(osa_adb_princ_t db, ovsec_kadm_princ_t name,
+ osa_princ_ent_t *entry)
+{
+ DBT dbkey;
+ DBT dbdata;
+ XDR xdrs;
+ int ret = 0;
+ char *aligned_data;
+
+ OPENLOCK(db, OSA_ADB_SHARED);
+
+ if(krb5_unparse_name(db->lock->context, name, (char **) &dbkey.data)) {
+ ret = OSA_ADB_BAD_PRINC;
+ goto error;
+ }
+ if((dbkey.size = strlen(dbkey.data)) == 0) {
+ ret = OSA_ADB_BAD_PRINC;
+ goto error;
+ }
+ dbdata.size = 0;
+ dbdata.data = NULL;
+ switch(db->db->get(db->db, &dbkey, &dbdata, 0)) {
+ case 1:
+ ret = OSA_ADB_NOENT;
+ break;
+ case 0:
+ break;
+ default:
+ ret = OSA_ADB_FAILURE;
+ break;
+ }
+ free(dbkey.data);
+ if (ret)
+ goto error;
+
+ if (!(*(entry) = (osa_princ_ent_t)malloc(sizeof(osa_princ_ent_rec)))) {
+ ret = ENOMEM;
+ goto error;
+ }
+
+ aligned_data = (char *) malloc(dbdata.size);
+ if (aligned_data == NULL) {
+ ret = ENOMEM;
+ goto error;
+ }
+ memcpy(aligned_data, dbdata.data, dbdata.size);
+
+ memset(*entry, 0, sizeof(osa_princ_ent_rec));
+ xdrmem_create(&xdrs, aligned_data, dbdata.size, XDR_DECODE);
+ if (!xdr_osa_princ_ent_rec(&xdrs, *entry)) {
+ xdr_destroy(&xdrs);
+ free(aligned_data);
+ ret = OSA_ADB_FAILURE;
+ goto error;
+ }
+ xdr_destroy(&xdrs);
+ free(aligned_data);
+ ret = OSA_ADB_OK;
+
+error:
+ CLOSELOCK(db);
+ return ret;
+}
+
+osa_adb_ret_t
+osa_adb_put_princ(osa_adb_princ_t db, osa_princ_ent_t entry)
+{
+ DBT dbkey;
+ DBT dbdata;
+ DBT tmpdb;
+ XDR xdrs;
+ int ret;
+
+ OPENLOCK(db, OSA_ADB_EXCLUSIVE);
+
+ if(krb5_unparse_name(db->lock->context,
+ entry->name, (char **) &dbkey.data)) {
+ ret = OSA_ADB_BAD_PRINC;
+ goto error;
+ }
+ if((dbkey.size = strlen(dbkey.data)) == 0) {
+ ret = OSA_ADB_BAD_PRINC;
+ goto error;
+ }
+
+ 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_princ_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;
+ else
+ ret = OSA_ADB_OK;
+ break;
+ default:
+ ret = OSA_ADB_FAILURE;
+ break;
+ }
+ xdralloc_release(&xdrs);
+ free(dbkey.data);
+
+error:
+ CLOSELOCK(db);
+ return ret;
+}
+
+osa_adb_ret_t
+osa_adb_iter_princ(osa_adb_princ_t db, osa_adb_iter_princ_func func,
+ void *data)
+{
+ DBT dbkey,
+ dbdata;
+ XDR xdrs;
+ int ret;
+ osa_princ_ent_t entry;
+ char *aligned_data;
+
+ OPENLOCK(db, OSA_ADB_EXCLUSIVE); /* hmmmm */
+
+ if((ret = db->db->seq(db->db, &dbkey, &dbdata, R_FIRST)) == -1) {
+ ret = errno;
+ goto error;
+ }
+ while (ret == 0) {
+ if (!(entry = (osa_princ_ent_t) malloc(sizeof(osa_princ_ent_rec)))) {
+ ret = ENOMEM;
+ goto error;
+ }
+
+ aligned_data = (char *) malloc(dbdata.size);
+ if (aligned_data == NULL) {
+ ret = ENOMEM;
+ goto error;
+ }
+ memcpy(aligned_data, dbdata.data, dbdata.size);
+
+ memset(entry, 0, sizeof(osa_princ_ent_rec));
+ xdrmem_create(&xdrs, aligned_data, dbdata.size, XDR_DECODE);
+ if(!xdr_osa_princ_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_princ_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;
+}
+
+#endif /* 0 */
diff --git a/src/lib/kadm5/adb_xdr.c b/src/lib/kadm5/adb_xdr.c
new file mode 100644
index 0000000000..944fb04b3e
--- /dev/null
+++ b/src/lib/kadm5/adb_xdr.c
@@ -0,0 +1,132 @@
+/*
+ * 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 <rpc/rpc.h>
+#include "adb.h"
+#include "admin_xdr.h"
+#include <memory.h>
+
+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_int16(xdrs, &objp->key_data_length[0]))
+ return(FALSE);
+ if (!xdr_krb5_int16(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);
+}
+
+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/src/lib/kadm5/admin.h b/src/lib/kadm5/admin.h
new file mode 100644
index 0000000000..1e98430dbb
--- /dev/null
+++ b/src/lib/kadm5/admin.h
@@ -0,0 +1,649 @@
+/*
+ * 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 <rpc/rpc.h>
+#include <krb5.h>
+#include <k5-int.h>
+#include <com_err.h>
+#include <kadm5/kadm_err.h>
+#include <kadm5/adb_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 \
+ ((char *) error_message(CHPASS_UTIL_NEW_PASSWORD_PROMPT))
+#define KADM5_PW_SECOND_PROMPT \
+ ((char *) error_message(CHPASS_UTIL_NEW_PASSWORD_AGAIN_PROMPT))
+
+/*
+ * Succsessfull return code
+ */
+#define KADM5_OK 0
+
+/*
+ * XXX This should be in kdb.h; it is here so that I do not have to
+ * change that file yet, but this should be *very* temporary.
+ * --- bjaspan, 5/23/96
+ */
+#define KRB5_TL_KADM5_E_DATA 0x0004
+
+/*
+ * 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
+
+/*
+ * 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;
+
+typedef struct __krb5_key_salt_tuple {
+ krb5_enctype ks_enctype;
+ krb5_int32 ks_salttype;
+} krb5_key_salt_tuple;
+
+/*
+ * Data structure returned by kadm5_get_config_params()
+ */
+typedef struct _kadm5_config_params {
+ long mask;
+ char * realm;
+ char * profile;
+ int kadmind_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_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_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_filler:7;
+ 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_realm_params(krb5_context kcontext,
+ kadm5_config_params *params);
+#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,
+ 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,
+ 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,
+ 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,
+ void **server_handle);
+#endif
+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_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);
+#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);
+#endif
+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);
+
+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
+
+#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))
+
+/*
+ * Succsessfull 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,
+ 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,
+ 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,
+ 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_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/src/lib/kadm5/admin_internal.h b/src/lib/kadm5/admin_internal.h
new file mode 100644
index 0000000000..d73837e679
--- /dev/null
+++ b/src/lib/kadm5/admin_internal.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ */
+
+#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 code; if (code = _kadm5_check_handle((void *)handle)) return code; }
+
+kadm5_ret_t _kadm5_chpass_principal_util(void *server_handle,
+ void *lhandle,
+ krb5_principal princ,
+ char *new_pw,
+ char **ret_pw,
+ char *msg_ret);
+
+/* 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/src/lib/kadm5/admin_xdr.h b/src/lib/kadm5/admin_xdr.h
new file mode 100644
index 0000000000..3e4f48f7ab
--- /dev/null
+++ b/src/lib/kadm5/admin_xdr.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ *
+ * $Log$
+ * Revision 1.5 1996/07/22 20:35:33 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.4.4.1 1996/07/18 03:08:25 marc
+ * merged in changes from OV_9510_BP to OV_9510_FINAL1
+ *
+ * Revision 1.4.2.1 1996/06/20 02:16:37 marc
+ * File added to the repository on a branch
+ *
+ * Revision 1.4 1996/05/30 16:36:34 bjaspan
+ * finish updating to kadm5 naming (oops)
+ *
+ * Revision 1.3 1996/05/22 00:28:19 bjaspan
+ * rename to kadm5
+ *
+ * Revision 1.2 1996/05/12 06:30:10 marc
+ * - fixup includes and data types to match beta6
+ *
+ * Revision 1.1 1993/11/09 04:06:01 shanzer
+ * Initial revision
+ *
+ */
+
+#include <kadm5/admin.h>
+#include "kadm_rpc.h"
+
+bool_t xdr_nullstring(XDR *xdrs, char **objp);
+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_kadm5_ret_t(XDR *xdrs, kadm5_ret_t *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_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_chrand_arg(XDR *xdrs, chrand_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_arg(XDR *xdrs, gprinc_arg *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_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_keyblock(XDR *xdrs, krb5_keyblock *objp);
diff --git a/src/lib/kadm5/alt_prof.c b/src/lib/kadm5/alt_prof.c
new file mode 100644
index 0000000000..2f36f76fa7
--- /dev/null
+++ b/src/lib/kadm5/alt_prof.c
@@ -0,0 +1,861 @@
+/*
+ * lib/kadm/alt_prof.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. M.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 <stdio.h>
+#include <ctype.h>
+
+/*
+ * 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 char *namelist[2];
+ profile_t profile;
+
+ namelist[1] = (char *) NULL;
+ profile = (profile_t) NULL;
+ if (envname) {
+ if ((namelist[0] = getenv(envname))) {
+ if (!(kret = profile_init(namelist, &profile))) {
+ *acontextp = (krb5_pointer) profile;
+ return(0);
+ }
+ }
+ }
+ namelist[0] = fname;
+ profile = (profile_t) NULL;
+ if (!(kret = profile_init(namelist, &profile))) {
+ *acontextp = (krb5_pointer) profile;
+ return(0);
+ }
+ return(kret);
+}
+
+/*
+ * 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_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 index;
+
+ if (!(kret = krb5_aprof_getvals(acontext, hierarchy, &values))) {
+ index = 0;
+ if (uselast) {
+ for (index=0; values[index]; index++);
+ index--;
+ }
+ valp = values[index];
+ kret = krb5_string_to_deltat(valp, deltatp);
+
+ /* Free the string storage */
+ for (index=0; values[index]; index++)
+ krb5_xfree(values[index]);
+ 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 index, i;
+
+ if (!(kret = krb5_aprof_getvals(acontext, hierarchy, &values))) {
+ index = 0;
+ if (uselast) {
+ for (index=0; values[index]; index++);
+ index--;
+ }
+
+ *stringp = values[index];
+
+ /* Free the string storage */
+ for (i=0; values[i]; i++)
+ if (i != index)
+ 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 index;
+
+ if (!(kret = krb5_aprof_getvals(acontext, hierarchy, &values))) {
+ index = 0;
+ if (uselast) {
+ for (index=0; values[index]; index++);
+ index--;
+ }
+
+ if (sscanf(values[index], "%d", intp) != 1)
+ kret = EINVAL;
+
+ /* Free the string storage */
+ for (index=0; values[index]; index++)
+ krb5_xfree(values[index]);
+ 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;
+
+ memset((char *) &params, 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);
+ 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);
+ params.mask |= KADM5_CONFIG_PROFILE;
+ envname = NULL;
+ } else {
+ /* XXX ummm... these defaults should to work on both sides */
+ 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.mask |= KADM5_CONFIG_ADMIN_SERVER;
+ params.admin_server = strdup(params_in->admin_server);
+ } else if (!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;
+ if (p = strchr(params.admin_server, ':')) {
+ 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.mask |= KADM5_CONFIG_DBNAME;
+ params.dbname = strdup(params_in->dbname);
+ } else if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
+ params.dbname = svalue;
+ params.mask |= KADM5_CONFIG_DBNAME;
+ }
+
+ /*
+ * Get the value for the admin (policy) database and lockfile.
+ * The logic here is slightly tricky. DBNAME, ADBNAME, and
+ * ADB_LOCKFILE are dependent on the earlier items in the
+ * sequence. If an earlier item was specified via the input
+ * parameters, that value overrides the variables in the config
+ * file and causes the later item to be set to ".kadm5" or
+ * ".lock", respectively. However, if no earlier item was
+ * specified, the variables in the config file are used, and the
+ * ".kadm5" and ".lock" suffixes are only added as a no-variable
+ * default.
+ *
+ * Read the spec.
+ */
+ hierarchy[2] = "admin_database_name";
+ if (params_in->mask & KADM5_CONFIG_ADBNAME) {
+ params.mask |= KADM5_CONFIG_ADBNAME;
+ params.admin_dbname = strdup(params_in->admin_dbname);
+ } else if (params_in->mask & KADM5_CONFIG_DBNAME) {
+ params.admin_dbname = (char *) malloc(strlen(params.dbname) + 6);
+ if (params.admin_dbname) {
+ sprintf(params.admin_dbname, "%s.kadm5", params.dbname);
+ params.mask |= KADM5_CONFIG_ADBNAME;
+ }
+ } else if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
+ params.admin_dbname = svalue;
+ params.mask |= KADM5_CONFIG_ADBNAME;
+ } else if (params.mask & KADM5_CONFIG_DBNAME) {
+ params.admin_dbname = (char *) malloc(strlen(params.dbname) + 6);
+ if (params.admin_dbname) {
+ sprintf(params.admin_dbname, "%s.kadm5", params.dbname);
+ params.mask |= KADM5_CONFIG_ADBNAME;
+ }
+ }
+
+ /* Get the value for the admin (policy) database lock file*/
+ hierarchy[2] = "admin_database_lockfile";
+ if (params_in->mask & KADM5_CONFIG_ADB_LOCKFILE) {
+ params.mask |= KADM5_CONFIG_ADB_LOCKFILE;
+ params.admin_lockfile = strdup(params_in->admin_lockfile);
+ } else if ((params_in->mask & KADM5_CONFIG_ADBNAME) ||
+ (params_in->mask & KADM5_CONFIG_DBNAME)) {
+ /* if DBNAME is set but ADBNAME is not, then admin_database
+ * will already have been set above */
+ 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;
+ }
+ } else if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
+ params.mask |= KADM5_CONFIG_ADB_LOCKFILE;
+ params.admin_lockfile = svalue;
+ } else 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.mask |= KADM5_CONFIG_ADMIN_KEYTAB;
+ params.admin_keytab = strdup(params_in->admin_keytab);
+ } else if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
+ params.mask |= KADM5_CONFIG_ADMIN_KEYTAB;
+ params.admin_keytab = svalue;
+ } else {
+ params.admin_keytab = (char *) getenv("KRB5_KTNAME");
+ if (params.admin_keytab) {
+ params.admin_keytab = strdup(params.admin_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.mask |= KADM5_CONFIG_ACL_FILE;
+ params.acl_file = strdup(params_in->acl_file);
+ } else if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
+ params.mask |= KADM5_CONFIG_ACL_FILE;
+ params.acl_file = svalue;
+ }
+
+ /* Get the name of the dict file */
+ hierarchy[2] = "dict_file";
+ if (params_in->mask & KADM5_CONFIG_DICT_FILE) {
+ params.mask |= KADM5_CONFIG_DICT_FILE;
+ params.dict_file = strdup(params_in->dict_file);
+ } else if (!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 (!krb5_aprof_get_int32(aprofile, hierarchy, TRUE,
+ &ivalue)) {
+ params.kadmind_port = ivalue;
+ params.mask |= KADM5_CONFIG_KADMIND_PORT;
+ } else {
+ params.kadmind_port = 749; /* assigned by IANA */
+ params.mask |= KADM5_CONFIG_KADMIND_PORT;
+ }
+ }
+
+ /* Get the value for the master key name */
+ hierarchy[2] = "master_key_name";
+ if (params_in->mask & KADM5_CONFIG_MKEY_NAME) {
+ params.mask |= KADM5_CONFIG_MKEY_NAME;
+ params.mkey_name = strdup(params_in->mkey_name);
+ } else if (!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 (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
+ if (!krb5_string_to_enctype(svalue, &params.enctype)) {
+ params.mask |= KADM5_CONFIG_ENCTYPE;
+ krb5_xfree(svalue);
+ }
+ }
+
+ /* 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.mask |= KADM5_CONFIG_STASH_FILE;
+ params.stash_file = strdup(params_in->stash_file);
+ } else if (!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 (!krb5_aprof_get_deltat(aprofile, hierarchy, TRUE, &dtvalue)) {
+ params.max_life = dtvalue;
+ params.mask |= KADM5_CONFIG_MAX_LIFE;
+ } else {
+ params.max_life = 0;
+ 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 (!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 (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
+ if (!krb5_string_to_timestamp(svalue, &params.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 (!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(*tp) && (tp < sp)) {
+ *tp = '\0';
+ tp--;
+ }
+ *ep = '\0';
+ ep++;
+ /* Skip over trailing whitespace of ep */
+ while (isspace(*ep) && (*ep)) ep++;
+ }
+ /* Convert this flag */
+ if (krb5_string_to_flags(sp,
+ "+",
+ "-",
+ &params.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) {
+ params.mask |= KADM5_CONFIG_ENCTYPES;
+ params.keysalts = params_in->keysalts;
+ params.num_keysalts = params_in->num_keysalts;
+ } else if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
+ params.keysalts = NULL;
+ params.num_keysalts = 0;
+ krb5_string_to_keysalts(svalue,
+ ", \t", /* Tuple separators */
+ ":.-", /* Key/salt separators */
+ 0, /* No duplicates */
+ &params.keysalts,
+ &params.num_keysalts);
+ if (params.num_keysalts)
+ params.mask |= KADM5_CONFIG_ENCTYPES;
+ krb5_xfree(svalue);
+ }
+
+ *params_out = params;
+
+cleanup:
+ if (aprofile)
+ krb5_aprof_finish(aprofile);
+ if (kret) {
+ kadm5_free_config_params(context, &params);
+ 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_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);
+ }
+ return(0);
+}
+
+/***********************************************************************
+ * 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_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;
+
+ /* 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);
+ }
+
+ /* 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(*tp) && (tp < sp)) {
+ *tp = '\0';
+ tp--;
+ }
+ *ep = '\0';
+ ep++;
+ /* Skip over trailing whitespace of ep */
+ while (isspace(*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);
+ }
+
+ /* Get the value for the supported enctype/salttype matrix */
+ hierarchy[2] = "supported_enctypes";
+ if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
+ krb5_string_to_keysalts(svalue,
+ ", \t", /* Tuple separators */
+ ":.-", /* Key/salt separators */
+ 0, /* No duplicates */
+ &rparams->realm_keysalts,
+ &rparams->realm_num_keysalts);
+ krb5_xfree(svalue);
+ }
+
+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);
+ krb5_xfree(rparams);
+ }
+ return(0);
+}
+
diff --git a/src/lib/kadm5/chpass_util.c b/src/lib/kadm5/chpass_util.c
new file mode 100644
index 0000000000..dbf610ce30
--- /dev/null
+++ b/src/lib/kadm5/chpass_util.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Header$
+ *
+ *
+ */
+
+
+#include <stdio.h>
+#include <memory.h>
+#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)
+{
+ int code, code2, 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) {
+ strcpy(msg_ret, string_text(CHPASS_UTIL_NEW_PASSWORD_MISMATCH));
+ return(code);
+ } else {
+ sprintf(msg_ret, "%s %s\n%s\n", error_message(code),
+ string_text(CHPASS_UTIL_WHILE_READING_PASSWORD),
+ string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED));
+ return(code);
+ }
+ }
+ if (pwsize == 0) {
+#ifdef ZEROPASSWD
+ memset(buffer, 0, sizeof(buffer));
+#endif
+ strcpy(msg_ret, string_text(CHPASS_UTIL_NO_PASSWORD_READ));
+ 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) {
+ strcpy(msg_ret, string_text(CHPASS_UTIL_PASSWORD_CHANGED));
+ 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) {
+ strcpy(msg_ret, string_text(CHPASS_UTIL_PASSWORD_REUSE));
+ return(code);
+ }
+
+ if (code == KADM5_PASS_Q_DICT) {
+ strcpy(msg_ret, string_text(CHPASS_UTIL_PASSWORD_IN_DICTIONARY));
+ return(code);
+ }
+
+ /* Look up policy for the remaining messages */
+
+ code2 = kadm5_get_principal (lhandle, princ, &princ_ent,
+ KADM5_PRINCIPAL_NORMAL_MASK);
+ if (code2 != 0) {
+ sprintf(msg_ret, "%s %s\n%s %s\n\n%s\n ", error_message(code2),
+ string_text(CHPASS_UTIL_GET_PRINC_INFO),
+ error_message(code),
+ string_text(CHPASS_UTIL_WHILE_TRYING_TO_CHANGE),
+ string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED));
+ return(code);
+ }
+
+ if ((princ_ent.aux_attributes & KADM5_POLICY) == 0) {
+ sprintf(msg_ret, "%s %s\n\n%s", error_message(code),
+ string_text(CHPASS_UTIL_NO_POLICY_YET_Q_ERROR),
+ string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED));
+ (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/src/lib/kadm5/chpass_util_strings.et b/src/lib/kadm5/chpass_util_strings.et
new file mode 100644
index 0000000000..0322549982
--- /dev/null
+++ b/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 ovpasswd 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/src/lib/kadm5/client_handle.c b/src/lib/kadm5/client_handle.c
new file mode 100644
index 0000000000..895777a6ed
--- /dev/null
+++ b/src/lib/kadm5/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/src/lib/kadm5/client_init.c b/src/lib/kadm5/client_init.c
new file mode 100644
index 0000000000..bfc1c3a3c6
--- /dev/null
+++ b/src/lib/kadm5/client_init.c
@@ -0,0 +1,554 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <stdio.h>
+#include <netdb.h>
+#include <memory.h>
+#include <string.h>
+#include <com_err.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <krb5.h>
+#include <k5-int.h> /* for KRB5_ADM_DEFAULT_PORT */
+#ifdef __STDC__
+#include <stdlib.h>
+#endif
+
+#include <kadm5/admin.h>
+#include <kadm5/kadm_rpc.h>
+#include "client_internal.h"
+
+#include <rpc/rpc.h>
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_krb5.h>
+#include <rpc/auth_gssapi.h>
+
+#define ADM_CCACHE "/tmp/ovsec_adm.XXXXXX"
+
+#ifndef _POSIX_SOURCE /* Perhaps this should actually say __STDC__ */
+int setenv(const char *var, const char *val, int flag);
+void unsetenv(const char *var);
+#endif
+
+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,
+ 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)
+{
+ return _kadm5_init_any(client_name, INIT_CREDS, NULL, ccache,
+ service_name, params,
+ struct_version, api_version,
+ 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,
+ void **server_handle)
+{
+ return _kadm5_init_any(client_name, INIT_PASS, pass, NULL,
+ service_name, params, struct_version,
+ api_version, 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,
+ void **server_handle)
+{
+ return _kadm5_init_any(client_name, INIT_PASS, pass, NULL,
+ service_name, params, struct_version,
+ api_version, 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,
+ void **server_handle)
+{
+ return _kadm5_init_any(client_name, INIT_SKEY, keytab, NULL,
+ service_name, params, struct_version,
+ api_version, server_handle);
+}
+
+/*
+ * Try no preauthentication first; then try the encrypted timestamp
+ * (stolen from krb5 kinit.c)
+ */
+static int preauth_search_list[] = {
+ 0,
+ KRB5_PADATA_ENC_UNIX_TIME,
+ -1
+};
+
+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,
+ void **server_handle)
+{
+ struct sockaddr_in addr;
+ struct hostent *hp;
+ struct servent *srv;
+ int fd;
+ int i;
+
+ char full_service_name[BUFSIZ], host[MAXHOSTNAMELEN], *ccname_orig;
+ char *realm;
+ krb5_creds creds;
+ krb5_ccache ccache = NULL;
+ krb5_timestamp now;
+
+ OM_uint32 gssstat, minor_stat;
+ gss_buffer_desc input_name;
+ gss_name_t gss_target, gss_client;
+ gss_cred_id_t gss_client_creds = GSS_C_NO_CREDENTIAL;
+
+ 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);
+ krb5_init_ets(handle->context);
+
+ if(service_name == NULL || client_name == NULL) {
+ free(handle);
+ return EINVAL;
+ }
+ memset((char *) &creds, 0, sizeof(creds));
+
+ /*
+ * 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 *) &params_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;
+ params_in = &params_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,
+ "/etc/krb5.conf",
+ "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 KRB5_CONFIG_BADFORMAT;
+ }
+
+ /*
+ * Acquire a service ticket for service_name@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.
+ */
+
+ if ((code = krb5_parse_name(handle->context, client_name, &creds.client)))
+ goto error;
+
+ if (realm) {
+ sprintf(full_service_name, "%s@%s", service_name, realm);
+ } else {
+ /* krb5_princ_realm(creds.client) is not null terminated */
+ strcpy(full_service_name, service_name);
+ strcat(full_service_name, "@");
+ strncat(full_service_name, krb5_princ_realm(handle->context,
+ creds.client)->data,
+ krb5_princ_realm(handle->context, creds.client)->length);
+ }
+
+ if ((code = krb5_parse_name(handle->context, full_service_name,
+ &creds.server)))
+ goto error;
+
+ /* XXX temporarily fix a bug in krb5_cc_get_type */
+#undef krb5_cc_get_type
+#define krb5_cc_get_type(context, cache) ((cache)->ops->prefix)
+
+
+ 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 {
+ handle->cache_name =
+ (char *) malloc(strlen(ADM_CCACHE)+strlen("FILE:")+1);
+ if (handle->cache_name == NULL) {
+ code = ENOMEM;
+ goto error;
+ }
+ sprintf(handle->cache_name, "FILE:%s", ADM_CCACHE);
+ mktemp(handle->cache_name + strlen("FILE:"));
+
+ if ((code = krb5_cc_resolve(handle->context, handle->cache_name,
+ &ccache)))
+ goto error;
+
+ if ((code = krb5_cc_initialize (handle->context, ccache,
+ creds.client)))
+ goto error;
+
+ handle->destroy_cache = 1;
+ }
+ handle->lhandle->cache_name = handle->cache_name;
+
+ if ((code = krb5_timeofday(handle->context, &now)))
+ goto error;
+
+ /*
+ * Get a ticket, use the method specified in init_type.
+ */
+
+ creds.times.starttime = 0; /* start timer at KDC */
+ creds.times.endtime = 0; /* endtime will be limited by service */
+
+ if (init_type == INIT_PASS) {
+ for (i=0; preauth_search_list[i] >= 0; i++) {
+ code = krb5_get_in_tkt_with_password(handle->context,
+ 0, /* no options */
+ 0, /* default addresses */
+ NULL,
+ NULL, /* XXX preauth */
+ pass,
+ ccache,
+ &creds,
+ NULL);
+ if (code != KRB5KDC_ERR_PREAUTH_FAILED &&
+ code != KRB5KDC_ERR_PREAUTH_REQUIRED &&
+ code != KRB5KRB_ERR_GENERIC)
+ break;
+ }
+ } else if (init_type == INIT_SKEY) {
+ krb5_keytab kt = NULL;
+
+ if (pass && (code = krb5_kt_resolve(handle->context, pass, &kt)))
+ ;
+ else {
+ for (i=0; preauth_search_list[i] >= 0; i++) {
+ code = krb5_get_in_tkt_with_keytab(handle->context,
+ 0, /* no options */
+ 0, /* default addrs */
+ NULL,
+ NULL, /* XXX preauth */
+ kt,
+ ccache,
+ &creds,
+ NULL);
+ if (code != KRB5KDC_ERR_PREAUTH_FAILED &&
+ code != KRB5KDC_ERR_PREAUTH_REQUIRED &&
+ code != KRB5KRB_ERR_GENERIC)
+ break;
+ }
+
+ if (pass) krb5_kt_close(handle->context, kt);
+ }
+ }
+
+ /* 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;
+
+ if (code != 0) goto error;
+
+#ifdef ZEROPASSWD
+ if (pass != NULL)
+ memset(pass, 0, strlen(pass));
+#endif
+
+ /*
+ * We have ticket; open the RPC connection.
+ */
+
+ hp = gethostbyname(handle->params.admin_server);
+ if (hp == (struct hostent *) NULL) {
+ code = KRB5_CONFIG_BADFORMAT;
+ 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;
+ 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.
+ */
+
+ /* use the kadm5 cache */
+ ccname_orig = getenv("KRB5CCNAME");
+ if (ccname_orig)
+ ccname_orig = strdup(ccname_orig);
+
+ (void) setenv("KRB5CCNAME", handle->cache_name, 1);
+
+#ifndef INIT_TEST
+ input_name.value = full_service_name;
+ input_name.length = strlen((char *)input_name.value) + 1;
+ gssstat = gss_import_name(&minor_stat, &input_name,
+ gss_nt_krb5_name, &gss_target);
+ if (gssstat != GSS_S_COMPLETE) {
+ code = KADM5_GSS_ERROR;
+ goto error;
+ }
+#endif /* ! INIT_TEST */
+
+ input_name.value = client_name;
+ input_name.length = strlen((char *)input_name.value) + 1;
+ gssstat = gss_import_name(&minor_stat, &input_name,
+ 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);
+ (void) gss_release_name(&minor_stat, &gss_client);
+ if (gssstat != GSS_S_COMPLETE) {
+ code = KADM5_GSS_ERROR;
+ goto error;
+ }
+
+#ifndef INIT_TEST
+ handle->clnt->cl_auth = auth_gssapi_create(handle->clnt,
+ &gssstat,
+ &minor_stat,
+ gss_client_creds,
+ gss_target,
+ GSS_C_NULL_OID,
+ GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,
+ 0,
+ NULL,
+ NULL,
+ NULL);
+ (void) gss_release_name(&minor_stat, &gss_target);
+#endif /* ! INIT_TEST */
+
+ if (ccname_orig) {
+ (void) setenv("KRB5CCNAME", ccname_orig, 1);
+ free(ccname_orig);
+ } else
+ (void) unsetenv("KRB5CCNAME");
+
+
+ if (handle->clnt->cl_auth == NULL) {
+ code = KADM5_GSS_ERROR;
+ goto error;
+ }
+
+ r = init_1(&handle->api_version, handle->clnt);
+ if (r == NULL) {
+ code = KADM5_RPC_ERROR;
+ goto error;
+ }
+ if (r->code) {
+ code = r->code;
+ goto error;
+ }
+
+ *server_handle = (void *) handle;
+
+ if (init_type != INIT_CREDS)
+ krb5_cc_close(handle->context, ccache);
+
+ 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->destroy_cache && ccache)
+ krb5_cc_destroy(handle->context, ccache);
+ if(handle->clnt && handle->clnt->cl_auth)
+ AUTH_DESTROY(handle->clnt->cl_auth);
+ if(handle->clnt)
+ clnt_destroy(handle->clnt);
+
+cleanup:
+ krb5_free_cred_contents(handle->context, &creds);
+ if (gss_client_creds != GSS_C_NO_CREDENTIAL)
+ (void) gss_release_cred(&minor_stat, &gss_client_creds);
+
+ if (code)
+ free(handle);
+
+ return code;
+}
+
+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);
+
+ handle->magic_number = 0;
+ free(handle);
+
+ return code;
+}
+
+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/src/lib/kadm5/client_internal.h b/src/lib/kadm5/client_internal.h
new file mode 100644
index 0000000000..5a246158eb
--- /dev/null
+++ b/src/lib/kadm5/client_internal.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ *
+ * $Log$
+ * 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/src/lib/kadm5/client_principal.c b/src/lib/kadm5/client_principal.c
new file mode 100644
index 0000000000..c419227223
--- /dev/null
+++ b/src/lib/kadm5/client_principal.c
@@ -0,0 +1,307 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <rpc/rpc.h>
+#include <kadm5/admin.h>
+#include <kadm5/kadm_rpc.h>
+#include <memory.h>
+#include "client_internal.h"
+
+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);
+
+ arg.mask = mask;
+ arg.passwd = pw;
+ arg.api_version = handle->api_version;
+
+ if(princ == NULL)
+ return EINVAL;
+ 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_1(&arg, handle->clnt);
+
+ if (handle->api_version == KADM5_API_VERSION_1)
+ krb5_free_principal(handle->context, arg.rec.mod_name);
+
+ if(r == NULL)
+ return KADM5_RPC_ERROR;
+ 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_1(&arg, handle->clnt);
+ if(r == NULL)
+ return KADM5_RPC_ERROR;
+ 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);
+
+ arg.mask = mask;
+ arg.api_version = handle->api_version;
+ /*
+ * cough cough gag gag
+ * see comment in create_principal.
+ */
+ if(princ == NULL)
+ return EINVAL;
+ 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_1(&arg, handle->clnt);
+
+ if (handle->api_version == KADM5_API_VERSION_1)
+ krb5_free_principal(handle->context, arg.rec.mod_name);
+
+ if(r == NULL)
+ return KADM5_RPC_ERROR;
+ 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;
+ krb5_error_code retval;
+
+ 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_1(&arg, handle->clnt);
+ if(r == NULL)
+ return KADM5_RPC_ERROR;
+ 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));
+ }
+
+ 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;
+ krb5_error_code retval;
+
+ CHECK_HANDLE(server_handle);
+
+ if(princs == NULL || count == NULL)
+ return EINVAL;
+ arg.exp = exp;
+ arg.api_version = handle->api_version;
+ r = get_princs_1(&arg, handle->clnt);
+ if(r == NULL)
+ return KADM5_RPC_ERROR;
+ if(r->code == 0) {
+ *count = r->count;
+ *princs = r->princs;
+ } else {
+ *count = 0;
+ *princs = NULL;
+ }
+
+ 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_1(&arg, handle->clnt);
+ if(r == NULL)
+ return KADM5_RPC_ERROR;
+ 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_1(&arg, handle->clnt);
+ if(r == NULL)
+ return KADM5_RPC_ERROR;
+ 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;
+ krb5_keyblock new;
+ 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_1(&arg, handle->clnt);
+ if(r == NULL)
+ return KADM5_RPC_ERROR;
+ 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) {
+ *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;
+ }
+ }
+ }
+ }
+
+ 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/src/lib/kadm5/client_rpc.c b/src/lib/kadm5/client_rpc.c
new file mode 100644
index 0000000000..547844a2c9
--- /dev/null
+++ b/src/lib/kadm5/client_rpc.c
@@ -0,0 +1,221 @@
+#include <rpc/rpc.h>
+#include <kadm5/kadm_rpc.h>
+#include <krb5.h>
+#include <kadm5/admin.h>
+#include <memory.h>
+
+/* Default timeout can be changed using clnt_control() */
+static struct timeval TIMEOUT = { 25, 0 };
+
+generic_ret *
+create_principal_1(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 *
+delete_principal_1(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_1(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_1(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_1(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_1(argp, clnt)
+ gprinc_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_1(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);
+}
+
+chrand_ret *
+chrand_principal_1(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);
+}
+
+generic_ret *
+create_policy_1(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_1(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_1(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_1(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_1(argp, clnt)
+ gprinc_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_1(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_1(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/src/lib/kadm5/clnt_chpass_util.c b/src/lib/kadm5/clnt_chpass_util.c
new file mode 100644
index 0000000000..d6c7f0bfb2
--- /dev/null
+++ b/src/lib/kadm5/clnt_chpass_util.c
@@ -0,0 +1,15 @@
+#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)
+{
+ 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);
+}
diff --git a/src/lib/kadm5/clnt_policy.c b/src/lib/kadm5/clnt_policy.c
new file mode 100644
index 0000000000..f81cf7471b
--- /dev/null
+++ b/src/lib/kadm5/clnt_policy.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <rpc/rpc.h>
+#include <kadm5/admin.h>
+#include <kadm5/kadm_rpc.h>
+#include "client_internal.h"
+#include <stdlib.h>
+#include <string.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_1(&arg, handle->clnt);
+ if(r == NULL)
+ return KADM5_RPC_ERROR;
+ 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_1(&arg, handle->clnt);
+ if(r == NULL)
+ return KADM5_RPC_ERROR;
+ 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_1(&arg, handle->clnt);
+ if(r == NULL)
+ return KADM5_RPC_ERROR;
+ 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_1(&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));
+ }
+
+ 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;
+ krb5_error_code retval;
+
+ CHECK_HANDLE(server_handle);
+
+ if(pols == NULL || count == NULL)
+ return EINVAL;
+ arg.exp = exp;
+ arg.api_version = handle->api_version;
+ r = get_pols_1(&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;
+ }
+
+ return r->code;
+}
diff --git a/src/lib/kadm5/clnt_privs.c b/src/lib/kadm5/clnt_privs.c
new file mode 100644
index 0000000000..93ea199e26
--- /dev/null
+++ b/src/lib/kadm5/clnt_privs.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Id$
+ * $Source$
+ *
+ * $Log$
+ * 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 <rpc/rpc.h>
+#include <kadm5/admin.h>
+#include <kadm5/kadm_rpc.h>
+#include "client_internal.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_1(&handle->api_version, handle->clnt);
+ if (r == NULL)
+ return KADM5_RPC_ERROR;
+ else if (r->code == KADM5_OK)
+ *privs = r->privs;
+ return r->code;
+}
diff --git a/src/lib/kadm5/configure.in b/src/lib/kadm5/configure.in
new file mode 100644
index 0000000000..6466673a8a
--- /dev/null
+++ b/src/lib/kadm5/configure.in
@@ -0,0 +1,49 @@
+AC_INIT(configure.in)
+CONFIG_RULES
+AC_PROG_ARCHIVE
+AC_PROG_ARCHIVE_ADD
+AC_PROG_RANLIB
+AC_PROG_INSTALL
+AC_PROG_LEX
+AC_PROG_AWK
+AC_CHECK_HEADERS(syslog.h)
+AC_REPLACE_FUNCS(setenv)
+save_LIBS="$LIBS"
+LIBS=-lgen
+AC_CHECK_FUNCS(compile step)
+[if test "$krb5_cv_func_compile" = true ; then
+ LIBS="$save_LIBS -lgen"
+else
+ LIBS="$save_LIBS"
+fi]
+AC_CHECK_FUNCS(re_comp re_exec regcomp regexec openlog syslog closelog strftime vsprintf)
+V5_SHARED_LIB_OBJS
+V5_MAKE_SHARED_LIB(libkadm5srv,1.0,.., ./kadm5,srv)
+V5_MAKE_SHARED_LIB(libkadm5clnt,1.0,.., ./kadm5,clnt)
+GSSRPC_SH_VERS=$krb5_cv_shlib_version_libgssrpc
+AC_SUBST(GSSRPC_SH_VERS)
+GSSAPI_KRB5_SH_VERS=$krb5_cv_shlib_version_libgssapi_krb5
+AC_SUBST(GSSAPI_KRB5_SH_VERS)
+KDB5_SH_VERS=$krb5_cv_shlib_version_libkdb5
+AC_SUBST(KDB5_SH_VERS)
+KRB5_SH_VERS=$krb5_cv_shlib_version_libkrb5
+AC_SUBST(KRB5_SH_VERS)
+CRYPTO_SH_VERS=$krb5_cv_shlib_version_libcrypto
+AC_SUBST(CRYPTO_SH_VERS)
+COMERR_SH_VERS=$krb5_cv_shlib_version_libcom_err
+AC_SUBST(COMERR_SH_VERS)
+DYN_SH_VERS=$krb5_cv_shlib_version_libdyn
+AC_SUBST(DYN_SH_VERS)
+CopySrcHeader(adb.h,[$](BUILDTOP)/include/kadm5)
+CopySrcHeader(admin.h,[$](BUILDTOP)/include/kadm5)
+CopySrcHeader(admin_internal.h,[$](BUILDTOP)/include/kadm5)
+CopySrcHeader(admin_xdr.h,[$](BUILDTOP)/include/kadm5)
+CopySrcHeader(client_internal.h,[$](BUILDTOP)/include/kadm5)
+CopySrcHeader(kadm_rpc.h,[$](BUILDTOP)/include/kadm5)
+CopySrcHeader(server_acl.h,[$](BUILDTOP)/include/kadm5)
+CopySrcHeader(server_internal.h,[$](BUILDTOP)/include/kadm5)
+CopyHeader(adb_err.h,[$](BUILDTOP)/include/kadm5)
+CopyHeader(chpass_util_strings.h,[$](BUILDTOP)/include/kadm5)
+CopyHeader(kadm_err.h,[$](BUILDTOP)/include/kadm5)
+AppendRule([all:: all-$(WHAT)])
+V5_AC_OUTPUT_MAKEFILE
diff --git a/src/lib/kadm5/get_admhst.c b/src/lib/kadm5/get_admhst.c
new file mode 100644
index 0000000000..a398997d6c
--- /dev/null
+++ b/src/lib/kadm5/get_admhst.c
@@ -0,0 +1,89 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1985, 1986, 1987, 1988 by the Massachusetts Institute
+ * of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ */
+
+#ifndef lint
+static char *rcsid =
+"$Header$";
+#endif /* lint */
+
+#include <stdio.h>
+#include <krb5/osconf.h>
+#include <string.h>
+
+/*
+ * Given a Kerberos realm, find a host on which the Kerberos database
+ * administration server can be found.
+ *
+ * krb5_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 DEFAULT_CONFIG_FILENAME.
+ *
+ * If the realm is NULL, the default realm is used.
+ *
+ * On error, get_admhst returns 0. If all goes well, the routine
+ * returns 1.
+ *
+ * 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_get_admhst(char *h, char *r, int n)
+{
+ FILE *cnffile;
+ char *realm = NULL;
+ char tr[BUFSIZ];
+ char linebuf[BUFSIZ];
+ char scratch[64];
+ register int i;
+ int ret;
+
+ if(r == NULL) {
+ if((ret = krb5_get_default_realm(&realm)) != 0)
+ return ret;
+ r = realm;
+ }
+ if ((cnffile = fopen(DEFAULT_CONFIG_FILENAME, "r")) == NULL) {
+ return(0);
+ }
+ if (fgets(linebuf, BUFSIZ, cnffile) == NULL) {
+ /* error reading */
+ (void) fclose(cnffile);
+ return(0);
+ }
+ if (!strchr(linebuf, '\n')) {
+ /* didn't all fit into buffer, punt */
+ (void) fclose(cnffile);
+ if(realm)
+ free(realm);
+ return(0);
+ }
+ for (i = 0; i < n; ) {
+ /* run through the file, looking for admin host */
+ if (fgets(linebuf, BUFSIZ, cnffile) == NULL) {
+ (void) fclose(cnffile);
+ if(realm)
+ free(realm);
+ return(0);
+ }
+ /* need to scan for a token after 'admin' to make sure that
+ admin matched correctly */
+ if (sscanf(linebuf, "%s %s admin %s", tr, h, scratch) != 3)
+ continue;
+ if (!strcmp(tr,r))
+ i++;
+ }
+ (void) fclose(cnffile);
+ if(realm)
+ free(realm);
+ return(1);
+}
diff --git a/src/lib/kadm5/kadm_err.et b/src/lib/kadm5/kadm_err.et
new file mode 100644
index 0000000000..446a38de1c
--- /dev/null
+++ b/src/lib/kadm5/kadm_err.et
@@ -0,0 +1,54 @@
+# 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"
+end
diff --git a/src/lib/kadm5/kadm_rpc.h b/src/lib/kadm5/kadm_rpc.h
new file mode 100644
index 0000000000..b0f97e6cb9
--- /dev/null
+++ b/src/lib/kadm5/kadm_rpc.h
@@ -0,0 +1,205 @@
+#include <rpc/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;
+bool_t xdr_cprinc_arg();
+
+struct generic_ret {
+ krb5_ui_4 api_version;
+ kadm5_ret_t code;
+};
+typedef struct generic_ret generic_ret;
+bool_t xdr_generic_ret();
+
+struct dprinc_arg {
+ krb5_ui_4 api_version;
+ krb5_principal princ;
+};
+typedef struct dprinc_arg dprinc_arg;
+bool_t xdr_dprinc_arg();
+
+struct mprinc_arg {
+ krb5_ui_4 api_version;
+ kadm5_principal_ent_rec rec;
+ long mask;
+};
+typedef struct mprinc_arg mprinc_arg;
+bool_t xdr_mprinc_arg();
+
+struct rprinc_arg {
+ krb5_ui_4 api_version;
+ krb5_principal src;
+ krb5_principal dest;
+};
+typedef struct rprinc_arg rprinc_arg;
+bool_t xdr_rprinc_arg();
+
+struct gprincs_arg {
+ krb5_ui_4 api_version;
+ char *exp;
+};
+typedef struct gprincs_arg gprincs_arg;
+bool_t xdr_gprincs_arg();
+
+struct gprincs_ret {
+ krb5_ui_4 api_version;
+ kadm5_ret_t code;
+ char **princs;
+ int count;
+};
+typedef struct gprincs_ret gprincs_ret;
+bool_t xdr_gprincs_ret();
+
+struct chpass_arg {
+ krb5_ui_4 api_version;
+ krb5_principal princ;
+ char *pass;
+};
+typedef struct chpass_arg chpass_arg;
+bool_t xdr_chpass_arg();
+
+struct chrand_arg {
+ krb5_ui_4 api_version;
+ krb5_principal princ;
+};
+typedef struct chrand_arg chrand_arg;
+bool_t xdr_chrand_arg();
+
+struct chrand_ret {
+ krb5_ui_4 api_version;
+ kadm5_ret_t code;
+ krb5_keyblock key;
+ krb5_keyblock *keys;
+ int n_keys;
+};
+typedef struct chrand_ret chrand_ret;
+bool_t xdr_chrand_ret();
+
+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();
+bool_t xdr_kadm5_ret_t();
+bool_t xdr_kadm5_principal_ent_rec();
+bool_t xdr_kadm5_policy_ent_rec();
+bool_t xdr_krb5_keyblock();
+bool_t xdr_krb5_principal();
+bool_t xdr_krb5_enctype();
+bool_t xdr_krb5_octet();
+bool_t xdr_krb5_int32();
+bool_t xdr_u_int32();
+
+struct cpol_arg {
+ krb5_ui_4 api_version;
+ kadm5_policy_ent_rec rec;
+ long mask;
+};
+typedef struct cpol_arg cpol_arg;
+bool_t xdr_cpol_arg();
+
+struct dpol_arg {
+ krb5_ui_4 api_version;
+ char *name;
+};
+typedef struct dpol_arg dpol_arg;
+bool_t xdr_dpol_arg();
+
+struct mpol_arg {
+ krb5_ui_4 api_version;
+ kadm5_policy_ent_rec rec;
+ long mask;
+};
+typedef struct mpol_arg mpol_arg;
+bool_t xdr_mpol_arg();
+
+struct gpol_arg {
+ krb5_ui_4 api_version;
+ char *name;
+};
+typedef struct gpol_arg gpol_arg;
+bool_t xdr_gpol_arg();
+
+struct gpol_ret {
+ krb5_ui_4 api_version;
+ kadm5_ret_t code;
+ kadm5_policy_ent_rec rec;
+};
+typedef struct gpol_ret gpol_ret;
+bool_t xdr_gpol_ret();
+
+struct gpols_arg {
+ krb5_ui_4 api_version;
+ char *exp;
+};
+typedef struct gpols_arg gpols_arg;
+bool_t xdr_gpols_arg();
+
+struct gpols_ret {
+ krb5_ui_4 api_version;
+ kadm5_ret_t code;
+ char **pols;
+ int count;
+};
+typedef struct gpols_ret gpols_ret;
+bool_t xdr_gpols_ret();
+
+struct getprivs_ret {
+ krb5_ui_4 api_version;
+ kadm5_ret_t code;
+ long privs;
+};
+typedef struct getprivs_ret getprivs_ret;
+bool_t xdr_getprivs_ret();
+
+#define KADM ((krb5_ui_4)2112)
+#define KADMVERS ((krb5_ui_4)2)
+#define CREATE_PRINCIPAL ((krb5_ui_4)1)
+extern generic_ret *create_principal_1();
+#define DELETE_PRINCIPAL ((krb5_ui_4)2)
+extern generic_ret *delete_principal_1();
+#define MODIFY_PRINCIPAL ((krb5_ui_4)3)
+extern generic_ret *modify_principal_1();
+#define RENAME_PRINCIPAL ((krb5_ui_4)4)
+extern generic_ret *rename_principal_1();
+#define GET_PRINCIPAL ((krb5_ui_4)5)
+extern gprinc_ret *get_principal_1();
+#define CHPASS_PRINCIPAL ((krb5_ui_4)6)
+extern generic_ret *chpass_principal_1();
+#define CHRAND_PRINCIPAL ((krb5_ui_4)7)
+extern chrand_ret *chrand_principal_1();
+#define CREATE_POLICY ((krb5_ui_4)8)
+extern generic_ret *create_policy_1();
+#define DELETE_POLICY ((krb5_ui_4)9)
+extern generic_ret *delete_policy_1();
+#define MODIFY_POLICY ((krb5_ui_4)10)
+extern generic_ret *modify_policy_1();
+#define GET_POLICY ((krb5_ui_4)11)
+extern gpol_ret *get_policy_1();
+#define GET_PRIVS ((krb5_ui_4)12)
+extern getprivs_ret *get_privs_1();
+#define INIT ((krb5_ui_4)13)
+extern generic_ret *init_1();
+#define GET_PRINCS ((krb5_ui_4) 14)
+extern gprincs_ret *get_princs_1();
+#define GET_POLS ((krb5_ui_4) 15)
+extern gpols_ret *get_pols_1();
+
diff --git a/src/lib/kadm5/kadm_rpc_xdr.c b/src/lib/kadm5/kadm_rpc_xdr.c
new file mode 100644
index 0000000000..6cce9391ee
--- /dev/null
+++ b/src/lib/kadm5/kadm_rpc_xdr.c
@@ -0,0 +1,830 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <rpc/rpc.h>
+#include <krb5.h>
+#include <k5-int.h>
+#include <kadm5/admin.h>
+#include <kadm5/kadm_rpc.h>
+#include <malloc.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, (rpc_u_int32 *) 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, (rpc_int32 *) objp)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_krb5_kvno(XDR *xdrs, krb5_kvno *objp)
+{
+ unsigned char tmp;
+
+ 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, (rpc_int32 *) 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, (rpc_int32 *) objp)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_krb5_ui_4(XDR *xdrs, krb5_ui_4 *objp)
+{
+ if (!xdr_u_int32(xdrs, (rpc_u_int32 *) 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);
+}
+
+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.
+ */
+
+ 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[0])) {
+ 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;
+ int len;
+
+ switch (xdrs->x_op) {
+ case XDR_FREE:
+ 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)
+{
+ rpc_u_int32 tmp;
+
+ if (xdrs->x_op == XDR_ENCODE)
+ tmp = (rpc_u_int32) *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_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);
+ }
+ 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);
+ }
+ }
+ 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_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_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;
+ }
+ }
+
+ 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);
+ }
+ }
+ }
+ 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);
+ }
+ 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);
+ }
+ }
+ 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;
+ 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((ret = krb5_unparse_name(context, *objp, &p)) != 0)
+ return FALSE;
+ if(!xdr_nullstring(xdrs, &p))
+ return FALSE;
+ free(p);
+ break;
+ case XDR_DECODE:
+ if(!xdr_nullstring(xdrs, &p))
+ return FALSE;
+ ret = krb5_parse_name(context, p, &pr);
+ if(ret != 0)
+ return FALSE;
+ *objp = pr;
+ free(p);
+ 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_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/src/lib/kadm5/logger.c b/src/lib/kadm5/logger.c
new file mode 100644
index 0000000000..924fb9a23e
--- /dev/null
+++ b/src/lib/kadm5/logger.c
@@ -0,0 +1,940 @@
+/*
+ * 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. M.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(_MSDOS)
+
+/*
+ * 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>
+#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 */
+
+static const char lspec_parse_err_1[] = "%s: cannot parse <%s>\n";
+static const char lspec_parse_err_2[] = "%s: warning - logging entry syntax error\n";
+static const char log_file_err[] = "%s: error writing to %s\n";
+static const char log_device_err[] = "%s: error writing to %s device\n";
+static const char log_ufo_string[] = "???";
+static const char log_emerg_string[] = "EMERGENCY";
+static const char log_alert_string[] = "ALERT";
+static const char log_crit_string[] = "CRITICAL";
+static const char log_err_string[] = "Error";
+static const char log_warning_string[] = "Warning";
+static const char log_notice_string[] = "Notice";
+static const char log_info_string[] = "info";
+static const char 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, m) >= 0) ? \
+ (fprintf(f, "\r\n"), 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(whoami, code, format, ap)
+ const char *whoami;
+ long code;
+ const char *format;
+ va_list ap;
+{
+ char outbuf[KRB5_KLOG_MAX_ERRMSG_SIZE];
+ int lindex;
+ 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) {
+ strcat(outbuf, error_message(code));
+ strcat(outbuf, " - ");
+ }
+ cp = &outbuf[strlen(outbuf)];
+
+ actual_format = (char *) 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 = (char *) (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,
+ outbuf) < 0) {
+ /* Attempt to report error */
+ fprintf(stderr, log_file_err, whoami,
+ log_control.log_entries[lindex].lfu_fname);
+ }
+ else {
+ fprintf(log_control.log_entries[lindex].lfu_filep, "\n");
+ 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, 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(kcontext, ename, whoami, do_com_err)
+ 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;
+ 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(*cp); cp++);
+ for (cp2 = &logging_specs[i][strlen(logging_specs[i])-1];
+ isspace(*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.
+ */
+ if (cp2 = strchr(&cp[7], ':')) {
+ 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) {
+ if (!strcasecmp(cp2, "AUTH")) {
+ log_control.log_entries[i].lsu_facility = LOG_AUTH;
+ }
+#ifdef LOG_KERN
+ else if (!strcasecmp(cp2, "KERN")) {
+ log_control.log_entries[i].lsu_facility = LOG_KERN;
+ }
+#endif /* LOG_KERN */
+#ifdef LOG_USER
+ else if (!strcasecmp(cp2, "USER")) {
+ log_control.log_entries[i].lsu_facility = LOG_USER;
+ }
+#endif /* LOG_USER */
+#ifdef LOG_MAIL
+ else if (!strcasecmp(cp2, "MAIL")) {
+ log_control.log_entries[i].lsu_facility = LOG_MAIL;
+ }
+#endif /* LOG_MAIL */
+#ifdef LOG_DAEMON
+ else if (!strcasecmp(cp2, "DAEMON")) {
+ log_control.log_entries[i].lsu_facility = LOG_DAEMON;
+ }
+#endif /* LOG_DAEMON */
+#ifdef LOG_LPR
+ else if (!strcasecmp(cp2, "LPR")) {
+ log_control.log_entries[i].lsu_facility = LOG_LPR;
+ }
+#endif /* LOG_LPR */
+#ifdef LOG_NEWS
+ else if (!strcasecmp(cp2, "NEWS")) {
+ log_control.log_entries[i].lsu_facility = LOG_NEWS;
+ }
+#endif /* LOG_NEWS */
+#ifdef LOG_UUCP
+ else if (!strcasecmp(cp2, "UUCP")) {
+ log_control.log_entries[i].lsu_facility = LOG_UUCP;
+ }
+#endif /* LOG_UUCP */
+#ifdef LOG_CRON
+ else if (!strcasecmp(cp2, "CRON")) {
+ log_control.log_entries[i].lsu_facility = LOG_CRON;
+ }
+#endif /* LOG_CRON */
+#ifdef LOG_LOCAL0
+ else if (!strcasecmp(cp2, "LOCAL0")) {
+ log_control.log_entries[i].lsu_facility = LOG_LOCAL0;
+ }
+#endif /* LOG_LOCAL0 */
+#ifdef LOG_LOCAL1
+ else if (!strcasecmp(cp2, "LOCAL1")) {
+ log_control.log_entries[i].lsu_facility = LOG_LOCAL1;
+ }
+#endif /* LOG_LOCAL1 */
+#ifdef LOG_LOCAL2
+ else if (!strcasecmp(cp2, "LOCAL2")) {
+ log_control.log_entries[i].lsu_facility = LOG_LOCAL2;
+ }
+#endif /* LOG_LOCAL2 */
+#ifdef LOG_LOCAL3
+ else if (!strcasecmp(cp2, "LOCAL3")) {
+ log_control.log_entries[i].lsu_facility = LOG_LOCAL3;
+ }
+#endif /* LOG_LOCAL3 */
+#ifdef LOG_LOCAL4
+ else if (!strcasecmp(cp2, "LOCAL4")) {
+ log_control.log_entries[i].lsu_facility = LOG_LOCAL4;
+ }
+#endif /* LOG_LOCAL4 */
+#ifdef LOG_LOCAL5
+ else if (!strcasecmp(cp2, "LOCAL5")) {
+ log_control.log_entries[i].lsu_facility = LOG_LOCAL5;
+ }
+#endif /* LOG_LOCAL5 */
+#ifdef LOG_LOCAL6
+ else if (!strcasecmp(cp2, "LOCAL6")) {
+ log_control.log_entries[i].lsu_facility = LOG_LOCAL6;
+ }
+#endif /* LOG_LOCAL6 */
+#ifdef LOG_LOCAL7
+ else if (!strcasecmp(cp2, "LOCAL7")) {
+ log_control.log_entries[i].lsu_facility = LOG_LOCAL7;
+ }
+#endif /* LOG_LOCAL7 */
+ 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")) {
+ if (log_control.log_entries[i].lfu_filep =
+ fdopen(fileno(stderr), "a+")) {
+ 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")) {
+ if (log_control.log_entries[i].ldu_filep =
+ CONSOLE_OPEN("a+")) {
+ 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] == '=') {
+ if (log_control.log_entries[i].ldu_filep =
+ DEVICE_OPEN(&cp[7], "w")) {
+ 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_control.log_entries->lsu_facility = LOG_AUTH;
+ log_control.log_entries->lsu_severity = LOG_ERR;
+ log_control.log_nentries = 1;
+ }
+ if (log_control.log_nentries) {
+ if (log_control.log_whoami = (char *) malloc(strlen(whoami)+1))
+ strcpy(log_control.log_whoami, whoami);
+ if (log_control.log_hostname = (char *) malloc(MAXHOSTNAMELEN))
+ gethostname(log_control.log_hostname, MAXHOSTNAMELEN);
+#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(kcontext)
+ 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 char *
+severity2string(severity)
+ 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((char *) 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(priority, format, arglist)
+ 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[%d](%s): ",
+ log_control.log_hostname, log_control.log_whoami, 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 */
+
+ /*
+ * 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,
+ outbuf) < 0) {
+ /* Attempt to report error */
+ fprintf(stderr, log_file_err,
+ log_control.log_entries[lindex].lfu_fname);
+ }
+ else {
+ fprintf(log_control.log_entries[lindex].lfu_filep, "\n");
+ 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_entries[lindex].ldu_devname);
+ }
+ break;
+#ifdef HAVE_SYSLOG
+ case K_LOG_SYSLOG:
+ /*
+ * System log.
+ */
+
+ /* Log the message with our header trimmed off */
+ syslog(priority, syslogp);
+ break;
+#endif /* HAVE_SYSLOG */
+ default:
+ break;
+ }
+ }
+ return(0);
+}
+
+#ifdef HAVE_STDARG_H
+int
+krb5_klog_syslog(int priority, const char *format, ...)
+#else /* HAVE_STDARG_H */
+int
+krb5_klog_syslog(priority, format, va_alist)
+ int priority;
+ const char *format;
+ va_dcl
+#endif /* HAVE_STDARG_H */
+{
+ int retval;
+ va_list pvar;
+
+#ifdef HAVE_STDARG_H
+ va_start(pvar, format);
+#else /* HAVE_STDARG_H */
+ va_start(pvar);
+#endif /* HAVE_STDARG_H */
+ retval = klog_vsyslog(priority, format, pvar);
+ va_end(pvar);
+ return(retval);
+}
+#endif /* !defined(_MSDOS) */
diff --git a/src/lib/kadm5/misc_free.c b/src/lib/kadm5/misc_free.c
new file mode 100644
index 0000000000..cfe28a4117
--- /dev/null
+++ b/src/lib/kadm5/misc_free.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+#include <kadm5/admin.h>
+#include <malloc.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);
+}
+
+
+/* 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]);
+ }
+ }
+}
+
+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/src/lib/kadm5/ovsec_glue.c b/src/lib/kadm5/ovsec_glue.c
new file mode 100644
index 0000000000..6118282df3
--- /dev/null
+++ b/src/lib/kadm5/ovsec_glue.c
@@ -0,0 +1,188 @@
+#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,
+ void **server_handle)
+{
+ return kadm5_init_with_password(client_name, pass, service_name,
+ realm, struct_version, api_version,
+ 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,
+ void **server_handle)
+{
+ return kadm5_init_with_skey(client_name, keytab, service_name, realm,
+ struct_version, api_version,
+ 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,
+ void **server_handle)
+{
+ return kadm5_init(client_name, from_stash, service_name,
+ realm, struct_version, api_version,
+ 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)
+{
+ return kadm5_chpass_principal_util(server_handle, princ, new_pw,
+ ret_pw, msg_ret);
+}
+
+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/src/lib/kadm5/server_acl.c b/src/lib/kadm5/server_acl.c
new file mode 100644
index 0000000000..16a7f4e402
--- /dev/null
+++ b/src/lib/kadm5/server_acl.c
@@ -0,0 +1,511 @@
+/*
+ * kadmin/v5server/srv_acl.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. M.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 <sys/param.h>
+#include <gssapi/gssapi_generic.h>
+#include "k5-int.h"
+#include "server_acl.h"
+#include <kadm5/server_internal.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;
+} 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 },
+ { 'x', ACL_ALL_MASK },
+ { '*', ACL_ALL_MASK },
+ { '\0', 0 }
+};
+
+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\n";
+static const char *acl_op_bad_msg = "Unrecognized ACL operation '%c' in %s\n";
+static const char *acl_syn_err_msg = "%s: syntax error at line %d <%10s...>\n";
+static const char *acl_cantopen_msg = "\007cannot open ACL file";
+
+/*
+ * acl_get_line() - Get a line from the ACL file.
+ */
+static char *
+acl_get_line(fp, lnp)
+ FILE *fp;
+ int *lnp;
+{
+ int i, domore;
+ static char acl_buf[BUFSIZ];
+
+ for (domore = 1; domore && !feof(fp); ) {
+ /* Copy in the line */
+ for (i=0;
+ ((i<BUFSIZ) &&
+ (!feof(fp)) &&
+ ((acl_buf[i] = fgetc(fp)) != '\n'));
+ i++);
+
+ /* Check if we exceeded our buffer size */
+ if ((i == BUFSIZ) && (!feof(fp)) && (acl_buf[i] != '\n')) {
+ fprintf(stderr, acl_line2long_msg, acl_acl_file, *lnp);
+ while (fgetc(fp) != '\n');
+ }
+ acl_buf[i] = '\0';
+ if (acl_buf[0] == (char) EOF) /* ptooey */
+ acl_buf[0] = '\0';
+ else
+ (*lnp)++;
+ if ((acl_buf[0] != '#') && (acl_buf[0] != '\0'))
+ domore = 0;
+ }
+ if (domore || (strlen(acl_buf) == 0))
+ return((char *) NULL);
+ else
+ return(acl_buf);
+}
+
+/*
+ * acl_parse_line() - Parse the contents of an ACL line.
+ */
+static aent_t *
+acl_parse_line(lp)
+ char *lp;
+{
+ static char acle_principal[BUFSIZ];
+ static char acle_ops[BUFSIZ];
+ static char acle_object[BUFSIZ];
+ aent_t *acle;
+ char *op;
+ int t, found, opok, nmatch;
+
+ DPRINT(DEBUG_CALLS, acl_debug_level,
+ ("* acl_parse_line(line=%20s)\n", lp));
+ /*
+ * Format is very simple:
+ * entry ::= <whitespace> <principal> <whitespace> <opstring> <whitespace>
+ * [<target> <whitespace>]
+ */
+ acle = (aent_t *) NULL;
+ acle_object[0] = '\0';
+ nmatch = sscanf(lp, "%s %s %s", acle_principal, acle_ops, acle_object);
+ 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(*op)) ? tolower(*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) {
+ fprintf(stderr, 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;
+ }
+ }
+ }
+ DPRINT(DEBUG_CALLS, acl_debug_level,
+ ("X acl_parse_line() = %x\n", (long) acle));
+ return(acle);
+}
+
+/*
+ * acl_free_entries() - Free all ACL entries.
+ */
+static void
+acl_free_entries()
+{
+ aent_t *ap;
+ aent_t *np;
+
+ DPRINT(DEBUG_CALLS, acl_debug_level, ("* 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);
+ 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 acl_free_entries()\n"));
+}
+
+/*
+ * acl_load_acl_file() - Open and parse the ACL file.
+ */
+static int
+acl_load_acl_file()
+{
+char tmpbuf[10];
+ FILE *afp;
+ char *alinep;
+ aent_t **aentpp;
+ int alineno;
+ int retval = 1;
+
+ DPRINT(DEBUG_CALLS, acl_debug_level, ("* acl_load_acl_file()\n"));
+ /* Open the ACL file for read */
+ if (afp = fopen(acl_acl_file, "r")) {
+ alineno = 1;
+ aentpp = &acl_list_head;
+
+ /* Get a non-comment line */
+ while (alinep = acl_get_line(afp, &alineno)) {
+ /* Parse it */
+ *aentpp = acl_parse_line(alinep);
+ /* If syntax error, then fall out */
+ if (!*aentpp) {
+ fprintf(stderr, acl_syn_err_msg,
+ acl_acl_file, alineno, alinep);
+ retval = 0;
+ break;
+ }
+ acl_list_tail = *aentpp;
+ aentpp = &(*aentpp)->ae_next;
+ }
+
+ if (acl_catchall_entry) {
+ strcpy(tmpbuf, acl_catchall_entry);
+ if (*aentpp = acl_parse_line(tmpbuf)) {
+ acl_list_tail = *aentpp;
+ }
+ else {
+ retval = 0;
+ DPRINT(DEBUG_OPERATION, acl_debug_level,
+ ("> catchall acl entry (%s) load failed\n",
+ acl_catchall_entry));
+ }
+ fclose(afp);
+ }
+ }
+ else {
+ com_err(acl_acl_file, errno, acl_cantopen_msg);
+ if (acl_list_head = 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) {
+ acl_free_entries();
+ }
+ DPRINT(DEBUG_CALLS, acl_debug_level,
+ ("X acl_load_acl_file() = %d\n", retval));
+ return(retval);
+}
+
+/*
+ * acl_match_data() - See if two data entries match.
+ *
+ * Wildcarding is only supported for a whole component.
+ */
+static krb5_boolean
+acl_match_data(e1, e2)
+ krb5_data *e1, *e2;
+{
+ 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) ||
+ !strncmp(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);
+}
+
+/*
+ * acl_find_entry() - Find a matching entry.
+ */
+static aent_t *
+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;
+
+ DPRINT(DEBUG_CALLS, acl_debug_level, ("* acl_find_entry()\n"));
+ for (entry=acl_list_head; entry; entry = entry->ae_next) {
+ if (!strcmp(entry->ae_name, "*")) {
+ DPRINT(DEBUG_ACL, acl_debug_level, ("A wildcard ACL match\n"));
+ break;
+ }
+ 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,
+ ("A Bad ACL entry %s\n", entry->ae_name));
+ continue;
+ }
+ if (entry->ae_target &&
+ !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,
+ ("A Bad target in an ACL entry for %s\n", entry->ae_name));
+ entry->ae_name_bad = 1;
+ continue;
+ }
+ matchgood = 0;
+ if (acl_match_data(&entry->ae_principal->realm,
+ &principal->realm) &&
+ (entry->ae_principal->length == principal->length)) {
+ matchgood = 1;
+ for (i=0; i<principal->length; i++) {
+ if (!acl_match_data(&entry->ae_principal->data[i],
+ &principal->data[i])) {
+ matchgood = 0;
+ break;
+ }
+ }
+ }
+ if (!matchgood)
+ continue;
+
+ /* We've matched the principal. If we have a target, then try it */
+ if (entry->ae_target && entry->ae_target_princ && dest_princ) {
+ if (acl_match_data(&entry->ae_target_princ->realm,
+ &dest_princ->realm) &&
+ (entry->ae_target_princ->length == dest_princ->length)) {
+ for (i=0; i<dest_princ->length; i++) {
+ if (!acl_match_data(&entry->ae_target_princ->data[i],
+ &dest_princ->data[i])) {
+ matchgood = 0;
+ break;
+ }
+ }
+ }
+ else
+ matchgood = 0;
+ }
+
+ if (matchgood)
+ break;
+ }
+ DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_find_entry()=%x\n",entry));
+ return(entry);
+}
+
+/*
+ * acl_init() - Initialize ACL context.
+ */
+krb5_error_code
+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,
+ ("* acl_init(afile=%s)\n",
+ ((acl_file) ? acl_file : "(null)")));
+ acl_acl_file = (acl_file) ? acl_file : (char *) KRB5_DEFAULT_ADMIN_ACL;
+ acl_inited = acl_load_acl_file();
+
+ DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_init() = %d\n", kret));
+ return(kret);
+}
+
+/*
+ * acl_finish - Terminate ACL context.
+ */
+void
+acl_finish(kcontext, debug_level)
+ krb5_context kcontext;
+ int debug_level;
+{
+ DPRINT(DEBUG_CALLS, acl_debug_level, ("* acl_finish()\n"));
+ acl_free_entries();
+ DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_finish()\n"));
+}
+
+/*
+ * acl_op_permitted() - 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
+acl_check(kcontext, caller, opmask, principal)
+ krb5_context kcontext;
+ gss_name_t caller;
+ krb5_int32 opmask;
+ krb5_principal principal;
+{
+ 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;
+ if (aentry = acl_find_entry(kcontext, caller_princ, principal)) {
+ if ((aentry->ae_op_allowed & opmask) == opmask)
+ retval = 1;
+ }
+
+ 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)
+{
+ kadm5_server_handle_t handle = server_handle;
+
+ 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/src/lib/kadm5/server_acl.h b/src/lib/kadm5/server_acl.h
new file mode 100644
index 0000000000..9dfc8daba7
--- /dev/null
+++ b/src/lib/kadm5/server_acl.h
@@ -0,0 +1,81 @@
+/*
+ * kadmin/v5server/kadm5_defs.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. M.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_RENAME (ACL_ADD+ACL_DELETE)
+
+#define ACL_ALL_MASK (ACL_ADD | \
+ ACL_DELETE | \
+ ACL_MODIFY | \
+ ACL_CHANGEPW | \
+ ACL_INQUIRE | \
+ ACL_LIST)
+
+krb5_error_code acl_init
+ KRB5_PROTOTYPE((krb5_context,
+ int,
+ char *));
+void acl_finish
+ KRB5_PROTOTYPE((krb5_context,
+ int));
+krb5_boolean acl_check
+ KRB5_PROTOTYPE((krb5_context,
+ gss_name_t,
+ krb5_int32,
+ krb5_principal));
+
+#endif /* SERVER_ACL_H__ */
diff --git a/src/lib/kadm5/server_dict.c b/src/lib/kadm5/server_dict.c
new file mode 100644
index 0000000000..6c0bcef037
--- /dev/null
+++ b/src/lib/kadm5/server_dict.c
@@ -0,0 +1,199 @@
+/*
+ * 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 <kadm5/admin.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <malloc.h>
+#include <memory.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 int word_count = 0; /* number of words */
+extern int errno;
+
+/*
+ * 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(*(char **)s1, *(char **)s2));
+}
+
+/*
+ * Function: init-dict
+ *
+ * Purpose: Initialize in memory word dictionary
+ *
+ * Arguments:
+ * none
+ * <return value> KADM5_OK on sucsess 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)) {
+ 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) {
+ 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/src/lib/kadm5/server_handle.c b/src/lib/kadm5/server_handle.c
new file mode 100644
index 0000000000..53abe94dd2
--- /dev/null
+++ b/src/lib/kadm5/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/src/lib/kadm5/server_init.c b/src/lib/kadm5/server_init.c
new file mode 100644
index 0000000000..653f6d896e
--- /dev/null
+++ b/src/lib/kadm5/server_init.c
@@ -0,0 +1,330 @@
+/*
+ * 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 <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;
+}
+
+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,
+ void **server_handle)
+{
+ return kadm5_init(client_name, pass, service_name, params,
+ struct_version, api_version,
+ 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)
+{
+ /*
+ * 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,
+ 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,
+ 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,
+ 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,
+ 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));
+
+ if (ret = (int) krb5_init_context(&(handle->context))) {
+ free(handle);
+ return(ret);
+ }
+
+ initialize_ovk_error_table();
+ initialize_adb_error_table();
+ initialize_ovku_error_table();
+ krb5_init_ets(handle->context);
+
+ 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 *) &params_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 = &params_local;
+ }
+
+#define ILLEGAL_PARAMS (KADM5_CONFIG_ADMIN_SERVER)
+ if (params_in && (params_in->mask & ILLEGAL_PARAMS)) {
+ krb5_free_context(handle->context);
+ free(handle);
+ return KADM5_BAD_SERVER_PARAMS;
+ }
+
+ if (ret = kadm5_get_config_params(handle->context,
+ (char *) NULL,
+ (char *) NULL,
+ params_in,
+ &handle->params)) {
+ krb5_free_context(handle->context);
+ 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(handle);
+ return KRB5_CONFIG_BADFORMAT;
+ }
+
+ /*
+ * Set the db_name based on configuration before calling
+ * krb5_db_init, so it will get used.
+ */
+ if (ret = krb5_dbm_db_set_name(handle->context,
+ handle->params.dbname)) {
+ free(handle);
+ return(ret);
+ }
+
+ if (ret = krb5_db_init(handle->context)) {
+ krb5_free_context(handle->context);
+ 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(handle);
+ return ret;
+ }
+
+ if (! (handle->lhandle = malloc(sizeof(*handle)))) {
+ krb5_db_fini(handle->context);
+ krb5_free_context(handle->context);
+ 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 */
+ if (ret = check_handle((void *) 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".
+ */
+ if (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))
+ )) {
+ krb5_db_fini(handle->context);
+ krb5_free_context(handle->context);
+ free(handle);
+ return ret;
+ }
+
+ if ((ret = kdb_init_hist(handle, handle->params.realm))) {
+ krb5_db_fini(handle->context);
+ krb5_free_context(handle->context);
+ free(handle);
+ return ret;
+ }
+
+ if (ret = init_dict(&handle->params)) {
+ krb5_db_fini(handle->context);
+ krb5_free_principal(handle->context, handle->current_caller);
+ krb5_free_context(handle->context);
+ free(handle);
+ return ret;
+ }
+
+ if (ret = adb_policy_init(handle)) {
+ krb5_db_fini(handle->context);
+ krb5_free_principal(handle->context, handle->current_caller);
+ krb5_free_context(handle->context);
+ free(handle);
+ return ret;
+ }
+ handle->lhandle->policy_db = handle->policy_db;
+
+ *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);
+ krb5_free_context(handle->context);
+ handle->magic_number = 0;
+ free(handle->lhandle);
+ free(handle);
+
+ 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)) ||
+ /*
+ * Set the db_name based on configuration before calling
+ * krb5_db_init, so it will get used.
+ */
+ (ret = krb5_dbm_db_set_name(handle->context,
+ handle->params.dbname)) ||
+ (ret = krb5_db_init(handle->context)) ||
+ (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/src/lib/kadm5/server_internal.h b/src/lib/kadm5/server_internal.h
new file mode 100644
index 0000000000..415f6d7d7f
--- /dev/null
+++ b/src/lib/kadm5/server_internal.h
@@ -0,0 +1,103 @@
+/*
+ * 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__
+
+#include <memory.h>
+#include <malloc.h>
+#include "k5-int.h"
+#include <krb5/kdb.h>
+#include <kadm5/admin.h>
+#include "admin_internal.h"
+#include "adb.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;
+ osa_adb_policy_t policy_db;
+} kadm5_server_handle_rec, *kadm5_server_handle_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);
+
+int init_dict(kadm5_config_params *);
+int find_word(const char *word);
+void destroy_dict(void);
+
+/*
+ * *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)
+
+#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)
+
+#endif /* __KADM5_SERVER_INTERNAL_H__ */
diff --git a/src/lib/kadm5/server_kdb.c b/src/lib/kadm5/server_kdb.c
new file mode 100644
index 0000000000..1a900a380f
--- /dev/null
+++ b/src/lib/kadm5/server_kdb.c
@@ -0,0 +1,424 @@
+/*
+ * 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_encrypt_block master_encblock;
+krb5_keyblock master_keyblock;
+krb5_db_entry master_db;
+
+krb5_principal hist_princ;
+krb5_encrypt_block hist_encblock;
+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_keyblock tmk;
+
+ 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;
+
+ krb5_use_enctype(handle->context, &master_encblock,
+ master_keyblock.enctype);
+
+ if (ret = krb5_db_fetch_mkey(handle->context, master_princ,
+ &master_encblock, from_keyboard,
+ 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))
+ goto done;
+
+ if ((ret = krb5_db_init(handle->context)) != KSUCCESS)
+ goto done;
+
+ if ((ret = krb5_db_verify_master_key(handle->context, master_princ,
+ &master_keyblock,
+ &master_encblock))) {
+ krb5_db_fini(handle->context);
+ return ret;
+ }
+
+ /* the kdc gets the db mkvno here. The admin server never uses this
+ bit of information, so there's no reason to retrieve it. */
+
+ if ((ret = krb5_process_key(handle->context, &master_encblock,
+ &master_keyblock))) {
+ krb5_db_fini(handle->context);
+ goto done;
+ }
+
+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;
+
+ 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;
+
+ if (ret = kadm5_create_principal(handle, &ent,
+ (KADM5_PRINCIPAL |
+ KADM5_MAX_LIFE |
+ KADM5_ATTRIBUTES),
+ "to-be-random"))
+ goto done;
+
+ /* this won't let us randomize the hist_princ. So we cheat. */
+
+ hist_princ = NULL;
+
+ ret = kadm5_randkey_principal(handle, ent.principal, 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;
+
+ }
+
+ if (ret = krb5_dbe_find_enctype(handle->context,
+ &hist_db,
+ handle->params.enctype,
+ -1,
+ -1,
+ &key_data))
+ goto done;
+
+ if (ret = krb5_dbekd_decrypt_key_data(handle->context, &master_encblock,
+ key_data, &hist_key, NULL))
+ goto done;
+
+ krb5_use_enctype(handle->context, &hist_encblock, hist_key.enctype);
+
+ if ((ret = krb5_process_key(handle->context, &hist_encblock,
+ &hist_key)) != KSUCCESS)
+ 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;
+
+ if (ret = krb5_db_get_principal(handle->context, principal, kdb, &nprincs,
+ &more))
+ 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(OSA_ADB_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;
+
+ if (ret = krb5_timeofday(handle->context, &now))
+ return(ret);
+
+ if (ret = krb5_dbe_update_mod_princ_data(handle->context, kdb, now,
+ handle->current_caller))
+ return(ret);
+
+ xdralloc_create(&xdrs, XDR_ENCODE);
+ if(! xdr_osa_princ_ent_rec(&xdrs, adb)) {
+ xdr_destroy(&xdrs);
+ return(OSA_ADB_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;
+
+ if (ret = krb5_db_put_principal(handle->context, kdb, &one))
+ 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,
+ void (*iter_fct)(void *, krb5_principal), void *data)
+{
+ iter_data id;
+ krb5_error_code ret;
+
+ id.func = iter_fct;
+ id.data = data;
+
+ if (ret = krb5_db_iterate(handle->context, kdb_iter_func, &id))
+ return(ret);
+
+ return(0);
+}
+
+
diff --git a/src/lib/kadm5/server_misc.c b/src/lib/kadm5/server_misc.c
new file mode 100644
index 0000000000..24f101ce5a
--- /dev/null
+++ b/src/lib/kadm5/server_misc.c
@@ -0,0 +1,101 @@
+/*
+ * 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 "adb.h"
+
+/* for strcasecmp */
+#include <string.h>
+
+#include "server_internal.h"
+
+kadm5_ret_t
+adb_policy_init(kadm5_server_handle_t handle)
+{
+ osa_adb_ret_t ret;
+ if(handle->policy_db == (osa_adb_policy_t) NULL)
+ if((ret = osa_adb_open_policy(&handle->policy_db,
+ &handle->params)) != OSA_ADB_OK)
+ return ret;
+ return KADM5_OK;
+}
+
+kadm5_ret_t
+adb_policy_close(kadm5_server_handle_t handle)
+{
+ osa_adb_ret_t ret;
+ if(handle->policy_db != (osa_adb_policy_t) NULL)
+ if((ret = osa_adb_close_policy(handle->policy_db)) != OSA_ADB_OK)
+ return ret;
+ handle->policy_db = NULL;
+ return KADM5_OK;
+}
+
+/* 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;
+
+ if(use_policy) {
+ if(strlen(password) < pol->pw_min_length)
+ return KADM5_PASS_Q_TOOSHORT;
+ s = password;
+ while ((c = *s++)) {
+ if (islower(c)) {
+ nlower = 1;
+ continue;
+ }
+ else if (isupper(c)) {
+ nupper = 1;
+ continue;
+ } else if (isdigit(c)) {
+ ndigit = 1;
+ continue;
+ } else if (ispunct(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 {
+ char *cp;
+ int c, 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 (c = 0; c < n ; c++) {
+ cp = krb5_princ_component(handle->context, principal, c)->data;
+ if (strcasecmp(cp, password) == 0)
+ return KADM5_PASS_Q_DICT;
+ }
+ return KADM5_OK;
+ }
+ } else {
+ if (strlen(password) < 1)
+ return KADM5_PASS_Q_TOOSHORT;
+ }
+ return KADM5_OK;
+}
diff --git a/src/lib/kadm5/setenv.c b/src/lib/kadm5/setenv.c
new file mode 100644
index 0000000000..47904de1b5
--- /dev/null
+++ b/src/lib/kadm5/setenv.c
@@ -0,0 +1,163 @@
+/*
+ * 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>
+
+/*
+ * setenv --
+ * Set the value of the environmental variable "name" to be
+ * "value". If rewrite is set, replace any current value.
+ */
+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 !defined(sun) && !defined(hpux)
+ char *malloc(), *realloc();
+#endif
+ char *_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.
+ */
+
+/* based on @(#)getenv.c 5.5 (Berkeley) 6/27/88 */
+
+/*
+ * getenv --
+ * Returns ptr to value associated with name, if any, else NULL.
+ */
+char *
+getenv(name)
+ const char *name;
+{
+ int offset;
+ char *_findenv();
+
+ return(_findenv(name, &offset));
+}
+
+/*
+ * _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/src/lib/kadm5/str_conv.c b/src/lib/kadm5/str_conv.c
new file mode 100644
index 0000000000..8828929337
--- /dev/null
+++ b/src/lib/kadm5/str_conv.c
@@ -0,0 +1,397 @@
+/*
+ * 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. M.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"
+
+/*
+ * 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 */
+ if (*ksaltp = (krb5_key_salt_tuple *)
+ malloc((len + 1) * sizeof(krb5_key_salt_tuple))) {
+
+ /* 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;
+ }
+ 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_NPROTOTYPE((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)) {
+ if (kret = (*iterator)(&scratch, arg))
+ break;
+ }
+ }
+ return(kret);
+}
diff --git a/src/lib/kadm5/svr_chpass_util.c b/src/lib/kadm5/svr_chpass_util.c
new file mode 100644
index 0000000000..df2bf4c47b
--- /dev/null
+++ b/src/lib/kadm5/svr_chpass_util.c
@@ -0,0 +1,15 @@
+#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)
+{
+ 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);
+}
diff --git a/src/lib/kadm5/svr_iters.c b/src/lib/kadm5/svr_iters.c
new file mode 100644
index 0000000000..19c9000212
--- /dev/null
+++ b/src/lib/kadm5/svr_iters.c
@@ -0,0 +1,248 @@
+/*
+ * 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>
+#include "adb.h"
+#include <dyn.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;
+ DynObject matches;
+ 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, "@<realm>" 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 $
+ */
+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 ? (strlen(realm)+1) : 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++ = '@';
+ strcpy(p, realm);
+ p += strlen(realm);
+ }
+
+ *p++ = '$';
+ *p++ = '\0';
+ return KADM5_OK;
+}
+
+void get_either_iter(struct iter_data *data, char *name)
+{
+ if (
+#ifdef SOLARIS_REGEXPS
+ (step(name, data->expbuf) != 0)
+#endif
+#ifdef POSIX_REGEXPS
+ (regexec(&data->preg, name, 0, NULL, 0) == 0)
+#endif
+#ifdef BSD_REGEXPS
+ (re_exec(name) != 0)
+#endif
+ )
+ {
+ (void) DynAdd(data->matches, &name);
+ } else
+ free(name);
+}
+
+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);
+}
+
+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);
+}
+
+kadm5_ret_t kadm5_get_either(int princ,
+ void *server_handle,
+ char *exp,
+ char ***princs,
+ int *count)
+{
+ struct iter_data data;
+ char *msg, *regexp;
+ int 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,
+ &regexp)) != 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;
+ }
+
+ if ((data.matches = DynCreate(sizeof(char *), -4)) == NULL) {
+ free(regexp);
+ return ENOMEM;
+ }
+
+ if (princ) {
+ data.context = handle->context;
+ ret = kdb_iter_entry(handle, get_princs_iter, (void *) &data);
+ } else {
+ ret = osa_adb_iter_policy(handle->policy_db, get_pols_iter, (void *)&data);
+ }
+
+ if (ret != OSA_ADB_OK) {
+ free(regexp);
+ DynDestroy(data.matches);
+ return ret;
+ }
+
+ (*princs) = (char **) DynArray(data.matches);
+ *count = DynSize(data.matches);
+ DynRelease(data.matches);
+ free(regexp);
+ 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/src/lib/kadm5/svr_misc_free.c b/src/lib/kadm5/svr_misc_free.c
new file mode 100644
index 0000000000..5c76a1ebc5
--- /dev/null
+++ b/src/lib/kadm5/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 <malloc.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/src/lib/kadm5/svr_policy.c b/src/lib/kadm5/svr_policy.c
new file mode 100644
index 0000000000..74e2521157
--- /dev/null
+++ b/src/lib/kadm5/svr_policy.c
@@ -0,0 +1,315 @@
+/*
+ * 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 "adb.h"
+#include "server_internal.h"
+#include <stdlib.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 sucsessfull 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);
+
+ 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 sucsessfull 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
+ * sucsessfull.
+ *
+ */
+
+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 = osa_adb_create_policy(handle->policy_db, &pent)) == OSA_ADB_OK)
+ return KADM5_OK;
+ else
+ return ret;
+}
+
+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;
+
+ CHECK_HANDLE(server_handle);
+
+ if(name == (kadm5_policy_t) NULL)
+ return EINVAL;
+ if(strlen(name) == 0)
+ return KADM5_BAD_POLICY;
+ if ((ret = osa_adb_get_policy(handle->policy_db, name, &entry)) != OSA_ADB_OK)
+ return ret;
+ if(entry->policy_refcnt != 0) {
+ osa_free_policy_ent(entry);
+ return KADM5_POLICY_REF;
+ }
+ osa_free_policy_ent(entry);
+ if ((ret = osa_adb_destroy_policy(handle->policy_db, name)) == OSA_ADB_OK)
+ return KADM5_OK;
+ else
+ return ret;
+}
+
+kadm5_ret_t
+kadm5_modify_policy(void *server_handle,
+ kadm5_policy_ent_t entry, long mask)
+{
+ CHECK_HANDLE(server_handle);
+
+ 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;
+
+ 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;
+
+ switch ((ret = osa_adb_get_policy(handle->policy_db, entry->policy, &p))) {
+ case OSA_ADB_OK:
+ break;
+ case OSA_ADB_NOENT:
+ return KADM5_UNK_POLICY;
+ default:
+ break;
+ }
+ 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) {
+ osa_free_policy_ent(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) {
+ osa_free_policy_ent(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) {
+ osa_free_policy_ent(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) {
+ osa_free_policy_ent(p);
+ return KADM5_BAD_HISTORY;
+ }
+ p->pw_history_num = entry->pw_history_num;
+ }
+ if ((mask & KADM5_REF_COUNT))
+ p->policy_refcnt = entry->policy_refcnt;
+ switch ((ret = osa_adb_put_policy(handle->policy_db, p))) {
+ case OSA_ADB_OK:
+ ret = KADM5_OK;
+ break;
+ case OSA_ADB_NOENT: /* this should not happen here ... */
+ ret = KADM5_UNK_POLICY;
+ break;
+ }
+ osa_free_policy_ent(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;
+
+ CHECK_HANDLE(server_handle);
+
+ /*
+ * 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;
+ switch((ret = osa_adb_get_policy(handle->policy_db, name, &t))) {
+ case OSA_ADB_OK:
+ break;
+ case OSA_ADB_NOENT:
+ return KADM5_UNK_POLICY;
+ default:
+ return ret;
+ }
+ if ((entry->policy = (char *) malloc(strlen(t->name) + 1)) == NULL) {
+ osa_free_policy_ent(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;
+ osa_free_policy_ent(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);
+ osa_free_policy_ent(t);
+ return ENOMEM;
+ }
+ *new = *entry;
+ *entry_orig = new;
+ }
+
+ return KADM5_OK;
+}
diff --git a/src/lib/kadm5/svr_principal.c b/src/lib/kadm5/svr_principal.c
new file mode 100644
index 0000000000..6f9671fcfb
--- /dev/null
+++ b/src/lib/kadm5/svr_principal.c
@@ -0,0 +1,1350 @@
+/*
+ * 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 <kadm5/admin.h>
+#include "adb.h"
+#include "k5-int.h"
+#include <krb5/kdb.h>
+#include <stdio.h>
+#include <string.h>
+#include "server_internal.h"
+#include <stdarg.h>
+#include <stdlib.h>
+
+extern krb5_principal master_princ;
+extern krb5_principal hist_princ;
+extern krb5_encrypt_block master_encblock;
+extern krb5_encrypt_block hist_encblock;
+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);
+
+/*
+ * XXX Functions that ought to be in libkrb5.a, but aren't.
+ */
+int krb5_free_keyblock_contents(context, key)
+ krb5_context context;
+ krb5_keyblock *key;
+{
+ memset(key->contents, 0, key->length);
+ krb5_xfree(key->contents);
+ return 0;
+}
+
+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++) {
+ 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;
+}
+
+kadm5_ret_t
+kadm5_create_principal(void *server_handle,
+ kadm5_principal_ent_t entry, long mask,
+ 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);
+
+ /*
+ * 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)) {
+ if(!kdb.pw_expiration)
+ kdb.pw_expiration = entry->pw_expiration;
+ else {
+ if(entry->pw_expiration != 0)
+ kdb.pw_expiration = (entry->pw_expiration < kdb.pw_expiration) ?
+ entry->pw_expiration : kdb.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 = krb5_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_dbe_free_contents(handle->context, &kdb);
+ 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_encblock,
+ handle->params.keysalts,
+ handle->params.num_keysalts,
+ password,
+ (mask & KADM5_KVNO)?entry->kvno:1, &kdb)) {
+ krb5_dbe_free_contents(handle->context, &kdb);
+ 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_dbe_free_contents(handle->context, &kdb);
+ 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_next;
+ tl_data_tail = tl_data_tail->tl_data_next)
+ ;
+ tl_data_tail->tl_data_next = kdb.tl_data;
+ kdb.tl_data = entry->tl_data;
+ }
+
+ /* store the new db entry */
+ ret = kdb_put_entry(handle, &kdb, &adb);
+
+ if (mask & KADM5_TL_DATA) {
+ /* remove entry->tl_data from the front of kdb.tl_data */
+ tl_data_tail->tl_data_next = NULL;
+ kdb.tl_data = tl_data_orig;
+ }
+
+ krb5_dbe_free_contents(handle->context, &kdb);
+
+ 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);
+
+ 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, *tl_data_tail;
+ osa_princ_ent_rec adb;
+ kadm5_server_handle_t handle = server_handle;
+
+ CHECK_HANDLE(server_handle);
+
+ 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 (ret = kdb_get_entry(handle, entry->principal, &kdb, &adb))
+ return(ret);
+
+ /*
+ * This is pretty much the same as create ...
+ */
+
+ if ((mask & KADM5_POLICY)) {
+ ret = kadm5_get_policy(handle->lhandle, entry->policy, &npol);
+ switch(ret) {
+ case EINVAL:
+ ret = KADM5_BAD_POLICY;
+ break;
+ case KADM5_UNK_POLICY:
+ case KADM5_BAD_POLICY:
+ ret = KADM5_UNK_POLICY;
+ goto done;
+ break;
+ case KADM5_OK:
+ have_npol = 1;
+ if(adb.aux_attributes & KADM5_POLICY) {
+ 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++;
+ adb.aux_attributes |= KADM5_POLICY;
+ if (adb.policy)
+ free(adb.policy);
+ adb.policy = strdup(entry->policy);
+ if (npol.pw_max_life) {
+ if (ret =
+ krb5_dbe_lookup_last_pwd_change(handle->context, &kdb,
+ &(kdb.pw_expiration)))
+ goto done;
+ kdb.pw_expiration += npol.pw_max_life;
+ } else {
+ kdb.pw_expiration = 0;
+ }
+ break;
+ default:
+ goto done;
+ }
+ if ((mask & KADM5_PW_EXPIRATION)) {
+ if(kdb.pw_expiration == 0)
+ kdb.pw_expiration = entry->pw_expiration;
+ else if(entry->pw_expiration != 0)
+ kdb.pw_expiration = (entry->pw_expiration < kdb.pw_expiration) ?
+ entry->pw_expiration : kdb.pw_expiration;
+ }
+ }
+ if ((mask & KADM5_PW_EXPIRATION) && !(mask & KADM5_POLICY)) {
+ if(kdb.pw_expiration == 0)
+ kdb.pw_expiration = entry->pw_expiration;
+ else if(entry->pw_expiration != 0)
+ kdb.pw_expiration = (entry->pw_expiration < kdb.pw_expiration) ?
+ entry->pw_expiration : kdb.pw_expiration;
+ }
+
+ if ((mask & KADM5_POLICY_CLR)) {
+ if (adb.aux_attributes & KADM5_POLICY) {
+ adb.aux_attributes &= ~KADM5_POLICY;
+ kdb.pw_expiration = 0;
+ 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;
+ 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;
+ /* the pw_expiration logic would go here if it wasn't spread
+ all over the policy code */
+ 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) {
+ /* 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_next;
+ tl_data_tail = tl_data_tail->tl_data_next)
+ ;
+ tl_data_tail->tl_data_next = kdb.tl_data;
+ kdb.tl_data = entry->tl_data;
+ }
+
+ if ((ret = kdb_put_entry(handle, &kdb, &adb)))
+ goto done;
+
+ if (mask & KADM5_TL_DATA) {
+ /* remove entry->tl_data from the front of kdb.tl_data */
+ tl_data_tail->tl_data_next = NULL;
+ kdb.tl_data = tl_data_orig;
+ }
+
+ 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);
+
+ 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;
+ }
+ }
+
+ krb5_free_principal(handle->context, kdb.princ);
+ if (ret = krb5_copy_principal(handle->context, target, &kdb.princ)) {
+ 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;
+ osa_adb_ret_t 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);
+
+ /*
+ * 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)) {
+ if (ret = krb5_dbe_lookup_mod_princ_data(handle->context, &kdb,
+ &(entry->mod_date),
+ &(entry->mod_name))) {
+ 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 td, *tl, *tl2;
+
+ entry->n_tl_data = kdb.n_tl_data;
+ entry->tl_data = NULL;
+
+ tl = kdb.tl_data;
+ while (tl) {
+ if ((tl2 = dup_tl_data(tl)) == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ tl2->tl_data_next = entry->tl_data;
+ entry->tl_data = tl2;
+
+ tl = tl->tl_data_next;
+ }
+
+ if (kdb.e_length) {
+ td.tl_data_type = KRB5_TL_KADM5_E_DATA;
+ td.tl_data_length = kdb.e_length;
+ td.tl_data_contents = kdb.e_data;
+
+ if ((tl = dup_tl_data(&td)) == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ tl->tl_data_next = entry->tl_data;
+ entry->tl_data = tl;
+ }
+ }
+ if (mask & KADM5_KEY_DATA) {
+ entry->n_key_data = kdb.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;
+ }
+ for (i = 0; i < entry->n_key_data; i++)
+ if (ret = krb5_copy_key_data_contents(handle->context,
+ &kdb.key_data[i],
+ &entry->key_data[i]))
+ 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
+ * histkey_encblock (r) the encblock 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 histkey_encblock
+ * 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_encblock
+ * for each password in pw_hist_data:
+ * for each hist_key in password:
+ * decrypt hist_key with histkey_encblock
+ * 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_encrypt_block *histkey_encblock,
+ int n_new_key_data, krb5_key_data *new_key_data,
+ 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++) {
+ if (ret = krb5_dbekd_decrypt_key_data(context,
+ &master_encblock,
+ &(new_key_data[x]),
+ &newkey, NULL))
+ return(ret);
+ for (y = 0; y < n_pw_hist_data; y++) {
+ for (z = 0; z < pw_hist_data[y].n_key_data; z++) {
+ if (ret =
+ krb5_dbekd_decrypt_key_data(context,
+ histkey_encblock,
+ &pw_hist_data[y].key_data[z],
+ &histkey, NULL))
+ 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_encblock, re-encrypted
+ * in hist_encblock, and added to hist->key_data. hist->n_key_data is
+ * set to n_key_data.
+ */
+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++) {
+ if (ret = krb5_dbekd_decrypt_key_data(context,
+ &master_encblock,
+ &key_data[i],
+ &key, &salt))
+ return ret;
+ if (ret = krb5_dbekd_encrypt_key_data(context,
+ &hist_encblock,
+ &key, &salt,
+ key_data[i].key_data_kvno,
+ &hist->key_data[i]))
+ return ret;
+ krb5_free_keyblock_contents(context, &key);
+ /* krb5_free_keysalt(context, &salt); */
+ }
+
+ hist->n_key_data = n_key_data;
+ return 0;
+}
+
+int 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 hist, *histp;
+ int ret, i;
+
+ /* A history of 1 means just check the current password */
+ if (pol->pw_history_num == 1)
+ return 0;
+
+ /* resize the adb->old_keys array if necessary */
+ if (adb->old_key_len < pol->pw_history_num-1) {
+ adb->old_keys = (osa_pw_hist_ent *)
+ realloc(adb->old_keys,
+ (adb->old_key_len+1)*sizeof(osa_pw_hist_ent));
+ if (adb->old_keys == NULL)
+ return(ENOMEM);
+
+ memset(&adb->old_keys[adb->old_key_len],0,sizeof(osa_pw_hist_ent));
+ adb->old_key_len++;
+ }
+
+ /* free the old pw history entry if it contains data */
+ histp = &adb->old_keys[adb->old_key_next];
+ for (i = 0; i < histp->n_key_data; i++)
+ krb5_free_key_data_contents(context, &histp->key_data[i]);
+
+ /* store the new entry */
+ adb->old_keys[adb->old_key_next] = *pw;
+
+ /* update the next pointer */
+ if (++adb->old_key_next == pol->pw_history_num-1)
+ adb->old_key_next = 0;
+
+ return(0);
+}
+
+kadm5_ret_t
+kadm5_chpass_principal(void *server_handle,
+ krb5_principal principal, 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, i, hist_added;
+ int have_pol = 0;
+ kadm5_server_handle_t handle = server_handle;
+ osa_pw_hist_ent hist;
+
+ CHECK_HANDLE(server_handle);
+
+ 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;
+
+ if (ret = krb5_dbe_cpw(handle->context, &master_encblock,
+ handle->params.keysalts,
+ handle->params.num_keysalts,
+ password, 0 /* increment kvno */, &kdb))
+ goto done;
+
+ kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
+
+ if (ret = krb5_timeofday(handle->context, &now))
+ goto done;
+
+ if ((adb.aux_attributes & KADM5_POLICY)) {
+ /* the policy was loaded before */
+
+ if (ret = krb5_dbe_lookup_last_pwd_change(handle->context,
+ &kdb, &last_pwd))
+ 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 (ret = create_history_entry(handle->context,
+ kdb_save.n_key_data,
+ kdb_save.key_data, &hist))
+ goto done;
+
+ if (ret = check_pw_reuse(handle->context,
+ &hist_encblock,
+ kdb.n_key_data, kdb.key_data,
+ 1, &hist))
+ goto done;
+
+ 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_encblock,
+ kdb.n_key_data, kdb.key_data,
+ adb.old_key_len, adb.old_keys))
+ goto done;
+
+ if (ret = add_to_history(handle->context, &adb, &pol, &hist))
+ 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;
+ }
+
+ 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:
+ 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_dbe_free_contents(handle->context, &kdb);
+
+ 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)
+{
+ krb5_db_entry kdb;
+ osa_princ_ent_rec adb;
+ krb5_int32 now;
+ kadm5_policy_ent_rec pol;
+ krb5_key_data *key_data;
+ krb5_keyblock *keyblock;
+ int ret, last_pwd, have_pol = 0;
+ kadm5_server_handle_t handle = server_handle;
+
+ 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);
+
+ if (ret = krb5_dbe_crk(handle->context, &master_encblock,
+ handle->params.keysalts,
+ handle->params.num_keysalts,
+ &kdb))
+ goto done;
+
+ 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 (ret = krb5_dbe_lookup_last_pwd_change(handle->context,
+ &kdb, &last_pwd))
+ 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;
+ }
+
+ if (ret = check_pw_reuse(handle->context,
+ &hist_encblock,
+ kdb.n_key_data, kdb.key_data,
+ adb.old_key_len, adb.old_keys))
+ 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;
+ }
+
+ if (ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now))
+ goto done;
+
+ if (keyblocks) {
+ if (handle->api_version == KADM5_API_VERSION_1) {
+ /* Version 1 clients will expect to see a DES_CRC enctype. */
+ if (ret = krb5_dbe_find_enctype(handle->context, &kdb,
+ ENCTYPE_DES_CBC_CRC,
+ -1, -1, &key_data))
+ goto done;
+
+ if (ret = decrypt_key_data(handle->context, 1, key_data,
+ keyblocks, NULL))
+ 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;
+}
+
+/*
+ * 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_encblock, 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++) {
+ if (ret = krb5_dbekd_decrypt_key_data(context,
+ &master_encblock,
+ &key_data[i],
+ &keys[i], NULL)) {
+
+ 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_encblock, key_data,
+ keyblock, keysalt))
+ return ret;
+
+ if (kvnop)
+ *kvnop = key_data->key_data_kvno;
+
+ return KADM5_OK;
+}
diff --git a/src/lib/kadm5/unit-test/ChangeLog b/src/lib/kadm5/unit-test/ChangeLog
new file mode 100644
index 0000000000..172084c20f
--- /dev/null
+++ b/src/lib/kadm5/unit-test/ChangeLog
@@ -0,0 +1,18 @@
+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/src/lib/kadm5/unit-test/Makefile.ov b/src/lib/kadm5/unit-test/Makefile.ov
new file mode 100644
index 0000000000..208bedeb3c
--- /dev/null
+++ b/src/lib/kadm5/unit-test/Makefile.ov
@@ -0,0 +1,154 @@
+TOP = ../../../kadmin
+include $(TOP)/config.mk/template
+
+CFLAGS := $(CFLAGS) -DUSE_KADM5_API_VERSION=1
+
+LIBS := $(LIBADMCLNT) $(LIBCOM_ERR) $(LIBRPCLIB) $(LIBDYN) \
+ $(LIBGSSAPI_KRB5) $(LIBKDB5) \
+ $(LIBKRB5) $(LIBCRYPTO) $(LIBISODE) $(LIBTCL) $(LIBM) \
+ $(LIBDB) $(NDBMLIB) $(BSDLIB) $(NETLIB)
+
+INIT_SRCS = init-test.c ../client_init.c
+DESTROY_SRCS = destroy-test.c
+HANDLE_SRCS = handle-test.c
+RANDKEY_SRCS = randkey-test.c
+ITER_SRCS = iter-test.c
+LOCKTEST_SRCS = lock-test.c
+SIZE_SRCS = sizes-test.c
+
+PROG = init-test
+SRCS = $(INIT_SRCS)
+OBJS = init-test.o client_init.o
+
+client_init.o: ../client_init.c
+ $(CC) $(CFLAGS) -DUSE_KADM5_API_VERSION=2 -DINIT_TEST -c -I.. $<
+
+expand Program
+
+PROG = destroy-test
+SRCS = $(DESTROY_SRCS)
+OBJS = destroy-test.o
+
+expand Program
+
+PROG = client-handle-test
+SRCS = $(HANDLE_SRCS)
+OBJS = handle-test.o
+
+expand Program
+
+PROG = client-iter-test
+SRCS = $(ITER_SRCS)
+OBJS = iter-test.o
+
+expand Program
+
+LIBS := $(LIBADMSRV) $(LIBCOM_ERR) $(LIBRPCLIB) $(LIBDYN) \
+ $(LIBGSSAPI_KRB5) $(LIBKDB5) $(LIBKRB5) \
+ $(LIBCRYPTO) $(LIBISODE) $(LIBTCL) $(LIBM) $(LIBDB) \
+ $(NDBMLIB) $(BSDLIB) $(NETLIB)
+
+PROG = randkey-test
+SRCS = $(RANDKEY_SRCS)
+OBJS = randkey-test.o
+
+expand Program
+
+PROG = server-handle-test
+SRCS = $(HANDLE_SRCS)
+OBJS = handle-test.o
+
+expand Program
+
+PROG = lock-test
+SRCS = $(LOCKTEST_SRCS)
+OBJS = lock-test.o
+
+expand Program
+
+LIBS := $(LIBS) $(REGEXLIB)
+PROG = server-iter-test
+SRCS = $(ITER_SRCS)
+OBJS = iter-test.o
+
+expand Program
+
+PROG = sizes-test
+SRCS = $(SIZE_SRCS)
+OBJS = sizes-test.o
+
+expand Program
+
+SRCS = $(INIT_SRCS) $(DESTROY_SRCS) $(HANDLE_SRCS) \
+ $(RANDKEY_SRCS) $(LOCKTEST_SRCS) $(ITER_SRCS) \
+ $(SIZE_SRCS)
+
+expand Depend
+
+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
+ ./randkey-test
+
+test-handle-server:: server-handle-test
+ ./server-handle-test
+
+test-handle-client:: client-handle-test
+ ./client-handle-test
+
+test-noauth: init-test
+ ./init-test
+
+test-destroy: destroy-test
+ ./destroy-test
+
+test-sizes: sizes-test
+ ./sizes-test
+
+unit-test-client-setup::
+ $(START_SERVERS)
+
+unit-test-client-cleanup::
+ $(STOP_SERVERS)
+
+unit-test-server-setup::
+ $(START_SERVERS_LOCAL)
+
+unit-test-server-cleanup::
+ $(STOP_SERVERS_LOCAL)
+
+capi.0: api.0
+ -rm -f capi.0
+ ln -s api.0 capi.0
+
+capi.2: api.2
+ -rm -f capi.2
+ ln -s api.2 capi.2
+
+unit-test-client-body: capi.0 capi.2 site.exp test-noauth test-destroy test-handle-client test-sizes
+ $(RUNTEST) --tool capi API=$(CLNTTCL) KDBFIVE_EDIT=$(TOP)/../admin/edit/kdb5_edit KINIT=$(TOP)/../clients/kinit/kinit KDESTROY=$(TOP)/../clients/kdestroy/kdestroy KADMIN_LOCAL=$(TOP)/cli/kadmin.local TOP=$(TOP) RPC=1
+
+sapi.0: api.0
+ -rm -f sapi.0
+ ln -s api.0 sapi.0
+
+sapi.1: api.1
+ -rm -f sapi.1
+ ln -s api.1 sapi.1
+
+sapi.2: api.2
+ -rm -f sapi.2
+ ln -s api.2 sapi.2
+
+unit-test-server-body: sapi.0 sapi.1 sapi.2 site.exp randkey-test test-handle-server \
+ lock-test test-sizes
+ $(RUNTEST) --tool sapi API=$(SRVTCL) LOCKTEST=./lock-test KDBFIVE_EDIT=$(TOP)/../admin/edit/kdb5_edit KADMIN_LOCAL=$(TOP)/cli/kadmin.local TOP=$(TOP) RPC=0
+
+clean::
+ $(CLEAN) -r *.log *.plog *.sum *.psum unit-test-log.*
diff --git a/src/lib/kadm5/unit-test/api.0/chpass-principal.exp b/src/lib/kadm5/unit-test/api.0/chpass-principal.exp
new file mode 100644
index 0000000000..12fa3b9d16
--- /dev/null
+++ b/src/lib/kadm5/unit-test/api.0/chpass-principal.exp
@@ -0,0 +1,176 @@
+source 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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$test: unexpected failure in destroy"
+ return
+ }
+}
+test183
+
+return ""
diff --git a/src/lib/kadm5/unit-test/api.0/crte-policy.exp b/src/lib/kadm5/unit-test/api.0/crte-policy.exp
new file mode 100644
index 0000000000..dbf4f1cbc1
--- /dev/null
+++ b/src/lib/kadm5/unit-test/api.0/crte-policy.exp
@@ -0,0 +1,991 @@
+source 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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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/src/lib/kadm5/unit-test/api.0/crte-principal.exp b/src/lib/kadm5/unit-test/api.0/crte-principal.exp
new file mode 100644
index 0000000000..12c300793a
--- /dev/null
+++ b/src/lib/kadm5/unit-test/api.0/crte-principal.exp
@@ -0,0 +1,1330 @@
+source 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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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 { [expr "$mod_date + $pw_max_life - $pw_expire"] > 5 } {
+ fail "$test: pw_expire is wrong"
+ return
+ }
+ if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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 { [expr "$mod_date + $pw_max_life - $pw_expire"] > 5 } {
+ fail "$test: pw_expire is wrong"
+ return
+ }
+ if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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/src/lib/kadm5/unit-test/api.0/destroy.exp b/src/lib/kadm5/unit-test/api.0/destroy.exp
new file mode 100644
index 0000000000..31b8447861
--- /dev/null
+++ b/src/lib/kadm5/unit-test/api.0/destroy.exp
@@ -0,0 +1,203 @@
+source 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
+ }]} {
+ error "$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
+# }]} {
+# error "$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
+# }]} {
+# error "$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
+# }]} {
+# error "$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
+# }]} {
+# error "$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
+ }]} {
+ error "$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/src/lib/kadm5/unit-test/api.0/dlte-policy.exp b/src/lib/kadm5/unit-test/api.0/dlte-policy.exp
new file mode 100644
index 0000000000..7f349b02cd
--- /dev/null
+++ b/src/lib/kadm5/unit-test/api.0/dlte-policy.exp
@@ -0,0 +1,207 @@
+source 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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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/src/lib/kadm5/unit-test/api.0/dlte-principal.exp b/src/lib/kadm5/unit-test/api.0/dlte-principal.exp
new file mode 100644
index 0000000000..bb52301df3
--- /dev/null
+++ b/src/lib/kadm5/unit-test/api.0/dlte-principal.exp
@@ -0,0 +1,329 @@
+source 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
+ }]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$test: unexpected failure in init"
+ return
+ }
+ if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol p1}]} {
+ error "$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}]} {
+ error "$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}]} {
+ error "$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/src/lib/kadm5/unit-test/api.0/get-policy.exp b/src/lib/kadm5/unit-test/api.0/get-policy.exp
new file mode 100644
index 0000000000..329e7886ab
--- /dev/null
+++ b/src/lib/kadm5/unit-test/api.0/get-policy.exp
@@ -0,0 +1,199 @@
+source 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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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/src/lib/kadm5/unit-test/api.0/get-principal.exp b/src/lib/kadm5/unit-test/api.0/get-principal.exp
new file mode 100644
index 0000000000..05937055eb
--- /dev/null
+++ b/src/lib/kadm5/unit-test/api.0/get-principal.exp
@@ -0,0 +1,346 @@
+source 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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+
+ error "$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
+ }]} {
+ error "$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}]} {
+
+ error "$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
+ }]} {
+ error "$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}]} {
+
+ error "$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
+ }]} {
+ error "$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}]} {
+
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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/src/lib/kadm5/unit-test/api.0/init.exp b/src/lib/kadm5/unit-test/api.0/init.exp
new file mode 100644
index 0000000000..5df5dcfc94
--- /dev/null
+++ b/src/lib/kadm5/unit-test/api.0/init.exp
@@ -0,0 +1,727 @@
+source 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 {
+ {Enter password:} { }
+ 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 {
+ {Enter password:} { }
+ -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 {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 ":$" { 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 ":$" { 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 succsess"
+ 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 kdb5_edit env
+
+ spawn $kdb5_edit -R "del $service"
+ expect {
+ {Type 'yes' to confirm:} {
+ send "yes\n"
+ }
+ default {
+ error "kdb5_edit del 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
+ exec $kdb5_edit -R "ark $service"
+
+ # 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 /krb5/ovsec_adm.srvtab
+ exec $env(MAKE_KEYTAB) -princ ovsec_adm/admin -princ ovsec_adm/changepw \
+ -princ kadmin/admin -princ kadmin/changepw /krb5/ovsec_adm.srvtab
+}
+
+return ""
+
diff --git a/src/lib/kadm5/unit-test/api.0/mod-policy.exp b/src/lib/kadm5/unit-test/api.0/mod-policy.exp
new file mode 100644
index 0000000000..67f8457b6a
--- /dev/null
+++ b/src/lib/kadm5/unit-test/api.0/mod-policy.exp
@@ -0,0 +1,703 @@
+source 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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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/src/lib/kadm5/unit-test/api.0/mod-principal.exp b/src/lib/kadm5/unit-test/api.0/mod-principal.exp
new file mode 100644
index 0000000000..c4bc2bed18
--- /dev/null
+++ b/src/lib/kadm5/unit-test/api.0/mod-principal.exp
@@ -0,0 +1,1942 @@
+source 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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$test: unexpected failure in init"
+ return
+ }
+ if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol p1}]} {
+ error "$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}]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$test: unexpected failure in init"
+ return
+ }
+ if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol p1}]} {
+ error "$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}]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$test: unexpected failure in init"
+ return
+ }
+ if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol p1}]} {
+ error "$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]]} {
+ error "$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}]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$test: unexpected failure in init"
+ return
+ }
+ if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol old_p1}]} {
+ error "$test: unexpected failure on get policy"
+ return
+ }
+ if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol-nopw old_p2}]} {
+ error "$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}]} {
+ error "$test: unexpected failure on get policy"
+ return
+ }
+ if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol-nopw new_p2}]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$test: unexpected failure in init"
+ return
+ }
+ if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol old_p1}]} {
+ error "$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}]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$test: unexpected failure in destroy"
+ return
+ }
+}
+test23
+
+test "modify-principal 24"
+proc test24 {} {
+ 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
+ }]} {
+ 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 { [expr "$pw_mod_date + $pw_max_life"] != $pw_expire } {
+ fail "$test: pw_expire is wrong"
+ return
+ }
+ if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$test: unexpected failure in init"
+ return
+ }
+ if { ! [cmd [format {
+ ovsec_kadm_modify_principal $server_handle \
+ {"%s/a" 0 0 900 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 { [expr "$pw_mod_date + $pw_max_life"] == $pw_expire } {
+ fail "$test: pw_expire is wrong"
+ return
+ }
+ pass "$test"
+ if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+ error "$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])} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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])} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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"])} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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"])} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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"])} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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"])} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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"])} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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"])} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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"])} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$test: unexpected failure in init"
+ return
+ }
+ if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol pol}]} {
+ error "$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}]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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"])} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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"])} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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/src/lib/kadm5/unit-test/api.0/randkey-principal.exp b/src/lib/kadm5/unit-test/api.0/randkey-principal.exp
new file mode 100644
index 0000000000..259cd8f031
--- /dev/null
+++ b/src/lib/kadm5/unit-test/api.0/randkey-principal.exp
@@ -0,0 +1,319 @@
+source 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]]} {
+ error "$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}]} {
+ error "$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]]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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]]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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]]} {
+ error "$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}]} {
+ error "$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]]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$test: unexpected failure in destroy"
+ return
+ }
+}
+
+test33
+
+return ""
diff --git a/src/lib/kadm5/unit-test/api.0/rename-principal.exp b/src/lib/kadm5/unit-test/api.0/rename-principal.exp
new file mode 100644
index 0000000000..56e4129552
--- /dev/null
+++ b/src/lib/kadm5/unit-test/api.0/rename-principal.exp
@@ -0,0 +1,509 @@
+source 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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$test: unexpected failure in destroy"
+ return
+ }
+}
+test18
+
+return ""
diff --git a/src/lib/kadm5/unit-test/api.1/lock.exp b/src/lib/kadm5/unit-test/api.1/lock.exp
new file mode 100644
index 0000000000..67ab80060d
--- /dev/null
+++ b/src/lib/kadm5/unit-test/api.1/lock.exp
@@ -0,0 +1,242 @@
+# 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.
+
+source lib.t
+
+if { $RPC } {
+ return
+}
+
+set locktest $LOCKTEST
+set lockfile "/krb5/ovsec_adm.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
+
+ 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 }
+ }
+
+ 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 {}
+}
+
+lock_test 1 [list \
+ [list shared "shared"] \
+ [list release "released"] \
+ [list eof 0]]
+
+lock_test 2 [list \
+ [list exclusive exclusive] \
+ [list release released] \
+ [list eof 0]]
+
+lock_test 3 [list \
+ [list permanent permanent] \
+ [list release released] \
+ [list eof 0]]
+
+lock_test 4 [list \
+ [list release "Database not locked"] \
+ [list eof 0]]
+
+set lock5 [lock_test_start 5 [list \
+ [list shared shared] \
+ [list wait ""] \
+ [list eof 0]]]
+lock_test 5.1 [list \
+ [list shared shared] \
+ [list eof 0]]
+eval lock_test_continue $lock5
+
+set lock6 [lock_test_start 6 [list \
+ [list exclusive exclusive] \
+ [list wait ""] \
+ [list eof 0]]]
+lock_test 6.1 [list \
+ [list shared "Cannot lock database"] \
+ [list eof 0]]
+eval lock_test_continue $lock6
+
+set lock7 [lock_test_start 7 [list \
+ [list shared shared] \
+ [list wait ""] \
+ [list eof 0]]]
+lock_test 7.1 [list \
+ [list exclusive "Cannot lock database"] \
+ [list eof 0]]
+eval lock_test_continue $lock7
+
+set lock8 [lock_test_start 8 [list \
+ [list permanent permanent] \
+ [list wait ""] \
+ [list release "released" ] \
+ [list eof 0]]]
+lock_test 8.1 [list \
+ [list "" "administration database lock file missing while opening database" ] \
+ [list eof 1]]
+eval lock_test_continue $lock8
+
+set lock9 [lock_test_start 9 [list \
+ [list wait ""] \
+ [list exclusive "database lock file missing while getting exclusive"] \
+ [list eof 0]]]
+set lock9_1 [lock_test_start 9.1 [list \
+ [list permanent permanent] \
+ [list wait ""] \
+ [list release released] \
+ [list eof 0]]]
+eval lock_test_continue $lock9
+eval lock_test_continue $lock9_1
+
+if {! [file exists $lockfile]} {
+ error "lock file missing before test 10"
+}
+set lock10 [lock_test_start 10 [list \
+ [list permanent permanent] \
+ [list wait ""] \
+ [list release released] \
+ [list eof 0]]]
+if {[file exists $lockfile]} {
+ fail "test 10: lock file exists"
+}
+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]]]
+lock_test 12.1 [list \
+ [list "get test-pol" retrieved] \
+ [list eof 0]]
+eval lock_test_continue $lock12
+
+# This test doesn't work yet, somehow I or expect am confused about
+# the spawn_id's between the lock-test and api.
+warning "test 13: doesn't work, bug in unit-test"
+# set lock13 [lock_test_start 13 [list \
+# [list "get lock13" "Principal or policy does not exist"] \
+# [list wait ""] \
+# [list "get lock13" retrieved] \
+# [list eof 0]]]
+# create_policy lock13
+# eval lock_test_continue $lock13
+# delete_policy lock13
diff --git a/src/lib/kadm5/unit-test/api.2/chpass-principal-v2.exp b/src/lib/kadm5/unit-test/api.2/chpass-principal-v2.exp
new file mode 100644
index 0000000000..88aed8bca9
--- /dev/null
+++ b/src/lib/kadm5/unit-test/api.2/chpass-principal-v2.exp
@@ -0,0 +1,68 @@
+source 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
+ }]]} {
+ error "$test: unexpected failure in init"
+ return
+ }
+ if {! [cmd [format {
+ kadm5_chpass_principal $server_handle "%s/a" newpassword
+ } $test]]} {
+ error "$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]]} {
+ error "$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 == 2} {
+ pass "$test"
+ } else {
+ fail "$test: $num_keys keys, should be 2"
+ }
+ if { ! [cmd {kadm5_destroy $server_handle}]} {
+ error "$test: unexpected failure in destroy"
+ return
+ }
+}
+test200
+
+return ""
diff --git a/src/lib/kadm5/unit-test/api.2/chpass-principal.exp b/src/lib/kadm5/unit-test/api.2/chpass-principal.exp
new file mode 100644
index 0000000000..3efdfa9b90
--- /dev/null
+++ b/src/lib/kadm5/unit-test/api.2/chpass-principal.exp
@@ -0,0 +1,176 @@
+source 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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$test: unexpected failure in destroy"
+ return
+ }
+}
+test183
+
+return ""
diff --git a/src/lib/kadm5/unit-test/api.2/crte-policy.exp b/src/lib/kadm5/unit-test/api.2/crte-policy.exp
new file mode 100644
index 0000000000..b0ea04630d
--- /dev/null
+++ b/src/lib/kadm5/unit-test/api.2/crte-policy.exp
@@ -0,0 +1,991 @@
+source 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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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/src/lib/kadm5/unit-test/api.2/crte-principal.exp b/src/lib/kadm5/unit-test/api.2/crte-principal.exp
new file mode 100644
index 0000000000..653d1222a8
--- /dev/null
+++ b/src/lib/kadm5/unit-test/api.2/crte-principal.exp
@@ -0,0 +1,1330 @@
+source 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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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 { [expr "$mod_date + $pw_max_life - $pw_expire"] > 5 } {
+ fail "$test: pw_expire is wrong"
+ return
+ }
+ if { ! [cmd {kadm5_destroy $server_handle}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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 { [expr "$mod_date + $pw_max_life - $pw_expire"] > 5 } {
+ fail "$test: pw_expire is wrong"
+ return
+ }
+ if { ! [cmd {kadm5_destroy $server_handle}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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/src/lib/kadm5/unit-test/api.2/destroy.exp b/src/lib/kadm5/unit-test/api.2/destroy.exp
new file mode 100644
index 0000000000..808f0b401c
--- /dev/null
+++ b/src/lib/kadm5/unit-test/api.2/destroy.exp
@@ -0,0 +1,203 @@
+source 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
+ }]} {
+ error "$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
+# }]} {
+# error "$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
+# }]} {
+# error "$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
+# }]} {
+# error "$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
+# }]} {
+# error "$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
+ }]} {
+ error "$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/src/lib/kadm5/unit-test/api.2/dlte-policy.exp b/src/lib/kadm5/unit-test/api.2/dlte-policy.exp
new file mode 100644
index 0000000000..95a57dc201
--- /dev/null
+++ b/src/lib/kadm5/unit-test/api.2/dlte-policy.exp
@@ -0,0 +1,207 @@
+source 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
+ }]} {
+ error "$test: unexpected failure in init"
+ return
+ }
+ one_line_fail_test \
+ {kadm5_delete_policy $server_handle ""} "BAD_POL"
+ if { ! [cmd {kadm5_destroy $server_handle}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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/src/lib/kadm5/unit-test/api.2/dlte-principal.exp b/src/lib/kadm5/unit-test/api.2/dlte-principal.exp
new file mode 100644
index 0000000000..fe157e880b
--- /dev/null
+++ b/src/lib/kadm5/unit-test/api.2/dlte-principal.exp
@@ -0,0 +1,329 @@
+source 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
+ }]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$test: unexpected failure in init"
+ return
+ }
+ if { ! [cmd {kadm5_get_policy $server_handle test-pol p1}]} {
+ error "$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}]} {
+ error "$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}]} {
+ error "$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/src/lib/kadm5/unit-test/api.2/get-policy.exp b/src/lib/kadm5/unit-test/api.2/get-policy.exp
new file mode 100644
index 0000000000..ff41c17b9b
--- /dev/null
+++ b/src/lib/kadm5/unit-test/api.2/get-policy.exp
@@ -0,0 +1,199 @@
+source 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
+ }]} {
+ error "$test: unexpected failure in init"
+ return
+ }
+ one_line_fail_test {kadm5_get_policy $server_handle "" p} "BAD_POLICY"
+ if { ! [cmd {kadm5_destroy $server_handle}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$test: unexpected failure in init"
+ return
+ }
+ one_line_succeed_test {kadm5_get_policy $server_handle test-pol p}
+ if { ! [cmd {kadm5_destroy $server_handle}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$test: unexpected failure in init"
+ return
+ }
+ one_line_succeed_test {kadm5_get_policy $server_handle test-pol p}
+ if { ! [cmd {kadm5_destroy $server_handle}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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/src/lib/kadm5/unit-test/api.2/get-principal-v2.exp b/src/lib/kadm5/unit-test/api.2/get-principal-v2.exp
new file mode 100644
index 0000000000..486d1a6ab3
--- /dev/null
+++ b/src/lib/kadm5/unit-test/api.2/get-principal-v2.exp
@@ -0,0 +1,234 @@
+source 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
+ }]} {
+ error "$test: unexpected failure in init"
+ return
+ }
+ if {! [cmd {
+ kadm5_get_principal $server_handle testuser p \
+ {KADM5_PRINCIPAL_NORMAL_MASK}
+ }]} {
+ error "$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 {}"
+ set failed 1
+ }
+ if {$failed == 0} {
+ pass "$test"
+ }
+
+ if { ! [cmd {kadm5_destroy $server_handle}]} {
+ error "$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
+ }]} {
+ error "$test: unexpected failure in init"
+ return
+ }
+ if {! [cmd {
+ kadm5_get_principal $server_handle testuser p \
+ {KADM5_PRINCIPAL_NORMAL_MASK KADM5_KEY_DATA}
+ }]} {
+ error "$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 != 2} {
+ fail "$test: num_keys $num_keys should be 2"
+ 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}]} {
+ error "$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 {! [cmd {
+ kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+ $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+ server_handle
+ }]} {
+ error "$test: unexpected failure in init"
+ return
+ }
+ if {! [cmd {
+ kadm5_get_principal $server_handle testuser p \
+ {KADM5_PRINCIPAL_NORMAL_MASK KADM5_TL_DATA}
+ }]} {
+ error "$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 == {}} {
+ fail "$test: tl_data $tl_data should not be {}"
+ } else {
+ pass "$test"
+ }
+
+ if { ! [cmd {kadm5_destroy $server_handle}]} {
+ error "$test: unexpected failure in destroy"
+ return
+ }
+}
+test103
+
+return ""
+
+
+
+
diff --git a/src/lib/kadm5/unit-test/api.2/get-principal.exp b/src/lib/kadm5/unit-test/api.2/get-principal.exp
new file mode 100644
index 0000000000..4f91b33bb2
--- /dev/null
+++ b/src/lib/kadm5/unit-test/api.2/get-principal.exp
@@ -0,0 +1,346 @@
+source 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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+
+ error "$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
+ }]} {
+ error "$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}]} {
+
+ error "$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
+ }]} {
+ error "$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}]} {
+
+ error "$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
+ }]} {
+ error "$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}]} {
+
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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/src/lib/kadm5/unit-test/api.2/init-v2.exp b/src/lib/kadm5/unit-test/api.2/init-v2.exp
new file mode 100644
index 0000000000..5de25d6fe0
--- /dev/null
+++ b/src/lib/kadm5/unit-test/api.2/init-v2.exp
@@ -0,0 +1,545 @@
+source lib.t
+
+api_exit
+api_start
+
+test "init 100"
+proc test100 {} {
+ global 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
+ } "ENOENT"
+}
+test100
+
+test "init 101"
+proc test101 {} {
+ global test
+
+ # 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} {localhost 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} {localhost 1}] \
+ $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
+ } "CONFIG_BADFORMAT"
+}
+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
+
+test "init 104"
+proc test104 {} {
+ global test
+
+ # This is slightly lame, but it works: if CONFIG_ADBNAME is obeyed,
+ # then the lock file will be set based on it, and it won't exist.
+ 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
+ } "NOLOCKFILE"
+}
+if {! $RPC} test104
+
+test "init 105"
+proc test105 {} {
+ global test
+
+ # The lock info is stored in a static structure so that it applies
+ # to all handles in the process (why?). We need to restart the api
+ # in order to ensure we are using the new lockfile.
+ api_exit
+ api_start
+
+ one_line_fail_test {
+ kadm5_init admin admin $KADM5_ADMIN_SERVICE \
+ [config_params {KADM5_CONFIG_ADB_LOCKFILE} /does-not-exist] \
+ $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+ server_handle
+ } "NOLOCKFILE"
+
+ api_exit
+ api_start
+}
+if {! $RPC} test105
+
+test "init 106"
+proc test106 {} {
+ global test prompt
+
+ 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 ":$" { 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"
+ 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}]} {
+ error "$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
+
+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
+
+ set env(KRB5CCNAME) /tmp/krb5cc_kadm5_init_v2
+ 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
+
+ set env(KRB5CCNAME) /tmp/krb5cc_kadm5_init_v2
+ 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
+ } "GSS_ERROR"
+}
+if {$RPC} test152
+
+test "init 153"
+proc test153 {} {
+ global test KADM5_ADMIN_SERVICE
+
+ set env(KRB5CCNAME) /tmp/krb5cc_kadm5_init_v2
+ 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
+ } "GSS_ERROR"
+}
+if {$RPC} test153
+
+return ""
diff --git a/src/lib/kadm5/unit-test/api.2/init.exp b/src/lib/kadm5/unit-test/api.2/init.exp
new file mode 100644
index 0000000000..97a99e0baa
--- /dev/null
+++ b/src/lib/kadm5/unit-test/api.2/init.exp
@@ -0,0 +1,731 @@
+source 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 {
+ {Enter password:} { }
+ 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 {
+ {Enter password:} { }
+ -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 succsess"
+ 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 kdb5_edit env
+
+ spawn $kdb5_edit -R "del $service"
+ expect {
+ {Type 'yes' to confirm:} {
+ send "yes\n"
+ }
+ default {
+ error "kdb5_edit del 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
+ exec $kdb5_edit -R "ark $service"
+
+ # 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 /krb5/ovsec_adm.srvtab
+ exec $env(MAKE_KEYTAB) -princ ovsec_adm/admin -princ ovsec_adm/changepw \
+ -princ kadmin/admin -princ kadmin/changepw /krb5/ovsec_adm.srvtab
+}
+
+return ""
+
diff --git a/src/lib/kadm5/unit-test/api.2/mod-policy.exp b/src/lib/kadm5/unit-test/api.2/mod-policy.exp
new file mode 100644
index 0000000000..07e2e62dbf
--- /dev/null
+++ b/src/lib/kadm5/unit-test/api.2/mod-policy.exp
@@ -0,0 +1,703 @@
+source 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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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/src/lib/kadm5/unit-test/api.2/mod-principal.exp b/src/lib/kadm5/unit-test/api.2/mod-principal.exp
new file mode 100644
index 0000000000..5e24e08b02
--- /dev/null
+++ b/src/lib/kadm5/unit-test/api.2/mod-principal.exp
@@ -0,0 +1,1942 @@
+source 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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$test: unexpected failure in init"
+ return
+ }
+ if { ! [cmd {kadm5_get_policy $server_handle test-pol p1}]} {
+ error "$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}]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$test: unexpected failure in init"
+ return
+ }
+ if { ! [cmd {kadm5_get_policy $server_handle test-pol p1}]} {
+ error "$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}]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$test: unexpected failure in init"
+ return
+ }
+ if { ! [cmd {kadm5_get_policy $server_handle test-pol p1}]} {
+ error "$test: unexpected failure on get policy"
+ return
+ }
+ if {! [cmd [format {
+ kadm5_modify_principal $server_handle [simple_principal "%s/a"] \
+ {KADM5_POLICY_CLR}
+ } $test]]} {
+ error "$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}]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$test: unexpected failure in init"
+ return
+ }
+ if { ! [cmd {kadm5_get_policy $server_handle test-pol old_p1}]} {
+ error "$test: unexpected failure on get policy"
+ return
+ }
+ if { ! [cmd {kadm5_get_policy $server_handle test-pol-nopw old_p2}]} {
+ error "$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}]} {
+ error "$test: unexpected failure on get policy"
+ return
+ }
+ if { ! [cmd {kadm5_get_policy $server_handle test-pol-nopw new_p2}]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$test: unexpected failure in init"
+ return
+ }
+ if { ! [cmd {kadm5_get_policy $server_handle test-pol old_p1}]} {
+ error "$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}]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$test: unexpected failure in destroy"
+ return
+ }
+}
+test23
+
+test "modify-principal 24"
+proc test24 {} {
+ 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
+ }]} {
+ 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 { [expr "$pw_mod_date + $pw_max_life"] != $pw_expire } {
+ fail "$test: pw_expire is wrong"
+ return
+ }
+ if { ! [cmd {kadm5_destroy $server_handle}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$test: unexpected failure in init"
+ return
+ }
+ if { ! [cmd [format {
+ kadm5_modify_principal $server_handle \
+ {"%s/a" 0 0 900 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 { [expr "$pw_mod_date + $pw_max_life"] == $pw_expire } {
+ fail "$test: pw_expire is wrong"
+ return
+ }
+ pass "$test"
+ if { ! [cmd {kadm5_destroy $server_handle}]} {
+ error "$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])} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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])} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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"])} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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"])} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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"])} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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"])} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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"])} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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"])} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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"])} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$test: unexpected failure in init"
+ return
+ }
+ if { ! [cmd {kadm5_get_policy $server_handle test-pol pol}]} {
+ error "$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}]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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"])} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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"])} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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/src/lib/kadm5/unit-test/api.2/randkey-principal-v2.exp b/src/lib/kadm5/unit-test/api.2/randkey-principal-v2.exp
new file mode 100644
index 0000000000..c3dfd18df5
--- /dev/null
+++ b/src/lib/kadm5/unit-test/api.2/randkey-principal-v2.exp
@@ -0,0 +1,62 @@
+source 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
+ }]]} {
+ error "$test: unexpected failure in init"
+ return
+ }
+ if {! [cmd [format {
+ kadm5_randkey_principal $server_handle "%s/a" keys num_keys
+ } $test]]} {
+ error "$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 == 1} {
+ pass "$test"
+ } else {
+ fail "$test: $num_keys keys, should be 1"
+ }
+ if { ! [cmd {kadm5_destroy $server_handle}]} {
+ error "$test: unexpected failure in destroy"
+ return
+ }
+}
+test100
+
+return ""
diff --git a/src/lib/kadm5/unit-test/api.2/randkey-principal.exp b/src/lib/kadm5/unit-test/api.2/randkey-principal.exp
new file mode 100644
index 0000000000..d693a2ac1e
--- /dev/null
+++ b/src/lib/kadm5/unit-test/api.2/randkey-principal.exp
@@ -0,0 +1,319 @@
+source 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]]} {
+ error "$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}]} {
+ error "$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]]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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]]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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]]} {
+ error "$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}]} {
+ error "$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]]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$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
+ }]} {
+ error "$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}]} {
+ error "$test: unexpected failure in destroy"
+ return
+ }
+}
+
+test33
+
+return ""
diff --git a/src/lib/kadm5/unit-test/config/unix.exp b/src/lib/kadm5/unit-test/config/unix.exp
new file mode 100644
index 0000000000..e9a681f935
--- /dev/null
+++ b/src/lib/kadm5/unit-test/config/unix.exp
@@ -0,0 +1,113 @@
+set stty_init {-onlcr -opost intr \^C kill \^U}
+set kdb5_edit $KDBFIVE_EDIT
+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
+}
+
+proc api_exit {} {
+ global spawn_id
+
+# puts stdout "Starting api_exit (spawn_id $spawn_id)."
+ catch {close} errMsg
+ catch {wait} errMsg
+# puts stdout "Finishing api_exit."
+}
+
+proc api_version {} {
+}
+
+proc api_start {} {
+ global API
+ global env
+ global spawn_id
+ global prompt
+
+ 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"
+ }
+ 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"}
+ }
+# puts stdout "Finishing api_start (spawn_id $spawn_id)."
+}
+api_start
+
diff --git a/src/lib/kadm5/unit-test/destroy-test.c b/src/lib/kadm5/unit-test/destroy-test.c
new file mode 100644
index 0000000000..0db69c3a18
--- /dev/null
+++ b/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
+
+main()
+{
+ ovsec_kadm_ret_t ret;
+ char *cp;
+ int x, i;
+ 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,
+ &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/src/lib/kadm5/unit-test/diff-files/destroy-1 b/src/lib/kadm5/unit-test/diff-files/destroy-1
new file mode 100644
index 0000000000..593d673207
--- /dev/null
+++ b/src/lib/kadm5/unit-test/diff-files/destroy-1
@@ -0,0 +1,2 @@
+##! nochanges
+
diff --git a/src/lib/kadm5/unit-test/diff-files/no-diffs b/src/lib/kadm5/unit-test/diff-files/no-diffs
new file mode 100644
index 0000000000..593d673207
--- /dev/null
+++ b/src/lib/kadm5/unit-test/diff-files/no-diffs
@@ -0,0 +1,2 @@
+##! nochanges
+
diff --git a/src/lib/kadm5/unit-test/handle-test.c b/src/lib/kadm5/unit-test/handle-test.c
new file mode 100644
index 0000000000..ced1d183d6
--- /dev/null
+++ b/src/lib/kadm5/unit-test/handle-test.c
@@ -0,0 +1,131 @@
+#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>
+
+
+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;
+ int *p;
+
+
+ krb5_init_context(&context);
+
+ ret = ovsec_kadm_init("admin/none", "admin", "ovsec_adm/admin", 0,
+ OVSEC_KADM_STRUCT_VERSION, OVSEC_KADM_API_VERSION_1,
+ &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/src/lib/kadm5/unit-test/init-test.c b/src/lib/kadm5/unit-test/init-test.c
new file mode 100644
index 0000000000..823dd222bf
--- /dev/null
+++ b/src/lib/kadm5/unit-test/init-test.c
@@ -0,0 +1,26 @@
+#include <kadm5/admin.h>
+#include <com_err.h>
+#include <stdio.h>
+#include <krb5.h>
+
+main()
+{
+ ovsec_kadm_ret_t ret;
+ void *server_handle;
+
+ ret = ovsec_kadm_init("admin", "admin", OVSEC_KADM_ADMIN_SERVICE, 0,
+ OVSEC_KADM_STRUCT_VERSION,
+ OVSEC_KADM_API_VERSION_1,
+ &server_handle);
+ if (ret == OVSEC_KADM_RPC_ERROR)
+ exit(0);
+ else if (ret != OVSEC_KADM_OK) {
+ com_err("init-test", ret, "while (hacked) initializing");
+ exit(1);
+ }
+ else {
+ fprintf(stderr, "Unexpected success while (hacked) initializing!\n");
+ (void) ovsec_kadm_destroy(server_handle);
+ exit(1);
+ }
+}
diff --git a/src/lib/kadm5/unit-test/iter-test.c b/src/lib/kadm5/unit-test/iter-test.c
new file mode 100644
index 0000000000..7ca43d44fe
--- /dev/null
+++ b/src/lib/kadm5/unit-test/iter-test.c
@@ -0,0 +1,47 @@
+#include <stdio.h>
+#include <kadm5/admin.h>
+
+main(int argc, char **argv)
+{
+ ovsec_kadm_ret_t ret;
+ void *server_handle;
+ char **names;
+ int count, princ;
+
+ 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,
+ &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 (ret = 0; ret < count; ret++)
+ printf("%d: %s\n", ret, names[ret]);
+
+ ovsec_kadm_free_name_list(server_handle, names, count);
+
+ (void) ovsec_kadm_destroy(server_handle);
+
+ return 0;
+}
+
diff --git a/src/lib/kadm5/unit-test/lib.t b/src/lib/kadm5/unit-test/lib.t
new file mode 100644
index 0000000000..110514de8b
--- /dev/null
+++ b/src/lib/kadm5/unit-test/lib.t
@@ -0,0 +1,367 @@
+global timeout
+set timeout 60
+
+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; api_start; return 0 }
+ }
+}
+
+proc tcl_cmd {command} {
+ global prompt
+ global spawn_id
+
+ 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; api_start; 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; api_start; 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; api_start; 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; api_start; return 0 }
+ }
+}
+
+proc resync {} {
+ global prompt
+ global spawn_id
+
+ expect {
+ -re "$prompt$" {}
+ "wrong # args" { error "$test: wrong number args"; return 0 }
+ eof { api_exit; api_start }
+ }
+}
+
+proc create_principal {name} {
+ api_exit
+ api_start
+
+ set ret [expr {
+ [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_create_principal $server_handle [simple_principal \
+ "%s"] {OVSEC_KADM_PRINCIPAL} "%s"
+ } $name $name]]
+ }]
+
+ cmd {ovsec_kadm_destroy $server_handle}
+
+ api_exit
+ api_start
+
+ return $ret
+}
+
+proc create_policy {name} {
+ api_exit
+ api_start
+
+ set ret [expr {
+ [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_create_policy $server_handle [simple_policy "%s"] \
+ {OVSEC_KADM_POLICY}
+ } $name $name]]
+ }]
+
+ cmd {ovsec_kadm_destroy $server_handle}
+
+ api_exit
+ api_start
+
+ return $ret
+}
+
+proc create_principal_pol {name policy} {
+ api_exit
+ api_start
+
+ set ret [expr {
+ [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_create_principal $server_handle [princ_w_pol "%s" \
+ "%s"] {OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY} "%s"
+ } $name $policy $name]]
+ }]
+
+ cmd {ovsec_kadm_destroy $server_handle}
+
+ api_exit
+ api_start
+
+ return $ret
+}
+
+proc delete_principal {name} {
+ api_exit
+ api_start
+
+ set ret [expr {
+ [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_delete_principal $server_handle "%s"
+ } $name]]
+ }]
+
+ cmd {ovsec_kadm_destroy $server_handle}
+
+ api_exit
+ api_start
+
+ return $ret
+}
+
+proc delete_policy {name} {
+ api_exit
+ api_start
+
+ set ret [expr {
+ [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_delete_policy $server_handle "%s"} $name]]
+ }]
+
+ cmd {ovsec_kadm_destroy $server_handle}
+
+ api_exit
+ api_start
+
+ return $ret
+}
+
+proc principal_exists {name} {
+ api_exit
+ api_start
+
+# puts stdout "Starting principal_exists."
+
+ set ret [expr {
+ [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" principal
+ } $name]]
+ }]
+
+ cmd {ovsec_kadm_destroy $server_handle}
+
+ api_exit
+ api_start
+
+# puts stdout "Finishing principal_exists."
+
+ return $ret
+}
+
+proc policy_exists {name} {
+ api_exit
+ api_start
+
+# puts stdout "Starting policy_exists."
+
+ set ret [expr {
+ [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_policy $server_handle "%s" policy
+ } $name]]
+ }]
+
+ cmd {ovsec_kadm_destroy $server_handle}
+
+ api_exit
+ api_start
+
+# puts stdout "Finishing policy_exists."
+
+ return $ret
+}
+
+proc error_and_restart {error} {
+ api_exit
+ api_start
+ error $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 $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 {
+ 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 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/src/lib/kadm5/unit-test/lock-test.c b/src/lib/kadm5/unit-test/lock-test.c
new file mode 100644
index 0000000000..cff3423861
--- /dev/null
+++ b/src/lib/kadm5/unit-test/lock-test.c
@@ -0,0 +1,105 @@
+#include <stdio.h>
+#include <krb5.h>
+#include <kadm5/admin.h>
+#include <kadm5/adb.h>
+
+char *whoami;
+
+void usage()
+{
+ fprintf(stderr,
+ "Usage: %s {shared|exclusive|permanent|release|"
+ "get name|wait} ...\n", whoami);
+ exit(1);
+}
+
+main(int argc, char **argv)
+{
+ osa_adb_ret_t ret;
+ osa_adb_policy_t policy_db;
+ osa_policy_ent_t entry;
+ krb5_context context;
+ kadm5_config_params params;
+
+ whoami = argv[0];
+
+ krb5_init_context(&context);
+
+ initialize_ovk_error_table();
+ initialize_adb_error_table();
+ initialize_ovku_error_table();
+ krb5_init_ets(context);
+
+ params.mask = 0;
+ if (ret = kadm5_get_config_params(context, NULL, NULL, &params,
+ &params)) {
+ 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 = osa_adb_open_policy(&policy_db, &params);
+ if (ret != OSA_ADB_OK) {
+ com_err(whoami, ret, "while opening database");
+ exit(1);
+ }
+
+ argc--; argv++;
+ while (argc) {
+ if (strcmp(*argv, "shared") == 0) {
+ ret = osa_adb_get_lock(policy_db, OSA_ADB_SHARED);
+ if (ret != OSA_ADB_OK)
+ com_err(whoami, ret, "while getting shared lock");
+ else
+ printf("shared\n");
+ } else if (strcmp(*argv, "exclusive") == 0) {
+ ret = osa_adb_get_lock(policy_db, OSA_ADB_EXCLUSIVE);
+ if (ret != OSA_ADB_OK)
+ com_err(whoami, ret, "while getting exclusive lock");
+ else
+ printf("exclusive\n");
+ } else if (strcmp(*argv, "permanent") == 0) {
+ ret = osa_adb_get_lock(policy_db, OSA_ADB_PERMANENT);
+ if (ret != OSA_ADB_OK)
+ com_err(whoami, ret, "while getting permanent lock");
+ else
+ printf("permanent\n");
+ } else if (strcmp(*argv, "release") == 0) {
+ ret = osa_adb_release_lock(policy_db);
+ if (ret != OSA_ADB_OK)
+ com_err(whoami, ret, "while releasing lock");
+ else
+ printf("released\n");
+ } else if (strcmp(*argv, "get") == 0) {
+ argc--; argv++;
+ if (!argc) usage();
+ if ((ret = osa_adb_get_policy(policy_db, *argv,
+ &entry)) != OSA_ADB_OK) {
+ com_err(whoami, ret, "while getting policy");
+ } else {
+ printf("retrieved\n");
+ osa_free_policy_ent(entry);
+ }
+ } else if (strcmp(*argv, "wait") == 0) {
+ getchar();
+ } else {
+ fprintf(stderr, "%s: Invalid argument \"%s\"\n",
+ whoami, *argv);
+ usage();
+ }
+
+ argc--; argv++;
+ }
+
+ ret = osa_adb_close_policy(policy_db);
+ if (ret != OSA_ADB_OK) {
+ com_err(whoami, ret, "while closing database");
+ exit(1);
+ }
+
+ return 0;
+}
diff --git a/src/lib/kadm5/unit-test/randkey-test.c b/src/lib/kadm5/unit-test/randkey-test.c
new file mode 100644
index 0000000000..8d7e2fecef
--- /dev/null
+++ b/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
+
+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,
+ &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/src/lib/kadm5/unit-test/site.exp b/src/lib/kadm5/unit-test/site.exp
new file mode 100644
index 0000000000..18b435dd12
--- /dev/null
+++ b/src/lib/kadm5/unit-test/site.exp
@@ -0,0 +1,2 @@
+set tool ovsec_kadm_srv_tcl
+set prompt "% "
diff --git a/src/lib/kadm5/unit-test/sizes-test.c b/src/lib/kadm5/unit-test/sizes-test.c
new file mode 100644
index 0000000000..5bcbd62523
--- /dev/null
+++ b/src/lib/kadm5/unit-test/sizes-test.c
@@ -0,0 +1,21 @@
+#include <stdio.h>
+#include <rpc/types.h>
+#include <krb5.h>
+
+#define stringify(a) #a
+
+#define test_size(a,b) if (sizeof(a) != sizeof(b)) { \
+ fprintf(stderr, "sizeof(%s) != sizeof(%s)\n", stringify(a), stringify(b)); \
+ exit(1); \
+}
+
+main()
+{
+ test_size(unsigned long, krb5_ui_4);
+ test_size(long, krb5_timestamp);
+ test_size(long, krb5_deltat);
+ test_size(long, krb5_flags);
+
+ exit(0);
+}
+
diff --git a/src/lib/kdb/ChangeLog b/src/lib/kdb/ChangeLog
index fa274c12ae..4e5440cc91 100644
--- a/src/lib/kdb/ChangeLog
+++ b/src/lib/kdb/ChangeLog
@@ -1,3 +1,25 @@
+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
@@ -12,6 +34,24 @@ 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
diff --git a/src/lib/kdb/Makefile.in b/src/lib/kdb/Makefile.in
index 7b1176d890..ba683222a4 100644
--- a/src/lib/kdb/Makefile.in
+++ b/src/lib/kdb/Makefile.in
@@ -3,6 +3,10 @@ KRB5_RUN_ENV = @KRB5_RUN_ENV@
all:: $(OBJS)
+.c.o:
+ $(CC) $(CFLAGS) -c $(srcdir)/$*.c
+@SHARED_RULE@
+
SRCS= \
$(srcdir)/keytab.c \
$(srcdir)/encrypt_key.c \
@@ -27,6 +31,21 @@ OBJS= \
setup_mkey.o \
store_mkey.o
+LIB_SUBDIRS= .
+LIBDONE = DONE
+
+all-unix:: shared
+shared::
+ test -d shared || mkdir shared
+
+clean-unix::
+ $(RM) shared/*
+ -rmdir shared
+
+DONE: $(OBJS)
+ $(RM) DONE
+ echo $(OBJS) > DONE
+
libkdb5.a: $(OBJS)
$(RM) $@
$(ARADD) $@ $(OBJS)
@@ -37,7 +56,7 @@ install:: libkdb5.a
$(RANLIB) $(DESTDIR)$(KRB5_LIBDIR)/libkdb5.a
clean::
- $(RM) libkdb5.a
+ $(RM) libkdb5.a DONE
t_kdb: t_kdb.o $(DEPLIBS)
$(LD) $(LDFLAGS) $(LDARGS) -o t_kdb t_kdb.o $(LIBS)
diff --git a/src/lib/kdb/configure.in b/src/lib/kdb/configure.in
index ec7f93ec1a..e480603e4c 100644
--- a/src/lib/kdb/configure.in
+++ b/src/lib/kdb/configure.in
@@ -8,8 +8,9 @@ AC_HAVE_HEADERS(unistd.h)
AC_CHECK_FUNCS(srand48 srand srandom umask)
KRB5_RUN_FLAGS
V5_USE_SHARED_LIB
-USE_KDB5_LIBRARY
KRB5_LIBRARIES
+V5_SHARED_LIB_OBJS
+V5_MAKE_SHARED_LIB(libkdb5,0.1,.., ./kdb)
LinkFileDir(../libkdb5.a, libkdb5.a, ./kdb)
AppendRule([all:: libkdb5.a])
AppendRule([all-unix:: ../libkdb5.a])
diff --git a/src/lib/kdb/kdb_cpw.c b/src/lib/kdb/kdb_cpw.c
index 0928eba2a1..54316dde09 100644
--- a/src/lib/kdb/kdb_cpw.c
+++ b/src/lib/kdb/kdb_cpw.c
@@ -188,7 +188,7 @@ add_key_rnd(context, master_eblock, ks_tuple, ks_tuple_count, db_entry, kvno)
krb5_finish_key(context, &krbtgt_eblock);
if (retval = krb5_dbekd_encrypt_key_data(context, master_eblock,
- key, NULL, kvno + 1,
+ key, NULL, kvno,
&db_entry->key_data[db_entry->n_key_data-1])) {
krb5_free_keyblock(context, key);
goto add_key_rnd_err;
@@ -233,6 +233,9 @@ krb5_dbe_crk(context, master_eblock, ks_tuple, ks_tuple_count, db_entry)
db_entry->key_data = NULL;
db_entry->n_key_data = 0;
+ /* increment the kvno */
+ kvno++;
+
if (retval = add_key_rnd(context, master_eblock, ks_tuple,
ks_tuple_count, db_entry, kvno)) {
cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
@@ -271,15 +274,18 @@ krb5_dbe_ark(context, master_eblock, ks_tuple, ks_tuple_count, db_entry)
db_entry->key_data = NULL;
db_entry->n_key_data = 0;
+ /* increment the kvno */
+ kvno++;
+
if (retval = add_key_rnd(context, master_eblock, 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 */
+ /* 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) {
+ 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);
@@ -318,6 +324,8 @@ add_key_pwd(context, master_eblock, ks_tuple, ks_tuple_count, passwd,
krb5_boolean found;
int i, j;
+ retval = 0;
+
for (i = 0; i < ks_tuple_count; i++) {
krb5_enctype new_enctype, old_enctype;
@@ -405,7 +413,7 @@ add_key_pwd(context, master_eblock, ks_tuple, ks_tuple_count, passwd,
if (retval = krb5_dbekd_encrypt_key_data(context, master_eblock, &key,
(const krb5_keysalt *)&key_salt,
- kvno + 1, &db_entry->key_data[db_entry->n_key_data-1])) {
+ kvno, &db_entry->key_data[db_entry->n_key_data-1])) {
krb5_xfree(key.contents);
return(retval);
}
@@ -421,28 +429,36 @@ add_key_pwd(context, master_eblock, ks_tuple, ks_tuple_count, passwd,
* As a side effect all old keys are nuked.
*/
krb5_error_code
-krb5_dbe_cpw(context, master_eblock, ks_tuple, ks_tuple_count, passwd, db_entry)
+krb5_dbe_cpw(context, master_eblock, ks_tuple, ks_tuple_count, passwd,
+ new_kvno, db_entry)
krb5_context context;
krb5_encrypt_block * master_eblock;
krb5_key_salt_tuple * ks_tuple;
int ks_tuple_count;
char * passwd;
+ int new_kvno;
krb5_db_entry * db_entry;
{
int key_data_count;
krb5_key_data * key_data;
krb5_error_code retval;
- int kvno;
+ int old_kvno;
/* First save the old keydata */
- kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data);
+ 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;
+
if (retval = add_key_pwd(context, master_eblock, ks_tuple, ks_tuple_count,
- passwd, db_entry, kvno)) {
+ 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;
@@ -470,25 +486,29 @@ krb5_dbe_apw(context, master_eblock, ks_tuple, ks_tuple_count, passwd, db_entry)
int key_data_count;
krb5_key_data * key_data;
krb5_error_code retval;
- int kvno;
+ int old_kvno, new_kvno;
int i;
/* First save the old keydata */
- kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data);
+ 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_eblock, ks_tuple, ks_tuple_count,
- passwd, db_entry, kvno)) {
+ 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 = kvno */
+ /* Copy keys with key_data_kvno == old_kvno */
for (i = 0; i < key_data_count; i++) {
- if (key_data[i].key_data_kvno = kvno) {
+ 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);
diff --git a/src/lib/kdb/kdb_dbm.c b/src/lib/kdb/kdb_dbm.c
index e42e31f9d3..3931389f47 100644
--- a/src/lib/kdb/kdb_dbm.c
+++ b/src/lib/kdb/kdb_dbm.c
@@ -22,6 +22,8 @@
*
*/
+#define DB_OPENCLOSE
+
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
@@ -341,9 +343,13 @@ krb5_dbm_db_init(context)
return(retval);
db_ctx = context->db_context;
+#ifdef DB_OPENCLOSE
+ db_ctx->db_dbm_ctx = NULL;
+#else
if (!(db_ctx->db_dbm_ctx = (DBM *)KDBM_OPEN(db_ctx, db_ctx->db_name,
O_RDWR, 0600)))
return errno;
+#endif
if (!(filename = gen_dbsuffix (db_ctx->db_name, KDBM_LOCK_EXT(db_ctx))))
return ENOMEM;
@@ -367,7 +373,9 @@ krb5_dbm_db_init(context)
return 0;
err_out:
+#ifndef DB_OPENCLOSE
KDBM_CLOSE(db_ctx, db_ctx->db_dbm_ctx);
+#endif
db_ctx->db_dbm_ctx = (DBM *) NULL;
k5dbm_clear_context(db_ctx);
return (retval);
@@ -387,6 +395,7 @@ krb5_dbm_db_fini(context)
db_ctx = (krb5_db_context *) context->db_context;
if (k5dbm_inited(context)) {
+#ifndef DB_OPENCLOSE
if (db_ctx->db_dbm_ctx) {
/* dbm_close returns void, but it is possible for there to be an
error in close(). Possible changes to this routine: check errno
@@ -395,6 +404,7 @@ krb5_dbm_db_fini(context)
KDBM_CLOSE(db_ctx, db_ctx->db_dbm_ctx);
db_ctx->db_dbm_ctx = NULL;
}
+#endif
if (close(db_ctx->db_lf_file))
retval = errno;
@@ -471,6 +481,8 @@ krb5_dbm_db_get_mkey(context, db_context, eblock)
*
* 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
@@ -621,6 +633,17 @@ krb5_dbm_db_lock(context, mode)
if ((retval = krb5_dbm_db_get_age(context, NULL, &mod_time)))
goto lock_error;
+#ifdef DB_OPENCLOSE
+ if ((db = KDBM_OPEN(db_ctx, db_ctx->db_name,
+ mode == KRB5_LOCKMODE_SHARED ? O_RDONLY : O_RDWR,
+ 0600))) {
+ db_ctx->db_lf_time = mod_time;
+ db_ctx->db_dbm_ctx = db;
+ } else {
+ retval = errno;
+ goto lock_error;
+ }
+#else
if (mod_time != db_ctx->db_lf_time) {
KDBM_CLOSE(db_ctx, db_ctx->db_dbm_ctx);
if ((db = KDBM_OPEN(db_ctx, db_ctx->db_name, O_RDWR, 0600))) {
@@ -631,12 +654,15 @@ krb5_dbm_db_lock(context, mode)
goto lock_error;
}
}
+#endif
db_ctx->db_lock_mode = mode;
db_ctx->db_locks_held++;
return 0;
lock_error:;
+ db_ctx->db_lock_mode = 0;
+ db_ctx->db_locks_held = 0;
(void) krb5_dbm_db_unlock(context);
return retval;
}
@@ -655,6 +681,10 @@ krb5_dbm_db_unlock(context)
if (!db_ctx->db_locks_held) /* lock already unlocked */
return KRB5_KDB_NOTLOCKED;
+#ifdef DB_OPENCLOSE
+ KDBM_CLOSE(db_ctx, db_ctx->db_dbm_ctx);
+#endif
+
if (--(db_ctx->db_locks_held) == 0) {
retval = krb5_lock_file(context, db_ctx->db_lf_file,
KRB5_LOCKMODE_UNLOCK);
@@ -720,9 +750,8 @@ destroy_file_suffix(dbname, suffix)
if (filename == 0)
return ENOMEM;
if ((fd = open(filename, O_RDWR, 0)) < 0) {
- int retval = errno == ENOENT ? 0 : errno;
free(filename);
- return retval;
+ return errno;
}
/* fstat() will probably not fail unless using a remote filesystem
(which is inappropriate for the kerberos database) so this check
@@ -796,26 +825,40 @@ krb5_dbm_db_destroy(context, dbname)
krb5_context context;
char *dbname;
{
- krb5_error_code retval;
+ krb5_error_code retval1, retval2, retval3;
krb5_boolean tmpcontext;
tmpcontext = 0;
if (!context->db_context) {
tmpcontext = 1;
- if ((retval = k5dbm_init_context(context)))
- return(retval);
+ if ((retval1 = k5dbm_init_context(context)))
+ return(retval1);
}
- if (KDBM_DATA_EXT(context->db_context) &&
- (retval = destroy_file_suffix(dbname,
- KDBM_DATA_EXT(context->db_context))))
- return(retval);
- if (KDBM_INDEX_EXT(context->db_context) &&
- (retval = destroy_file_suffix(dbname,
- KDBM_INDEX_EXT(context->db_context))))
- return(retval);
- if ((retval = destroy_file_suffix(dbname,
- KDBM_LOCK_EXT(context->db_context))))
- return(retval);
+ retval1 = retval2 = retval3 = 0;
+ if (KDBM_DATA_EXT(context->db_context))
+ retval1 = destroy_file_suffix(dbname,
+ KDBM_DATA_EXT(context->db_context));
+ if (KDBM_INDEX_EXT(context->db_context))
+ retval2 = destroy_file_suffix(dbname,
+ KDBM_INDEX_EXT(context->db_context));
+ retval3 = destroy_file_suffix(dbname,
+ KDBM_LOCK_EXT(context->db_context));
+ /*
+ * This kludgery is needed because it is possible to link
+ * against BSD DB but use the ndbm interface. The result is
+ * that the dispatch table thinks the file extensions are
+ * .dir and .pag, but the database layer uses .db.
+ */
+ if (retval1 == ENOENT && retval2 == ENOENT &&
+ KDBM_INDEX_EXT(context->db_context) &&
+ strcmp(KDBM_INDEX_EXT(context->db_context), ".dir") == 0 &&
+ KDBM_DATA_EXT(context->db_context) &&
+ strcmp(KDBM_DATA_EXT(context->db_context), ".pag") == 0) {
+ retval1 = retval2 = destroy_file_suffix(dbname, ".db");
+ }
+ if (retval1 || retval2 || retval3)
+ return (retval1 ? retval1 : (retval2 ? retval2 : retval3));
+
if (tmpcontext) {
k5dbm_clear_context((krb5_db_context *) context->db_context);
free(context->db_context);
@@ -841,6 +884,7 @@ krb5_dbm_db_rename(context, from, to)
char *from;
char *to;
{
+ DBM *db;
char *fromdir = 0;
char *todir = 0;
char *frompag = 0;
@@ -853,19 +897,28 @@ krb5_dbm_db_rename(context, from, to)
s_context = context->db_context;
context->db_context = (void *) NULL;
if (!(retval = k5dbm_init_context(context))) {
+ db_ctx = (krb5_db_context *) context->db_context;
+
+ /*
+ * Create the database, failing if it already exists; the
+ * files must exist because krb5_dbm_db_lock, called below,
+ * will fail otherwise.
+ */
+ db = KDBM_OPEN(db_ctx, to, O_RDWR|O_CREAT|O_EXCL, 0600);
+ if (db == NULL) {
+ retval = errno;
+ goto errout;
+ }
+ else
+ KDBM_CLOSE(db_ctx, db);
+
/*
* Set the database to the target, so that other processes sharing
* the target will stop their activity, and notice the new database.
*/
- db_ctx = (krb5_db_context *) context->db_context;
-
retval = krb5_dbm_db_set_name(context, to);
- if (retval) {
- if (retval == ENOENT)
- db_ctx->db_name = strdup(to);
- else
+ if (retval)
goto errout;
- }
db_ctx->db_lf_name = gen_dbsuffix(db_ctx->db_name,
KDBM_LOCK_EXT(db_ctx));
@@ -931,8 +984,39 @@ krb5_dbm_db_rename(context, from, to)
(void) unlink(fromok);
retval = krb5_dbm_db_end_update(context);
} else {
- (void) krb5_dbm_db_end_update(context);
- retval = errno;
+ /*
+ * This kludgery is needed because it is possible to link
+ * against BSD DB but use the ndbm interface. The result is
+ * that the dispatch table thinks the file extensions are
+ * .dir and .pag, but the database layer uses .db.
+ */
+ if (errno == ENOENT &&
+ KDBM_INDEX_EXT(context->db_context) &&
+ strcmp(KDBM_INDEX_EXT(context->db_context), ".dir") == 0 &&
+ KDBM_DATA_EXT(context->db_context) &&
+ strcmp(KDBM_DATA_EXT(context->db_context), ".pag") == 0) {
+ free(fromdir); free(todir); free(frompag); free(topag);
+
+ fromdir = todir = NULL;
+ frompag = gen_dbsuffix (from, ".db");
+ topag = gen_dbsuffix (to, ".db");
+ if (!frompag || !topag) {
+ retval = ENOMEM;
+ goto errout;
+ }
+ if (rename(frompag, topag) == 0) {
+ /* We only need to unlink the source lock file */
+ if (fromok)
+ (void) unlink(fromok);
+ retval = krb5_dbm_db_end_update(context);
+ } else {
+ (void) krb5_dbm_db_end_update(context);
+ retval = errno;
+ }
+ } else {
+ (void) krb5_dbm_db_end_update(context);
+ retval = errno;
+ }
}
@@ -1082,6 +1166,7 @@ krb5_dbm_db_put_principal(context, entries, nentries)
}
if (KDBM_STORE(db_ctx, db_ctx->db_dbm_ctx, key, contents, DBM_REPLACE))
retval = errno;
+#ifndef DB_OPENCLOSE
else {
DBM *db;
@@ -1093,6 +1178,7 @@ krb5_dbm_db_put_principal(context, entries, nentries)
else
retval = errno;
}
+#endif
krb5_free_princ_contents(context, &contents);
krb5_free_princ_dbmkey(context, &key);
if (retval)
@@ -1166,6 +1252,7 @@ krb5_dbm_db_delete_principal(context, searchfor, nentries)
else {
if (KDBM_DELETE(db_ctx, db, key))
retval = errno;
+#ifndef DB_OPENCLOSE
else {
DBM *db;
@@ -1177,6 +1264,7 @@ krb5_dbm_db_delete_principal(context, searchfor, nentries)
else
retval = errno;
}
+#endif
}
krb5_free_princ_contents(context, &contents2);
cleancontents:
diff --git a/src/lib/kdb/kdb_xdr.c b/src/lib/kdb/kdb_xdr.c
index 5953d6dd25..044ce4c7fe 100644
--- a/src/lib/kdb/kdb_xdr.c
+++ b/src/lib/kdb/kdb_xdr.c
@@ -23,200 +23,223 @@
*/
#include "k5-int.h"
+#include <string.h>
#include <stdio.h>
#include <errno.h>
+#define safe_realloc(p,n) ((p)?(realloc(p,n)):(malloc(n)))
+
krb5_error_code
krb5_dbe_create_key_data(context, entry)
krb5_context context;
krb5_db_entry * entry;
{
- if (entry->n_key_data) {
- if ((entry->key_data = (krb5_key_data *)realloc(entry->key_data,
- sizeof(krb5_key_data) * (entry->n_key_data + 1))))
- memset(entry->key_data + entry->n_key_data,0,sizeof(krb5_key_data));
- else
- return ENOMEM;
- } else {
- if ((entry->key_data = (krb5_key_data *)malloc(sizeof(krb5_key_data))))
- memset(entry->key_data, 0, sizeof(krb5_key_data));
- else
- return ENOMEM;
- }
+ if ((entry->key_data =
+ (krb5_key_data *) safe_realloc(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_encode_last_pwd_change(context, stamp, entry)
+krb5_dbe_update_tl_data(context, entry, new_tl_data)
krb5_context context;
- krb5_tl_last_change * stamp;
krb5_db_entry * entry;
+ krb5_tl_data * new_tl_data;
{
- krb5_tl_data ** tl_data;
- krb5_octet * nextloc;
-
- /* Find any old versions and delete them. */
- for (tl_data = &(entry->tl_data); *tl_data;
- tl_data = &((*tl_data)->tl_data_next)) {
- if ((*tl_data)->tl_data_type == KRB5_TL_LAST_PWD_CHANGE) {
- break;
- }
- }
+ krb5_tl_data * tl_data;
+ krb5_octet * tmp;
+
+ /* copy the new data first, so we can fail cleanly if malloc()
+ fails */
- if ((*tl_data) ||
- /* Only zero data if it is freshly allocated */
- ((*tl_data) = (krb5_tl_data *)calloc(1, sizeof(krb5_tl_data)))) {
- if (!(*tl_data)->tl_data_type) {
- if ((nextloc = (*tl_data)->tl_data_contents =
- (krb5_octet *)malloc(sizeof(krb5_timestamp))) == NULL) {
- krb5_xfree(*tl_data);
- (*tl_data) = NULL;
- return ENOMEM;
- }
- (*tl_data)->tl_data_type = KRB5_TL_LAST_PWD_CHANGE;
- (*tl_data)->tl_data_length = sizeof(krb5_timestamp);
- entry->n_tl_data++;
- }
-
- *nextloc++ = (krb5_octet)(stamp->last_pwd_change & 0xff);
- *nextloc++ = (krb5_octet)((stamp->last_pwd_change >> 8) & 0xff);
- *nextloc++ = (krb5_octet)((stamp->last_pwd_change >> 16) & 0xff);
- *nextloc++ = (krb5_octet)((stamp->last_pwd_change >> 24) & 0xff);
-
- return 0;
+ if ((tmp = (krb5_octet *) malloc(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 */
+
+ 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 *) calloc(1, sizeof(krb5_tl_data)))
+ == NULL) {
+ free(tmp);
+ return(ENOMEM);
+ }
+ tl_data->tl_data_next = entry->tl_data;
+ entry->tl_data = tl_data;
+ entry->n_tl_data++;
}
- return ENOMEM;
+
+ /* fill in the record */
+
+ if (tl_data->tl_data_contents)
+ free(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);
}
krb5_error_code
-krb5_dbe_decode_last_pwd_change(context, entry, stamp)
+krb5_dbe_lookup_tl_data(context, entry, ret_tl_data)
krb5_context context;
krb5_db_entry * entry;
- krb5_tl_last_change * stamp;
+ krb5_tl_data * ret_tl_data;
{
- krb5_tl_data * 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 == KRB5_TL_LAST_PWD_CHANGE) {
- krb5_octet * nextloc = tl_data->tl_data_contents;
-
- stamp->last_pwd_change = *nextloc++;
- stamp->last_pwd_change += (*nextloc++ << 8);
- stamp->last_pwd_change += (*nextloc++ << 16);
- stamp->last_pwd_change += (*nextloc++ << 24);
- return 0;
- }
+ if (tl_data->tl_data_type == ret_tl_data->tl_data_type) {
+ *ret_tl_data = *tl_data;
+ return(0);
+ }
}
- stamp->last_pwd_change = 0;
- 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_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_encode_mod_princ_data(context, mod_princ, entry)
+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);
+}
+
+/* it seems odd that there's no function to remove a tl_data, but if
+ I need one, I'll add one */
+
+krb5_error_code
+krb5_dbe_update_mod_princ_data(context, entry, mod_date, mod_princ)
krb5_context context;
- krb5_tl_mod_princ * mod_princ;
krb5_db_entry * entry;
+ krb5_timestamp mod_date;
+ krb5_principal mod_princ;
{
+ krb5_tl_data tl_data;
+
krb5_error_code retval = 0;
- krb5_tl_data ** tl_data;
krb5_octet * nextloc = 0;
char * unparse_mod_princ = 0;
int unparse_mod_princ_size;
- /*
- * Allocate *tl_data if necessary otherwise reuse it
- * Need 04 bytes for date
- * Need XX bytes for string
- */
- if ((retval = krb5_unparse_name(context, mod_princ->mod_princ,
- &unparse_mod_princ)))
+ if ((retval = krb5_unparse_name(context, mod_princ,
+ &unparse_mod_princ)))
return(retval);
unparse_mod_princ_size = (int) strlen(unparse_mod_princ) + 1;
- if ((nextloc = malloc(unparse_mod_princ_size + 4)) == NULL) {
- retval = ENOMEM;
- goto cleanup;
- }
-
- /* Find any old versions and delete them. */
- for (tl_data = &(entry->tl_data); *tl_data;
- tl_data = &((*tl_data)->tl_data_next)) {
- if ((*tl_data)->tl_data_type == KRB5_TL_MOD_PRINC) {
- free((*tl_data)->tl_data_contents);
- entry->n_tl_data--;
- break;
- }
+ if ((nextloc = (krb5_octet *) malloc(unparse_mod_princ_size + 4))
+ == NULL) {
+ free(unparse_mod_princ);
+ return(ENOMEM);
}
- /* Allocate a new TL_MOD_PRINC structure if necessary */
- if (*tl_data == 0) {
- (*tl_data) = (krb5_tl_data *)calloc(1, sizeof(krb5_tl_data));
- if (*tl_data == 0) {
- retval = ENOMEM;
- goto cleanup;
- }
- }
-
- entry->n_tl_data++;
- (*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;
+ 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_princ->mod_date, nextloc);
- nextloc += 4;
+ krb5_kdb_encode_int32(mod_date, nextloc);
/* Mod Princ */
- memcpy(nextloc, unparse_mod_princ, unparse_mod_princ_size);
- nextloc = 0;
+ memcpy(nextloc+4, unparse_mod_princ, unparse_mod_princ_size);
-cleanup:
- if (nextloc)
- free(nextloc);
- if (unparse_mod_princ)
- free(unparse_mod_princ);
- return retval;
+ retval = krb5_dbe_update_tl_data(context, entry, &tl_data);
+
+ free(unparse_mod_princ);
+ free(nextloc);
+
+ return(retval);
}
krb5_error_code
-krb5_dbe_decode_mod_princ_data(context, entry, mod_princ)
+krb5_dbe_lookup_mod_princ_data(context, entry, mod_time, mod_princ)
krb5_context context;
krb5_db_entry * entry;
- krb5_tl_mod_princ ** mod_princ;
+ krb5_timestamp * mod_time;
+ krb5_principal * mod_princ;
{
- krb5_error_code retval;
- krb5_tl_data * tl_data;
- krb5_octet * nextloc;
+ krb5_tl_data tl_data;
+ krb5_error_code code;
+ krb5_int32 tmp;
- retval = 0;
- for (tl_data = entry->tl_data; tl_data; tl_data = tl_data->tl_data_next) {
- if (tl_data->tl_data_type == KRB5_TL_MOD_PRINC) {
- if ((*mod_princ = malloc(sizeof(krb5_tl_mod_princ))) == NULL)
- return ENOMEM;
-
- nextloc = tl_data->tl_data_contents;
-
- /* Mod Date */
- krb5_kdb_decode_int32(nextloc, (*mod_princ)->mod_date);
- nextloc += 4;
-
- /* Mod Princ */
- if ((retval = krb5_parse_name(context, (const char *) nextloc,
- &((*mod_princ)->mod_princ))))
- break;
- if ((strlen((char *) nextloc) + 1 + 4) !=
- (size_t) tl_data->tl_data_length) {
- retval = KRB5_KDB_TRUNCATED_RECORD;
- break;
- }
- }
- }
+ tl_data.tl_data_type = KRB5_TL_MOD_PRINC;
- if (retval && (*mod_princ))
- free(*mod_princ);
- return retval;
+ 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
diff --git a/src/lib/krb5/keytab/file/ChangeLog b/src/lib/krb5/keytab/file/ChangeLog
index 58112dcccc..39c3974343 100644
--- a/src/lib/krb5/keytab/file/ChangeLog
+++ b/src/lib/krb5/keytab/file/ChangeLog
@@ -1,3 +1,8 @@
+Fri Jul 12 21:16:50 1996 Marc Horowitz <marc@mit.edu>
+
+ * 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>
* ser_ktf.c: Add #ifdef _WIN32 in places where we had #ifdef _MSDOS
diff --git a/src/lib/krb5/keytab/file/ktf_g_name.c b/src/lib/krb5/keytab/file/ktf_g_name.c
index a8f27c4746..dd8aadc743 100644
--- a/src/lib/krb5/keytab/file/ktf_g_name.c
+++ b/src/lib/krb5/keytab/file/ktf_g_name.c
@@ -36,10 +36,24 @@ krb5_ktfile_get_name(context, id, name, 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.
+ * 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);
- strncpy(name, KTFILENAME(id), len);
+
+ if (len < strlen(id->ops->prefix)+2)
+ return(ENAMETOOLONG);
+ 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(ENAMETOOLONG);
+ strcpy(name, KTFILENAME(id));
+ /* strcpy will NUL-terminate the destination */
+
return(0);
}
diff --git a/src/lib/krb5/os/ChangeLog b/src/lib/krb5/os/ChangeLog
index 75d2f0d3ea..721ce1e5ef 100644
--- a/src/lib/krb5/os/ChangeLog
+++ b/src/lib/krb5/os/ChangeLog
@@ -1,3 +1,8 @@
+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):
diff --git a/src/lib/krb5/os/ktdefname.c b/src/lib/krb5/os/ktdefname.c
index 433c1c9da8..29eb54fe2c 100644
--- a/src/lib/krb5/os/ktdefname.c
+++ b/src/lib/krb5/os/ktdefname.c
@@ -37,12 +37,22 @@ krb5_kt_default_name(context, name, namesize)
int namesize;
{
char *cp = 0;
+ krb5_error_code code;
+ char *retval;
- if (context->profile_secure == FALSE) cp = getenv("KRB5_KTNAME");
- if (cp) {
+ if ((context->profile_secure == FALSE) &&
+ (cp = getenv("KRB5_KTNAME"))) {
strncpy(name, cp, namesize);
if (strlen(cp) >= (size_t) namesize)
return KRB5_CONFIG_NOTENUFSPACE;
+ } else if (((code = profile_get_string(context->profile,
+ "libdefaults",
+ "default_keytab_name", NULL,
+ NULL, &retval)) == 0) &&
+ retval) {
+ strncpy(name, retval, namesize);
+ if ((size_t) namesize < strlen(retval))
+ return KRB5_CONFIG_NOTENUFSPACE;
} else {
#if defined (_MSDOS) || defined(_WIN32)
{
diff --git a/src/lib/rpc/ChangeLog b/src/lib/rpc/ChangeLog
new file mode 100644
index 0000000000..a78d05c37c
--- /dev/null
+++ b/src/lib/rpc/ChangeLog
@@ -0,0 +1,20 @@
+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/src/lib/rpc/Makefile.in b/src/lib/rpc/Makefile.in
new file mode 100644
index 0000000000..9426bb94c7
--- /dev/null
+++ b/src/lib/rpc/Makefile.in
@@ -0,0 +1,148 @@
+CFLAGS = $(CCOPTS) $(DEFS) -DDEBUG_GSSAPI -I$(srcdir)/..
+
+##DOSBUILDTOP = ..\..
+##DOSLIBNAME=libgssrpc.lib
+
+.c.o:
+ $(CC) $(CFLAGS) -c $(srcdir)/$*.c
+@SHARED_RULE@
+
+SRCS = $(srcdir)/auth_none.c \
+ $(srcdir)/auth_unix.c \
+ $(srcdir)/auth_any.c \
+ $(srcdir)/authunix_prot.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)/rpc_dtablesize.c \
+ $(srcdir)/get_myaddress.c \
+ $(srcdir)/getrpcent.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_unix.c \
+ $(srcdir)/svc_auth_any.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) \
+ auth_any.$(OBJEXT) \
+ authunix_prot.$(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) \
+ rpc_dtablesize.$(OBJEXT) \
+ get_myaddress.$(OBJEXT) \
+ getrpcent.$(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_unix.$(OBJEXT) \
+ svc_auth_any.$(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)
+
+LIB_SUBDIRS= .
+LIBDONE= DONE
+#
+# Depends on libgssapi_krb5, libkrb5, libcrypto, libcom_err
+#
+GSSAPI_KRB5_VER=@GSSAPI_KRB5_SH_VERS@
+KRB5_VER=@KRB5_SH_VERS@
+CRYPTO_VER=@CRYPTO_SH_VERS@
+COMERR_VER=@COMERR_SH_VERS@
+DEPLIBS=$(TOPLIBD)/libgssapi_krb5.$(SHEXT).$(COMERR_VER) \
+ $(TOPLIBD)/libkrb5.$(SHEXT).$(KRB5_VER) \
+ $(TOPLIBD)/libcrypto.$(SHEXT).$(CRYPTO_VER) \
+ $(TOPLIBD)/libcom_err.$(SHEXT).$(COMERR_VER)
+
+SHLIB_LIBS=-lkrb5 -lcrypto -lcom_err -ldyn
+SHLIB_LDFLAGS= $(LDFLAGS) @SHLIB_RPATH_DIRS@
+SHLIB_LIBDIRS= @SHLIB_LIBDIRS@
+
+all-unix:: shared includes $(OBJS)
+all-mac:: $(OBJS)
+all-windows:: $(OBJS)
+
+shared:
+ mkdir shared
+
+check-windows::
+
+clean-unix::
+ $(RM) shared/*
+
+clean-mac::
+clean-windows::
+
+DONE: $(OBJS)
+ $(RM) DONE
+ echo $(OBJS) > DONE
+
+libgssrpc.$(STEXT): $(OBJS)
+ $(RM) $@
+ $(ARADD) $@ $(OBJS)
+ $(RANLIB) $@
+
+install:: libgssrpc.a
+ $(INSTALL_DATA) libgssrpc.a $(DESTDIR)$(KRB5_LIBDIR)/libgssrpc.a
+ $(RANLIB) $(DESTDIR)$(KRB5_LIBDIR)/libgssrpc.a
+
+clean::
+ $(RM) libgssrpc.$(LIBEXT) libgssrpc.bak DONE
+
diff --git a/src/lib/rpc/Makefile.ov b/src/lib/rpc/Makefile.ov
new file mode 100644
index 0000000000..d64c77e223
--- /dev/null
+++ b/src/lib/rpc/Makefile.ov
@@ -0,0 +1,52 @@
+#
+# Makefile for librpclib.a.
+#
+# $Id$
+# $Source$
+#
+TOP = ..
+include $(TOP)/config.mk/template
+
+SUBDIRS = unit-test
+
+SRCS = auth_none.c auth_unix.c auth_any.c authunix_prot.c \
+ auth_gssapi.c auth_gssapi_misc.c bindresvport.c \
+ clnt_generic.c clnt_perror.c clnt_raw.c clnt_simple.c clnt_tcp.c \
+ clnt_udp.c rpc_dtablesize.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_prot.c rpc_commondata.c rpc_callmsg.c \
+ svc.c svc_auth.c svc_auth_unix.c svc_auth_any.c svc_auth_gssapi.c \
+ svc_raw.c svc_run.c svc_simple.c \
+ svc_tcp.c svc_udp.c xdr.c xdr_array.c xdr_float.c xdr_mem.c \
+ xdr_rec.c xdr_reference.c xdr_stdio.c xdr_alloc.c
+
+OBJS = auth_none.o auth_unix.o auth_any.o authunix_prot.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 rpc_dtablesize.o get_myaddress.o getrpcent.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_unix.o svc_auth_any.o svc_auth_gssapi.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
+
+HDRS = auth.h auth_unix.h auth_gssapi.h clnt.h pmap_clnt.h \
+ pmap_prot.h pmap_rmt.h rpc.h rpc_msg.h svc.h svc_auth.h types.h xdr.h
+
+HDRS_DIR = rpc
+
+LIB = librpclib.a
+
+CFLAGS := -I.. $(CFLAGS) -DDEBUG_GSSAPI=0 $(D_NEEDS_RPCENT)
+
+expand StageLibrary
+
+expand StageIncludes
+
+expand Depend
+
+expand SubdirTarget
+
+expand Saber
+
diff --git a/src/lib/rpc/auth.h b/src/lib/rpc/auth.h
new file mode 100644
index 0000000000..4b0a40ccc0
--- /dev/null
+++ b/src/lib/rpc/auth.h
@@ -0,0 +1,197 @@
+/* @(#)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".
+ */
+
+
+#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 */
+};
+
+union des_block {
+#if 0 /* XXX nothing uses this, anyway */
+ struct {
+ rpc_u_int32 high;
+ rpc_u_int32 low;
+ } key;
+#endif
+ char c[8];
+};
+typedef union des_block des_block;
+extern bool_t 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 */
+ unsigned int oa_length; /* not to exceed MAX_AUTH_BYTES */
+};
+
+
+/*
+ * Auth handle, interface to client side authenticators.
+ */
+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 */
+ void (*ah_destroy)(); /* destroy this structure */
+ int (*ah_wrap)(); /* encode data for wire */
+ int (*ah_unwrap)(); /* decode data from wire */
+ } *ah_ops;
+ caddr_t 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))
+
+
+extern struct opaque_auth _null_auth;
+
+
+/*
+ * These are the various implementations of client side authenticators.
+ */
+
+/*
+ * Any style authentication. These routines can be used by any
+ * authentication style that does not use the wrap/unwrap functions.
+ */
+int authany_wrap(), authany_unwrap();
+
+/*
+ * 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();
+extern AUTH *authunix_create_default(); /* takes no parameters */
+extern AUTH *authnone_create(); /* takes no parameters */
+extern AUTH *authdes_create();
+
+/*
+ * GSS-API style authentication:
+ * see <rpc/auth_gssapi.h>
+ */
+
+#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 */
+
+/*
+ * BACKWARDS COMPATIBILIY! OpenV*Secure 1.0 had AUTH_GSSAPI == 4. We
+ * need to accept this value until 1.0 is dead.
+ */
+#define AUTH_GSSAPI_COMPAT 4
diff --git a/src/lib/rpc/auth_any.c b/src/lib/rpc/auth_any.c
new file mode 100644
index 0000000000..5e2a8633a4
--- /dev/null
+++ b/src/lib/rpc/auth_any.c
@@ -0,0 +1,19 @@
+/*
+ * auth_any.c
+ * Provides default functions for authentication flavors that do not
+ * use all the fields in structauth_ops.
+ */
+
+#include <stdio.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/auth.h>
+
+int authany_wrap(auth, xdrs, xfunc, xwhere)
+ AUTH *auth;
+ XDR *xdrs;
+ xdrproc_t xfunc;
+ caddr_t xwhere;
+{
+ return (*xfunc)(xdrs, xwhere);
+}
diff --git a/src/lib/rpc/auth_gssapi.c b/src/lib/rpc/auth_gssapi.c
new file mode 100644
index 0000000000..0ffe96d188
--- /dev/null
+++ b/src/lib/rpc/auth_gssapi.c
@@ -0,0 +1,901 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Header$
+ *
+ * $Log$
+ * Revision 1.23 1996/07/22 20:39:39 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.22.4.1 1996/07/18 04:18:29 marc
+ * merged in changes from OV_9510_BP to OV_9510_FINAL1
+ *
+ * Revision 1.22.2.1 1996/06/20 23:35:31 marc
+ * File added to the repository on a branch
+ *
+ * Revision 1.22 1996/06/05 20:56:16 bjaspan
+ * memset bindings to zero before use
+ *
+ * Revision 1.21 1996/05/12 06:11:38 marc
+ * renamed lots of types: u_foo to unsigned foo, and foo32 to rpc_foo32. This is to make autoconfiscation less painful.
+ *
+ * Revision 1.20 1995/12/13 14:02:45 grier
+ * Longs to ints for Alpha
+ *
+ * Revision 1.19 1995/10/31 16:36:00 bjaspan
+ * GS reported this bug. When talking to a 1.1 server, the server will
+ * not fail indicating the version is wrong because it never checks the
+ * version; it just responds with call_res.version 1. So we have to
+ * deal. Oops.
+ *
+ * It's amazing what can fall through the cracks when most of the
+ * development team is fired..
+ *
+ * Revision 1.18 1995/10/31 16:07:06 bjaspan
+ * fix from grier
+ *
+ * Revision 1.17 1995/08/24 21:06:26 bjaspan
+ * set acceptor channel bindings
+ *
+ * Revision 1.16 1995/08/23 20:27:37 bjaspan
+ * [secure-rpc/3392] add channel bindinds to the rpc
+ *
+ * Revision 1.15 1995/05/08 22:32:01 marc
+ * change call_arg.version from 1 to 2 to indicate the new client is in use.
+ *
+ * Revision 1.14 1995/03/22 22:05:20 jik
+ * Reorder the auth_ops structure, to agree with the order of the version of
+ * this library in the GK source tree. I chose to reorder this one rather
+ * than reorder the GK tree because Barry says that the order in the GK tree
+ * makes more sense.
+ *
+ * Revision 1.13 1994/10/27 12:39:02 jik
+ * [secure-rpc/2808: add credential versioning]
+ *
+ * Sandbox:
+ *
+ * [secure-rpc/2808] add version field to client creds
+ *
+ * change to use GSS_ERROR &c macros; I don't think this is correct
+ * =============================================================================
+ *
+ * Revision 1.14 1994/10/26 20:03:46 bjaspan
+ * [secure-rpc/2808] add version field to client creds
+ *
+ * Revision 1.13 1994/04/07 16:12:06 jik
+ * The second argument to xdr_opaque_auth is struct auth *, not struct
+ * auth.
+ *
+ * Revision 1.12 1993/12/08 21:42:43 bjaspan
+ * use AUTH_GSSAPI_DISPLAY_STATUS macro, reindent
+ *
+ * Revision 1.11 1993/12/06 21:21:03 bjaspan
+ * debugging levels
+ *
+ * Revision 1.10 1993/11/18 23:13:07 bjaspan
+ * add some function comments
+ *
+ * Revision 1.9 1993/11/15 19:50:03 bjaspan
+ * redefine AUTH_REFRESH to take the error message as an argument, and
+ * change auth_gssapi_refresh to increment the seq_num on REJECTEDVERF
+ *
+ * Revision 1.8 1993/11/12 02:31:59 bjaspan
+ * set rpc_createerr as appropriate
+ *
+ * Revision 1.7 1993/11/03 21:21:02 bjaspan
+ * fix seq_num handling in cases of errors and retransmission
+ *
+ * Revision 1.6 1993/11/01 19:55:20 bjaspan
+ * display gss_major and gss_minor, and unstatic auth_gssapi_debug
+ *
+ * Revision 1.5 1993/10/28 22:07:33 bjaspan
+ * create_default takes char *, use seq_num in args/results
+ *
+ * Revision 1.4 1993/10/26 21:11:53 bjaspan
+ * working
+ *
+ * Revision 1.3 1993/10/21 19:01:09 bjaspan
+ * added auth_gssapi_destroy, cleaned up a few things
+ *
+ * Revision 1.2 1993/10/19 03:10:58 bjaspan
+ * snapshot: GSS-API working in hacked up state, not seal/unseal
+ *
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/errno.h>
+
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_generic.h>
+
+#include <rpc/rpc.h>
+#include <rpc/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();
+static bool_t auth_gssapi_marshall();
+static bool_t auth_gssapi_validate();
+static bool_t auth_gssapi_refresh();
+static bool_t auth_gssapi_wrap();
+static bool_t auth_gssapi_unwrap();
+static void auth_gssapi_destroy();
+
+static bool_t marshall_new_creds();
+
+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;
+ rpc_u_int32 seq_num;
+ int def_cred;
+
+ /* pre-serialized ah_cred */
+ unsigned char cred_buf[MAX_AUTH_BYTES];
+ rpc_u_int32 cred_len;
+};
+#define AUTH_PRIVATE(auth) ((struct auth_gssapi_data *)auth->ah_private)
+
+extern struct rpc_createerr rpc_createerr;
+
+/*
+ * 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,
+ int req_flags,
+ OM_uint32 time_req,
+ gss_OID *actual_mech_type,
+ int *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 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;
+
+ 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);
+
+ /* don't assume the caller will want to change clnt->cl_auth */
+ save_auth = clnt->cl_auth;
+ clnt->cl_auth = auth;
+
+ /* start by trying latest version */
+ call_arg.version = 3;
+
+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;
+
+ if (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",
+ *((rpc_u_int32 *)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(rpc_u_int32)) {
+ PRINTF(("gssapi_create: gss_unseal gave %d bytes\n",
+ isn_buf.length));
+ goto cleanup;
+ }
+
+ AUTH_PRIVATE(auth)->seq_num = (rpc_u_int32)
+ ntohl(*((rpc_u_int32*)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",
+ *((rpc_u_int32 *)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_msg, client_handle)
+ 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, 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 *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, xdrs)
+ AUTH *auth;
+ XDR *xdrs;
+{
+ OM_uint32 minor_stat;
+ gss_buffer_desc out_buf;
+ rpc_u_int32 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, verf)
+ AUTH *auth;
+ struct opaque_auth *verf;
+{
+ gss_buffer_desc in_buf;
+ rpc_u_int32 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, msg)
+ 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 *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, out_xdrs, xdr_func, xdr_ptr)
+ 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, in_xdrs, xdr_func, xdr_ptr)
+ 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/src/lib/rpc/auth_gssapi.h b/src/lib/rpc/auth_gssapi.h
new file mode 100644
index 0000000000..9092149a55
--- /dev/null
+++ b/src/lib/rpc/auth_gssapi.h
@@ -0,0 +1,161 @@
+/*
+ * auth_gssapi.h, Protocol for GSS-API style authentication parameters for RPC
+ *
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Id$
+ * $Source$
+ *
+ * $Log$
+ * Revision 1.18 1996/07/22 20:39:41 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.17.4.1 1996/07/18 04:18:31 marc
+ * merged in changes from OV_9510_BP to OV_9510_FINAL1
+ *
+ * Revision 1.17.2.1 1996/06/20 23:35:44 marc
+ * File added to the repository on a branch
+ *
+ * Revision 1.17 1996/05/12 06:11:38 marc
+ * renamed lots of types: u_foo to unsigned foo, and foo32 to rpc_foo32. This is to make autoconfiscation less painful.
+ *
+ * Revision 1.16 1996/01/31 19:16:16 grier
+ * [secure/3570]
+ * Remove (void *) casts to memcpy() args
+ *
+ * Revision 1.15 1995/12/28 17:54:34 jik
+ * Don't define DEBUG_GSSAPI here.
+ *
+ * Revision 1.14 1995/12/13 14:03:01 grier
+ * Longs to ints for Alpha
+ *
+ * Revision 1.13 1995/11/07 23:15:26 grier
+ * memcpy() casts
+ *
+ * Revision 1.12 1995/05/25 18:35:59 bjaspan
+ * [secure-rpc/3103] log misc errors from RPC
+ *
+ * Revision 1.11 1994/10/27 12:39:14 jik
+ * [secure-rpc/2808: add credential versioning]
+ *
+ * Sandbox:
+ *
+ * [secure-rpc/2808] add version field to client creds
+ *
+ * Revision 1.11 1994/10/26 20:04:00 bjaspan
+ * [secure-rpc/2808] add version field to client creds
+ *
+ * Revision 1.10 1993/11/12 02:32:50 bjaspan
+ * add badauth, don't use const_gss_OID
+ *
+ * Revision 1.9 1993/11/03 23:46:15 bjaspan
+ * new log_badverf format
+ *
+ * Revision 1.8 1993/11/03 21:21:38 bjaspan
+ * added log_badverf
+ *
+ * Revision 1.7 1993/11/03 01:29:56 bjaspan
+ * add const to gss_nt_*
+ *
+ */
+
+#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
+
+typedef struct _auth_gssapi_name {
+ char *name;
+ gss_OID type;
+} auth_gssapi_name;
+
+typedef struct _auth_gssapi_creds {
+ rpc_u_int32 version;
+ bool_t auth_msg;
+ gss_buffer_desc client_handle;
+} auth_gssapi_creds;
+
+typedef struct _auth_gssapi_init_arg {
+ rpc_u_int32 version;
+ gss_buffer_desc token;
+} auth_gssapi_init_arg;
+
+typedef struct _auth_gssapi_init_res {
+ rpc_u_int32 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_authgssapi_creds();
+bool_t xdr_authgssapi_init_arg();
+bool_t xdr_authgssapi_init_res();
+
+bool_t auth_gssapi_wrap_data(OM_uint32 *major, OM_uint32 *minor,
+ gss_ctx_id_t context, rpc_u_int32 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, rpc_u_int32 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,
+ int req_flags,
+ OM_uint32 time_req,
+ gss_OID *actual_mech_type,
+ int *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 _svcauth_gssapi_set_name(char *name, gss_OID name_type);
+
+void _svcauth_set_log_badauth_func(auth_gssapi_log_badauth_func func,
+ caddr_t data);
+void _svcauth_set_log_badverf_func(auth_gssapi_log_badverf_func func,
+ caddr_t data);
+void _svcauth_set_log_miscerr_func(auth_gssapi_log_miscerr_func 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)))
+
diff --git a/src/lib/rpc/auth_gssapi_misc.c b/src/lib/rpc/auth_gssapi_misc.c
new file mode 100644
index 0000000000..bd7b6e5a3f
--- /dev/null
+++ b/src/lib/rpc/auth_gssapi_misc.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Header$
+ *
+ * $Log$
+ * Revision 1.14 1996/07/22 20:39:44 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.13.4.1 1996/07/18 04:18:32 marc
+ * merged in changes from OV_9510_BP to OV_9510_FINAL1
+ *
+ * Revision 1.13.2.1 1996/06/20 23:35:49 marc
+ * File added to the repository on a branch
+ *
+ * Revision 1.13 1996/05/12 06:11:38 marc
+ * renamed lots of types: u_foo to unsigned foo, and foo32 to rpc_foo32. This is to make autoconfiscation less painful.
+ *
+ * Revision 1.12 1996/02/25 15:53:57 grier
+ * [secure/3570]
+ * OSF1 long changes
+ *
+ * Revision 1.11 1995/12/13 14:03:30 grier
+ * Longs to ints for Alpha
+ *
+ * Revision 1.10 1994/10/27 12:39:23 jik
+ * [secure-rpc/2808: add credential versioning]
+ *
+ * Sandbox:
+ *
+ * [secure-rpc/2808] back out the backwards compat hack (I only put it
+ * there in case we ever decide we want it, which we won't) and just
+ * handle the version field as if it were always there
+ *
+ * [secure-rpc/2808] add a backwards-compatible version field encoder
+ *
+ * change to use GSS_ERROR &c macros; I don't think this is correct
+ * =============================================================================
+ *
+ * Revision 1.12 1994/10/26 19:48:45 bjaspan
+ * [secure-rpc/2808] back out the backwards compat hack (I only put it
+ * there in case we ever decide we want it, which we won't) and just
+ * handle the version field as if it were always there
+ *
+ * Revision 1.11 1994/10/26 19:47:42 bjaspan
+ * [secure-rpc/2808] add a backwards-compatible version field encoder
+ *
+ * Revision 1.10 1993/12/19 22:19:40 bjaspan
+ * [secure-rpc/1077] use free instead of xdr_free(xdr_bytes,...) because
+ * xdr_bytes takes non-standard arguments
+ *
+ * Revision 1.9 1993/12/08 21:43:37 bjaspan
+ * use AUTH_GSSAPI_DISPLAY_STATUS macro, reindent
+ *
+ * Revision 1.8 1993/12/06 21:21:21 bjaspan
+ * debugging levels
+ *
+ * Revision 1.7 1993/11/03 23:46:34 bjaspan
+ * add debugging printfs showing amount of data wrapped/unwrapped
+ *
+ * Revision 1.6 1993/11/03 21:21:53 bjaspan
+ * unstatic misc_debug_gssapi
+ *
+ * Revision 1.5 1993/11/01 19:55:54 bjaspan
+ * improve display_status messages, and include gss_{major,minor}
+ *
+ * Revision 1.4 1993/10/28 22:08:21 bjaspan
+ * wrap/unwrap_data include sequence number in arg/result block
+ *
+ * Revision 1.3 1993/10/27 18:26:16 bjaspan
+ * use xdr_free instead of free(in_buf.value); doesn't actually make a
+ * difference, though
+ *
+ * Revision 1.2 1993/10/26 21:12:38 bjaspan
+ * cleaning
+ *
+ * Revision 1.1 1993/10/19 03:12:28 bjaspan
+ * Initial revision
+ *
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <rpc/rpc.h>
+#include <stdio.h>
+
+#include <gssapi/gssapi.h>
+#include <rpc/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(xdrs, 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.
+ */
+ return xdr_bytes(xdrs, (char **) &buf->value, (unsigned int *) &buf->length,
+ (xdrs->x_op == XDR_DECODE && buf->value == NULL)
+ ? (unsigned int) -1 : (unsigned int) buf->length);
+}
+
+bool_t xdr_authgssapi_creds(xdrs, 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(xdrs, 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(xdrs, 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(context, seq_num, out_buf)
+ gss_ctx_id_t context;
+ rpc_u_int32 seq_num;
+ gss_buffer_t out_buf;
+{
+ gss_buffer_desc in_buf;
+ OM_uint32 gssstat, minor_stat;
+ rpc_u_int32 nl_seq_num;
+
+ nl_seq_num = htonl(seq_num);
+
+ in_buf.length = sizeof(rpc_u_int32);
+ 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(context, in_buf, seq_num)
+ gss_ctx_id_t context;
+ gss_buffer_t in_buf;
+ rpc_u_int32 *seq_num;
+{
+ gss_buffer_desc out_buf;
+ OM_uint32 gssstat, minor_stat;
+ rpc_u_int32 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(rpc_u_int32)) {
+ PRINTF(("gssapi_unseal_seq: unseal gave %d bytes\n",
+ out_buf.length));
+ gss_release_buffer(&minor_stat, &out_buf);
+ return FALSE;
+ }
+
+ nl_seq_num = *((rpc_u_int32 *) out_buf.value);
+ *seq_num = (rpc_u_int32) 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;
+ int 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
+ fprintf(stderr,"GSS-API authentication error %s: "
+ "recursive failure!\n", msg);
+ return;
+ }
+
+ fprintf(stderr, "GSS-API authentication error %s: %s\n", m,
+ (char *)msg.value);
+ (void) gss_release_buffer(&minor_stat, &msg);
+
+ if (!msg_ctx)
+ break;
+ }
+}
+
+bool_t auth_gssapi_wrap_data(major, minor, context, seq_num, out_xdrs,
+ xdr_func, xdr_ptr)
+ OM_uint32 *major, *minor;
+ gss_ctx_id_t context;
+ rpc_u_int32 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;
+
+ 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",
+ in_buf.length, out_buf.length));
+
+ /* write the token */
+ if (! xdr_bytes(out_xdrs, (char **) &out_buf.value,
+ (unsigned int *) &out_buf.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(major, minor, context, seq_num,
+ in_xdrs, xdr_func, xdr_ptr)
+ OM_uint32 *major, *minor;
+ gss_ctx_id_t context;
+ rpc_u_int32 seq_num;
+ XDR *in_xdrs;
+ bool_t (*xdr_func)();
+ caddr_t xdr_ptr;
+{
+ gss_buffer_desc in_buf, out_buf;
+ XDR temp_xdrs;
+ rpc_u_int32 verf_seq_num;
+ int conf, qop;
+
+ 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,
+ (unsigned int *) &in_buf.length, (unsigned int) -1)) {
+ PRINTF(("gssapi_unwrap_data: deserializing encrypted data failed\n"));
+ return FALSE;
+ }
+
+ *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_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/src/lib/rpc/auth_none.c b/src/lib/rpc/auth_none.c
new file mode 100644
index 0000000000..90f3bb8be1
--- /dev/null
+++ b/src/lib/rpc/auth_none.c
@@ -0,0 +1,136 @@
+/* @(#)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 <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/auth.h>
+#include <stdlib.h>
+#define MAX_MARSHEL_SIZE 20
+
+/*
+ * Authenticator operations routines
+ */
+static void authnone_verf();
+static void authnone_destroy();
+static bool_t authnone_marshal();
+static bool_t authnone_validate();
+static bool_t authnone_refresh();
+
+static struct auth_ops ops = {
+ authnone_verf,
+ authnone_marshal,
+ authnone_validate,
+ authnone_refresh,
+ authnone_destroy,
+ authany_wrap,
+ authany_wrap,
+};
+
+static struct authnone_private {
+ AUTH no_client;
+ char marshalled_client[MAX_MARSHEL_SIZE];
+ unsigned int mcnt;
+} *authnone_private;
+
+AUTH *
+authnone_create()
+{
+ 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 = _null_auth;
+ ap->no_client.ah_ops = &ops;
+ xdrs = &xdr_stream;
+ xdrmem_create(xdrs, ap->marshalled_client, (unsigned 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(client, xdrs)
+ 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));
+}
+
+static void
+authnone_verf()
+{
+}
+
+static bool_t
+authnone_validate()
+{
+
+ return (TRUE);
+}
+
+static bool_t
+authnone_refresh()
+{
+
+ return (FALSE);
+}
+
+static void
+authnone_destroy()
+{
+}
diff --git a/src/lib/rpc/auth_unix.c b/src/lib/rpc/auth_unix.c
new file mode 100644
index 0000000000..b41e442fc9
--- /dev/null
+++ b/src/lib/rpc/auth_unix.c
@@ -0,0 +1,322 @@
+/* @(#)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 <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/auth.h>
+#include <rpc/auth_unix.h>
+
+
+/*
+ * Unix authenticator operations vector
+ */
+static void authunix_nextverf();
+static bool_t authunix_marshal();
+static bool_t authunix_validate();
+static bool_t authunix_refresh();
+static void authunix_destroy();
+
+static struct auth_ops auth_unix_ops = {
+ authunix_nextverf,
+ authunix_marshal,
+ authunix_validate,
+ authunix_refresh,
+ authunix_destroy,
+ authany_wrap,
+ authany_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 */
+ rpc_u_int32 au_shfaults; /* short hand cache faults */
+ char au_marshed[MAX_AUTH_BYTES];
+ unsigned int au_mpos; /* xdr pos at end of marshed */
+};
+#define AUTH_PRIVATE(auth) ((struct audata *)auth->ah_private)
+
+static bool_t marshal_new_auth();
+
+
+/*
+ * Create a unix style authenticator.
+ * Returns an auth handle with the given stuff in it.
+ */
+AUTH *
+authunix_create(machname, uid, gid, len, aup_gids)
+ 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 = _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 = (unsigned 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((unsigned int) len);
+#else
+ if ((au->au_origcred.oa_base = mem_alloc((unsigned int) len)) == NULL) {
+ (void)fprintf(stderr, "authunix_create: out of memory\n");
+ return (NULL);
+ }
+#endif
+ memmove(au->au_origcred.oa_base, mymem, (unsigned 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()
+{
+ register int len;
+ char machname[MAX_MACHINE_NAME + 1];
+ register int uid;
+ register int gid;
+ int gids[NGRPS];
+
+ if (gethostname(machname, MAX_MACHINE_NAME) == -1)
+ abort();
+ machname[MAX_MACHINE_NAME] = 0;
+ uid = geteuid();
+ gid = getegid();
+ if ((len = getgroups(NGRPS, gids)) < 0)
+ abort();
+ return (authunix_create(machname, uid, gid, len, gids));
+}
+
+/*
+ * authunix operations
+ */
+
+static void
+authunix_nextverf(auth)
+ AUTH *auth;
+{
+ /* no action necessary */
+}
+
+static bool_t
+authunix_marshal(auth, xdrs)
+ 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(auth, verf)
+ 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(auth)
+ register AUTH *auth;
+{
+ 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(auth)
+ 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 bool_t
+marshal_new_auth(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);
+}
diff --git a/src/lib/rpc/auth_unix.h b/src/lib/rpc/auth_unix.h
new file mode 100644
index 0000000000..4b54f1db69
--- /dev/null
+++ b/src/lib/rpc/auth_unix.h
@@ -0,0 +1,72 @@
+/* @(#)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.
+ */
+
+/*
+ * 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 {
+ rpc_u_int32 aup_time;
+ char *aup_machname;
+ int aup_uid;
+ int aup_gid;
+ unsigned int aup_len;
+ int *aup_gids;
+};
+
+extern bool_t xdr_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;
+};
diff --git a/src/lib/rpc/authunix_prot.c b/src/lib/rpc/authunix_prot.c
new file mode 100644
index 0000000000..36770f2989
--- /dev/null
+++ b/src/lib/rpc/authunix_prot.c
@@ -0,0 +1,66 @@
+/* @(#)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 <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/auth.h>
+#include <rpc/auth_unix.h>
+
+/*
+ * XDR for unix authentication parameters.
+ */
+bool_t
+xdr_authunix_parms(xdrs, p)
+ 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/src/lib/rpc/bindresvport.c b/src/lib/rpc/bindresvport.c
new file mode 100644
index 0000000000..875aeefb64
--- /dev/null
+++ b/src/lib/rpc/bindresvport.c
@@ -0,0 +1,79 @@
+static char sccsid[] = "@(#)bindresvport.c 2.2 88/07/29 4.0 RPCSRC 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
+ */
+
+/*
+ * Copyright (c) 1987 by Sun Microsystems, Inc.
+ */
+
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+/*
+ * Bind a socket to a privileged IP port
+ */
+bindresvport(sd, sin)
+ int sd;
+ struct sockaddr_in *sin;
+{
+ int res;
+ static short port;
+ struct sockaddr_in myaddr;
+ extern int errno;
+ int i;
+
+#define STARTPORT 600
+#define ENDPORT (IPPORT_RESERVED - 1)
+#define NPORTS (ENDPORT - STARTPORT + 1)
+
+ if (sin == (struct sockaddr_in *)0) {
+ sin = &myaddr;
+ memset(sin, 0, sizeof (*sin));
+ sin->sin_family = AF_INET;
+ } else if (sin->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++) {
+ sin->sin_port = htons(port++);
+ if (port > ENDPORT) {
+ port = STARTPORT;
+ }
+ res = bind(sd, (struct sockaddr *) sin,
+ sizeof(struct sockaddr_in));
+ }
+ return (res);
+}
diff --git a/src/lib/rpc/clnt.h b/src/lib/rpc/clnt.h
new file mode 100644
index 0000000000..442a96d44d
--- /dev/null
+++ b/src/lib/rpc/clnt.h
@@ -0,0 +1,335 @@
+/* @(#)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 _CLNT_
+#define _CLNT_
+
+/*
+ * 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 {
+ rpc_u_int32 low; /* lowest verion supported */
+ rpc_u_int32 high; /* highest verion supported */
+ } RE_vers;
+ struct { /* maybe meaningful if RPC_FAILED */
+ rpc_int32 s1;
+ rpc_int32 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 {
+ AUTH *cl_auth; /* authenticator */
+ struct clnt_ops {
+ enum clnt_stat (*cl_call)(); /* call remote procedure */
+ void (*cl_abort)(); /* abort a call */
+ void (*cl_geterr)(); /* get specific error code */
+ bool_t (*cl_freeres)(); /* frees results */
+ void (*cl_destroy)();/* destroy this structure */
+ bool_t (*cl_control)();/* the ioctl() of rpc */
+ } *cl_ops;
+ caddr_t 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;
+ * rpc_u_int32 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;
+ * unsigned 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 ((rpc_u_int32)1)
+#define RPCTEST_VERSION ((rpc_u_int32)1)
+#define RPCTEST_NULL_PROC ((rpc_u_int32)2)
+#define RPCTEST_NULL_BATCH_PROC ((rpc_u_int32)3)
+
+/*
+ * By convention, procedure 0 takes null arguments and returns them
+ */
+
+#define NULLPROC ((rpc_u_int32)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)
+ * rpc_u_int32 prog;
+ * rpc_u_int32 vers;
+ */
+extern CLIENT *clntraw_create();
+
+
+/*
+ * Generic client creation routine. Supported protocols are "udp" and "tcp"
+ */
+extern CLIENT *
+clnt_create(/*host, prog, vers, prot*/); /*
+ char *host; -- hostname
+ rpc_u_int32 prog; -- program number
+ rpc_u_int32 vers; -- version number
+ char *prot; -- protocol
+*/
+
+
+
+
+/*
+ * TCP based rpc
+ * CLIENT *
+ * clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz)
+ * struct sockaddr_in *raddr;
+ * rpc_u_int32 prog;
+ * rpc_u_int32 version;
+ * register int *sockp;
+ * unsigned int sendsz;
+ * unsigned int recvsz;
+ */
+extern CLIENT *clnttcp_create();
+
+/*
+ * UDP based rpc.
+ * CLIENT *
+ * clntudp_create(raddr, program, version, wait, sockp)
+ * struct sockaddr_in *raddr;
+ * rpc_u_int32 program;
+ * rpc_u_int32 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;
+ * rpc_u_int32 program;
+ * rpc_u_int32 version;
+ * struct timeval wait;
+ * int *sockp;
+ * unsigned int sendsz;
+ * unsigned int recvsz;
+ */
+extern CLIENT *clntudp_create();
+extern CLIENT *clntudp_bufcreate();
+
+/*
+ * Print why creation failed
+ */
+void clnt_pcreateerror(/* char *msg */); /* stderr */
+char *clnt_spcreateerror(/* char *msg */); /* string */
+
+/*
+ * Like clnt_perror(), but is more verbose in its output
+ */
+void clnt_perrno(/* enum clnt_stat num */); /* stderr */
+
+/*
+ * Print an English error message, given the client error code
+ */
+void clnt_perror(/* CLIENT *clnt, char *msg */); /* stderr */
+char *clnt_sperror(/* CLIENT *clnt, char *msg */); /* 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 */
+
+#endif /*!_CLNT_*/
diff --git a/src/lib/rpc/clnt_generic.c b/src/lib/rpc/clnt_generic.c
new file mode 100644
index 0000000000..f111c2e147
--- /dev/null
+++ b/src/lib/rpc/clnt_generic.c
@@ -0,0 +1,110 @@
+/* @(#)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 <rpc/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(hostname, prog, vers, proto)
+ char *hostname;
+ unsigned prog;
+ unsigned vers;
+ char *proto;
+{
+ struct hostent *h;
+ struct protoent *p;
+ struct sockaddr_in sin;
+ 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);
+ }
+ sin.sin_family = h->h_addrtype;
+ sin.sin_port = 0;
+ memset(sin.sin_zero, 0, sizeof(sin.sin_zero));
+ memmove((char*)&sin.sin_addr, h->h_addr, h->h_length);
+ 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(&sin, 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(&sin, 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/src/lib/rpc/clnt_perror.c b/src/lib/rpc/clnt_perror.c
new file mode 100644
index 0000000000..63eef49f0f
--- /dev/null
+++ b/src/lib/rpc/clnt_perror.c
@@ -0,0 +1,306 @@
+/* @(#)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 <rpc/types.h>
+#include <rpc/auth.h>
+#include <rpc/clnt.h>
+
+#ifdef NEED_SYS_ERRLIST
+extern char *sys_errlist[];
+#endif
+static char *auth_errmsg();
+
+extern char *strcpy();
+
+static char *buf;
+
+static char *
+_buf()
+{
+
+ if (buf == 0)
+ buf = (char *)malloc(256);
+ return (buf);
+}
+
+/*
+ * Print reply error info
+ */
+char *
+clnt_sperror(rpch, s)
+ CLIENT *rpch;
+ char *s;
+{
+ struct rpc_err e;
+ void clnt_perrno();
+ char *err;
+ char *str = _buf();
+ char *strstart = str;
+
+ if (str == 0)
+ return (0);
+ CLNT_GETERR(rpch, &e);
+
+ (void) sprintf(str, "%s: ", s);
+ str += strlen(str);
+
+ (void) strcpy(str, clnt_sperrno(e.re_status));
+ 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:
+ (void) sprintf(str, "; errno = %s",
+ sys_errlist[e.re_errno]);
+ str += strlen(str);
+ break;
+
+ case RPC_VERSMISMATCH:
+ (void) sprintf(str,
+ "; low version = %lu, high version = %lu",
+ e.re_vers.low, e.re_vers.high);
+ str += strlen(str);
+ break;
+
+ case RPC_AUTHERROR:
+ err = auth_errmsg(e.re_why);
+ (void) sprintf(str,"; why = ");
+ str += strlen(str);
+ if (err != NULL) {
+ (void) sprintf(str, "%s",err);
+ } else {
+ (void) sprintf(str,
+ "(unknown authentication error - %d)",
+ (int) e.re_why);
+ }
+ str += strlen(str);
+ break;
+
+ case RPC_PROGVERSMISMATCH:
+ (void) sprintf(str,
+ "; low version = %lu, high version = %lu",
+ e.re_vers.low, e.re_vers.high);
+ str += strlen(str);
+ break;
+
+ default: /* unknown */
+ (void) sprintf(str,
+ "; s1 = %lu, s2 = %lu",
+ e.re_lb.s1, e.re_lb.s2);
+ str += strlen(str);
+ break;
+ }
+ (void) sprintf(str, "\n");
+ return(strstart) ;
+}
+
+void
+clnt_perror(rpch, s)
+ 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(stat)
+ 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(num)
+ enum clnt_stat num;
+{
+ (void) fprintf(stderr,"%s",clnt_sperrno(num));
+}
+
+
+char *
+clnt_spcreateerror(s)
+ char *s;
+{
+ extern int sys_nerr;
+ char *str = _buf();
+
+ if (str == 0)
+ return(0);
+ (void) sprintf(str, "%s: ", s);
+ (void) strcat(str, clnt_sperrno(rpc_createerr.cf_stat));
+ switch (rpc_createerr.cf_stat) {
+ case RPC_PMAPFAILURE:
+ (void) strcat(str, " - ");
+ (void) strcat(str,
+ clnt_sperrno(rpc_createerr.cf_error.re_status));
+ break;
+
+ case RPC_SYSTEMERROR:
+ (void) strcat(str, " - ");
+ if (rpc_createerr.cf_error.re_errno > 0
+ && rpc_createerr.cf_error.re_errno < sys_nerr)
+ (void) strcat(str,
+ sys_errlist[rpc_createerr.cf_error.re_errno]);
+ else
+ (void) sprintf(&str[strlen(str)], "Error %d",
+ rpc_createerr.cf_error.re_errno);
+ break;
+ }
+ (void) strcat(str, "\n");
+ return (str);
+}
+
+void
+clnt_pcreateerror(s)
+ 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(stat)
+ 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/src/lib/rpc/clnt_raw.c b/src/lib/rpc/clnt_raw.c
new file mode 100644
index 0000000000..d05dbaa7e1
--- /dev/null
+++ b/src/lib/rpc/clnt_raw.c
@@ -0,0 +1,239 @@
+/* @(#)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 <rpc/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];
+ char mashl_callmsg[MCALL_MSG_SIZE];
+ unsigned int mcnt;
+} *clntraw_private;
+
+static enum clnt_stat clntraw_call();
+static void clntraw_abort();
+static void clntraw_geterr();
+static bool_t clntraw_freeres();
+static bool_t clntraw_control();
+static void clntraw_destroy();
+
+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(prog, vers)
+ rpc_u_int32 prog;
+ rpc_u_int32 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->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(h, proc, xargs, argsp, xresults, resultsp, timeout)
+ CLIENT *h;
+ rpc_u_int32 proc;
+ xdrproc_t xargs;
+ caddr_t argsp;
+ xdrproc_t xresults;
+ caddr_t 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);
+ ((struct rpc_msg *)clp->mashl_callmsg)->rm_xid ++ ;
+ if ((! XDR_PUTBYTES(xdrs, clp->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 = _null_auth;
+ msg.acpted_rply.ar_results.where = resultsp;
+ msg.acpted_rply.ar_results.proc = xresults;
+ if (! xdr_replymsg(xdrs, &msg))
+ return (RPC_CANTDECODERES);
+ sunrpc_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);
+}
+
+static void
+clntraw_geterr()
+{
+}
+
+
+static bool_t
+clntraw_freeres(cl, xdr_res, res_ptr)
+ CLIENT *cl;
+ xdrproc_t xdr_res;
+ caddr_t 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));
+}
+
+static void
+clntraw_abort()
+{
+}
+
+static bool_t
+clntraw_control()
+{
+ return (FALSE);
+}
+
+static void
+clntraw_destroy()
+{
+}
diff --git a/src/lib/rpc/clnt_simple.c b/src/lib/rpc/clnt_simple.c
new file mode 100644
index 0000000000..0d8f7a4df7
--- /dev/null
+++ b/src/lib/rpc/clnt_simple.c
@@ -0,0 +1,112 @@
+/* @(#)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>
+#include <rpc/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;
+
+callrpc(host, prognum, versnum, procnum, inproc, in, outproc, out)
+ char *host;
+ xdrproc_t inproc, outproc;
+ char *in, *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);
+ 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;
+ memmove((char *)&server_addr.sin_addr, hp->h_addr, hp->h_length);
+ server_addr.sin_family = AF_INET;
+ server_addr.sin_port = 0;
+ if ((crp->client = clntudp_create(&server_addr, (rpc_u_int32)prognum,
+ (rpc_u_int32)versnum, timeout, &crp->socket)) == NULL)
+ return ((int) rpc_createerr.cf_stat);
+ crp->valid = 1;
+ crp->oldprognum = prognum;
+ crp->oldversnum = versnum;
+ (void) strcpy(crp->oldhost, host);
+ }
+ 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/src/lib/rpc/clnt_tcp.c b/src/lib/rpc/clnt_tcp.c
new file mode 100644
index 0000000000..c573897f73
--- /dev/null
+++ b/src/lib/rpc/clnt_tcp.c
@@ -0,0 +1,476 @@
+/* @(#)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 <rpc/rpc.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <errno.h>
+#include <rpc/pmap_clnt.h>
+
+#define MCALL_MSG_SIZE 24
+
+extern int errno;
+
+static int readtcp();
+static int writetcp();
+
+static enum clnt_stat clnttcp_call();
+static void clnttcp_abort();
+static void clnttcp_geterr();
+static bool_t clnttcp_freeres();
+static bool_t clnttcp_control();
+static void clnttcp_destroy();
+
+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;
+ char ct_mcall[MCALL_MSG_SIZE]; /* marshalled callmsg */
+ unsigned int ct_mpos; /* pos after marshal */
+ XDR ct_xdrs;
+};
+
+/*
+ * 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(raddr, prog, vers, sockp, sendsz, recvsz)
+ struct sockaddr_in *raddr;
+ rpc_u_int32 prog;
+ rpc_u_int32 vers;
+ register int *sockp;
+ unsigned int sendsz;
+ unsigned int recvsz;
+{
+ CLIENT *h;
+ register struct ct_data *ct;
+ 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) {
+ unsigned 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_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(h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout)
+ register CLIENT *h;
+ rpc_u_int32 proc;
+ xdrproc_t xdr_args;
+ caddr_t args_ptr;
+ xdrproc_t xdr_results;
+ caddr_t 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;
+ rpc_u_int32 x_id;
+ rpc_u_int32 *msg_x_id = (rpc_u_int32 *)(ct->ct_mcall); /* 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_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 = _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)) {
+ 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
+ */
+ sunrpc_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(h, errp)
+ 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(cl, xdr_res, res_ptr)
+ CLIENT *cl;
+ xdrproc_t xdr_res;
+ caddr_t 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));
+}
+
+static void
+clnttcp_abort()
+{
+}
+
+static bool_t
+clnttcp_control(cl, request, info)
+ CLIENT *cl;
+ int request;
+ char *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(h)
+ 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(ct, buf, len)
+ register struct ct_data *ct;
+ caddr_t buf;
+ register int len;
+{
+#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;
+ switch (select(_rpc_dtablesize(), &readfds, (fd_set*)NULL, (fd_set*)NULL,
+ &(ct->ct_wait))) {
+ 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, 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(ct, buf, len)
+ struct ct_data *ct;
+ caddr_t buf;
+ int len;
+{
+ register int i, cnt;
+
+ for (cnt = len; cnt > 0; cnt -= i, buf += i) {
+ if ((i = write(ct->ct_sock, buf, cnt)) == -1) {
+ ct->ct_error.re_errno = errno;
+ ct->ct_error.re_status = RPC_CANTSEND;
+ return (-1);
+ }
+ }
+ return (len);
+}
diff --git a/src/lib/rpc/clnt_udp.c b/src/lib/rpc/clnt_udp.c
new file mode 100644
index 0000000000..000b9683df
--- /dev/null
+++ b/src/lib/rpc/clnt_udp.c
@@ -0,0 +1,460 @@
+/* @(#)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 <rpc/rpc.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#if defined(sparc)
+#include <sys/filio.h>
+#endif
+#include <netdb.h>
+#include <errno.h>
+#include <rpc/pmap_clnt.h>
+
+extern int errno;
+
+/*
+ * UDP bases client side rpc operations
+ */
+static enum clnt_stat clntudp_call();
+static void clntudp_abort();
+static void clntudp_geterr();
+static bool_t clntudp_freeres();
+static bool_t clntudp_control();
+static void clntudp_destroy();
+
+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 timeval cu_wait;
+ struct timeval cu_total;
+ struct rpc_err cu_error;
+ XDR cu_outxdrs;
+ unsigned int cu_xdrpos;
+ unsigned int cu_sendsz;
+ char *cu_outbuf;
+ unsigned 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(raddr, program, version, wait, sockp, sendsz, recvsz)
+ struct sockaddr_in *raddr;
+ rpc_u_int32 program;
+ rpc_u_int32 version;
+ struct timeval wait;
+ register int *sockp;
+ unsigned int sendsz;
+ unsigned int recvsz;
+{
+ CLIENT *cl;
+ register struct cu_data *cu;
+ 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) {
+ unsigned 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;
+ }
+ 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(raddr, program, version, wait, sockp)
+ struct sockaddr_in *raddr;
+ rpc_u_int32 program;
+ rpc_u_int32 version;
+ struct timeval wait;
+ register int *sockp;
+{
+
+ return(clntudp_bufcreate(raddr, program, version, wait, sockp,
+ UDPMSGSIZE, UDPMSGSIZE));
+}
+
+static enum clnt_stat
+clntudp_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout)
+ register CLIENT *cl; /* client handle */
+ rpc_u_int32 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 */
+ 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;
+ 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
+ */
+ (*(unsigned short *)(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 (sendto(cu->cu_sock, cu->cu_outbuf, outlen, 0,
+ (struct sockaddr *)&(cu->cu_raddr), cu->cu_rlen)
+ != 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 = _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;
+ switch (select(_rpc_dtablesize(), &readfds, (fd_set *)NULL,
+ (fd_set *)NULL, &(cu->cu_wait))) {
+
+ 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,
+ (int) 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(rpc_u_int32))
+ continue;
+ /* see if reply transaction id matches sent id */
+ if (*((rpc_u_int32 *)(cu->cu_inbuf)) != *((rpc_u_int32 *)(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, (unsigned int)inlen, XDR_DECODE);
+ ok = xdr_replymsg(&reply_xdrs, &reply_msg);
+ /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */
+ if (ok) {
+ sunrpc_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 {
+ cu->cu_error.re_status = RPC_CANTDECODERES;
+ }
+ return (cu->cu_error.re_status);
+}
+
+static void
+clntudp_geterr(cl, errp)
+ 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(cl, xdr_res, res_ptr)
+ CLIENT *cl;
+ xdrproc_t xdr_res;
+ caddr_t 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));
+}
+
+static void
+clntudp_abort(/*h*/)
+ /*CLIENT *h;*/
+{
+}
+
+static bool_t
+clntudp_control(cl, request, info)
+ CLIENT *cl;
+ int request;
+ char *info;
+{
+ register struct cu_data *cu = (struct cu_data *)cl->cl_private;
+ int len;
+
+ 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:
+ len = sizeof(struct sockaddr);
+ if (getsockname(cu->cu_sock, (struct sockaddr*)info, &len) < 0)
+ return FALSE;
+ else
+ return TRUE;
+ default:
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+static void
+clntudp_destroy(cl)
+ 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/src/lib/rpc/configure.in b/src/lib/rpc/configure.in
new file mode 100644
index 0000000000..6084638d3d
--- /dev/null
+++ b/src/lib/rpc/configure.in
@@ -0,0 +1,41 @@
+AC_INIT(auth_gssapi.c)
+CONFIG_RULES
+AC_PROG_ARCHIVE
+AC_PROG_ARCHIVE_ADD
+AC_PROG_RANLIB
+AC_PROG_INSTALL
+
+AC_CHECK_SIZEOF(int)
+SIZEOF_INT=$ac_cv_sizeof_int
+AC_SUBST(SIZEOF_INT)
+AC_CHECK_SIZEOF(long)
+SIZEOF_LONG=$ac_cv_sizeof_long
+AC_SUBST(SIZEOF_LONG)
+
+DECLARE_SYS_ERRLIST
+
+V5_SHARED_LIB_OBJS
+V5_MAKE_SHARED_LIB(libgssrpc,1.0,.., ./rpc)
+GSSAPI_KRB5_SH_VERS=$krb5_cv_shlib_version_libgssapi_krb5
+AC_SUBST(GSSAPI_KRB5_SH_VERS)
+KRB5_SH_VERS=$krb5_cv_shlib_version_libkrb5
+AC_SUBST(KRB5_SH_VERS)
+CRYPTO_SH_VERS=$krb5_cv_shlib_version_libcrypto
+AC_SUBST(CRYPTO_SH_VERS)
+COMERR_SH_VERS=$krb5_cv_shlib_version_libcom_err
+AC_SUBST(COMERR_SH_VERS)
+CopySrcHeader(auth.h,[$](BUILDTOP)/include/rpc)
+CopySrcHeader(auth_gssapi.h,[$](BUILDTOP)/include/rpc)
+CopySrcHeader(auth_unix.h,[$](BUILDTOP)/include/rpc)
+CopySrcHeader(clnt.h,[$](BUILDTOP)/include/rpc)
+CopySrcHeader(netdb.h,[$](BUILDTOP)/include/rpc)
+CopySrcHeader(pmap_clnt.h,[$](BUILDTOP)/include/rpc)
+CopySrcHeader(pmap_prot.h,[$](BUILDTOP)/include/rpc)
+CopySrcHeader(pmap_rmt.h,[$](BUILDTOP)/include/rpc)
+CopySrcHeader(rpc.h,[$](BUILDTOP)/include/rpc)
+CopySrcHeader(rpc_msg.h,[$](BUILDTOP)/include/rpc)
+CopySrcHeader(svc.h,[$](BUILDTOP)/include/rpc)
+CopySrcHeader(svc_auth.h,[$](BUILDTOP)/include/rpc)
+CopyHeader(types.h,[$](BUILDTOP)/include/rpc)
+CopySrcHeader(xdr.h,[$](BUILDTOP)/include/rpc)
+V5_AC_OUTPUT_MAKEFILE( ,types.h:types.hin)
diff --git a/src/lib/rpc/get_myaddress.c b/src/lib/rpc/get_myaddress.c
new file mode 100644
index 0000000000..fa4c54e784
--- /dev/null
+++ b/src/lib/rpc/get_myaddress.c
@@ -0,0 +1,95 @@
+/* @(#)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.
+ */
+
+#include <rpc/types.h>
+#include <rpc/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(addr)
+ struct sockaddr_in *addr;
+{
+ int s;
+ char buf[BUFSIZ];
+ 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);
+}
diff --git a/src/lib/rpc/getrpcent.c b/src/lib/rpc/getrpcent.c
new file mode 100644
index 0000000000..e48d5b1e92
--- /dev/null
+++ b/src/lib/rpc/getrpcent.c
@@ -0,0 +1,256 @@
+/* @(#)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 <rpc/rpc.h>
+#include <rpc/netdb.h>
+#include <netdb.h>
+#include <string.h>
+#include <sys/socket.h>
+
+/* setrpcent is declared as int-returning in netdb.h on hpux */
+/* setrpcent is declared as int-returning in rpc/rpcent.h on Solaris */
+#if !defined(hpux) && !(defined(sun) && defined(__svr4__))
+#define SETRPCENT_TYPE void
+#else
+#define SETRPCENT_TYPE int
+#endif
+
+/* endrpcent is declared as int-returning in netdb.h on hpux */
+#ifndef hpux
+#define ENDRPCENT_TYPE void
+#else
+#define ENDRPCENT_TYPE int
+#endif
+
+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 *_rpcdata();
+
+static struct rpcent *interpret();
+struct hostent *gethostent();
+char *inet_ntoa();
+
+static char RPCDB[] = "/etc/rpc";
+
+static struct rpcdata *
+_rpcdata()
+{
+ register struct rpcdata *d = rpcdata;
+
+ if (d == 0) {
+ d = (struct rpcdata *)calloc(1, sizeof (struct rpcdata));
+ rpcdata = d;
+ }
+ return (d);
+}
+
+struct rpcent *
+getrpcbynumber(number)
+ register int number;
+{
+ register struct rpcdata *d = _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(name)
+ 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(f)
+ 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()
+{
+ 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()
+{
+ 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(val, len)
+char *val;
+{
+ 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/src/lib/rpc/getrpcport.c b/src/lib/rpc/getrpcport.c
new file mode 100644
index 0000000000..d209a15274
--- /dev/null
+++ b/src/lib/rpc/getrpcport.c
@@ -0,0 +1,55 @@
+/* @(#)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 <rpc/rpc.h>
+#include <netdb.h>
+#include <sys/socket.h>
+
+getrpcport(host, prognum, versnum, proto)
+ char *host;
+{
+ struct sockaddr_in addr;
+ struct hostent *hp;
+
+ if ((hp = gethostbyname(host)) == NULL)
+ return (0);
+ memmove((char *) &addr.sin_addr, hp->h_addr, hp->h_length);
+ addr.sin_family = AF_INET;
+ addr.sin_port = 0;
+ return (pmap_getport(&addr, prognum, versnum, proto));
+}
diff --git a/src/lib/rpc/netdb.h b/src/lib/rpc/netdb.h
new file mode 100644
index 0000000000..f6b6374b55
--- /dev/null
+++ b/src/lib/rpc/netdb.h
@@ -0,0 +1,50 @@
+#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 */
+
+/* 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> */
+
+struct rpcent {
+ char *r_name; /* name of server for this rpc program */
+ char **r_aliases; /* alias list */
+ int r_number; /* rpc program number */
+};
+
+struct rpcent *getrpcbyname(), *getrpcbynumber(), *getrpcent();
+
+#endif
diff --git a/src/lib/rpc/pmap_clnt.c b/src/lib/rpc/pmap_clnt.c
new file mode 100644
index 0000000000..7218777ccf
--- /dev/null
+++ b/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 <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/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(program, version, protocol, port)
+ rpc_u_int32 program;
+ rpc_u_int32 version;
+ int protocol;
+ unsigned short 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(program, version)
+ rpc_u_int32 program;
+ rpc_u_int32 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/src/lib/rpc/pmap_clnt.h b/src/lib/rpc/pmap_clnt.h
new file mode 100644
index 0000000000..dfb00dcc55
--- /dev/null
+++ b/src/lib/rpc/pmap_clnt.h
@@ -0,0 +1,65 @@
+/* @(#)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.
+ */
+
+/*
+ * 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.
+ */
+
+extern bool_t pmap_set();
+extern bool_t pmap_unset();
+extern struct pmaplist *pmap_getmaps();
+enum clnt_stat pmap_rmtcall();
+enum clnt_stat clnt_broadcast();
+extern unsigned short pmap_getport();
diff --git a/src/lib/rpc/pmap_getmaps.c b/src/lib/rpc/pmap_getmaps.c
new file mode 100644
index 0000000000..472b2a46db
--- /dev/null
+++ b/src/lib/rpc/pmap_getmaps.c
@@ -0,0 +1,88 @@
+/* @(#)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 <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_clnt.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#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>
+#define NAMELEN 255
+#define MAX_BROADCAST_SIZE 1400
+
+extern int errno;
+
+/*
+ * Get a copy of the current port maps.
+ * Calls the pmap service remotely to do get the maps.
+ */
+struct pmaplist *
+pmap_getmaps(address)
+ struct sockaddr_in *address;
+{
+ struct pmaplist *head = (struct pmaplist *)NULL;
+ int socket = -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, &socket, 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(socket);
+ address->sin_port = 0;
+ return (head);
+}
diff --git a/src/lib/rpc/pmap_getport.c b/src/lib/rpc/pmap_getport.c
new file mode 100644
index 0000000000..40b764880c
--- /dev/null
+++ b/src/lib/rpc/pmap_getport.c
@@ -0,0 +1,91 @@
+/* @(#)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 <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/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.
+ */
+unsigned short
+pmap_getport(address, program, version, protocol)
+ struct sockaddr_in *address;
+ rpc_u_int32 program;
+ rpc_u_int32 version;
+ unsigned int protocol;
+{
+ unsigned short port = 0;
+ int socket = -1;
+ register CLIENT *client;
+ struct pmap parms;
+
+ address->sin_port = htons(PMAPPORT);
+ client = clntudp_bufcreate(address, PMAPPROG,
+ PMAPVERS, timeout, &socket, 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(socket);
+ address->sin_port = 0;
+ return (port);
+}
diff --git a/src/lib/rpc/pmap_prot.c b/src/lib/rpc/pmap_prot.c
new file mode 100644
index 0000000000..1dffffe17b
--- /dev/null
+++ b/src/lib/rpc/pmap_prot.c
@@ -0,0 +1,57 @@
+/* @(#)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 <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/pmap_prot.h>
+
+
+bool_t
+xdr_pmap(xdrs, regs)
+ XDR *xdrs;
+ struct pmap *regs;
+{
+
+ if (xdr_u_int32(xdrs, &regs->pm_prog) &&
+ xdr_u_int32(xdrs, &regs->pm_vers) &&
+ xdr_u_int32(xdrs, &regs->pm_prot))
+ return (xdr_u_int32(xdrs, &regs->pm_port));
+ return (FALSE);
+}
diff --git a/src/lib/rpc/pmap_prot.h b/src/lib/rpc/pmap_prot.h
new file mode 100644
index 0000000000..4f76580f4e
--- /dev/null
+++ b/src/lib/rpc/pmap_prot.h
@@ -0,0 +1,94 @@
+/* @(#)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 (rpc_int32 unsigned).
+ * 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(unsigned, unsigned, unsigned, 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.
+ */
+
+#define PMAPPORT ((unsigned short)111)
+#define PMAPPROG ((rpc_u_int32)100000)
+#define PMAPVERS ((rpc_u_int32)2)
+#define PMAPVERS_PROTO ((rpc_u_int32)2)
+#define PMAPVERS_ORIG ((rpc_u_int32)1)
+#define PMAPPROC_NULL ((rpc_u_int32)0)
+#define PMAPPROC_SET ((rpc_u_int32)1)
+#define PMAPPROC_UNSET ((rpc_u_int32)2)
+#define PMAPPROC_GETPORT ((rpc_u_int32)3)
+#define PMAPPROC_DUMP ((rpc_u_int32)4)
+#define PMAPPROC_CALLIT ((rpc_u_int32)5)
+
+struct pmap {
+ rpc_u_int32 pm_prog;
+ rpc_u_int32 pm_vers;
+ rpc_u_int32 pm_prot;
+ rpc_u_int32 pm_port;
+};
+
+extern bool_t xdr_pmap();
+
+struct pmaplist {
+ struct pmap pml_map;
+ struct pmaplist *pml_next;
+};
+
+extern bool_t xdr_pmaplist();
diff --git a/src/lib/rpc/pmap_prot2.c b/src/lib/rpc/pmap_prot2.c
new file mode 100644
index 0000000000..5f48f2a283
--- /dev/null
+++ b/src/lib/rpc/pmap_prot2.c
@@ -0,0 +1,116 @@
+/* @(#)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 <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/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(xdrs, rp)
+ 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;
+
+ 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,
+ (unsigned int)sizeof(struct pmaplist), xdr_pmap))
+ return (FALSE);
+ rp = (freeing) ? next : &((*rp)->pml_next);
+ }
+}
diff --git a/src/lib/rpc/pmap_rmt.c b/src/lib/rpc/pmap_rmt.c
new file mode 100644
index 0000000000..6a23767639
--- /dev/null
+++ b/src/lib/rpc/pmap_rmt.c
@@ -0,0 +1,403 @@
+/* @(#)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 <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_clnt.h>
+#include <rpc/pmap_rmt.h>
+#include <sys/socket.h>
+#ifdef sparc
+#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
+
+extern int errno;
+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(addr, prog, vers, proc, xdrargs, argsp, xdrres, resp, tout, port_ptr)
+ struct sockaddr_in *addr;
+ rpc_u_int32 prog, vers, proc;
+ xdrproc_t xdrargs, xdrres;
+ caddr_t argsp, resp;
+ struct timeval tout;
+ rpc_u_int32 *port_ptr;
+{
+ int socket = -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, &socket);
+ 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(socket);
+ addr->sin_port = 0;
+ return (stat);
+}
+
+
+/*
+ * XDR remote call arguments
+ * written for XDR_ENCODE direction only
+ */
+bool_t
+xdr_rmtcall_args(xdrs, cap)
+ register XDR *xdrs;
+ register struct rmtcallargs *cap;
+{
+ unsigned 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 = (rpc_u_int32)position - (rpc_u_int32)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(xdrs, crp)
+ register XDR *xdrs;
+ register struct rmtcallres *crp;
+{
+ caddr_t port_ptr;
+
+ port_ptr = (caddr_t)crp->port_ptr;
+ if (xdr_reference(xdrs, &port_ptr, sizeof (rpc_u_int32),
+ xdr_u_int32) && xdr_u_int32(xdrs, &crp->resultslen)) {
+ crp->port_ptr = (rpc_u_int32 *)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 .
+ */
+
+static int
+getbroadcastnets(addrs, sock, buf)
+ 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 *sin;
+ int n, i;
+
+ ifc.ifc_len = UDPMSGSIZE;
+ ifc.ifc_buf = buf;
+ 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) {
+ sin = (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(sparc) && defined(__svr4__)) || defined(linux) || (defined(__osf__) && defined(__alpha__))
+ (sin->sin_addr), INADDR_ANY);
+#else /* hpux or solaris */
+ (sin->sin_addr.s_addr), INADDR_ANY);
+#endif
+#endif
+ } else {
+ addrs[i++] = ((struct sockaddr_in*)
+ &ifreq.ifr_addr)->sin_addr;
+ }
+#else /* 4.2 BSD */
+ addrs[i++] = inet_makeaddr(inet_netof
+ (sin->sin_addr.s_addr), INADDR_ANY);
+#endif
+ }
+ }
+ return (i);
+}
+
+typedef bool_t (*resultproc_t)();
+
+enum clnt_stat
+clnt_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp, eachresult)
+ rpc_u_int32 prog; /* program number */
+ rpc_u_int32 vers; /* version number */
+ rpc_u_int32 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 rpc_u_int32 xid;
+ rpc_u_int32 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;
+ char outbuf[MAX_BROADCAST_SIZE], inbuf[UDPMSGSIZE];
+
+ /*
+ * 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);
+ bzero((char *)&baddr, 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 = _null_auth;
+ msg.acpted_rply.ar_results.where = (caddr_t)&r;
+ msg.acpted_rply.ar_results.proc = xdr_rmtcallres;
+ readfds = mask;
+ switch (select(_rpc_dtablesize(), &readfds, (fd_set *)NULL,
+ (fd_set *)NULL, &t)) {
+
+ 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(rpc_u_int32))
+ goto recv_again;
+ /*
+ * see if reply transaction id matches sent id.
+ * If so, decode the results.
+ */
+ xdrmem_create(xdrs, inbuf, (unsigned 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((unsigned 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/src/lib/rpc/pmap_rmt.h b/src/lib/rpc/pmap_rmt.h
new file mode 100644
index 0000000000..2ea22120e9
--- /dev/null
+++ b/src/lib/rpc/pmap_rmt.h
@@ -0,0 +1,53 @@
+/* @(#)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.
+ */
+
+struct rmtcallargs {
+ rpc_u_int32 prog, vers, proc, arglen;
+ caddr_t args_ptr;
+ xdrproc_t xdr_args;
+};
+
+bool_t xdr_rmtcall_args();
+
+struct rmtcallres {
+ rpc_u_int32 *port_ptr;
+ rpc_u_int32 resultslen;
+ caddr_t results_ptr;
+ xdrproc_t xdr_results;
+};
+
+bool_t xdr_rmtcallres();
diff --git a/src/lib/rpc/rpc.h b/src/lib/rpc/rpc.h
new file mode 100644
index 0000000000..d0280aaa09
--- /dev/null
+++ b/src/lib/rpc/rpc.h
@@ -0,0 +1,74 @@
+/* @(#)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 __RPC_HEADER__
+#define __RPC_HEADER__
+
+#include <rpc/types.h> /* some typedefs */
+#include <netinet/in.h>
+
+/* external data representation interfaces */
+#include <rpc/xdr.h> /* generic (de)serializer */
+
+/* Client side only authentication */
+#include <rpc/auth.h> /* generic authenticator (client side) */
+
+/* Client side (mostly) remote procedure call */
+#include <rpc/clnt.h> /* generic rpc stuff */
+
+/* semi-private protocol headers */
+#include <rpc/rpc_msg.h> /* protocol for rpc messages */
+#include <rpc/auth_unix.h> /* protocol for unix style cred */
+/*
+ * Uncomment-out the next line if you are building the rpc library with
+ * DES Authentication (see the README file in the secure_rpc/ directory).
+ */
+/*#include <rpc/auth_des.h> protocol for des style cred */
+
+/* Server side only remote procedure callee */
+#include <rpc/svc_auth.h> /* service side authenticator */
+#include <rpc/svc.h> /* service manager and multiplexer */
+
+/*
+ * 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 */
+#include <netdb.h>
+#include <rpc/netdb.h> /* structures and routines to parse /etc/rpc */
+
+#endif /* ndef __RPC_HEADER__ */
diff --git a/src/lib/rpc/rpc_callmsg.c b/src/lib/rpc/rpc_callmsg.c
new file mode 100644
index 0000000000..370e79ff98
--- /dev/null
+++ b/src/lib/rpc/rpc_callmsg.c
@@ -0,0 +1,195 @@
+/* @(#)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 <rpc/rpc.h>
+
+/*
+ * XDR a call message
+ */
+bool_t
+xdr_callmsg(xdrs, cmsg)
+ register XDR *xdrs;
+ register struct rpc_msg *cmsg;
+{
+ register rpc_int32 *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_int32 *) XDR_INLINE(xdrs, 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) / sizeof (rpc_int32);
+ }
+ 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) / sizeof (rpc_int32);
+ */
+ }
+ return (TRUE);
+ }
+ }
+ if (xdrs->x_op == XDR_DECODE) {
+ buf = (rpc_int32 *) 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_int32 *)
+ XDR_INLINE(xdrs, 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) /
+ sizeof (rpc_int32);
+ */
+ }
+ }
+ oa = &cmsg->rm_call.cb_verf;
+ buf = (rpc_int32 *)
+ 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_int32 *)
+ XDR_INLINE(xdrs, 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) /
+ sizeof (rpc_int32);
+ */
+ }
+ }
+ 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/src/lib/rpc/rpc_commondata.c b/src/lib/rpc/rpc_commondata.c
new file mode 100644
index 0000000000..75cead0875
--- /dev/null
+++ b/src/lib/rpc/rpc_commondata.c
@@ -0,0 +1,41 @@
+/* @(#)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 <rpc/rpc.h>
+/*
+ * This file should only contain common data (global data) that is exported
+ * by public interfaces
+ */
+struct opaque_auth _null_auth;
+#ifdef FD_SETSIZE
+fd_set svc_fdset;
+#else
+int svc_fds;
+#endif /* def FD_SETSIZE */
+struct rpc_createerr rpc_createerr;
diff --git a/src/lib/rpc/rpc_dtablesize.c b/src/lib/rpc/rpc_dtablesize.c
new file mode 100644
index 0000000000..d252d6acdf
--- /dev/null
+++ b/src/lib/rpc/rpc_dtablesize.c
@@ -0,0 +1,60 @@
+/* @(#)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>
+
+/*
+ * Cache the result of getdtablesize(), so we don't have to do an
+ * expensive system call every time.
+ */
+_rpc_dtablesize()
+{
+ 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/src/lib/rpc/rpc_msg.h b/src/lib/rpc/rpc_msg.h
new file mode 100644
index 0000000000..66b10c5fbc
--- /dev/null
+++ b/src/lib/rpc/rpc_msg.h
@@ -0,0 +1,187 @@
+/* @(#)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.
+ */
+
+#define RPC_MSG_VERSION ((rpc_u_int32) 2)
+#define RPC_SERVICE_PORT ((unsigned 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 {
+ rpc_u_int32 low;
+ rpc_u_int32 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 {
+ rpc_u_int32 low;
+ rpc_u_int32 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 {
+ rpc_u_int32 cb_rpcvers; /* must be equal to two */
+ rpc_u_int32 cb_prog;
+ rpc_u_int32 cb_vers;
+ rpc_u_int32 cb_proc;
+ struct opaque_auth cb_cred;
+ struct opaque_auth cb_verf; /* protocol specific - provided by client */
+};
+
+/*
+ * The rpc message
+ */
+struct rpc_msg {
+ rpc_u_int32 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 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 routine to handle a rpc reply.
+ * xdr_replymsg(xdrs, rmsg)
+ * XDR *xdrs;
+ * struct rpc_msg *rmsg;
+ */
+extern bool_t xdr_replymsg();
+
+/*
+ * Fills in the error part of a reply message.
+ * _seterr_reply(msg, error)
+ * struct rpc_msg *msg;
+ * struct rpc_err *error;
+ */
+extern void _seterr_reply();
diff --git a/src/lib/rpc/rpc_prot.c b/src/lib/rpc/rpc_prot.c
new file mode 100644
index 0000000000..6fea605e67
--- /dev/null
+++ b/src/lib/rpc/rpc_prot.c
@@ -0,0 +1,287 @@
+/* @(#)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 <rpc/rpc.h>
+
+/* * * * * * * * * * * * * * XDR Authentication * * * * * * * * * * * */
+
+/*
+ * XDR an opaque authentication struct
+ * (see auth.h)
+ */
+bool_t
+xdr_opaque_auth(xdrs, ap)
+ register XDR *xdrs;
+ register 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(xdrs, blkp)
+ register XDR *xdrs;
+ register 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(xdrs, ar)
+ register XDR *xdrs;
+ register 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_u_int32(xdrs, &(ar->ar_vers.low)))
+ return (FALSE);
+ return (xdr_u_int32(xdrs, &(ar->ar_vers.high)));
+ }
+ return (TRUE); /* TRUE => open ended set of problems */
+}
+
+/*
+ * XDR the MSG_DENIED part of a reply message union
+ */
+bool_t
+xdr_rejected_reply(xdrs, rr)
+ register XDR *xdrs;
+ register 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_u_int32(xdrs, &(rr->rj_vers.low)))
+ return (FALSE);
+ return (xdr_u_int32(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(xdrs, rmsg)
+ register XDR *xdrs;
+ register 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(xdrs, cmsg)
+ register XDR *xdrs;
+ register 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_u_int32(xdrs, &(cmsg->rm_call.cb_rpcvers)) &&
+ xdr_u_int32(xdrs, &(cmsg->rm_call.cb_prog)) )
+ return (xdr_u_int32(xdrs, &(cmsg->rm_call.cb_vers)));
+ return (FALSE);
+}
+
+/* ************************** Client utility routine ************* */
+
+static void
+accepted(acpt_stat, error)
+ register enum accept_stat acpt_stat;
+ register 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 = (rpc_int32)MSG_ACCEPTED;
+ error->re_lb.s2 = (rpc_int32)acpt_stat;
+}
+
+static void
+rejected(rjct_stat, error)
+ register enum reject_stat rjct_stat;
+ register struct rpc_err *error;
+{
+
+ switch (rjct_stat) {
+
+ case RPC_VERSMISMATCH:
+ 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 = (rpc_int32)MSG_DENIED;
+ error->re_lb.s2 = (rpc_int32)rjct_stat;
+}
+
+/*
+ * given a reply message, fills in the error
+ */
+void
+sunrpc_seterr_reply(msg, error)
+ register struct rpc_msg *msg;
+ register 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 = (rpc_int32)(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;
+ }
+}
diff --git a/src/lib/rpc/svc.c b/src/lib/rpc/svc.c
new file mode 100644
index 0000000000..cb4d877a74
--- /dev/null
+++ b/src/lib/rpc/svc.c
@@ -0,0 +1,492 @@
+/* @(#)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.
+ */
+
+#include <sys/errno.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_clnt.h>
+#include <stdio.h>
+
+extern int errno;
+
+#ifdef FD_SETSIZE
+static SVCXPRT **xports;
+#else
+#define NOFILE 32
+
+static SVCXPRT *xports[NOFILE];
+#endif /* def FD_SETSIZE */
+
+#define NULL_SVC ((struct svc_callout *)0)
+#define RQCRED_SIZE 400 /* 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;
+ rpc_u_int32 sc_prog;
+ rpc_u_int32 sc_vers;
+ void (*sc_dispatch)();
+} *svc_head;
+
+static struct svc_callout *svc_find();
+
+/* *************** SVCXPRT related stuff **************** */
+
+/*
+ * Activate a transport handle.
+ */
+void
+xprt_register(xprt)
+ SVCXPRT *xprt;
+{
+ register int sock = xprt->xp_sock;
+
+#ifdef FD_SETSIZE
+ if (xports == NULL) {
+ xports = (SVCXPRT **)
+ mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *));
+ }
+ if (sock < _rpc_dtablesize()) {
+ xports[sock] = xprt;
+ FD_SET(sock, &svc_fdset);
+ }
+#else
+ if (sock < NOFILE) {
+ xports[sock] = xprt;
+ svc_fds |= (1 << sock);
+ }
+#endif /* def FD_SETSIZE */
+
+}
+
+/*
+ * De-activate a transport handle.
+ */
+void
+xprt_unregister(xprt)
+ SVCXPRT *xprt;
+{
+ register int sock = xprt->xp_sock;
+
+#ifdef FD_SETSIZE
+ if ((sock < _rpc_dtablesize()) && (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 */
+}
+
+
+/* ********************** 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(xprt, prog, vers, dispatch, protocol)
+ SVCXPRT *xprt;
+ rpc_u_int32 prog;
+ rpc_u_int32 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(prog, vers)
+ rpc_u_int32 prog;
+ rpc_u_int32 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, (unsigned 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(prog, vers, prev)
+ rpc_u_int32 prog;
+ rpc_u_int32 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(xprt, xdr_results, xdr_location)
+ 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(xprt)
+ 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(xprt)
+ 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(xprt)
+ 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(xprt, why)
+ 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(xprt)
+ SVCXPRT *xprt;
+{
+
+ svcerr_auth(xprt, AUTH_TOOWEAK);
+}
+
+/*
+ * Program unavailable error reply
+ */
+void
+svcerr_noprog(xprt)
+ 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(xprt, low_vers, high_vers)
+ register SVCXPRT *xprt;
+ rpc_u_int32 low_vers;
+ rpc_u_int32 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(rdfds)
+ int rdfds;
+{
+#ifdef FD_SETSIZE
+ fd_set readfds;
+
+ FD_ZERO(&readfds);
+ readfds.fds_bits[0] = rdfds;
+ svc_getreqset(&readfds);
+#else
+ int readfds = rdfds & svc_fds;
+
+ svc_getreqset(&readfds);
+#endif /* def FD_SETSIZE */
+}
+
+void
+svc_getreqset(readfds)
+#ifdef FD_SETSIZE
+ fd_set *readfds;
+{
+#else
+ int *readfds;
+{
+ int readfds_local = *readfds;
+#endif /* def FD_SETSIZE */
+ enum xprt_stat stat;
+ struct rpc_msg msg;
+ int prog_found;
+ rpc_u_int32 low_vers;
+ rpc_u_int32 high_vers;
+ struct svc_req r;
+ register SVCXPRT *xprt;
+ rpc_u_int32 mask;
+ int bit;
+ rpc_u_int32 *maskp;
+ register int setsize;
+ register int sock;
+ bool_t no_dispatch;
+
+ char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE];
+ msg.rm_call.cb_cred.oa_base = cred_area;
+ msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]);
+ r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]);
+
+#ifdef FD_SETSIZE
+ setsize = _rpc_dtablesize();
+
+ maskp = (rpc_u_int32 *)readfds->fds_bits;
+ for (sock = 0; sock < setsize; sock += NFDBITS) {
+ for (mask = *maskp++; bit = ffs(mask); mask ^= (1 << (bit - 1))) {
+ /* sock has input waiting */
+ xprt = xports[sock + bit - 1];
+#else
+ for (sock = 0; readfds_local != 0; sock++, readfds_local >>= 1) {
+ if ((readfds_local & 1) != 0) {
+ /* sock has input waiting */
+ xprt = xports[sock];
+#endif /* def FD_SETSIZE */
+ /* now receive msgs from xprtprt (support batch calls) */
+ do {
+ if (SVC_RECV(xprt, &msg)) {
+
+ /* now find the exported program and call it */
+ register struct svc_callout *s;
+ enum auth_stat why;
+
+ 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;
+
+ /* in case _authenticate has been replaced
+ with an old-style version */
+ r.rq_xprt->xp_auth = &svc_auth_any;
+ no_dispatch = FALSE;
+
+ /* first authenticate the message */
+ why=_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 = 0 - 1;
+ 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);
+ }
+ }
+}
diff --git a/src/lib/rpc/svc.h b/src/lib/rpc/svc.h
new file mode 100644
index 0000000000..2114d6249e
--- /dev/null
+++ b/src/lib/rpc/svc.h
@@ -0,0 +1,298 @@
+/* @(#)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 __SVC_HEADER__
+#define __SVC_HEADER__
+
+/*
+ * 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 {
+ int xp_sock;
+ unsigned 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;
+
+/*
+ * 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 {
+ rpc_u_int32 rq_prog; /* service program number */
+ rpc_u_int32 rq_vers; /* service protocol version */
+ rpc_u_int32 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 */
+
+ /* 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;
+ * rpc_u_int32 prog;
+ * rpc_u_int32 vers;
+ * void (*dispatch)();
+ * int protocol; like TCP or UDP, zero means do not register
+ */
+extern bool_t svc_register();
+
+/*
+ * Service un-registration
+ *
+ * svc_unregister(prog, vers)
+ * rpc_u_int32 prog;
+ * rpc_u_int32 vers;
+ */
+extern void svc_unregister();
+
+/*
+ * Transport registration.
+ *
+ * xprt_register(xprt)
+ * SVCXPRT *xprt;
+ */
+extern void xprt_register();
+
+/*
+ * Transport un-register
+ *
+ * xprt_unregister(xprt)
+ * SVCXPRT *xprt;
+ */
+extern void xprt_unregister();
+
+
+
+
+/*
+ * 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();
+extern void svcerr_decode();
+extern void svcerr_weakauth();
+extern void svcerr_noproc();
+extern void svcerr_progvers();
+extern void svcerr_auth();
+extern void svcerr_noprog();
+extern void svcerr_systemerr();
+
+/*
+ * 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
+ */
+#ifdef FD_SETSIZE
+extern fd_set svc_fdset;
+#define svc_fds svc_fdset.fds_bits[0] /* compatibility */
+#else
+extern int svc_fds;
+#endif /* def FD_SETSIZE */
+
+/*
+ * 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();
+extern void svc_getreqset(); /* takes fdset instead of int */
+extern void svc_run(); /* 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();
+
+/*
+ * Udp based rpc.
+ */
+extern SVCXPRT *svcudp_create();
+extern SVCXPRT *svcudp_bufcreate();
+
+/*
+ * Tcp based rpc.
+ */
+extern SVCXPRT *svctcp_create();
+
+#endif /* !__SVC_HEADER__ */
diff --git a/src/lib/rpc/svc_auth.c b/src/lib/rpc/svc_auth.c
new file mode 100644
index 0000000000..281d7cba48
--- /dev/null
+++ b/src/lib/rpc/svc_auth.c
@@ -0,0 +1,119 @@
+#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 <rpc/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;
+ *
+ */
+
+enum auth_stat _svcauth_null(); /* no authentication */
+enum auth_stat _svcauth_unix(); /* unix style (uid, gids) */
+enum auth_stat _svcauth_short(); /* short hand unix style */
+enum auth_stat _svcauth_gssapi(); /* GSS-API style */
+
+static struct svcauthsw_type {
+ unsigned int flavor;
+ enum auth_stat (*authenticator)();
+} svcauthsw[] = {
+ AUTH_GSSAPI, _svcauth_gssapi, /* AUTH_GSSAPI */
+ AUTH_NONE, _svcauth_null, /* AUTH_NULL */
+ AUTH_GSSAPI_COMPAT, _svcauth_gssapi, /* AUTH_GSSAPI_COMPAT */
+ AUTH_UNIX, _svcauth_unix, /* AUTH_UNIX */
+ AUTH_SHORT, _svcauth_short, /* AUTH_SHORT */
+};
+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
+_authenticate(rqst, msg, no_dispatch)
+ 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 = _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);
+}
+
+enum auth_stat
+_svcauth_null(rqst, msg)
+ struct svc_req *rqst;
+ struct rpc_msg *msg;
+{
+ rqst->rq_xprt->xp_auth = &svc_auth_any;
+ return (AUTH_OK);
+}
diff --git a/src/lib/rpc/svc_auth.h b/src/lib/rpc/svc_auth.h
new file mode 100644
index 0000000000..4d59631445
--- /dev/null
+++ b/src/lib/rpc/svc_auth.h
@@ -0,0 +1,61 @@
+/* @(#)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.
+ */
+typedef struct {
+ struct svc_auth_ops {
+ int (*svc_ah_wrap)();
+ int (*svc_ah_unwrap)();
+ } *svc_ah_ops;
+ caddr_t svc_ah_private;
+} SVCAUTH;
+
+extern SVCAUTH svc_auth_any;
+
+/*
+ * Server side authenticator
+ */
+extern enum auth_stat _authenticate();
+
+#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))
+
+
diff --git a/src/lib/rpc/svc_auth_any.c b/src/lib/rpc/svc_auth_any.c
new file mode 100644
index 0000000000..2f0a66dc85
--- /dev/null
+++ b/src/lib/rpc/svc_auth_any.c
@@ -0,0 +1,22 @@
+/*
+ * svc_auth_any.c
+ * Provides default service-side functions for authentication flavors
+ * that do not use all the fields in struct svc_auth_ops.
+ *
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ */
+
+#include <stdio.h>
+#include <rpc/rpc.h>
+
+extern int authany_wrap();
+
+struct svc_auth_ops svc_auth_any_ops = {
+ authany_wrap,
+ authany_wrap,
+};
+
+SVCAUTH svc_auth_any = {
+ &svc_auth_any_ops,
+ NULL,
+};
diff --git a/src/lib/rpc/svc_auth_gssapi.c b/src/lib/rpc/svc_auth_gssapi.c
new file mode 100644
index 0000000000..07cf59ab8b
--- /dev/null
+++ b/src/lib/rpc/svc_auth_gssapi.c
@@ -0,0 +1,1181 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Id$
+ * $Source$
+ *
+ * $Log$
+ * Revision 1.37 1996/07/22 20:41:00 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.36.4.1 1996/07/18 04:19:34 marc
+ * merged in changes from OV_9510_BP to OV_9510_FINAL1
+ *
+ * Revision 1.36.2.1 1996/06/20 23:39:22 marc
+ * File added to the repository on a branch
+ *
+ * Revision 1.36 1996/05/30 19:25:02 bjaspan
+ * zero bindings structure before using it
+ *
+ * Revision 1.35 1996/05/12 06:17:25 marc
+ * changed around the file includes, since krb5 has changed some.
+ *
+ * added conditionalization GSS_BACKWARD_HACK until and if this hack is
+ * reimplemented in the newly merged gssapi.
+ *
+ * conditionalize out the host-specific cruft for setting the local
+ * address to INADDR_ANY, since you can just assign it that way on all
+ * platforms I know of.
+ *
+ * Revision 1.34 1996/02/12 15:14:00 grier
+ * [secure/3570]
+ * restore (struct sockaddr *) cast that got mangled
+ *
+ * Revision 1.33 1996/02/07 13:09:52 jik
+ * Actually, I should have used krb5_error_code, not krb5_int32.
+ *
+ * Revision 1.32 1996/02/07 13:08:31 jik
+ * Include <krb5/krb5.h> to get the krb5_int32 typedef, which we then use
+ * in a cast when checking if the GSS-API minor status value is equal to
+ * a krb5 error code.
+ *
+ * Revision 1.31 1996/02/01 18:29:29 grier
+ * Restore use of error code definition.
+ * Return original code structure.
+ *
+ * Revision 1.30 1996/01/31 19:15:49 grier
+ * [secure/3570]
+ * Remove (void *) casts to memcpy() args
+ *
+ * Revision 1.29 1996/01/25 03:58:04 grier
+ * Remove debug code
+ *
+ * Revision 1.28 1996/01/25 03:56:50 grier
+ * secure/3570 - missed Alpha checkin
+ *
+ * Revision 1.26 1995/11/07 23:17:23 grier
+ * memcpy() cast
+ *
+ * Revision 1.25 1995/08/24 21:05:48 bjaspan
+ * set acceptor channel bindings
+ *
+ * Revision 1.24 1995/08/23 20:28:02 bjaspan
+ * [secure-rpc/3392] add channel bindinds to the rpc
+ *
+ * Revision 1.23 1995/07/10 18:49:22 bjaspan
+ * [secure-build/3377] remove use of BSD db
+ *
+ * Revision 1.22 1995/05/25 18:35:53 bjaspan
+ * [secure-rpc/3103] log misc errors from RPC
+ *
+ * Revision 1.21 1995/05/24 17:34:03 bjaspan
+ * [secure-rpc/3302] don't allow client to make server exit unless
+ * debugging is enabled
+ *
+ * Revision 1.20 1995/05/08 22:32:44 marc
+ * if a new client is in use, set the krb5 gssapi mech into
+ * backward-compatibility mode.
+ *
+ * Revision 1.19 1994/10/27 12:38:51 jik
+ * [secure-rpc/2808: add credential versioning]
+ *
+ * Sandbox:
+ *
+ * [secure-rpc/2808] add version field to client creds
+ *
+ * Revision 1.22 1994/10/26 20:03:27 bjaspan
+ * [secure-rpc/2808] add version field to client creds
+ *
+ * Revision 1.21 1994/05/23 01:26:01 bjaspan
+ * [secure-rpc/1911] set rq_svccred to the context instead of the service
+ * gss name
+ *
+ * Revision 1.20 1994/05/09 17:48:39 shanzer
+ * change sys/fcntl.h to fcntl.h
+ *
+ * Revision 1.19 1994/04/08 17:21:32 bjaspan
+ * remove KRB5KTNAME hack
+ *
+ * Revision 1.18 1994/03/18 15:48:13 shanzer
+ * include sys/fcntl.h
+ *
+ * Revision 1.17 1994/03/08 00:05:56 shanzer
+ * call rand() instead random()
+ *
+ * Revision 1.16 1993/12/08 21:43:54 bjaspan
+ * gss_delete_sec_context failure is not fatal (in fact, the context
+ * will often be expired); use AUTH_GSSAPI_DISPLAY_STATUS macro
+ *
+ * Revision 1.15 1993/12/08 20:20:08 bjaspan
+ * add debugging info to expire_client, correct comment above btree->put
+ *
+ * Revision 1.14 1993/12/08 06:52:49 bjaspan
+ * *many* debugging improvements to help find secure-rpc/586, and (I hope)
+ * the fix: don't change client_data->expiration without deleting it
+ * and reinserting it into the btree
+ *
+ * Revision 1.13 1993/12/06 21:22:26 bjaspan
+ * debugging levels, #ifdef PURIFY, call abort() on impossible failures
+ *
+ * Revision 1.12 1993/11/12 02:33:14 bjaspan
+ * add badauth
+ * /
+ *
+ * Revision 1.11 1993/11/03 23:46:15 bjaspan
+ * new log_badverf format
+ *
+ * Revision 1.10 1993/11/03 21:23:30 bjaspan
+ * handle GSS_C_INDEFINITE expiration, add log_badverf, set rq_svccred
+ *
+ * Revision 1.9 1993/11/03 01:30:36 bjaspan
+ * don't include gssapi_krb5.h, it isn't needed
+ *
+ * Revision 1.8 1993/11/02 22:09:02 bjaspan
+ * support multiple service-side names via _svcauth_gssapi_set_names
+ *
+ * Revision 1.7 1993/11/01 19:56:22 bjaspan
+ * unstatic svc_debug_gssapi, and send gss_{major,minor} back if
+ * accept_sec_context fails
+ *
+ * Revision 1.6 1993/10/28 22:09:58 bjaspan
+ * fix verifier mem leak, clean_clients() first to avoid dangling ref,
+ * only include hacked kt_default_name if DEBUG_GSSAPI defined
+ *
+ * Revision 1.5 1993/10/27 18:26:51 bjaspan
+ * use xdr_free instead of gss_release_buffer; this fixes memory leaks
+ * that were probably caused by zero-length seal/unseal tokens
+ *
+ * Revision 1.4 1993/10/26 21:12:51 bjaspan
+ * fully working
+ *
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+/*
+ * svc_auth_gssapi.c
+ * Handles the GSS-API flavor authentication parameters on the service
+ * side of RPC.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <rpc/rpc.h>
+
+#include <gssapi/gssapi_generic.h>
+#include <rpc/auth_gssapi.h>
+
+#ifdef GSS_BACKWARD_HACK
+#include <gssapi/gssapi_krb5.h>
+#endif
+
+/* This is here for the krb5_error_code typedef and the
+ KRB5KRB_AP_WRONG_PRINC #define.*/
+#include <krb5.h>
+
+#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;
+
+ rpc_u_int32 expiration;
+ rpc_u_int32 seq_num;
+ rpc_u_int32 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();
+static bool_t svc_auth_gssapi_unwrap();
+static svc_auth_gssapi_data *create_client();
+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(), cleanup();
+static void client_expire(svc_auth_gssapi_data *client_data, rpc_u_int32 exp);
+static void dump_db(char *msg);
+
+struct svc_auth_ops svc_auth_gssapi_ops = {
+ svc_auth_gssapi_wrap,
+ svc_auth_gssapi_unwrap,
+};
+
+/*
+ * 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;
+
+extern int errno;
+
+enum auth_stat _svcauth_gssapi(rqst, msg, no_dispatch)
+ 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;
+ struct sockaddr_in sockname;
+ OM_uint32 gssstat, minor_stat, time_rec;
+ struct opaque_auth *cred, *verf;
+ svc_auth_gssapi_data *client_data;
+ int ret_flags, ret, i;
+ rpc_u_int32 seq_num;
+ int flag;
+
+ 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_any;
+
+ 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_DESTROY(&xdrs);
+ ret = AUTH_BADCRED;
+ goto error;
+ }
+ XDR_DESTROY(&xdrs);
+
+ PRINTF(("svcauth_gssapi: got credentials, version %d, "
+ "client_handle len %d\n", creds.version,
+ 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",
+ *((rpc_u_int32 *) creds.client_handle.value),
+ 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:
+ 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) {
+ int len;
+
+ 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;
+
+ len = sizeof(sockname);
+ if (getsockname(rqst->rq_xprt->xp_sock,
+ (struct sockaddr *) &sockname, &len) < 0) {
+ LOG_MISCERR("cannot get local address");
+ PRINTF(("svcauth_gssapi: errno %d while getting address",
+ errno));
+ ret = AUTH_FAILED;
+ goto error;
+ }
+
+ bindings.acceptor_addrtype = GSS_C_AF_INET;
+ bindings.acceptor_address.length = 4;
+ bindings.acceptor_address.value = &sockname.sin_addr.s_addr;
+
+ 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];
+ }
+
+ 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 ||
+ /*
+ * XXX 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)) {
+ 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);
+
+ 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");
+ 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");
+ 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);
+ 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",
+ 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",
+ creds.client_handle.length));
+ xdr_free(xdr_authgssapi_creds, &creds);
+ }
+
+ PRINTF(("\n"));
+ return ret;
+}
+
+static void cleanup()
+{
+ 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()
+{
+ client_list *c;
+ svc_auth_gssapi_data *client_data;
+ static int client_key = 1;
+ int ret;
+
+ 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 = %#x\n", 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, rpc_u_int32 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;
+ rpc_u_int32 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;
+ int ret;
+
+ PRINTF(("destroy_client: destroying client_data\n"));
+ L_PRINTF(2, ("destroy_client: client_data = %#x\n", 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
+ 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);
+
+#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 = %#x, exp = %d\n",
+ client_data, client_data->expiration));
+ c = c->next;
+ }
+
+ L_PRINTF(3, ("\n"));
+}
+
+static void clean_client()
+{
+ 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 = %#x\n",
+ 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;
+ }
+ }
+
+done:
+ PRINTF(("clean_client: done\n"));
+}
+
+/*
+ * Function: _svcauth_gssapi_set_name
+ *
+ * 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++) {
+ in_buf.value = names[i].name;
+ in_buf.length = strlen(in_buf.value) + 1;
+
+ 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;
+ }
+ }
+
+ server_creds_count = num;
+
+ return TRUE;
+
+fail:
+ /* memory leak: not releasing names/creds already acquired */
+ if (server_creds_list)
+ free(server_creds_list);
+ if (server_name_list)
+ free(server_name_list);
+ return FALSE;
+}
+
+/*
+ * 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(auth, out_xdrs, xdr_func, xdr_ptr)
+ 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(auth, in_xdrs, xdr_func, xdr_ptr)
+ 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 *) 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;
+}
diff --git a/src/lib/rpc/svc_auth_unix.c b/src/lib/rpc/svc_auth_unix.c
new file mode 100644
index 0000000000..1ff21588cf
--- /dev/null
+++ b/src/lib/rpc/svc_auth_unix.c
@@ -0,0 +1,137 @@
+/* @(#)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 <rpc/rpc.h>
+
+/*
+ * Unix longhand authenticator
+ */
+enum auth_stat
+_svcauth_unix(rqst, msg)
+ register struct svc_req *rqst;
+ register struct rpc_msg *msg;
+{
+ register enum auth_stat stat;
+ XDR xdrs;
+ register struct authunix_parms *aup;
+ register rpc_int32 *buf;
+ struct area {
+ struct authunix_parms area_aup;
+ char area_machname[MAX_MACHINE_NAME+1];
+ int area_gids[NGRPS];
+ } *area;
+ unsigned int auth_len;
+ int str_len, gid_len;
+ register int i;
+
+ rqst->rq_xprt->xp_auth = &svc_auth_any;
+
+ area = (struct area *) rqst->rq_clntcred;
+ aup = &area->area_aup;
+ aup->aup_machname = area->area_machname;
+ aup->aup_gids = area->area_gids;
+ auth_len = (unsigned int)msg->rm_call.cb_cred.oa_length;
+ xdrmem_create(&xdrs, msg->rm_call.cb_cred.oa_base, auth_len,XDR_DECODE);
+ buf = (rpc_int32 *) XDR_INLINE(&xdrs, 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, (unsigned int)str_len);
+ aup->aup_machname[str_len] = 0;
+ str_len = RNDUP(str_len);
+ buf += str_len / sizeof (rpc_int32);
+ 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
+_svcauth_short(rqst, msg)
+ struct svc_req *rqst;
+ struct rpc_msg *msg;
+{
+ rqst->rq_xprt->xp_auth = &svc_auth_any;
+ return (AUTH_REJECTEDCRED);
+}
diff --git a/src/lib/rpc/svc_raw.c b/src/lib/rpc/svc_raw.c
new file mode 100644
index 0000000000..1170ecec83
--- /dev/null
+++ b/src/lib/rpc/svc_raw.c
@@ -0,0 +1,166 @@
+/* @(#)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 <rpc/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();
+static enum xprt_stat svcraw_stat();
+static bool_t svcraw_getargs();
+static bool_t svcraw_reply();
+static bool_t svcraw_freeargs();
+static void svcraw_destroy();
+
+static struct xp_ops server_ops = {
+ svcraw_recv,
+ svcraw_stat,
+ svcraw_getargs,
+ svcraw_reply,
+ svcraw_freeargs,
+ svcraw_destroy
+};
+
+SVCXPRT *
+svcraw_create()
+{
+ 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()
+{
+
+ return (XPRT_IDLE);
+}
+
+static bool_t
+svcraw_recv(xprt, msg)
+ 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(xprt, msg)
+ 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(xprt, xdr_args, args_ptr)
+ SVCXPRT *xprt;
+ xdrproc_t xdr_args;
+ caddr_t args_ptr;
+{
+ register struct svcraw_private *srp = svcraw_private;
+
+ if (srp == 0)
+ return (FALSE);
+ return ((*xdr_args)(&srp->xdr_stream, args_ptr));
+}
+
+static bool_t
+svcraw_freeargs(xprt, xdr_args, args_ptr)
+ SVCXPRT *xprt;
+ xdrproc_t xdr_args;
+ caddr_t 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()
+{
+}
diff --git a/src/lib/rpc/svc_run.c b/src/lib/rpc/svc_run.c
new file mode 100644
index 0000000000..d43aa2425c
--- /dev/null
+++ b/src/lib/rpc/svc_run.c
@@ -0,0 +1,72 @@
+/* @(#)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 <rpc/rpc.h>
+#include <sys/errno.h>
+
+void
+svc_run()
+{
+#ifdef FD_SETSIZE
+ fd_set readfds;
+#else
+ int readfds;
+#endif /* def FD_SETSIZE */
+ extern int errno;
+
+ for (;;) {
+#ifdef FD_SETSIZE
+ readfds = svc_fdset;
+#else
+ readfds = svc_fds;
+#endif /* def FD_SETSIZE */
+ switch (select(_rpc_dtablesize(), &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/src/lib/rpc/svc_simple.c b/src/lib/rpc/svc_simple.c
new file mode 100644
index 0000000000..2a22e57224
--- /dev/null
+++ b/src/lib/rpc/svc_simple.c
@@ -0,0 +1,143 @@
+/* @(#)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 <rpc/rpc.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();
+static SVCXPRT *transp;
+struct proglst *pl;
+
+registerrpc(prognum, versnum, procnum, progname, inproc, outproc)
+ char *(*progname)();
+ xdrproc_t inproc, outproc;
+{
+
+ 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((rpc_u_int32)prognum, (rpc_u_int32)versnum);
+ if (!svc_register(transp, (rpc_u_int32)prognum, (rpc_u_int32)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(rqstp, transp)
+ struct svc_req *rqstp;
+ SVCXPRT *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(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(transp, pl->p_inproc, xdrbuf)) {
+ svcerr_decode(transp);
+ return;
+ }
+ outdata = (*(pl->p_progname))(xdrbuf);
+ if (outdata == NULL && pl->p_outproc != xdr_void)
+ /* there was an error */
+ return;
+ if (!svc_sendreply(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(transp, pl->p_inproc, xdrbuf);
+ return;
+ }
+ (void) fprintf(stderr, "never registered prog %d\n", prog);
+ exit(1);
+}
+
diff --git a/src/lib/rpc/svc_tcp.c b/src/lib/rpc/svc_tcp.c
new file mode 100644
index 0000000000..e20a29b192
--- /dev/null
+++ b/src/lib/rpc/svc_tcp.c
@@ -0,0 +1,453 @@
+/* @(#)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 <rpc/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();
+static enum xprt_stat svctcp_stat();
+static bool_t svctcp_getargs();
+static bool_t svctcp_reply();
+static bool_t svctcp_freeargs();
+static void svctcp_destroy();
+
+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();
+static bool_t abortx();
+static enum xprt_stat rendezvous_stat();
+
+static struct xp_ops svctcp_rendezvous_op = {
+ rendezvous_request,
+ rendezvous_stat,
+ abortx,
+ abortx,
+ abortx,
+ svctcp_destroy
+};
+
+static int readtcp(), writetcp();
+static SVCXPRT *makefd_xprt();
+
+struct tcp_rendezvous { /* kept in xprt->xp_p1 */
+ unsigned int sendsize;
+ unsigned int recvsize;
+};
+
+struct tcp_conn { /* kept in xprt->xp_p1 */
+ enum xprt_stat strm_stat;
+ rpc_u_int32 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(sock, sendsize, recvsize)
+ register int sock;
+ unsigned int sendsize;
+ unsigned 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));
+ 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_verf = _null_auth;
+ xprt->xp_ops = &svctcp_rendezvous_op;
+ xprt->xp_port = ntohs(addr.sin_port);
+ xprt->xp_sock = sock;
+ xprt_register(xprt);
+ return (xprt);
+}
+
+/*
+ * Like svtcp_create(), except the routine takes any *open* UNIX file
+ * descriptor as its first input.
+ */
+SVCXPRT *
+svcfd_create(fd, sendsize, recvsize)
+ int fd;
+ unsigned int sendsize;
+ unsigned int recvsize;
+{
+
+ return (makefd_xprt(fd, sendsize, recvsize));
+}
+
+static SVCXPRT *
+makefd_xprt(fd, sendsize, recvsize)
+ int fd;
+ unsigned int sendsize;
+ unsigned 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_verf.oa_base = cd->verf_body;
+ xprt->xp_addrlen = 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(xprt)
+ register SVCXPRT *xprt;
+{
+ int sock;
+ struct tcp_rendezvous *r;
+ struct sockaddr_in addr;
+ int len;
+
+ r = (struct tcp_rendezvous *)xprt->xp_p1;
+ again:
+ len = sizeof(struct sockaddr_in);
+ if ((sock = accept(xprt->xp_sock, (struct sockaddr *)&addr,
+ &len)) < 0) {
+ if (errno == EINTR)
+ goto again;
+ 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;
+ return (FALSE); /* there is never an rpc msg to be processed */
+}
+
+static enum xprt_stat
+rendezvous_stat()
+{
+
+ return (XPRT_IDLE);
+}
+
+static void
+svctcp_destroy(xprt)
+ 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));
+ }
+ 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(xprt, buf, len)
+ register SVCXPRT *xprt;
+ caddr_t buf;
+ register int len;
+{
+ register int sock = xprt->xp_sock;
+#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 */
+ do {
+ readfds = mask;
+ if (select(_rpc_dtablesize(), &readfds, (fd_set*)NULL,
+ (fd_set*)NULL, &wait_per_try) <= 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ goto fatal_err;
+ }
+#ifdef FD_SETSIZE
+ } while (!FD_ISSET(sock, &readfds));
+#else
+ } while (readfds != mask);
+#endif /* def FD_SETSIZE */
+ if ((len = read(sock, buf, 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(xprt, buf, len)
+ register SVCXPRT *xprt;
+ caddr_t buf;
+ int len;
+{
+ register int i, cnt;
+
+ for (cnt = len; cnt > 0; cnt -= i, buf += i) {
+ if ((i = write(xprt->xp_sock, buf, cnt)) < 0) {
+ ((struct tcp_conn *)(xprt->xp_p1))->strm_stat =
+ XPRT_DIED;
+ return (-1);
+ }
+ }
+ return (len);
+}
+
+static enum xprt_stat
+svctcp_stat(xprt)
+ 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(xprt, msg)
+ 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(xprt, xdr_args, args_ptr)
+ SVCXPRT *xprt;
+ xdrproc_t xdr_args;
+ caddr_t args_ptr;
+{
+ return (SVCAUTH_UNWRAP(xprt->xp_auth,
+ &(((struct tcp_conn *)(xprt->xp_p1))->xdrs),
+ xdr_args, args_ptr));
+}
+
+static bool_t
+svctcp_freeargs(xprt, xdr_args, args_ptr)
+ SVCXPRT *xprt;
+ xdrproc_t xdr_args;
+ caddr_t 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(xprt, msg)
+ 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()
+{
+ abort();
+ return 1;
+}
+
diff --git a/src/lib/rpc/svc_udp.c b/src/lib/rpc/svc_udp.c
new file mode 100644
index 0000000000..d44c7f5d88
--- /dev/null
+++ b/src/lib/rpc/svc_udp.c
@@ -0,0 +1,496 @@
+/* @(#)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 <rpc/rpc.h>
+#include <sys/socket.h>
+#include <errno.h>
+
+
+#define rpc_buffer(xprt) ((xprt)->xp_p1)
+#ifndef MAX
+#define MAX(a, b) ((a > b) ? a : b)
+#endif
+
+static bool_t svcudp_recv();
+static bool_t svcudp_reply();
+static enum xprt_stat svcudp_stat();
+static bool_t svcudp_getargs();
+static bool_t svcudp_freeargs();
+static void svcudp_destroy();
+
+static void cache_set();
+static int cache_get();
+
+static struct xp_ops svcudp_op = {
+ svcudp_recv,
+ svcudp_stat,
+ svcudp_getargs,
+ svcudp_reply,
+ svcudp_freeargs,
+ svcudp_destroy
+};
+
+extern int errno;
+
+/*
+ * kept in xprt->xp_p2
+ */
+struct svcudp_data {
+ unsigned int su_iosz; /* byte size of send.recv buffer */
+ rpc_u_int32 su_xid; /* transaction id */
+ XDR su_xdrs; /* XDR handle */
+ char su_verfbody[MAX_AUTH_BYTES]; /* verifier body */
+ char * 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(sock, sendsz, recvsz)
+ register int sock;
+ unsigned int sendsz, 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));
+ 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_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(sock)
+ int sock;
+{
+
+ return(svcudp_bufcreate(sock, UDPMSGSIZE, UDPMSGSIZE));
+}
+
+static enum xprt_stat
+svcudp_stat(xprt)
+ SVCXPRT *xprt;
+{
+
+ return (XPRT_IDLE);
+}
+
+static bool_t
+svcudp_recv(xprt, msg)
+ register SVCXPRT *xprt;
+ struct rpc_msg *msg;
+{
+ register struct svcudp_data *su = su_data(xprt);
+ register XDR *xdrs = &(su->su_xdrs);
+ register int rlen;
+ char *reply;
+ rpc_u_int32 replylen;
+
+ again:
+ 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(rpc_u_int32))
+ 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(xprt, msg)
+ 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, (rpc_u_int32) slen);
+ }
+ }
+ }
+ return (stat);
+}
+
+static bool_t
+svcudp_getargs(xprt, xdr_args, args_ptr)
+ SVCXPRT *xprt;
+ xdrproc_t xdr_args;
+ caddr_t args_ptr;
+{
+ return (SVCAUTH_UNWRAP(xprt->xp_auth, &(su_data(xprt)->su_xdrs),
+ xdr_args, args_ptr));
+}
+
+static bool_t
+svcudp_freeargs(xprt, xdr_args, args_ptr)
+ SVCXPRT *xprt;
+ xdrproc_t xdr_args;
+ caddr_t 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(xprt)
+ register SVCXPRT *xprt;
+{
+ register struct svcudp_data *su = su_data(xprt);
+
+ xprt_unregister(xprt);
+ (void)close(xprt->xp_sock);
+ 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
+ */
+ rpc_u_int32 cache_xid;
+ rpc_u_int32 cache_proc;
+ rpc_u_int32 cache_vers;
+ rpc_u_int32 cache_prog;
+ struct sockaddr_in cache_addr;
+ /*
+ * The cached reply and length
+ */
+ char * cache_reply;
+ rpc_u_int32 cache_replylen;
+ /*
+ * Next node on the list, if there is a collision
+ */
+ cache_ptr cache_next;
+};
+
+
+
+/*
+ * The entire cache
+ */
+struct udp_cache {
+ rpc_u_int32 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 */
+ rpc_u_int32 uc_nextvictim; /* points to next victim in fifo list */
+ rpc_u_int32 uc_prog; /* saved program number */
+ rpc_u_int32 uc_vers; /* saved version number */
+ rpc_u_int32 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.
+ */
+svcudp_enablecache(transp, size)
+ SVCXPRT *transp;
+ rpc_u_int32 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(xprt, replylen)
+ SVCXPRT *xprt;
+ rpc_u_int32 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;
+ unsigned 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(xprt, msg, replyp, replylenp)
+ SVCXPRT *xprt;
+ struct rpc_msg *msg;
+ char **replyp;
+ rpc_u_int32 *replylenp;
+{
+ unsigned 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/src/lib/rpc/types.hin b/src/lib/rpc/types.hin
new file mode 100644
index 0000000000..619a9ce204
--- /dev/null
+++ b/src/lib/rpc/types.hin
@@ -0,0 +1,90 @@
+/* @(#)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 __TYPES_RPC_HEADER__
+#define __TYPES_RPC_HEADER__
+
+#include <sys/types.h>
+
+/* this is a 32-bit int type */
+
+#if @SIZEOF_INT@ == 4
+typedef int rpc_int32;
+typedef unsigned int rpc_u_int32;
+#elif @SIZEOF_LONG@ == 4
+typedef long rpc_int32;
+typedef unsigned long rpc_u_int32;
+#endif
+
+#define bool_t int
+#define enum_t int
+#ifndef FALSE
+# define FALSE (0)
+#endif
+#ifndef TRUE
+# define TRUE (1)
+#endif
+#define __dontcare__ -1
+#ifndef NULL
+# define NULL 0
+#endif
+
+#if defined(__osf__)
+#include <stdlib.h>
+#endif
+#define mem_alloc(bsize) (char *) malloc(bsize)
+#define mem_free(ptr, bsize) free(ptr)
+
+#ifndef makedev /* ie, we haven't already included it */
+#include <sys/types.h>
+#endif
+#ifdef _AIX
+#include <sys/select.h>
+#endif
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <sys/param.h>
+#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
+ */
+
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK (rpc_u_int32)0x7F000001
+#endif
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
+
+#endif /* ndef __TYPES_RPC_HEADER__ */
diff --git a/src/lib/rpc/unit-test/Makefile b/src/lib/rpc/unit-test/Makefile
new file mode 100644
index 0000000000..31853cb354
--- /dev/null
+++ b/src/lib/rpc/unit-test/Makefile
@@ -0,0 +1,97 @@
+# Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+#
+# $Id$
+# $Source$
+#
+# $Log$
+# Revision 1.9 1996/07/22 20:41:38 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.8.4.1 1996/07/18 04:20:01 marc
+# merged in changes from OV_9510_BP to OV_9510_FINAL1
+#
+# Revision 1.8.2.1 1996/06/20 23:41:48 marc
+# File added to the repository on a branch
+#
+# Revision 1.8 1995/12/07 17:36:54 jik
+# Use "rpc_test" instead of "rpc-test", to avoid problems with rpcgen on
+# some systems. See PR 3553.
+#
+# Revision 1.7 1995/10/02 08:02:49 jik
+# Delete rpc-tset_clnt.c, rpc-test_svc.c and rpc-test.h before creating
+# them, because rpcgen on some platforms won't output to a file that
+# already exists.
+#
+# Revision 1.6 1994/10/24 19:35:57 bjaspan
+# [secure-build/2649: cannot use -L when compiling]
+#
+# Sandbox:
+#
+# [secure-build/2649] don't use -L
+#
+# Revision 1.7 1994/10/11 20:06:14 bjaspan
+# [secure-build/2649] don't use -L
+#
+# Revision 1.6 1994/09/30 22:25:29 jik
+# Don't need to set MDFLAGS to -a anymore, because it's done
+# automatically by the rules now.
+#
+# Revision 1.5 1994/03/22 19:55:34 shanzer
+# change NETLIBS to NETLIB
+#
+# Revision 1.4 1994/03/18 17:47:00 shanzer
+# added NETLIBS and BSDLIB
+#
+# Revision 1.3 1993/12/13 02:00:39 bjaspan
+# recurse to testsuite subdir.
+#
+# Revision 1.2 1993/12/08 21:45:47 bjaspan
+# misc
+#
+# Revision 1.1 1993/11/03 23:53:58 bjaspan
+# Initial revision
+#
+
+TOP = ../..
+include $(TOP)/config.mk/template
+
+SUBDIRS = testsuite
+
+expand SubdirTarget
+
+SRCS = client.c server.c
+
+CFLAGS := -I../.. -I. $(CFLAGS)
+
+#LIBS = ../librpclib.a $(LIBGSSAPI_TRUST) $(LIBDB) $(LIBCOM_ERR) $(LIBDYN)
+LIBS = ../librpclib.a $(LIBGSSAPI_KRB5) $(LIBDB) $(LIBKRB5) \
+ $(LIBCRYPTO) $(LIBISODE) $(LIBCOM_ERR) $(LIBDYN) $(BSDLIB) $(NETLIB)
+DEPS = ../librpclib.a rpc_test.h
+DEPENDS = rpc_test.h
+
+PROG = client
+SRCS = client.c
+OBJS = client.o rpc_test_clnt.o
+
+expand Program
+expand Depend
+
+PROG = server
+SRCS = server.c
+OBJS = server.o rpc_test_svc.o
+
+expand Program
+expand Depend
+
+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
+ 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
diff --git a/src/lib/rpc/unit-test/client.c b/src/lib/rpc/unit-test/client.c
new file mode 100644
index 0000000000..bcf2700e5e
--- /dev/null
+++ b/src/lib/rpc/unit-test/client.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Id$
+ * $Source$
+ *
+ * $Log$
+ * Revision 1.13 1996/07/22 20:41:40 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.12.4.1 1996/07/18 04:20:03 marc
+ * merged in changes from OV_9510_BP to OV_9510_FINAL1
+ *
+ * Revision 1.12.2.1 1996/06/20 23:41:56 marc
+ * File added to the repository on a branch
+ *
+ * Revision 1.12 1996/05/12 06:58:10 marc
+ * type renamings for compatibility with beta6
+ *
+ * Revision 1.11 1996/02/12 15:58:42 grier
+ * [secure/3570]
+ * long conversion
+ *
+ * Revision 1.10 1995/12/07 17:37:03 jik
+ * Use "rpc_test" instead of "rpc-test", to avoid problems with rpcgen on
+ * some systems. See PR 3553.
+ *
+ * Revision 1.9 1994/09/21 18:38:56 bjaspan
+ * [secure-rpc/2536: unit test client.c: memory initialization and out-of-bounds reference bugs]
+ * [secure-releng/2537: audit secure-rpc/2536: minor memory problems in unit-test client]
+ *
+ * Sandbox:
+ *
+ * 1. Don't allow the count specifie on the command line to be bigger
+ * than the size of the buffer use for testing.
+ * 2. When initializing the buffer for the lengths test, initialize it to
+ * count bytes.
+ *
+ * Revision 1.9 1994/09/19 01:28:04 root
+ * 1. Don't allow the count specifie on the command line to be bigger
+ * than the size of the buffer use for testing.
+ * 2. When initializing the buffer for the lengths test, initialize it to
+ * count bytes.
+ *
+ * Revision 1.8 1994/04/06 22:13:01 jik
+ * Change -auth_once to -o, add -a, -m and -s arguments to set
+ * auth_debug_gssapi, svc_debug_gssapi and misc_debug_gssapi variables.
+ *
+ * Revision 1.7 1994/04/05 20:50:09 bjaspan
+ * fix typo that causes coredump when server blocks/fails
+ *
+ * Revision 1.6 1993/12/08 21:44:45 bjaspan
+ * test fix for secure-rpc/586, improve arg handlng
+ *
+ * Revision 1.5 1993/12/06 21:23:30 bjaspan
+ * accept count arg for RPC_TEST_LENGTHS
+ *
+ * Revision 1.4 1993/12/01 23:41:45 bjaspan
+ * don't free echo_resp if call fails
+ *
+ * Revision 1.3 1993/11/15 19:53:09 bjaspan
+ * test auto-syncrhonization
+ *
+ * Revision 1.2 1993/11/12 02:33:43 bjaspan
+ * use clnt_pcreateerror for auth failures
+ *
+ * Revision 1.1 1993/11/03 23:53:58 bjaspan
+ * Initial revision
+ *
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include <gssapi/gssapi.h>
+#include <rpc/rpc.h>
+#include <rpc/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];
+ rpc_int32 cred_len;
+};
+#define AUTH_PRIVATE(auth) ((struct auth_gssapi_data *)auth->ah_private)
+
+extern int auth_debug_gssapi;
+char *whoami;
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *host, *target, *echo_arg, **echo_resp, buf[BIG_BUF];
+ CLIENT *clnt;
+ AUTH *tmp_auth;
+ struct rpc_err e;
+ int i, count, auth_once;
+ extern int optind;
+ extern char *optarg;
+ extern int svc_debug_gssapi, misc_debug_gssapi, auth_debug_gssapi;
+ int c;
+
+ whoami = argv[0];
+ count = 1026;
+ auth_once = 0;
+
+ while ((c = getopt(argc, argv, "a:m:os:")) != -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 '?':
+ usage();
+ break;
+ }
+ }
+
+ argv += optind;
+ argc -= optind;
+
+ switch (argc) {
+ case 3:
+ count = atoi(argv[2]);
+ if (count > BIG_BUF) {
+ fprintf(stderr, "Test count cannot exceed %d.\n", BIG_BUF);
+ 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, "tcp");
+ 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", echo_arg, *echo_resp);
+ 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);
+ 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");
+ 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);
+}
+
+usage()
+{
+ fprintf(stderr, "usage: %s [-a] [-s num] [-m num] host service [count]\n",
+ whoami);
+ exit(1);
+}
diff --git a/src/lib/rpc/unit-test/rpc_test.x b/src/lib/rpc/unit-test/rpc_test.x
new file mode 100644
index 0000000000..e9ae27c979
--- /dev/null
+++ b/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/src/lib/rpc/unit-test/server.c b/src/lib/rpc/unit-test/server.c
new file mode 100644
index 0000000000..d98b2df0ba
--- /dev/null
+++ b/src/lib/rpc/unit-test/server.c
@@ -0,0 +1,306 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Id$
+ * $Source$
+ *
+ * $Log$
+ * Revision 1.15 1996/07/22 20:41:44 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.14.4.1 1996/07/18 04:20:06 marc
+ * merged in changes from OV_9510_BP to OV_9510_FINAL1
+ *
+ * Revision 1.14.2.1 1996/06/20 23:42:16 marc
+ * File added to the repository on a branch
+ *
+ * Revision 1.14 1996/05/12 06:59:06 marc
+ * change SERVICE_NAME to "host" instead of "server"
+ *
+ * remove KRB5KTNAME support, since the library supports it internally now.
+ *
+ * Revision 1.13 1995/12/07 17:36:58 jik
+ * Use "rpc_test" instead of "rpc-test", to avoid problems with rpcgen on
+ * some systems. See PR 3553.
+ *
+ * Revision 1.12 1995/11/07 23:20:44 grier
+ * Add stdlib.h
+ * Add string.h
+ *
+ * Revision 1.11 1995/03/24 19:55:28 jik
+ * Cast a const gss_OID to (gss_OID) to prevent a compiler warning.
+ *
+ * Revision 1.10 1995/02/22 15:54:17 jik
+ * I was a moron in revision 1.8. This is the server function, not the
+ * client function, so it gets a struct svc_req *, not a CLIENT *.
+ *
+ * Revision 1.9 1995/02/22 15:21:51 jik
+ * Linux's rpcgen names the server function differently from the client
+ * function ("_svc" is appended to the end of it).
+ *
+ * Revision 1.8 1995/02/22 14:35:05 jik
+ * RPC server functions have CLIENT * passed into them, so I added it as
+ * an argument to rpc_test_echo_1.
+ *
+ * Revision 1.7 1994/09/21 18:35:57 bjaspan
+ * [gssapi/438: gss_nt_service_name should default to local host]
+ * [secure-releng/2513: audit gssapi/438: gss_nt_service_name should default to local host]
+ *
+ * Sandbox:
+ *
+ * Don't need to get local host name and put it in the service name,
+ * since the gssapi library does that now. See PR 438.
+ *
+ * Revision 1.8 1994/09/01 17:21:59 jik
+ * Don't need to get local host name and put it in the service name,
+ * since the gssapi library does that now. See PR 438.
+ *
+ * Revision 1.7 1994/04/08 17:22:11 bjaspan
+ * add KRB5KTNAME hack so unit tests continue to work
+ *
+ * Revision 1.6 1994/04/05 20:50:26 bjaspan
+ * print "running" when ready to tests can proceed
+ *
+ * Revision 1.5 1994/04/05 19:49:54 jik
+ * Use host name instead of localhost.
+ *
+ * Revision 1.4 1994/03/08 00:14:58 shanzer
+ * changed call to inet_ntoa
+ *
+ * Revision 1.3 1993/12/13 01:37:54 bjaspan
+ * update for new test system
+ * ,.
+ *
+ * Revision 1.2 1993/12/08 21:45:16 bjaspan
+ * display badauth errors, improve arg handling
+ *
+ * Revision 1.1 1993/11/03 23:53:58 bjaspan
+ * Initial revision
+ *
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <rpc/rpc.h>
+#include <arpa/inet.h> /* inet_ntoa */
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_generic.h>
+#include <rpc/auth_gssapi.h>
+#include <sys/param.h> /* MAXHOSTNAMELEN */
+#include "rpc_test.h"
+
+#ifdef linux
+/*
+ For some reason, Linux's rpcgen names the server function
+ differently from the client function. I suppose this is useful if
+ you want to include them both in the same library or something, but
+ not useful at all if you want to link the client code directly to
+ the server code for testing, instead of going through the RPC layer.
+ */
+#define rpc_test_echo_1 rpc_test_echo_1_svc
+#endif
+
+extern void rpc_test_prog_1();
+
+extern int svc_debug_gssapi, misc_debug_gssapi;
+
+void rpc_test_badauth(OM_uint32 major, OM_uint32 minor,
+ struct sockaddr_in *addr, void *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 "host"
+#endif
+
+main(int argc, char **argv)
+{
+ auth_gssapi_name names[2];
+ register SVCXPRT *transp;
+
+ names[0].name = SERVICE_NAME;
+ names[0].type = (gss_OID) gss_nt_service_name;
+ names[1].name = 0;
+ names[1].type = 0;
+
+ switch (argc) {
+ case 3:
+ misc_debug_gssapi = atoi(argv[2]);
+ case 2:
+ svc_debug_gssapi = atoi(argv[1]);
+ case 1:
+ break;
+ default:
+ fprintf(stderr, "Usage: server [svc-debug] [misc-debug]\n");
+ exit(1);
+ }
+
+ (void) pmap_unset(RPC_TEST_PROG, RPC_TEST_VERS_1);
+
+ transp = svctcp_create(RPC_ANYSOCK, 0, 0);
+ 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, IPPROTO_TCP)) {
+ fprintf(stderr,
+ "unable to register (RPC_TEST_PROG, RPC_TEST_VERS_1, tcp).");
+ 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);
+
+ printf("running\n");
+
+ svc_run();
+ fprintf(stderr, "svc_run returned");
+ exit(1);
+ /* NOTREACHED */
+}
+
+char **rpc_test_echo_1(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",
+ client_name.value,
+ inet_ntoa(rqst->rq_xprt->xp_raddr.sin_addr),
+ ntohs(rqst->rq_xprt->xp_raddr.sin_port),
+ 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, void *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_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;
+ gss_buffer_desc msg;
+ int 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(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", msg);
+ return;
+ }
+
+ printf(", %s", (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/src/lib/rpc/unit-test/testsuite/Makefile b/src/lib/rpc/unit-test/testsuite/Makefile
new file mode 100644
index 0000000000..8a2cccdc2d
--- /dev/null
+++ b/src/lib/rpc/unit-test/testsuite/Makefile
@@ -0,0 +1,24 @@
+#
+# $Id$
+#
+
+TOP = ../../..
+include $(TOP)/config.mk/template
+
+export RPC_TEST_SRVTAB := /tmp/rpc_test_v5srvtab
+
+unit-test:: unit-test-setup unit-test-body unit-test-cleanup
+
+unit-test-setup::
+ $(START_SERVERS)
+ ./rpc_test_setup.sh
+
+unit-test-body::
+ $(RUNTEST) SERVER=../server CLIENT=../client --tool rpc_test
+
+unit-test-cleanup::
+ $(STOP_SERVERS)
+ -rm -f /tmp/rpc_test_v5srvtab /tmp/krb5cc_rpc_test_fullrun
+
+clean::
+ $(CLEAN) rpc_test.log rpc_test.plog rpc_test.sum rpc_test.psum
diff --git a/src/lib/rpc/unit-test/testsuite/config/unix.exp b/src/lib/rpc/unit-test/testsuite/config/unix.exp
new file mode 100644
index 0000000000..030837d49a
--- /dev/null
+++ b/src/lib/rpc/unit-test/testsuite/config/unix.exp
@@ -0,0 +1,79 @@
+#
+# $Id$
+#
+
+set kill /bin/kill
+set sleep /bin/sleep
+set kinit $env(TOP)/install/bin/kinit
+set kdestroy $env(TOP)/install/bin/kdestroy
+
+set hostname [exec hostname]
+
+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
+ global server_id
+ global server_pid
+ global server_started
+ global env
+
+ set env(KRB5KTNAME) FILE:$env(RPC_TEST_SRVTAB)
+
+ verbose "% $SERVER" 1
+ set server_pid [spawn $SERVER]
+ set server_id $spawn_id
+
+ unset env(KRB5KTNAME)
+
+ set timeout 30
+
+ expect {
+ "running" { }
+ eof {
+ fail "server exited!"
+ verbose $expect_out(buffer) 1
+ }
+ timeout {
+ fail "server didn't start in $timeout seconds"
+ verbose $expect_out(buffer) 1
+ }
+ }
+
+}
+
+rpc_test_start
diff --git a/src/lib/rpc/unit-test/testsuite/helpers.exp b/src/lib/rpc/unit-test/testsuite/helpers.exp
new file mode 100644
index 0000000000..1a37ad512a
--- /dev/null
+++ b/src/lib/rpc/unit-test/testsuite/helpers.exp
@@ -0,0 +1,128 @@
+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 kinit {princ pass lifetime} {
+ global kinit
+ global wait_error_index wait_errno_index wait_status_index
+
+ spawn -noecho $kinit -l $lifetime $princ
+ expect {
+ -re "Password for $princ.*: " { send "$pass\n" }
+ timeout { error "Timeout waiting for kinit"; close }
+ }
+ expect { eof {} }
+
+ set ret [wait]
+ if {[lindex $ret $wait_error_index] == -1} {
+ error \
+ "wait(kinit $princ) returned error [lindex $ret $wait_errno_index]"
+ } else {
+ if {[lindex $ret $wait_status_index] != 0} {
+ error \
+ "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
+ global CLIENT
+ global hostname
+ global spawn_id
+ global verbose
+
+ if {$target == ""} {
+ set target "server@$hostname"
+ }
+
+ set env(KRB5CCNAME) FILE:/tmp/krb5cc_rpc_test_$ccname
+ kinit $user $password $lifetime
+
+ if {$verbose > 0} {
+ spawn $CLIENT -a 1 -s 1 -m 1 $hostname $target $count
+ } else {
+ spawn $CLIENT $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
+ 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:/tmp/krb5cc_rpc_test_$ccname
+ if {[catch "exec $kdestroy"] != 0} {
+ error "$testname: cannot destroy client $ccname ccache"
+ }
+
+ unset env(KRB5CCNAME)
+}
diff --git a/src/lib/rpc/unit-test/testsuite/rpc_test.0/expire.exp b/src/lib/rpc/unit-test/testsuite/rpc_test.0/expire.exp
new file mode 100644
index 0000000000..d80bae6dae
--- /dev/null
+++ b/src/lib/rpc/unit-test/testsuite/rpc_test.0/expire.exp
@@ -0,0 +1,21 @@
+set timeout 40
+
+load_lib "helpers.exp"
+
+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
diff --git a/src/lib/rpc/unit-test/testsuite/rpc_test.0/fullrun.exp b/src/lib/rpc/unit-test/testsuite/rpc_test.0/fullrun.exp
new file mode 100644
index 0000000000..6e8acf80e8
--- /dev/null
+++ b/src/lib/rpc/unit-test/testsuite/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 8 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\]*\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/src/lib/rpc/unit-test/testsuite/rpc_test.0/gsserr.exp b/src/lib/rpc/unit-test/testsuite/rpc_test.0/gsserr.exp
new file mode 100644
index 0000000000..f9d53052de
--- /dev/null
+++ b/src/lib/rpc/unit-test/testsuite/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 8 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/src/lib/rpc/unit-test/testsuite/rpc_test_setup.sh b/src/lib/rpc/unit-test/testsuite/rpc_test_setup.sh
new file mode 100644
index 0000000000..2a97af4d3c
--- /dev/null
+++ b/src/lib/rpc/unit-test/testsuite/rpc_test_setup.sh
@@ -0,0 +1,56 @@
+#!/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 it's set, set it to true
+VERBOSE=${VERBOSE_TEST:+true}
+# Otherwise, set it to false
+DUMMY=${VERBOSE:=false}
+
+if $VERBOSE; then
+ REDIRECT=
+else
+ REDIRECT='>/dev/null'
+fi
+
+PATH=$TOP/install/admin:$PATH; export PATH
+
+CANON_HOST=`perl -e 'chop($_=\`hostname\`);($n,$a,$t,$l,@a)=gethostbyname($_);($_)=gethostbyaddr($a[0],$t); print;'`
+export CANON_HOST
+
+eval $CLNTTCL <<'EOF' $REDIRECT
+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]
+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
+
+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/src/lib/rpc/xdr.c b/src/lib/rpc/xdr.c
new file mode 100644
index 0000000000..7f44181620
--- /dev/null
+++ b/src/lib/rpc/xdr.c
@@ -0,0 +1,674 @@
+/* @(#)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>
+char *malloc();
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+
+/*
+ * constants specific to the xdr "protocol"
+ */
+#define XDR_FALSE ((rpc_int32) 0)
+#define XDR_TRUE ((rpc_int32) 1)
+#define LASTUNSIGNED ((unsigned 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(proc, objp)
+ xdrproc_t proc;
+ char *objp;
+{
+ XDR x;
+
+ x.x_op = XDR_FREE;
+ (*proc)(&x, objp);
+}
+
+/*
+ * XDR nothing
+ */
+bool_t
+xdr_void(/* xdrs, addr */)
+ /* XDR *xdrs; */
+ /* caddr_t addr; */
+{
+
+ return (TRUE);
+}
+
+/*
+ * XDR integers
+ */
+bool_t
+xdr_int(xdrs, ip)
+ XDR *xdrs;
+ int *ip;
+{
+
+#ifdef lint
+ (void) (xdr_short(xdrs, (short *)ip));
+ return (xdr_long(xdrs, (rpc_int32 *)ip));
+#else
+ if (sizeof (int) >= 4) {
+ 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);
+ }
+ } else {
+ return (xdr_short(xdrs, (short *)ip));
+ }
+#endif
+}
+
+/*
+ * XDR unsigned integers
+ */
+bool_t
+xdr_u_int(xdrs, up)
+ XDR *xdrs;
+ unsigned int *up;
+{
+#ifdef lint
+ (void) (xdr_short(xdrs, (short *)up));
+ return (xdr_u_long(xdrs, (rpc_u_int32 *)up));
+#else
+ if (sizeof (unsigned int) >= 4) {
+ unsigned long l;
+ switch (xdrs->x_op) {
+ case XDR_ENCODE:
+ l = *up;
+ return (xdr_u_long(xdrs, &l));
+
+ case XDR_DECODE:
+ if (!xdr_u_long(xdrs, &l)) {
+ return (FALSE);
+ }
+ *up = l;
+ return (TRUE);
+
+ case XDR_FREE:
+ return (TRUE);
+ }
+ } else {
+ return (xdr_short(xdrs, (short *)up));
+ }
+#endif
+}
+
+/*
+ * XDR long integers
+ * same as xdr_u_long - open coded to save a proc call!
+ */
+bool_t
+xdr_long(xdrs, lp)
+ register XDR *xdrs;
+ long *lp;
+{
+ if (xdrs->x_op == XDR_ENCODE) {
+ if (sizeof (long) > 4) {
+ /* See if the dereferenced value fits in 4 bytes. If not, return FALSE.
+ * Check by loading value into a rpc_int32, then loading back and comparing
+ * results.
+ */
+ rpc_int32 i = (int) *lp;
+ long l = i;
+ if (l != *lp) {
+ return (FALSE);
+ }
+ }
+ return (XDR_PUTLONG(xdrs, lp));
+ }
+ if (xdrs->x_op == XDR_DECODE)
+ return (XDR_GETLONG(xdrs, lp));
+
+ if (xdrs->x_op == XDR_FREE)
+ return (TRUE);
+
+ return (FALSE);
+}
+
+/*
+ * XDR unsigned long integers
+ * same as xdr_long - open coded to save a proc call!
+ */
+bool_t
+xdr_u_long(xdrs, ulp)
+ register XDR *xdrs;
+ unsigned long *ulp;
+{
+ if (xdrs->x_op == XDR_ENCODE) {
+ if (sizeof (unsigned long) > 4) {
+ /* See if the dereferenced value fits in 4 bytes. If not, return FALSE.
+ * Check by loading value into a rpc_int32, then loading back and comparing
+ * results.
+ */
+ unsigned int ui = *ulp;
+ unsigned long ul = ui;
+ if (ul != *ulp) {
+ return (FALSE);
+ }
+ }
+ return (XDR_PUTLONG(xdrs, ulp));
+ }
+ if (xdrs->x_op == XDR_DECODE) {
+ return (XDR_GETLONG(xdrs, (long *)ulp));
+ }
+ if (xdrs->x_op == XDR_FREE)
+ return (TRUE);
+ return (FALSE);
+}
+
+/*
+ * XDR short integers
+ */
+bool_t
+xdr_short(xdrs, sp)
+ 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);
+ }
+ *sp = (short) l;
+ return (TRUE);
+
+ case XDR_FREE:
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+/*
+ * XDR unsigned short integers
+ */
+bool_t
+xdr_u_short(xdrs, usp)
+ register XDR *xdrs;
+ unsigned short *usp;
+{
+ unsigned long l;
+
+ switch (xdrs->x_op) {
+
+ case XDR_ENCODE:
+ l = (unsigned long) *usp;
+ return (XDR_PUTLONG(xdrs, &l));
+
+ case XDR_DECODE:
+ if (!XDR_GETLONG(xdrs, &l)) {
+ return (FALSE);
+ }
+ *usp = (unsigned short) l;
+ return (TRUE);
+
+ case XDR_FREE:
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+
+/*
+ * XDR a char
+ */
+bool_t
+xdr_char(xdrs, cp)
+ 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(xdrs, cp)
+ XDR *xdrs;
+ char *cp;
+{
+ unsigned int u;
+
+ u = (*cp);
+ if (!xdr_u_int(xdrs, &u)) {
+ return (FALSE);
+ }
+ *cp = u;
+ return (TRUE);
+}
+
+/*
+ * XDR booleans
+ */
+bool_t
+xdr_bool(xdrs, bp)
+ 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(xdrs, ep)
+ 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 (rpc_int32)) {
+ return (xdr_int32(xdrs, (rpc_int32 *)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(xdrs, cp, cnt)
+ register XDR *xdrs;
+ caddr_t cp;
+ register unsigned int cnt;
+{
+ register unsigned int rndup;
+ static 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, 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(xdrs, cpp, sizep, maxsize)
+ register XDR *xdrs;
+ char **cpp;
+ register unsigned int *sizep;
+ unsigned int maxsize;
+{
+ register char *sp = *cpp; /* sp is the actual string pointer */
+ register unsigned 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(xdrs, np)
+ XDR *xdrs;
+ struct netobj *np;
+{
+
+ return (xdr_bytes(xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ));
+}
+
+bool_t
+xdr_int32(xdrs, ip)
+ XDR *xdrs;
+ rpc_int32 *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);
+ }
+}
+
+xdr_u_int32(xdrs, up)
+ XDR *xdrs;
+ rpc_u_int32 *up;
+{
+ unsigned 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);
+ }
+}
+
+/*
+ * 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(xdrs, dscmp, unp, choices, dfault)
+ register 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(xdrs, cpp, maxsize)
+ register XDR *xdrs;
+ char **cpp;
+ unsigned int maxsize;
+{
+ register char *sp = *cpp; /* sp is the actual string pointer */
+ unsigned int size;
+ unsigned 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;
+ }
+ 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(xdrs, cpp)
+ XDR *xdrs;
+ char **cpp;
+{
+ if (xdr_string(xdrs, cpp, LASTUNSIGNED)) {
+ return (TRUE);
+ }
+ return (FALSE);
+}
diff --git a/src/lib/rpc/xdr.h b/src/lib/rpc/xdr.h
new file mode 100644
index 0000000000..9f0819b61a
--- /dev/null
+++ b/src/lib/rpc/xdr.h
@@ -0,0 +1,276 @@
+/* @(#)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 __XDR_HEADER__
+#define __XDR_HEADER__
+
+/*
+ * 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 *);
+ */
+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 {
+ enum xdr_op x_op; /* operation; fast additional param */
+ struct xdr_ops {
+ bool_t (*x_getlong)(); /* get a long from underlying stream */
+ bool_t (*x_putlong)(); /* put a long to " */
+ bool_t (*x_getbytes)();/* get some bytes from " */
+ bool_t (*x_putbytes)();/* put some bytes to " */
+ unsigned int (*x_getpostn)();/* returns bytes off from beginning */
+ bool_t (*x_setpostn)();/* lets you reposition the stream */
+ rpc_int32 * (*x_inline)(); /* buf quick ptr to buffered data */
+ void (*x_destroy)(); /* free privates of this xdr_stream */
+ } *x_ops;
+ caddr_t x_public; /* users' data */
+ caddr_t 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;
+ * rpc_int32 *longp;
+ * caddr_t addr;
+ * unsigned int len;
+ * unsigned 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_LONG(buf) ((long)ntohl((rpc_u_int32)*(buf)++))
+#define IXDR_PUT_LONG(buf, v) (*(buf)++ = (rpc_int32)htonl((rpc_u_int32)v))
+
+#define IXDR_GET_BOOL(buf) ((bool_t)IXDR_GET_LONG(buf))
+#define IXDR_GET_ENUM(buf, t) ((t)IXDR_GET_LONG(buf))
+#define IXDR_GET_U_LONG(buf) ((rpc_u_int32)IXDR_GET_LONG(buf))
+#define IXDR_GET_SHORT(buf) ((short)IXDR_GET_LONG(buf))
+#define IXDR_GET_U_SHORT(buf) ((unsigned short)IXDR_GET_LONG(buf))
+
+#define IXDR_PUT_BOOL(buf, v) IXDR_PUT_LONG((buf), ((rpc_int32)(v)))
+#define IXDR_PUT_ENUM(buf, v) IXDR_PUT_LONG((buf), ((rpc_int32)(v)))
+#define IXDR_PUT_U_LONG(buf, v) IXDR_PUT_LONG((buf), ((rpc_int32)(v)))
+#define IXDR_PUT_SHORT(buf, v) IXDR_PUT_LONG((buf), ((rpc_int32)(v)))
+#define IXDR_PUT_U_SHORT(buf, v) IXDR_PUT_LONG((buf), ((rpc_int32)(v)))
+
+/*
+ * These are the "generic" xdr routines.
+ */
+extern bool_t xdr_void();
+extern bool_t xdr_int(XDR *, int *);
+extern bool_t xdr_u_int(XDR *, unsigned int *);
+extern bool_t xdr_long(XDR *, long *);
+extern bool_t xdr_u_long(XDR *, unsigned long *);
+extern bool_t xdr_short(XDR *, short *);
+extern bool_t xdr_u_short(XDR *, unsigned 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 *, unsigned int*, unsigned int, unsigned int, xdrproc_t);
+extern bool_t xdr_bytes(XDR *, char **, unsigned int *, unsigned int);
+extern bool_t xdr_opaque(XDR *, caddr_t, unsigned int);
+extern bool_t xdr_string(XDR *, char **, unsigned 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 *, char *);
+extern bool_t xdr_vector(XDR *, char *, unsigned int, unsigned 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 *, unsigned int, xdrproc_t);
+extern bool_t xdr_pointer(XDR *, char **, unsigned int, xdrproc_t);
+extern bool_t xdr_wrapstring(XDR *, char **);
+
+/*
+ * Common opaque bytes objects used by many rpc protocols;
+ * declared here due to commonality.
+ */
+#define MAX_NETOBJ_SZ 1024
+struct netobj {
+ unsigned int n_len;
+ char *n_bytes;
+};
+typedef struct netobj netobj;
+extern bool_t xdr_netobj(XDR *, struct netobj *);
+
+extern bool_t xdr_int32(XDR *, rpc_int32 *);
+extern bool_t xdr_u_int32(XDR *, rpc_u_int32 *);
+
+/*
+ * These are the public routines for the various implementations of
+ * xdr streams.
+ */
+extern void xdrmem_create(); /* XDR using memory buffers */
+extern void xdrstdio_create(); /* XDR using stdio library */
+extern void xdrrec_create(); /* XDR pseudo records for tcp */
+extern void xdralloc_create(); /* XDR allocating memory buffer */
+extern void xdralloc_release(); /* destroy xdralloc, save buf */
+extern bool_t xdrrec_endofrecord(); /* make end of xdr record */
+extern bool_t xdrrec_skiprecord(); /* move to beginning of next record */
+extern bool_t xdrrec_eof(); /* true if no more input */
+extern caddr_t xdralloc_getdata(); /* get buffer from xdralloc */
+
+#endif /* !__XDR_HEADER__ */
diff --git a/src/lib/rpc/xdr_alloc.c b/src/lib/rpc/xdr_alloc.c
new file mode 100644
index 0000000000..37ae71e823
--- /dev/null
+++ b/src/lib/rpc/xdr_alloc.c
@@ -0,0 +1,173 @@
+/* @(#)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.
+ *
+ * $Header$
+ *
+ * $Log$
+ * Revision 1.6 1996/07/22 20:41:21 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 04:19:49 marc
+ * merged in changes from OV_9510_BP to OV_9510_FINAL1
+ *
+ * Revision 1.5.2.1 1996/06/20 23:40:30 marc
+ * File added to the repository on a branch
+ *
+ * Revision 1.5 1996/05/12 06:19:25 marc
+ * renamed lots of types: u_foo to unsigned foo, and foo32 to rpc_foo32. This is to make autoconfiscation less painful.
+ *
+ * Revision 1.4 1995/12/13 14:03:14 grier
+ * Longs to ints for Alpha
+ *
+ * Revision 1.3 1993/12/09 18:57:25 bjaspan
+ * [secure-releng/833] misc bugfixes to admin library
+ *
+ * Revision 1.3 1993/12/06 21:23:08 bjaspan
+ * add xdralloc_release
+ *
+ * Revision 1.2 1993/10/26 21:13:19 bjaspan
+ * add casts for correctness
+ *
+ * Revision 1.1 1993/10/19 03:11:39 bjaspan
+ * Initial revision
+ *
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <dyn.h>
+
+static bool_t xdralloc_putlong();
+static bool_t xdralloc_putbytes();
+static unsigned int xdralloc_getpos();
+static rpc_int32 * xdralloc_inline();
+static void xdralloc_destroy();
+static bool_t xdralloc_notsup();
+
+static struct xdr_ops xdralloc_ops = {
+ xdralloc_notsup,
+ xdralloc_putlong,
+ xdralloc_notsup,
+ xdralloc_putbytes,
+ xdralloc_getpos,
+ xdralloc_notsup,
+ xdralloc_inline,
+ xdralloc_destroy,
+};
+
+/*
+ * The procedure xdralloc_create initializes a stream descriptor for a
+ * memory buffer.
+ */
+void xdralloc_create(xdrs, op)
+ register 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(xdrs)
+ XDR *xdrs;
+{
+ return (caddr_t) DynGet((DynObject) xdrs->x_private, 0);
+}
+
+void xdralloc_release(xdrs)
+ XDR *xdrs;
+{
+ DynRelease((DynObject) xdrs->x_private);
+}
+
+static void xdralloc_destroy(xdrs)
+ XDR *xdrs;
+{
+ DynDestroy((DynObject) xdrs->x_private);
+}
+
+static bool_t xdralloc_notsup()
+{
+ return FALSE;
+}
+
+static bool_t xdralloc_putlong(xdrs, lp)
+ register XDR *xdrs;
+ rpc_int32 *lp;
+{
+ int l = htonl((rpc_u_int32) *(int *)lp);
+
+ if (DynInsert((DynObject) xdrs->x_private,
+ DynSize((DynObject) xdrs->x_private), &l,
+ sizeof(int)) != DYN_OK)
+ return FALSE;
+ return (TRUE);
+}
+
+static bool_t xdralloc_putbytes(xdrs, addr, len)
+ register XDR *xdrs;
+ caddr_t addr;
+ register unsigned int len;
+{
+ if (DynInsert((DynObject) xdrs->x_private,
+ DynSize((DynObject) xdrs->x_private),
+ addr, len) != DYN_OK)
+ return FALSE;
+ return TRUE;
+}
+
+static unsigned int xdralloc_getpos(xdrs)
+ register XDR *xdrs;
+{
+ return DynSize((DynObject) xdrs->x_private);
+}
+
+
+static rpc_int32 *xdralloc_inline(xdrs, len)
+ register XDR *xdrs;
+ int len;
+{
+ return (rpc_int32 *) 0;
+}
diff --git a/src/lib/rpc/xdr_array.c b/src/lib/rpc/xdr_array.c
new file mode 100644
index 0000000000..09bd50abd1
--- /dev/null
+++ b/src/lib/rpc/xdr_array.c
@@ -0,0 +1,153 @@
+/* @(#)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 <rpc/types.h>
+#include <rpc/xdr.h>
+
+#define LASTUNSIGNED ((unsigned 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(xdrs, addrp, sizep, maxsize, elsize, elproc)
+ register XDR *xdrs;
+ caddr_t *addrp; /* array pointer */
+ unsigned int *sizep; /* number of elements */
+ unsigned int maxsize; /* max numberof elements */
+ unsigned int elsize; /* size in bytes of each element */
+ xdrproc_t elproc; /* xdr routine to handle each element */
+{
+ register unsigned int i;
+ register caddr_t target = *addrp;
+ register unsigned int c; /* the actual element count */
+ register bool_t stat = TRUE;
+ register unsigned int nodesize;
+
+ /* like strings, arrays are really counted arrays */
+ if (! xdr_u_int(xdrs, sizep)) {
+ return (FALSE);
+ }
+ c = *sizep;
+ if ((c > maxsize) && (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);
+ }
+
+ /*
+ * 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(xdrs, basep, nelem, elemsize, xdr_elem)
+ register XDR *xdrs;
+ register char *basep;
+ register unsigned int nelem;
+ register unsigned int elemsize;
+ register xdrproc_t xdr_elem;
+{
+ register unsigned 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/src/lib/rpc/xdr_float.c b/src/lib/rpc/xdr_float.c
new file mode 100644
index 0000000000..0c153c4723
--- /dev/null
+++ b/src/lib/rpc/xdr_float.c
@@ -0,0 +1,293 @@
+/* @(#)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 <rpc/types.h>
+#include <rpc/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(xdrs, fp)
+ register XDR *xdrs;
+ register 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, (rpc_int32 *)&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, (rpc_int32 *)&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(xdrs, dp)
+ register XDR *xdrs;
+ double *dp;
+{
+ register rpc_int32 *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 = (rpc_int32 *)dp;
+ if (sizeof(rpc_int32) == 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 = (rpc_int32 *)&id;
+ return (XDR_PUTLONG(xdrs, lp++) && XDR_PUTLONG(xdrs, lp));
+#endif
+
+ case XDR_DECODE:
+#if !defined(vax)
+ lp = (rpc_int32 *)dp;
+ if (sizeof(rpc_int32) == 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 = (rpc_int32 *)&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/src/lib/rpc/xdr_mem.c b/src/lib/rpc/xdr_mem.c
new file mode 100644
index 0000000000..39c0df203b
--- /dev/null
+++ b/src/lib/rpc/xdr_mem.c
@@ -0,0 +1,188 @@
+/* @(#)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 <rpc/types.h>
+#include <rpc/xdr.h>
+#include <netinet/in.h>
+#include <stdio.h>
+
+static bool_t xdrmem_getlong();
+static bool_t xdrmem_putlong();
+static bool_t xdrmem_getbytes();
+static bool_t xdrmem_putbytes();
+static unsigned int xdrmem_getpos();
+static bool_t xdrmem_setpos();
+static rpc_int32 * xdrmem_inline();
+static void xdrmem_destroy();
+
+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(xdrs, addr, size, op)
+ register XDR *xdrs;
+ caddr_t addr;
+ unsigned 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;
+}
+
+static void
+xdrmem_destroy(/*xdrs*/)
+ /*XDR *xdrs;*/
+{
+}
+
+static bool_t
+xdrmem_getlong(xdrs, lp)
+ register XDR *xdrs;
+ long *lp;
+{
+
+ if ((xdrs->x_handy -= sizeof(rpc_int32)) < 0)
+ return (FALSE);
+ *lp = (long)ntohl(*((rpc_u_int32 *)(xdrs->x_private)));
+ xdrs->x_private += sizeof(rpc_int32);
+ return (TRUE);
+}
+
+static bool_t
+xdrmem_putlong(xdrs, lp)
+ register XDR *xdrs;
+ long *lp;
+{
+
+ if ((xdrs->x_handy -= sizeof(rpc_int32)) < 0)
+ return (FALSE);
+ *(rpc_int32 *)xdrs->x_private = (rpc_int32)htonl((rpc_u_int32)(*lp));
+ xdrs->x_private += sizeof(rpc_int32);
+ return (TRUE);
+}
+
+static bool_t
+xdrmem_getbytes(xdrs, addr, len)
+ register XDR *xdrs;
+ caddr_t addr;
+ register unsigned int len;
+{
+
+ if ((xdrs->x_handy -= len) < 0)
+ return (FALSE);
+ memmove(addr, xdrs->x_private, len);
+ xdrs->x_private += len;
+ return (TRUE);
+}
+
+static bool_t
+xdrmem_putbytes(xdrs, addr, len)
+ register XDR *xdrs;
+ caddr_t addr;
+ register unsigned int len;
+{
+
+ if ((xdrs->x_handy -= len) < 0)
+ return (FALSE);
+ memmove(xdrs->x_private, addr, len);
+ xdrs->x_private += len;
+ return (TRUE);
+}
+
+static unsigned int
+xdrmem_getpos(xdrs)
+ register XDR *xdrs;
+{
+/*
+ * 11/3/95 - JRG - Rather than recast everything for 64 bit, just convert
+ * pointers to longs, then cast to int.
+ */
+ return (unsigned int)((unsigned long)xdrs->x_private - (unsigned long)xdrs->x_base);
+}
+
+static bool_t
+xdrmem_setpos(xdrs, pos)
+ register XDR *xdrs;
+ unsigned int pos;
+{
+ register caddr_t newaddr = xdrs->x_base + pos;
+ register caddr_t lastaddr = 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_int32 *
+xdrmem_inline(xdrs, len)
+ register XDR *xdrs;
+ int len;
+{
+ rpc_int32 *buf = 0;
+
+ if (xdrs->x_handy >= len) {
+ xdrs->x_handy -= len;
+ buf = (rpc_int32 *) xdrs->x_private;
+ xdrs->x_private += len;
+ }
+ return (buf);
+}
diff --git a/src/lib/rpc/xdr_rec.c b/src/lib/rpc/xdr_rec.c
new file mode 100644
index 0000000000..99ce9235aa
--- /dev/null
+++ b/src/lib/rpc/xdr_rec.c
@@ -0,0 +1,596 @@
+/* @(#)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(rpc_u_int32). 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 <rpc/types.h>
+#include <rpc/xdr.h>
+#include <netinet/in.h>
+
+#include <unistd.h>
+
+static unsigned int fix_buf_size();
+static bool_t flush_out();
+static bool_t get_input_bytes();
+static bool_t set_input_fragment();
+static bool_t skip_input_bytes();
+
+static bool_t xdrrec_getlong();
+static bool_t xdrrec_putlong();
+static bool_t xdrrec_getbytes();
+static bool_t xdrrec_putbytes();
+static unsigned int xdrrec_getpos();
+static bool_t xdrrec_setpos();
+static rpc_int32 * xdrrec_inline();
+static void xdrrec_destroy();
+
+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 two-byte header followed by zero to
+ * 2**32-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 ((rpc_u_int32)(1 << 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 */
+ rpc_u_int32 *frag_header; /* beginning of curren fragment */
+ bool_t frag_sent; /* true if buffer sent in middle of record */
+ /*
+ * in-coming bits
+ */
+ int (*readit)();
+ rpc_u_int32 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 */
+ rpc_int32 fbtbc; /* fragment bytes to be consumed */
+ bool_t last_frag;
+ unsigned int sendsize;
+ unsigned int recvsize;
+} RECSTREAM;
+
+
+/*
+ * 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(xdrs, sendsize, recvsize, tcp_handle, readit, writeit)
+ register XDR *xdrs;
+ register unsigned int sendsize;
+ register unsigned 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... */
+ (unsigned 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 = (rpc_u_int32 *)rstrm->out_base;
+ rstrm->out_finger += sizeof(rpc_u_int32);
+ 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(xdrs, lp)
+ XDR *xdrs;
+ long *lp;
+{
+ register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
+ register rpc_int32 *buflp = (rpc_int32 *)(rstrm->in_finger);
+ int mylong;
+
+ /* first try the inline, fast case */
+ if ((rstrm->fbtbc >= sizeof(rpc_int32)) &&
+ (((long)rstrm->in_boundry - (long)buflp) >= sizeof(rpc_int32))) {
+ *lp = (long)ntohl((rpc_u_int32)(*buflp));
+ rstrm->fbtbc -= sizeof(rpc_int32);
+ rstrm->in_finger += sizeof(rpc_int32);
+ } else {
+ if (! xdrrec_getbytes(xdrs, (caddr_t)&mylong, sizeof(rpc_int32)))
+ return (FALSE);
+ *lp = (long)ntohl((unsigned int)mylong);
+ }
+ return (TRUE);
+}
+
+static bool_t
+xdrrec_putlong(xdrs, lp)
+ XDR *xdrs;
+ long *lp;
+{
+ register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
+ register rpc_int32 *dest_lp = ((rpc_int32 *)(rstrm->out_finger));
+
+ if ((rstrm->out_finger += sizeof(rpc_int32)) > rstrm->out_boundry) {
+ /*
+ * this case should almost never happen so the code is
+ * inefficient
+ */
+ rstrm->out_finger -= sizeof(rpc_int32);
+ rstrm->frag_sent = TRUE;
+ if (! flush_out(rstrm, FALSE))
+ return (FALSE);
+ dest_lp = ((rpc_int32 *)(rstrm->out_finger));
+ rstrm->out_finger += sizeof(rpc_int32);
+ }
+ *dest_lp = (rpc_int32)htonl((rpc_u_int32)(*lp));
+ return (TRUE);
+}
+
+static bool_t /* must manage buffers, fragments, and records */
+xdrrec_getbytes(xdrs, addr, len)
+ XDR *xdrs;
+ register caddr_t addr;
+ register unsigned 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(xdrs, addr, len)
+ XDR *xdrs;
+ register caddr_t addr;
+ register unsigned int len;
+{
+ register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
+ register int current;
+
+ while (len > 0) {
+ current = (int) ((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 unsigned int
+xdrrec_getpos(xdrs)
+ register XDR *xdrs;
+{
+ register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
+ register int pos;
+
+/* 11/5/95 JRG HELP! lseek() can't take a pointer as the first arg
+ * This code must have always failed, and the failure let the arithmetic
+ * calculations proceed
+ */
+#ifdef __osf__
+ pos = -1;
+#else
+ pos = lseek((int)rstrm->tcp_handle, (long) 0, 1);
+#endif
+ if (pos != -1)
+ switch (xdrs->x_op) {
+
+ case XDR_ENCODE:
+ pos += rstrm->out_finger - rstrm->out_base;
+ break;
+
+ case XDR_DECODE:
+ pos -= rstrm->in_boundry - rstrm->in_finger;
+ break;
+
+ default:
+ pos = (unsigned int) -1;
+ break;
+ }
+ return ((unsigned int) pos);
+}
+
+static bool_t
+xdrrec_setpos(xdrs, pos)
+ register XDR *xdrs;
+ unsigned int pos;
+{
+ register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
+ unsigned 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;
+ }
+ return (FALSE);
+}
+
+static rpc_int32 *
+xdrrec_inline(xdrs, len)
+ register XDR *xdrs;
+ int len;
+{
+ register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
+ rpc_int32 * buf = NULL;
+
+ switch (xdrs->x_op) {
+
+ case XDR_ENCODE:
+ if ((rstrm->out_finger + len) <= rstrm->out_boundry) {
+ buf = (rpc_int32 *) rstrm->out_finger;
+ rstrm->out_finger += len;
+ }
+ break;
+
+ case XDR_DECODE:
+ if ((len <= rstrm->fbtbc) &&
+ ((rstrm->in_finger + len) <= rstrm->in_boundry)) {
+ buf = (rpc_int32 *) rstrm->in_finger;
+ rstrm->fbtbc -= len;
+ rstrm->in_finger += len;
+ }
+ break;
+ }
+ return (buf);
+}
+
+static void
+xdrrec_destroy(xdrs)
+ register 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(xdrs)
+ 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(xdrs)
+ 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(xdrs, sendnow)
+ XDR *xdrs;
+ bool_t sendnow;
+{
+ register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
+ register rpc_u_int32 len; /* fragment length */
+
+ if (sendnow || rstrm->frag_sent ||
+ ((long)rstrm->out_finger + sizeof(unsigned int) >=
+ (long)rstrm->out_boundry)) {
+ rstrm->frag_sent = FALSE;
+ return (flush_out(rstrm, TRUE));
+ }
+ len = (long)(rstrm->out_finger) - (long)(rstrm->frag_header) -
+ sizeof(unsigned int);
+ *(rstrm->frag_header) = htonl((unsigned int)len | LAST_FRAG);
+ rstrm->frag_header = (rpc_u_int32 *)rstrm->out_finger;
+ rstrm->out_finger += sizeof(unsigned int);
+ return (TRUE);
+}
+
+
+/*
+ * Internal useful routines
+ */
+static bool_t
+flush_out(rstrm, eor)
+ register RECSTREAM *rstrm;
+ bool_t eor;
+{
+ register rpc_u_int32 eormask = (eor == TRUE) ? LAST_FRAG : 0;
+ register rpc_u_int32 len = (unsigned long)(rstrm->out_finger) -
+ (unsigned long)(rstrm->frag_header) - sizeof(rpc_u_int32);
+
+ *(rstrm->frag_header) = htonl(len | eormask);
+ len = (unsigned long)(rstrm->out_finger) - (unsigned long)(rstrm->out_base);
+ if ((*(rstrm->writeit))(rstrm->tcp_handle, rstrm->out_base, (int)len)
+ != (int)len)
+ return (FALSE);
+ rstrm->frag_header = (rpc_u_int32 *)rstrm->out_base;
+ rstrm->out_finger = (caddr_t)rstrm->out_base + sizeof(rpc_u_int32);
+ return (TRUE);
+}
+
+static bool_t /* knows nothing about records! Only about input buffers */
+fill_input_buf(rstrm)
+ register RECSTREAM *rstrm;
+{
+ register caddr_t where;
+ unsigned int i;
+ register int len;
+
+ where = rstrm->in_base;
+ i = (unsigned int)((unsigned 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(rstrm, addr, len)
+ register RECSTREAM *rstrm;
+ register caddr_t addr;
+ register int len;
+{
+ register int current;
+
+ while (len > 0) {
+ current = (int)((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 two bytes of the input stream are treated as a header */
+set_input_fragment(rstrm)
+ register RECSTREAM *rstrm;
+{
+ rpc_u_int32 header;
+
+ if (! get_input_bytes(rstrm, (caddr_t)&header, sizeof(header)))
+ return (FALSE);
+ header = (int)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(rstrm, cnt)
+ register RECSTREAM *rstrm;
+ rpc_int32 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 unsigned int
+fix_buf_size(s)
+ register unsigned int s;
+{
+
+ if (s < 100)
+ s = 4000;
+ return (RNDUP(s));
+}
diff --git a/src/lib/rpc/xdr_reference.c b/src/lib/rpc/xdr_reference.c
new file mode 100644
index 0000000000..ebf14b68e3
--- /dev/null
+++ b/src/lib/rpc/xdr_reference.c
@@ -0,0 +1,132 @@
+/* @(#)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 <rpc/types.h>
+#include <rpc/xdr.h>
+
+#define LASTUNSIGNED ((unsigned 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(xdrs, pp, size, proc)
+ register XDR *xdrs;
+ caddr_t *pp; /* the pointer to work on */
+ unsigned 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, (int)size);
+ 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(xdrs,objpp,obj_size,xdr_obj)
+ register XDR *xdrs;
+ char **objpp;
+ unsigned 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/src/lib/rpc/xdr_stdio.c b/src/lib/rpc/xdr_stdio.c
new file mode 100644
index 0000000000..6d59ad5c6e
--- /dev/null
+++ b/src/lib/rpc/xdr_stdio.c
@@ -0,0 +1,189 @@
+/* @(#)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 <rpc/types.h>
+#include <stdio.h>
+#include <rpc/xdr.h>
+
+static bool_t xdrstdio_getlong();
+static bool_t xdrstdio_putlong();
+static bool_t xdrstdio_getbytes();
+static bool_t xdrstdio_putbytes();
+static unsigned int xdrstdio_getpos();
+static bool_t xdrstdio_setpos();
+static rpc_int32 * xdrstdio_inline();
+static void xdrstdio_destroy();
+
+/*
+ * 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(xdrs, file, op)
+ register 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(xdrs)
+ register XDR *xdrs;
+{
+ (void)fflush((FILE *)xdrs->x_private);
+ /* xx should we close the file ?? */
+}
+
+static bool_t
+xdrstdio_getlong(xdrs, lp)
+ XDR *xdrs;
+ register long *lp;
+{
+ rpc_int32 tmp;
+ if (fread((caddr_t)&tmp,
+ sizeof(rpc_int32), 1, (FILE *)xdrs->x_private) != 1)
+ return (FALSE);
+#ifndef mc68000
+ *lp = ntohl(tmp);
+#endif
+ return (TRUE);
+}
+
+static bool_t
+xdrstdio_putlong(xdrs, lp)
+ XDR *xdrs;
+ long *lp;
+{
+
+#ifndef mc68000
+ rpc_int32 mycopy = htonl((rpc_int32)*lp);
+#endif
+ if (fwrite((caddr_t)&mycopy, sizeof(rpc_int32), 1, (FILE *)xdrs->x_private) != 1)
+ return (FALSE);
+ return (TRUE);
+}
+
+static bool_t
+xdrstdio_getbytes(xdrs, addr, len)
+ XDR *xdrs;
+ caddr_t addr;
+ unsigned int len;
+{
+
+ if ((len != 0) && (fread(addr, (int)len, 1, (FILE *)xdrs->x_private) != 1))
+ return (FALSE);
+ return (TRUE);
+}
+
+static bool_t
+xdrstdio_putbytes(xdrs, addr, len)
+ XDR *xdrs;
+ caddr_t addr;
+ unsigned int len;
+{
+
+ if ((len != 0) && (fwrite(addr, (int)len, 1, (FILE *)xdrs->x_private) != 1))
+ return (FALSE);
+ return (TRUE);
+}
+
+static unsigned int
+xdrstdio_getpos(xdrs)
+ XDR *xdrs;
+{
+
+ return ((unsigned int) ftell((FILE *)xdrs->x_private));
+}
+
+static bool_t
+xdrstdio_setpos(xdrs, pos)
+ XDR *xdrs;
+ unsigned int pos;
+{
+
+ return ((fseek((FILE *)xdrs->x_private, (long)pos, 0) < 0) ?
+ FALSE : TRUE);
+}
+
+static rpc_int32 *
+xdrstdio_inline(xdrs, len)
+ XDR *xdrs;
+ unsigned 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/src/tests/ChangeLog b/src/tests/ChangeLog
index ff23e2c682..aa7ccac08e 100644
--- a/src/tests/ChangeLog
+++ b/src/tests/ChangeLog
@@ -1,3 +1,11 @@
+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
diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
index 5632988d9b..6fc7ec501a 100644
--- a/src/tests/Makefile.in
+++ b/src/tests/Makefile.in
@@ -11,7 +11,7 @@ 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
+old-check-unix:: kdb_check
kdb_check:
$(RM) $(TEST_DB)*
diff --git a/src/tests/configure.in b/src/tests/configure.in
index 258b171418..9ab7794c68 100644
--- a/src/tests/configure.in
+++ b/src/tests/configure.in
@@ -1,6 +1,6 @@
AC_INIT(configure.in)
CONFIG_RULES
KRB5_RUN_FLAGS
-CONFIG_DIRS(resolve asn.1 create hammer verify gssapi dejagnu)
+CONFIG_DIRS(resolve asn.1 hammer verify gssapi dejagnu)
DO_SUBDIRS
V5_AC_OUTPUT_MAKEFILE
diff --git a/src/tests/dejagnu/config/ChangeLog b/src/tests/dejagnu/config/ChangeLog
index 62e2e13122..6f4019bea9 100644
--- a/src/tests/dejagnu/config/ChangeLog
+++ b/src/tests/dejagnu/config/ChangeLog
@@ -1,3 +1,9 @@
+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
diff --git a/src/tests/dejagnu/config/default.exp b/src/tests/dejagnu/config/default.exp
index c5102b6064..23c26361bb 100644
--- a/src/tests/dejagnu/config/default.exp
+++ b/src/tests/dejagnu/config/default.exp
@@ -93,11 +93,11 @@ if ![info exists KRB5KDC] {
}
if ![info exists KADMIND] {
- set KADMIND [findfile $objdir/../../kadmin/v5server/kadmind5]
+ set KADMIND [findfile $objdir/../../kadmin/server/kadmind]
}
if ![info exists KADMIN] {
- set KADMIN [findfile $objdir/../../kadmin/v5client/kadmin5]
+ set KADMIN [findfile $objdir/../../kadmin/cli/kadmin]
}
if ![info exists KINIT] {
@@ -334,16 +334,20 @@ proc setup_kerberos_files { } {
puts $conffile "\[realms\]"
puts $conffile " $REALMNAME = \{"
puts $conffile " database_name = $tmppwd/db"
- puts $conffile " master_key_name = master/key"
- puts $conffile " master_key_type = des-cbc-md5"
- puts $conffile " kdc_ports = 3088"
- puts $conffile " kadmind_port = 3750"
+ puts $conffile " admin_database_name = $tmppwd/adb"
+ puts $conffile " admin_database_lockfile = $tmppwd/adb.lock"
+ puts $conffile " admin_keytab = $tmppwd/admin-keytab"
puts $conffile " key_stash_file = $tmppwd/stash"
+ puts $conffile " acl_file = $tmppwd/acl"
+ puts $conffile " kadmind_port = 3750"
puts $conffile " max_life = 1:00:00"
puts $conffile " max_renewable_life = 3:00:00"
+ puts $conffile " master_key_type = des-cbc-md5"
+ puts $conffile " master_key_name = master/key"
+ puts $conffile " supported_enctypes = des-cbc-crc:normal des-cbc-md5:normal des-cbc-crc:v4 des-cbc-md5:norealm"
+ puts $conffile " kdc_ports = 3088"
puts $conffile " default_principal_expiration = 99.12.31.23.59.59"
puts $conffile " default_principal_flags = -postdateable forwardable"
- puts $conffile " supported_enctypes = des-cbc-crc:normal des-cbc-md5:normal des-cbc-crc:v4 des-cbc-md5:norealm des3-cbc-md5:normal"
puts $conffile " \}"
puts $conffile ""
close $conffile
@@ -502,46 +506,58 @@ proc setup_kadmind_srvtab { } {
global KEY
global tmppwd
- catch "exec rm -f tmpdir/cpw_srvtab"
+ catch "exec rm -f tmpdir/admin-keytab"
spawn $KDB5_EDIT -r $REALMNAME
expect_after {
timeout {
- fail "kdb5_edit cpw_srvtab"
- catch "exec rm -f tmpdir/cpw_srvtab"
+ fail "kdb5_edit admin-keytab (timeout)"
+ catch "exec rm -f tmpdir/admin-keytab"
catch "expect_after"
return 0
}
eof {
- fail "kdb5_edit cpw_srvtab"
- catch "exec rm -f tmpdir/cpw_srvtab"
+ fail "kdb5_edit admin-keytab (eof)"
+ catch "exec rm -f tmpdir/admin-keytab"
catch "expect_after"
return 0
}
}
expect "kdb5_edit:"
- send "xst $REALMNAME changepw\r"
- expect "'changepw/$REALMNAME@$REALMNAME' added to keytab"
+ send "xst admin kadmin\r"
+ expect "'kadmin/admin@$REALMNAME' added to keytab"
+ expect "kdb5_edit:"
+
+ catch "exec mv -f admin-new-srvtab changepw-new-srvtab" exec_output
+ if ![string match "" $exec_output] {
+ send_log "$exec_output\n"
+ verbose $exec_output
+ send_error "ERROR: can't mv admin-new-srvtab\n"
+ return 0
+ }
+
+ send "xst changepw kadmin\r"
+ expect "'kadmin/changepw@$REALMNAME' added to keytab"
expect "kdb5_edit:"
send "quit\r"
expect "\r"
expect_after
- if ![check_exit_status "kdb5_edit cpw_srvtab"] {
- catch "exec rm -f tmpdir/cpw_srvtab"
- send_error "ERROR: kdb5_edit cpw_srvtab exited abnormally\n"
+ if ![check_exit_status "kdb5_edit admin-keytab"] {
+ catch "exec rm -f tmpdir/admin-keytab"
+ send_error "ERROR: kdb5_edit admin-keytab exited abnormally\n"
return 0
}
- catch "exec mv -f $REALMNAME-new-srvtab tmpdir/cpw_srvtab" exec_output
+ catch "exec mv -f changepw-new-srvtab tmpdir/admin-keytab" exec_output
if ![string match "" $exec_output] {
send_log "$exec_output\n"
verbose $exec_output
- send_error "ERROR: can't mv new cpw_srvtab\n"
+ send_error "ERROR: can't mv new admin-keytab\n"
return 0
}
# 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 tmpdir/cpw_srvtab"
+ catch "exec chmod a+r tmpdir/admin-keytab"
return 1
}
@@ -686,7 +702,9 @@ proc setup_kerberos_db { standalone } {
expect "Re-enter password for verification:"
send "adminpass$KEY\r"
expect "kdb5_edit:"
- send "ark changepw/$REALMNAME@$REALMNAME\r"
+ send "ark kadmin/admin@$REALMNAME\r"
+ expect "kdb5_edit:"
+ send "ark kadmin/changepw@$REALMNAME\r"
expect "kdb5_edit:"
send "quit\r"
expect "\r"
@@ -702,6 +720,9 @@ proc setup_kerberos_db { standalone } {
return 0
}
+ # create the admin database lock file
+ catch "exec touch tmpdir/adb.lock"
+
if {$standalone} {
pass "kdb5_edit"
}
@@ -797,7 +818,7 @@ proc start_kerberos_daemons { standalone } {
# Start up the kadmind daemon
# XXXX kadmind uses stderr a lot. the sh -c and redirect can be
# removed when this is fixed
- spawn $BINSH -c "exec $KADMIND -a $tmppwd/acl -r $REALMNAME -n 2>>$kadmind_lfile"
+ spawn $BINSH -c "exec $KADMIND -r $REALMNAME -nofork 2>>$kadmind_lfile"
set kadmind_pid [exp_pid]
set kadmind_spawn_id $spawn_id
@@ -825,7 +846,7 @@ proc start_kerberos_daemons { standalone } {
stop_kerberos_daemons
return 0
}
- "administrative server starting" { }
+ "starting" { }
default {
fail "kadmind (startup)"
stop_kerberos_daemons
@@ -886,7 +907,7 @@ proc add_kerberos_key { kkey standalone } {
global spawn_id
# Use kadmin to add an key.
- spawn $KADMIN -m -p krbtest/admin@$REALMNAME
+ spawn $KADMIN -p krbtest/admin@$REALMNAME -q "ank $kkey@$REALMNAME"
expect_after {
"Cannot contact any KDC" {
fail "kadmin interactive add $kkey lost KDC"
@@ -904,23 +925,18 @@ proc add_kerberos_key { kkey standalone } {
return 0
}
}
- expect "kadmin5:"
- send "ank $kkey@$REALMNAME\r"
- expect "Enter password for krbtest/admin@$REALMNAME:"
+ expect "Enter password:"
send "adminpass$KEY\r"
- expect "Enter new password for $kkey@$REALMNAME :"
+ expect "Enter password for principal \"$kkey@$REALMNAME\":"
send "$kkey"
send "$KEY\r"
- expect "Re-enter new password for $kkey@$REALMNAME :"
+ expect "Re-enter password for principal \"$kkey@$REALMNAME\":"
send "$kkey"
send "$KEY\r"
expect {
- "principal $kkey@$REALMNAME added" { }
- "Principal $kkey@$REALMNAME already exists" { }
+ "Principal \"$kkey@$REALMNAME\" created" { }
+ "Principal or policy already exists while creating" { }
}
- expect "kadmin5:"
- send "q\r"
- expect "\r"
expect_after
if ![check_exit_status kadmin] {
return 0
@@ -946,7 +962,7 @@ proc add_random_key { kkey standalone } {
global spawn_id
# Use kadmin to add an key.
- spawn $KADMIN -m -p krbtest/admin@$REALMNAME
+ spawn $KADMIN -p krbtest/admin@$REALMNAME -q "ank -randkey $kkey@$REALMNAME"
expect_after {
timeout {
fail "kadmin $kkey"
@@ -959,17 +975,12 @@ proc add_random_key { kkey standalone } {
return 0
}
}
- expect "kadmin5:"
- send "ark $kkey@$REALMNAME\r"
- expect "Enter password for krbtest/admin@$REALMNAME:"
+ expect "Enter password:"
send "adminpass$KEY\r"
expect {
- "principal $kkey@$REALMNAME added" { }
- "Principal $kkey@$REALMNAME already exists" { }
+ "Principal \"$kkey@$REALMNAME\" created" { }
+ "Principal or policy already exists while creating" { }
}
- expect "kadmin5:"
- send "q\r"
- expect "\r"
expect_after
if ![check_exit_status kadmin] {
return 0
diff --git a/src/tests/dejagnu/krb-standalone/ChangeLog b/src/tests/dejagnu/krb-standalone/ChangeLog
index e15c072033..f1ef85e1a1 100644
--- a/src/tests/dejagnu/krb-standalone/ChangeLog
+++ b/src/tests/dejagnu/krb-standalone/ChangeLog
@@ -1,3 +1,13 @@
+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
diff --git a/src/tests/dejagnu/krb-standalone/gssapi.exp b/src/tests/dejagnu/krb-standalone/gssapi.exp
index 06790e97a4..58a9e12534 100644
--- a/src/tests/dejagnu/krb-standalone/gssapi.exp
+++ b/src/tests/dejagnu/krb-standalone/gssapi.exp
@@ -252,7 +252,7 @@ proc doit { } {
return
}
}
- expect -i $gss_server_spawn_id "Accepted connection: \"gsstest0@$REALMNAME\" at"
+ expect -i $gss_server_spawn_id "Accepted connection: \"gsstest0@$REALMNAME\""
expect -i $gss_server_spawn_id "Received message: \"message from gsstest0\""
catch "expect_after"
if ![check_exit_status gssclient0] {
@@ -293,7 +293,7 @@ proc doit { } {
return
}
}
- expect -i $gss_server_spawn_id "Accepted connection: \"gsstest1@$REALMNAME\" at"
+ expect -i $gss_server_spawn_id "Accepted connection: \"gsstest1@$REALMNAME\""
expect -i $gss_server_spawn_id "Received message: \"message from gsstest1\""
catch "expect_after"
if ![check_exit_status gssclient1] {
@@ -334,7 +334,7 @@ proc doit { } {
return
}
}
- expect -i $gss_server_spawn_id "Accepted connection: \"gsstest2@$REALMNAME\" at"
+ expect -i $gss_server_spawn_id "Accepted connection: \"gsstest2@$REALMNAME\""
expect -i $gss_server_spawn_id "Received message: \"message from gsstest2\""
catch "expect_after"
if ![check_exit_status gssclient2] {
@@ -360,7 +360,7 @@ proc doit { } {
return
}
}
- expect -i $gss_server_spawn_id "Accepted connection: \"gsstest3@$REALMNAME\" at"
+ expect -i $gss_server_spawn_id "Accepted connection: \"gsstest3@$REALMNAME\""
expect -i $gss_server_spawn_id "Received message: \"message from gsstest3\""
catch "expect_after"
expect_after {
@@ -388,7 +388,7 @@ proc doit { } {
# Try some V2 services.
# Now start the gss-server.
- spawn $GSSSERVER -port 5557 -v2 gssservice@$hostname
+ spawn $GSSSERVER -port 5557 gssservice@$hostname
set gss_server_pid [exp_pid]
set gss_server_spawn_id $spawn_id
catch "exec sleep 4"
@@ -396,7 +396,7 @@ proc doit { } {
# Start the client with client identity 0
set env(KRB5CCNAME) $tmppwd/gss_tk_0
verbose "KRB5CCNAME=$env(KRB5CCNAME)"
- spawn $GSSCLIENT -port 5557 -v2 $hostname gssservice@$hostname "message from gsstest0"
+ spawn $GSSCLIENT -port 5557 $hostname gssservice@$hostname "message from gsstest0"
expect_after {
-i $spawn_id
timeout {
@@ -425,7 +425,7 @@ proc doit { } {
return
}
}
- expect -i $gss_server_spawn_id "Accepted connection: \"gsstest0@$REALMNAME\" at"
+ expect -i $gss_server_spawn_id "Accepted connection: \"gsstest0@$REALMNAME\""
expect -i $gss_server_spawn_id "Received message: \"message from gsstest0\""
catch "expect_after"
if ![check_exit_status gssclient0] {
@@ -437,7 +437,7 @@ proc doit { } {
# Start the client with client identity 1
set env(KRB5CCNAME) $tmppwd/gss_tk_1
verbose "KRB5CCNAME=$env(KRB5CCNAME)"
- spawn $GSSCLIENT -port 5557 -v2 $hostname gssservice@$hostname "message from gsstest1"
+ spawn $GSSCLIENT -port 5557 $hostname gssservice@$hostname "message from gsstest1"
expect_after {
-i $spawn_id
timeout {
@@ -466,7 +466,7 @@ proc doit { } {
return
}
}
- expect -i $gss_server_spawn_id "Accepted connection: \"gsstest1@$REALMNAME\" at"
+ expect -i $gss_server_spawn_id "Accepted connection: \"gsstest1@$REALMNAME\""
expect -i $gss_server_spawn_id "Received message: \"message from gsstest1\""
catch "expect_after"
if ![check_exit_status gssclient1] {
@@ -478,7 +478,7 @@ proc doit { } {
# Start the client with client identity 2
set env(KRB5CCNAME) $tmppwd/gss_tk_2
verbose "KRB5CCNAME=$env(KRB5CCNAME)"
- spawn $GSSCLIENT -port 5557 -v2 $hostname gssservice@$hostname "message from gsstest2"
+ spawn $GSSCLIENT -port 5557 $hostname gssservice@$hostname "message from gsstest2"
expect_after {
-i $spawn_id
timeout {
@@ -507,7 +507,7 @@ proc doit { } {
return
}
}
- expect -i $gss_server_spawn_id "Accepted connection: \"gsstest2@$REALMNAME\" at"
+ expect -i $gss_server_spawn_id "Accepted connection: \"gsstest2@$REALMNAME\""
expect -i $gss_server_spawn_id "Received message: \"message from gsstest2\""
catch "expect_after"
if ![check_exit_status gssclient2] {
@@ -519,7 +519,7 @@ proc doit { } {
# Start the client with client identity 3
set env(KRB5CCNAME) $tmppwd/gss_tk_3
verbose "KRB5CCNAME=$env(KRB5CCNAME)"
- spawn $GSSCLIENT -port 5557 -v2 $hostname gssservice@$hostname "message from gsstest3"
+ spawn $GSSCLIENT -port 5557 $hostname gssservice@$hostname "message from gsstest3"
expect_after {
-i $gss_server_spawn_id
timeout {
@@ -533,7 +533,7 @@ proc doit { } {
return
}
}
- expect -i $gss_server_spawn_id "Accepted connection: \"gsstest3@$REALMNAME\" at"
+ expect -i $gss_server_spawn_id "Accepted connection: \"gsstest3@$REALMNAME\""
expect -i $gss_server_spawn_id "Received message: \"message from gsstest3\""
catch "expect_after"
expect_after {
diff --git a/src/tests/dejagnu/krb-standalone/gssftp.exp b/src/tests/dejagnu/krb-standalone/gssftp.exp
index ac67599ff6..748793ad1b 100644
--- a/src/tests/dejagnu/krb-standalone/gssftp.exp
+++ b/src/tests/dejagnu/krb-standalone/gssftp.exp
@@ -176,7 +176,7 @@ proc ftp_test { } {
set testname "ftp connection"
expect "Connected to $hostname"
- expect -re "$localhostname.*FTP server .Version \[0-9.\]*. ready."
+ 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 {
diff --git a/src/tests/gssapi/t_imp_name.c b/src/tests/gssapi/t_imp_name.c
index f1b3cd2ad2..d63faced32 100644
--- a/src/tests/gssapi/t_imp_name.c
+++ b/src/tests/gssapi/t_imp_name.c
@@ -83,7 +83,6 @@ static int test_import_name(name)
printf("\n");
(void) gss_release_buffer(&min_stat, &buffer_name);
- (void) gss_release_oid(&min_stat, &name_oid);
(void) gss_release_name(&min_stat, &gss_name);
return 0;
}
diff --git a/src/util/ChangeLog b/src/util/ChangeLog
index 8540d06a50..ab39db25da 100644
--- a/src/util/ChangeLog
+++ b/src/util/ChangeLog
@@ -1,3 +1,15 @@
+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
diff --git a/src/util/Makefile.in b/src/util/Makefile.in
index 1d0a278d2f..0faedfa1e8 100644
--- a/src/util/Makefile.in
+++ b/src/util/Makefile.in
@@ -11,6 +11,20 @@ all-unix:: libupdate makeshlib
all-mac::
all-windows: libupdate
+# this is necessary because the db2 build, which is intended to be
+# standalone, of course does not know to make symlinks in the right
+# magic places in the krb5 build tree so other parts of the tree can
+# find db2. So we make those links here. this can't use CopyHeader,
+# because there's no way in this make setup to do stuff after the
+# subdirectory recursion. fortunately, one does not need a
+# destination to make a link...
+
+all-unix::
+ $(RM) ../include/db.h ../include/db-config.h ../lib/libdb.a
+ ln -s ../util/db2/obj/db.h ../include
+ ln -s ../util/db2/obj/db-config.h ../include
+ ln -s ../util/db2/obj/libdb.a ../lib
+
unixmac: libupdate
libupdate: $(srcdir)/libupdate.sh
diff --git a/src/util/autoconf/ChangeLog b/src/util/autoconf/ChangeLog
index 67827c8e11..e317fe91e4 100644
--- a/src/util/autoconf/ChangeLog
+++ b/src/util/autoconf/ChangeLog
@@ -1,3 +1,12 @@
+Tue Jul 9 18:24:12 1996 Marc Horowitz <marc@mit.edu>
+
+ * autoheader.sh (TEMPLATES): add ./acconfig.h to the list of
+ header templates used. This is necessary when a subpackage is
+ being autoreconf'd.
+
+ * acgeneral.m4 (AC_CACHE_CHECK): added, from autoconf 2.7. db2
+ needs it.
+
Wed Jun 12 18:17:17 1996 Tom Yu <tlyu@voltage-multiplier.mit.edu>
* autoconf.texi (Output): document changes to AC_OUTPUT
diff --git a/src/util/autoconf/README.krb5 b/src/util/autoconf/README.krb5
new file mode 100644
index 0000000000..d4b7346583
--- /dev/null
+++ b/src/util/autoconf/README.krb5
@@ -0,0 +1,2 @@
+There have been a few local changes and bug-fixes made to this tree.
+Check out the ChangeLog file for details.
diff --git a/src/util/autoconf/autoconf.info b/src/util/autoconf/autoconf.info
index 050a253b8f..472783f0bc 100644
--- a/src/util/autoconf/autoconf.info
+++ b/src/util/autoconf/autoconf.info
@@ -1,5 +1,5 @@
-This is Info file ../autoconf.info, produced by Makeinfo-1.63 from the
-input file ../autoconf.texi.
+This is Info file autoconf.info, produced by Makeinfo-1.55 from the
+input file ./autoconf.texi.
START-INFO-DIR-ENTRY
* Autoconf: (autoconf). Create source code configuration scripts.
@@ -722,6 +722,10 @@ macro is `AC_INIT' (*note Input::.).
separated by a colon. For example,
AC_OUTPUT(Makefile:templates/top.mk lib/Makefile:templates/lib.mk)
+ You can also generate an output file from multiple input files by
+ separating the input files by a plus sign. For example,
+ AC_OUTPUT(Makefile:templates/pre.in+Makefile.in+templates/post.in)
+
If you pass EXTRA-CMDS, those commands will be inserted into
`config.status' to be run after all its other processing. If
INIT-CMDS are given, they are inserted just before EXTRA-CMDS,
@@ -3024,7 +3028,7 @@ automatically.
Notify the user of an error that prevents `configure' from
completing. This macro prints an error message on the standard
error output and exits `configure' with a nonzero status.
- ERROR-DESCRIPTION should be something like `invalid value $HOME
+ eRROR-DESCRIPTION should be something like `invalid value $HOME
for \$HOME'.
- Macro: AC_MSG_WARN (PROBLEM-DESCRIPTION)
@@ -3261,7 +3265,7 @@ it is considered obsolete.
- Macro: AC_PROVIDE (THIS-MACRO-NAME)
Record the fact that THIS-MACRO-NAME has been called.
- THIS-MACRO-NAME should be the name of the macro that is calling
+ tHIS-MACRO-NAME should be the name of the macro that is calling
`AC_PROVIDE'. An easy way to get it is from the `m4' builtin
variable `$0', like this:
@@ -4953,11 +4957,11 @@ Autoconf checks.
* Menu:
-* AC_MACRODIR <1>: Invoking autoupdate.
-* AC_MACRODIR <1>: Invoking autoheader.
-* AC_MACRODIR <1>: Invoking autoreconf.
-* AC_MACRODIR <1>: Invoking autoconf.
-* AC_MACRODIR <1>: Invoking ifnames.
+* AC_MACRODIR: Invoking autoupdate.
+* AC_MACRODIR: Invoking autoheader.
+* AC_MACRODIR: Invoking autoreconf.
+* AC_MACRODIR: Invoking autoconf.
+* AC_MACRODIR: Invoking ifnames.
* AC_MACRODIR: Invoking autoscan.
* CONFIG_FILES: Invoking config.status.
* CONFIG_HEADERS: Invoking config.status.
@@ -4987,17 +4991,18 @@ how this is done.
* build_cpu: System Type Variables.
* build_os: System Type Variables.
* build_vendor: System Type Variables.
-* CC <1>: UNIX Variants.
+* CC: UNIX Variants.
+* CC: Particular Programs.
* CC: Particular Programs.
-* CFLAGS <1>: Particular Programs.
* CFLAGS: Preset Output Variables.
+* CFLAGS: Particular Programs.
* configure_input: Preset Output Variables.
* CPP: Particular Programs.
* CPPFLAGS: Preset Output Variables.
* CXX: Particular Programs.
* CXXCPP: Particular Programs.
-* CXXFLAGS <1>: Particular Programs.
* CXXFLAGS: Preset Output Variables.
+* CXXFLAGS: Particular Programs.
* datadir: Preset Output Variables.
* DEFS: Preset Output Variables.
* exec_prefix: Preset Output Variables.
@@ -5014,15 +5019,17 @@ how this is done.
* KMEM_GROUP: Particular Functions.
* LDFLAGS: Preset Output Variables.
* LEX: Particular Programs.
-* LEX_OUTPUT_ROOT: Particular Programs.
* LEXLIB: Particular Programs.
+* LEX_OUTPUT_ROOT: Particular Programs.
* libdir: Preset Output Variables.
* libexecdir: Preset Output Variables.
-* LIBOBJS <1>: Structures.
-* LIBOBJS <1>: Generic Functions.
* LIBOBJS: Particular Functions.
-* LIBS <1>: UNIX Variants.
+* LIBOBJS: Particular Functions.
+* LIBOBJS: Generic Functions.
+* LIBOBJS: Structures.
* LIBS: Preset Output Variables.
+* LIBS: UNIX Variants.
+* LIBS: UNIX Variants.
* LN_S: Particular Programs.
* localstatedir: Preset Output Variables.
* mandir: Preset Output Variables.
@@ -5061,15 +5068,9 @@ use these names in `#if' directives.
* Menu:
-* __CHAR_UNSIGNED__: Compiler Characteristics.
-* _ALL_SOURCE: UNIX Variants.
-* _MINIX: UNIX Variants.
-* _POSIX_1_SOURCE: UNIX Variants.
-* _POSIX_SOURCE: UNIX Variants.
-* _POSIX_VERSION: Particular Headers.
-* C_ALLOCA: Particular Functions.
* CLOSEDIR_VOID: Particular Functions.
* const: Compiler Characteristics.
+* C_ALLOCA: Particular Functions.
* DGUX: Particular Functions.
* DIRENT: Particular Headers.
* GETGROUPS_T: Particular Typedefs.
@@ -5088,11 +5089,11 @@ use these names in `#if' directives.
* HAVE_MMAP: Particular Functions.
* HAVE_NDIR_H: Particular Headers.
* HAVE_RESTARTABLE_SYSCALLS: System Services.
+* HAVE_STRCOLL: Particular Functions.
+* HAVE_STRFTIME: Particular Functions.
* HAVE_ST_BLKSIZE: Structures.
* HAVE_ST_BLOCKS: Structures.
* HAVE_ST_RDEV: Structures.
-* HAVE_STRCOLL: Particular Functions.
-* HAVE_STRFTIME: Particular Functions.
* HAVE_SYS_DIR_H: Particular Headers.
* HAVE_SYS_NDIR_H: Particular Headers.
* HAVE_SYS_WAIT_H: Particular Headers.
@@ -5122,9 +5123,9 @@ use these names in `#if' directives.
* size_t: Particular Typedefs.
* STDC_HEADERS: Particular Headers.
* SVR4: Particular Functions.
-* SYS_SIGLIST_DECLARED: Particular Headers.
* SYSDIR: Particular Headers.
* SYSNDIR: Particular Headers.
+* SYS_SIGLIST_DECLARED: Particular Headers.
* TIME_WITH_SYS_TIME: Structures.
* TM_IN_SYS_TIME: Structures.
* uid_t: Particular Typedefs.
@@ -5135,6 +5136,13 @@ use these names in `#if' directives.
* VOID_CLOSEDIR: Particular Headers.
* WORDS_BIGENDIAN: Compiler Characteristics.
* YYTEXT_POINTER: Particular Programs.
+* _ALL_SOURCE: UNIX Variants.
+* _MINIX: UNIX Variants.
+* _POSIX_1_SOURCE: UNIX Variants.
+* _POSIX_SOURCE: UNIX Variants.
+* _POSIX_SOURCE: UNIX Variants.
+* _POSIX_VERSION: Particular Headers.
+* __CHAR_UNSIGNED__: Compiler Characteristics.

File: autoconf.info, Node: Macro Index, Prev: Preprocessor Symbol Index, Up: Top
@@ -5154,17 +5162,12 @@ list easier to use, the macros are listed without their preceding `AC_'.
* ARG_PROGRAM: Transforming Names.
* ARG_WITH: External Software.
* BEFORE: Suggested Ordering.
-* C_BIGENDIAN: Compiler Characteristics.
-* C_CHAR_UNSIGNED: Compiler Characteristics.
-* C_CONST: Compiler Characteristics.
-* C_CROSS: Test Programs.
-* C_INLINE: Compiler Characteristics.
-* C_LONG_DOUBLE: Compiler Characteristics.
* CACHE_CHECK: Caching Results.
* CACHE_VAL: Caching Results.
* CANONICAL_HOST: Canonicalizing.
* CANONICAL_SYSTEM: Canonicalizing.
* CHAR_UNSIGNED: Old Macro Names.
+* CHECKING: Printing Messages.
* CHECK_FUNC: Generic Functions.
* CHECK_FUNCS: Generic Functions.
* CHECK_HEADER: Generic Headers.
@@ -5175,13 +5178,18 @@ list easier to use, the macros are listed without their preceding `AC_'.
* CHECK_SIZEOF: Compiler Characteristics.
* CHECK_TOOL: Generic Programs.
* CHECK_TYPE: Generic Typedefs.
-* CHECKING: Printing Messages.
* COMPILE_CHECK: Examining Libraries.
* CONFIG_AUX_DIR: Input.
* CONFIG_HEADER: Configuration Headers.
* CONFIG_SUBDIRS: Subdirectories.
* CONST: Old Macro Names.
* CROSS_CHECK: Old Macro Names.
+* C_BIGENDIAN: Compiler Characteristics.
+* C_CHAR_UNSIGNED: Compiler Characteristics.
+* C_CONST: Compiler Characteristics.
+* C_CROSS: Test Programs.
+* C_INLINE: Compiler Characteristics.
+* C_LONG_DOUBLE: Compiler Characteristics.
* DECL_SYS_SIGLIST: Particular Headers.
* DECL_YYTEXT: Particular Programs.
* DEFINE: Defining Symbols.
@@ -5260,6 +5268,11 @@ list easier to use, the macros are listed without their preceding `AC_'.
* PREFIX: Old Macro Names.
* PREFIX_PROGRAM: Default Prefix.
* PREREQ: Versions.
+* PROGRAMS_CHECK: Old Macro Names.
+* PROGRAMS_PATH: Old Macro Names.
+* PROGRAM_CHECK: Old Macro Names.
+* PROGRAM_EGREP: Old Macro Names.
+* PROGRAM_PATH: Old Macro Names.
* PROG_AWK: Particular Programs.
* PROG_CC: Particular Programs.
* PROG_CC_C_O: Particular Programs.
@@ -5273,11 +5286,6 @@ list easier to use, the macros are listed without their preceding `AC_'.
* PROG_MAKE_SET: Output.
* PROG_RANLIB: Particular Programs.
* PROG_YACC: Particular Programs.
-* PROGRAM_CHECK: Old Macro Names.
-* PROGRAM_EGREP: Old Macro Names.
-* PROGRAM_PATH: Old Macro Names.
-* PROGRAMS_CHECK: Old Macro Names.
-* PROGRAMS_PATH: Old Macro Names.
* PROVIDE: Prerequisite Macros.
* REMOTE_TAPE: Old Macro Names.
* REPLACE_FUNCS: Generic Functions.
@@ -5288,15 +5296,12 @@ list easier to use, the macros are listed without their preceding `AC_'.
* REVISION: Versions.
* RSH: Old Macro Names.
* SCO_INTL: UNIX Variants.
-* SET_MAKE: Old Macro Names.
* SETVBUF_REVERSED: Old Macro Names.
-* SIZE_T: Old Macro Names.
+* SET_MAKE: Old Macro Names.
* SIZEOF_TYPE: Old Macro Names.
-* ST_BLKSIZE: Old Macro Names.
-* ST_BLOCKS: Old Macro Names.
-* ST_RDEV: Old Macro Names.
-* STAT_MACROS_BROKEN <1>: Old Macro Names.
+* SIZE_T: Old Macro Names.
* STAT_MACROS_BROKEN: Structures.
+* STAT_MACROS_BROKEN: Old Macro Names.
* STDC_HEADERS: Old Macro Names.
* STRCOLL: Old Macro Names.
* STRUCT_ST_BLKSIZE: Structures.
@@ -5304,6 +5309,9 @@ list easier to use, the macros are listed without their preceding `AC_'.
* STRUCT_ST_RDEV: Structures.
* STRUCT_TIMEZONE: Structures.
* STRUCT_TM: Structures.
+* ST_BLKSIZE: Old Macro Names.
+* ST_BLOCKS: Old Macro Names.
+* ST_RDEV: Old Macro Names.
* SUBST: Setting Output Variables.
* SUBST_FILE: Setting Output Variables.
* SYS_INTERPRETER: System Services.
@@ -5312,8 +5320,8 @@ list easier to use, the macros are listed without their preceding `AC_'.
* SYS_SIGLIST_DECLARED: Old Macro Names.
* TEST_CPP: Old Macro Names.
* TEST_PROGRAM: Old Macro Names.
-* TIME_WITH_SYS_TIME: Old Macro Names.
* TIMEZONE: Old Macro Names.
+* TIME_WITH_SYS_TIME: Old Macro Names.
* TRY_COMPILE: Examining Syntax.
* TRY_CPP: Examining Declarations.
* TRY_LINK: Examining Libraries.
@@ -5342,118 +5350,118 @@ list easier to use, the macros are listed without their preceding `AC_'.

Tag Table:
-Node: Top1177
-Node: Introduction9316
-Node: Making configure Scripts13156
-Node: Writing configure.in16221
-Node: Invoking autoscan19921
-Node: Invoking ifnames22226
-Node: Invoking autoconf23716
-Node: Invoking autoreconf25554
-Node: Setup27874
-Node: Input28760
-Node: Output30483
-Node: Makefile Substitutions33233
-Node: Preset Output Variables34817
-Node: Build Directories39319
-Node: Automatic Remaking40952
-Node: Configuration Headers43038
-Node: Header Templates45405
-Node: Invoking autoheader46584
-Node: Subdirectories49732
-Node: Default Prefix51075
-Node: Versions52479
-Node: Existing Tests54383
-Node: Alternative Programs55848
-Node: Particular Programs56512
-Node: Generic Programs62362
-Node: Libraries65188
-Node: Library Functions67017
-Node: Particular Functions67575
-Node: Generic Functions73878
-Node: Header Files75721
-Node: Particular Headers76280
-Node: Generic Headers83251
-Node: Structures84553
-Node: Typedefs86790
-Node: Particular Typedefs87294
-Node: Generic Typedefs88494
-Node: Compiler Characteristics88937
-Node: System Services91562
-Node: UNIX Variants93911
-Node: Writing Tests95930
-Node: Examining Declarations97896
-Node: Examining Syntax100366
-Node: Examining Libraries101423
-Node: Run Time103982
-Node: Test Programs104943
-Node: Guidelines107480
-Node: Test Functions108669
-Node: Portable Shell110212
-Node: Testing Values and Files112144
-Node: Multiple Cases113799
-Node: Language Choice114997
-Node: Results116555
-Node: Defining Symbols117314
-Node: Setting Output Variables120323
-Node: Caching Results122169
-Node: Cache Variable Names124450
-Node: Cache Files125999
-Node: Printing Messages128097
-Node: Writing Macros131384
-Node: Macro Definitions132003
-Node: Macro Names133108
-Node: Quoting135559
-Node: Dependencies Between Macros137461
-Node: Prerequisite Macros138093
-Node: Suggested Ordering139548
-Node: Obsolete Macros141078
-Node: Manual Configuration142302
-Node: Specifying Names143201
-Node: Canonicalizing145073
-Node: System Type Variables146387
-Node: Using System Type147134
-Node: Site Configuration148581
-Node: External Software149354
-Node: Package Options152052
-Node: Site Details154319
-Node: Transforming Names155542
-Node: Transformation Options156720
-Node: Transformation Examples157186
-Node: Transformation Rules158754
-Node: Site Defaults160163
-Node: Invoking configure163947
-Node: Basic Installation164896
-Node: Compilers and Options167476
-Node: Multiple Architectures168125
-Node: Installation Names169111
-Node: Optional Features170295
-Node: System Type171065
-Node: Sharing Defaults172087
-Node: Operation Controls172711
-Node: Invoking config.status173586
-Node: Questions176974
-Node: Distributing177506
-Node: Why GNU m4178632
-Node: Bootstrapping179445
-Node: Why Not Imake180061
-Node: Upgrading184470
-Node: Changed File Names185991
-Node: Changed Makefiles186727
-Node: Changed Macros187823
-Node: Invoking autoupdate189070
-Node: Changed Results190661
-Node: Changed Macro Writing192763
-Node: History194026
-Node: Genesis194733
-Node: Exodus195906
-Node: Leviticus198955
-Node: Numbers200478
-Node: Deuteronomy202394
-Node: Old Macro Names205058
-Node: Environment Variable Index208107
-Node: Output Variable Index209109
-Node: Preprocessor Symbol Index213792
-Node: Macro Index218607
+Node: Top1173
+Node: Introduction9312
+Node: Making configure Scripts13152
+Node: Writing configure.in16217
+Node: Invoking autoscan19917
+Node: Invoking ifnames22222
+Node: Invoking autoconf23712
+Node: Invoking autoreconf25550
+Node: Setup27870
+Node: Input28756
+Node: Output30479
+Node: Makefile Substitutions33440
+Node: Preset Output Variables35024
+Node: Build Directories39526
+Node: Automatic Remaking41159
+Node: Configuration Headers43245
+Node: Header Templates45612
+Node: Invoking autoheader46791
+Node: Subdirectories49939
+Node: Default Prefix51282
+Node: Versions52686
+Node: Existing Tests54590
+Node: Alternative Programs56055
+Node: Particular Programs56719
+Node: Generic Programs62569
+Node: Libraries65395
+Node: Library Functions67224
+Node: Particular Functions67782
+Node: Generic Functions74085
+Node: Header Files75928
+Node: Particular Headers76487
+Node: Generic Headers83458
+Node: Structures84760
+Node: Typedefs86997
+Node: Particular Typedefs87501
+Node: Generic Typedefs88701
+Node: Compiler Characteristics89144
+Node: System Services91769
+Node: UNIX Variants94118
+Node: Writing Tests96137
+Node: Examining Declarations98103
+Node: Examining Syntax100573
+Node: Examining Libraries101630
+Node: Run Time104189
+Node: Test Programs105150
+Node: Guidelines107687
+Node: Test Functions108876
+Node: Portable Shell110419
+Node: Testing Values and Files112351
+Node: Multiple Cases114006
+Node: Language Choice115204
+Node: Results116762
+Node: Defining Symbols117521
+Node: Setting Output Variables120530
+Node: Caching Results122376
+Node: Cache Variable Names124657
+Node: Cache Files126206
+Node: Printing Messages128304
+Node: Writing Macros131591
+Node: Macro Definitions132210
+Node: Macro Names133315
+Node: Quoting135766
+Node: Dependencies Between Macros137668
+Node: Prerequisite Macros138300
+Node: Suggested Ordering139755
+Node: Obsolete Macros141285
+Node: Manual Configuration142509
+Node: Specifying Names143408
+Node: Canonicalizing145280
+Node: System Type Variables146594
+Node: Using System Type147341
+Node: Site Configuration148788
+Node: External Software149561
+Node: Package Options152259
+Node: Site Details154526
+Node: Transforming Names155749
+Node: Transformation Options156927
+Node: Transformation Examples157393
+Node: Transformation Rules158961
+Node: Site Defaults160370
+Node: Invoking configure164154
+Node: Basic Installation165103
+Node: Compilers and Options167683
+Node: Multiple Architectures168332
+Node: Installation Names169318
+Node: Optional Features170502
+Node: System Type171272
+Node: Sharing Defaults172294
+Node: Operation Controls172918
+Node: Invoking config.status173793
+Node: Questions177181
+Node: Distributing177713
+Node: Why GNU m4178839
+Node: Bootstrapping179652
+Node: Why Not Imake180268
+Node: Upgrading184677
+Node: Changed File Names186198
+Node: Changed Makefiles186934
+Node: Changed Macros188030
+Node: Invoking autoupdate189277
+Node: Changed Results190868
+Node: Changed Macro Writing192970
+Node: History194233
+Node: Genesis194940
+Node: Exodus196113
+Node: Leviticus199162
+Node: Numbers200685
+Node: Deuteronomy202601
+Node: Old Macro Names205265
+Node: Environment Variable Index208314
+Node: Output Variable Index209316
+Node: Preprocessor Symbol Index214177
+Node: Macro Index219047

End Tag Table
diff --git a/src/util/autoconf/autoheader.sh b/src/util/autoconf/autoheader.sh
index abbc983500..a9aa446934 100644
--- a/src/util/autoconf/autoheader.sh
+++ b/src/util/autoconf/autoheader.sh
@@ -85,6 +85,7 @@ if test $show_version = yes; then
fi
TEMPLATES="${AC_MACRODIR}/acconfig.h"
+test -r ./acconfig.h && TEMPLATES="${TEMPLATES} ./acconfig.h"
test -r $localdir/acconfig.h && TEMPLATES="${TEMPLATES} $localdir/acconfig.h"
case $# in
diff --git a/src/util/autoconf/configure b/src/util/autoconf/configure
index 65ce229d57..d5f3ea864a 100644
--- a/src/util/autoconf/configure
+++ b/src/util/autoconf/configure
@@ -906,7 +906,19 @@ for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
esac
echo creating "$ac_file"
rm -f "$ac_file"
- configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ # allow for outfile[:infile1[+infile2[+infile3...]]] syntax
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}+"
+ ac_files_in=
+ for ac_file_name in $ac_file_in
+ do
+ ac_files_in="$ac_files_in $ac_given_srcdir/$ac_file_name"
+ done
+ IFS="$ac_save_ifs"
+ configure_input=`echo $ac_files_in | sed 's%/./%/%g
+s% *./%%g
+s% *%+%g
+s%^%Generated automatically from %
+s%$% by configure.%'`
case "$ac_file" in
*Makefile*) ac_comsub="1i\\
# $configure_input" ;;
@@ -917,7 +929,7 @@ s%@configure_input@%$configure_input%g
s%@srcdir@%$srcdir%g
s%@top_srcdir@%$top_srcdir%g
s%@INSTALL@%$INSTALL%g
-" -f conftest.subs $ac_given_srcdir/$ac_file_in > $ac_file
+" -f conftest.subs $ac_files_in > $ac_file
fi; done
rm -f conftest.subs
diff --git a/src/util/autoconf/standards.info b/src/util/autoconf/standards.info
index c673f9261f..a51f1e2d1a 100644
--- a/src/util/autoconf/standards.info
+++ b/src/util/autoconf/standards.info
@@ -1,4 +1,4 @@
-This is Info file standards.info, produced by Makeinfo-1.63 from the
+This is Info file standards.info, produced by Makeinfo-1.55 from the
input file ./standards.texi.
START-INFO-DIR-ENTRY
diff --git a/src/util/configure.in b/src/util/configure.in
index 77abe3b78b..ef2f3635e0 100644
--- a/src/util/configure.in
+++ b/src/util/configure.in
@@ -18,15 +18,6 @@ esac
SHLIB_TAIL_COMP=$krb5_cv_shlibs_tail_comp
AC_SUBST(SHLIB_TAIL_COMP)
-dbdir=
-WITH_ANAME_DB
-if test "$dbval" = db; then
- db=berk_db
-else
- WITH_KDB_DB
- if test "$dbval" = db; then db=berk_db; fi
-fi
-
-CONFIG_DIRS(et ss profile $db pty)
+CONFIG_DIRS(et ss profile pty dyn db2)
DO_SUBDIRS
V5_AC_OUTPUT_MAKEFILE
diff --git a/src/util/db2/CHANGELOG b/src/util/db2/CHANGELOG
new file mode 100644
index 0000000000..abd05f95d4
--- /dev/null
+++ b/src/util/db2/CHANGELOG
@@ -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/src/util/db2/ChangeLog b/src/util/db2/ChangeLog
new file mode 100644
index 0000000000..9d240ec940
--- /dev/null
+++ b/src/util/db2/ChangeLog
@@ -0,0 +1,77 @@
+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/src/util/db2/Makefile.in b/src/util/db2/Makefile.in
new file mode 100644
index 0000000000..3e6344baa2
--- /dev/null
+++ b/src/util/db2/Makefile.in
@@ -0,0 +1,12 @@
+SHELL = /bin/sh
+
+SUBDIRS = obj
+
+all clean distclean realclean check::
+ for i in ${SUBDIRS}; do (cd $$i; ${MAKE} $@) || exit 1; done
+
+distclean::
+ rm -rf config.status config.log config.cache db-config.h
+
+realclean::
+ rm -rf configure db-config.h.in
diff --git a/src/util/db2/Makefile.inc b/src/util/db2/Makefile.inc
new file mode 100644
index 0000000000..77af9c5123
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/README b/src/util/db2/README
new file mode 100644
index 0000000000..5700b73932
--- /dev/null
+++ b/src/util/db2/README
@@ -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/src/util/db2/acconfig.h b/src/util/db2/acconfig.h
new file mode 100644
index 0000000000..d36e23fe28
--- /dev/null
+++ b/src/util/db2/acconfig.h
@@ -0,0 +1,17 @@
+#undef ssize_t
+
+/* BSD4.3, non-posix types */
+
+#undef u_char
+#undef u_short
+#undef u_int
+#undef u_long
+
+/* sized types used by db internals */
+
+#undef int8_t
+#undef u_int8_t
+#undef int16_t
+#undef u_int16_t
+#undef int32_t
+#undef u_int32_t
diff --git a/src/util/db2/btree/Makefile.inc b/src/util/db2/btree/Makefile.inc
new file mode 100644
index 0000000000..8ed76494aa
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/btree/bt_close.c b/src/util/db2/btree/bt_close.c
new file mode 100644
index 0000000000..b731dcb5d5
--- /dev/null
+++ b/src/util/db2/btree/bt_close.c
@@ -0,0 +1,182 @@
+/*-
+ * 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))
+ 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/src/util/db2/btree/bt_conv.c b/src/util/db2/btree/bt_conv.c
new file mode 100644
index 0000000000..6cfa216ca8
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/btree/bt_debug.c b/src/util/db2/btree/bt_debug.c
new file mode 100644
index 0000000000..8cf1cdaf53
--- /dev/null
+++ b/src/util/db2/btree/bt_debug.c
@@ -0,0 +1,372 @@
+/*-
+ * 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;
+ (h = mpool_get(t->bt_mp, i, MPOOL_IGNOREPIN)) != NULL; ++i)
+ __bt_dpage(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)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(h);
+ (void)fflush(tracefp);
+ return (0);
+}
+
+/*
+ * BT_DPAGE -- Dump the page
+ *
+ * Parameters:
+ * h: pointer to the PAGE
+ */
+int
+__bt_dpage(h)
+ PAGE *h;
+{
+ BINTERNAL *bi;
+ BLEAF *bl;
+ RINTERNAL *ri;
+ RLEAF *rl;
+ indx_t cur, top;
+ 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;
+
+ top = NEXTINDEX(h);
+ (void)fprintf(tracefp, " lower %3d upper %3d nextind %d\n",
+ h->lower, h->upper, top);
+ for (cur = 0; cur < top; 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;
+ (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/src/util/db2/btree/bt_delete.c b/src/util/db2/btree/bt_delete.c
new file mode 100644
index 0000000000..078981c58b
--- /dev/null
+++ b/src/util/db2/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 index;
+ 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) {
+ index = parent->index + 1;
+ BT_PUSH(t, h->pgno, index);
+ break;
+ }
+ mpool_put(t->bt_mp, h, 0);
+ }
+
+ /* Restore the stack. */
+ while (level--) {
+ /* Push the next level down onto the stack. */
+ bi = GETBINTERNAL(h, index);
+ 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);
+ index = 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) {
+ index = parent->index - 1;
+ BT_PUSH(t, h->pgno, index);
+ break;
+ }
+ mpool_put(t->bt_mp, h, 0);
+ }
+
+ /* Restore the stack. */
+ while (level--) {
+ /* Push the next level down onto the stack. */
+ bi = GETBINTERNAL(h, index);
+ 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);
+
+ index = NEXTINDEX(h) - 1;
+ BT_PUSH(t, pgno, index);
+ }
+ 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, index, *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);
+
+ index = parent->index;
+ bi = GETBINTERNAL(pg, index);
+
+ /* 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[index];
+ for (cnt = index, ip = &pg->linp[0]; cnt--; ++ip)
+ if (ip[0] < offset)
+ ip[0] += nksize;
+ for (cnt = NEXTINDEX(pg) - index; --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
+ * index: index on page to delete
+ *
+ * Returns:
+ * RET_SUCCESS, RET_ERROR.
+ */
+int
+__bt_dleaf(t, key, h, index)
+ BTREE *t;
+ const DBT *key;
+ PAGE *h;
+ u_int index;
+{
+ 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 == index &&
+ __bt_curdel(t, key, h, index))
+ return (RET_ERROR);
+
+ /* If the entry uses overflow pages, make them available for reuse. */
+ to = bl = GETBLEAF(h, index);
+ 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[index];
+ for (cnt = index, ip = &h->linp[0]; cnt--; ++ip)
+ if (ip[0] < offset)
+ ip[0] += nbytes;
+ for (cnt = NEXTINDEX(h) - index; --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 > index)
+ --t->bt_cursor.pg.index;
+
+ return (RET_SUCCESS);
+}
+
+/*
+ * __bt_curdel --
+ * Delete the cursor.
+ *
+ * Parameters:
+ * t: tree
+ * key: referenced key (or NULL)
+ * h: page
+ * index: index on page to delete
+ *
+ * Returns:
+ * RET_SUCCESS, RET_ERROR.
+ */
+static int
+__bt_curdel(t, key, h, index)
+ BTREE *t;
+ const DBT *key;
+ PAGE *h;
+ u_int index;
+{
+ 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 = index;
+ 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 (index > 0) {
+ e.page = h;
+ e.index = index - 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 (index < NEXTINDEX(h) - 1) {
+ e.page = h;
+ e.index = index + 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 (index == 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 (index == 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 = index;
+ 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/src/util/db2/btree/bt_get.c b/src/util/db2/btree/bt_get.c
new file mode 100644
index 0000000000..b6318211a1
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/btree/bt_open.c b/src/util/db2/btree/bt_open.c
new file mode 100644
index 0000000000..3a7aa94627
--- /dev/null
+++ b/src/util/db2/btree/bt_open.c
@@ -0,0 +1,471 @@
+/*-
+ * 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, 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
+ 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/src/util/db2/btree/bt_overflow.c b/src/util/db2/btree/bt_overflow.c
new file mode 100644
index 0000000000..8b1f597912
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/btree/bt_page.c b/src/util/db2/btree/bt_page.c
new file mode 100644
index 0000000000..cb65040a73
--- /dev/null
+++ b/src/util/db2/btree/bt_page.c
@@ -0,0 +1,98 @@
+/*-
+ * 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;
+
+ /* 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;
+ return (h);
+ }
+ return (mpool_new(t->bt_mp, npg, MPOOL_PAGE_NEXT));
+}
diff --git a/src/util/db2/btree/bt_put.c b/src/util/db2/btree/bt_put.c
new file mode 100644
index 0000000000..abdb864294
--- /dev/null
+++ b/src/util/db2/btree/bt_put.c
@@ -0,0 +1,320 @@
+/*-
+ * 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;
+ PAGE *h;
+ indx_t index, 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) {
+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));
+ memmove(kb + sizeof(db_pgno_t),
+ &key->size, sizeof(u_int32_t));
+ dflags |= P_BIGKEY;
+ key = &tkey;
+ }
+ if (key->size + data->size > t->bt_ovflsize) {
+ if (__ovfl_put(t, data, &pg) == RET_ERROR)
+ return (RET_ERROR);
+ tdata.data = db;
+ tdata.size = NOVFLSIZE;
+ memmove(db, &pg, sizeof(db_pgno_t));
+ memmove(db + sizeof(db_pgno_t),
+ &data->size, 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);
+ index = 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;
+ index = 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, index) == 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, index)) != RET_SUCCESS)
+ return (status);
+ goto success;
+ }
+
+ if (index < (nxtindex = NEXTINDEX(h)))
+ memmove(h->linp + index + 1, h->linp + index,
+ (nxtindex - index) * sizeof(indx_t));
+ h->lower += sizeof(indx_t);
+
+ h->linp[index] = 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 >= index)
+ ++t->bt_cursor.pg.index;
+
+ if (t->bt_order == NOT)
+ if (h->nextpg == P_INVALID) {
+ if (index == NEXTINDEX(h) - 1) {
+ t->bt_order = FORWARD;
+ t->bt_last.index = index;
+ t->bt_last.pgno = h->pgno;
+ }
+ } else if (h->prevpg == P_INVALID) {
+ if (index == 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/src/util/db2/btree/bt_search.c b/src/util/db2/btree/bt_search.c
new file mode 100644
index 0000000000..869f1ef3f4
--- /dev/null
+++ b/src/util/db2/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, index, 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 = index = 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 = index + 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.
+ */
+ index = base ? base - 1 : base;
+
+next: BT_PUSH(t, h->pgno, index);
+ pg = GETBINTERNAL(h, index)->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 index;
+ 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) {
+ index = parent->index + 1;
+ BT_PUSH(t, h->pgno, index);
+ break;
+ }
+ mpool_put(t->bt_mp, h, 0);
+ }
+
+ /* Restore the stack. */
+ while (level--) {
+ /* Push the next level down onto the stack. */
+ bi = GETBINTERNAL(h, index);
+ 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);
+ index = 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 index;
+ 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) {
+ index = parent->index - 1;
+ BT_PUSH(t, h->pgno, index);
+ break;
+ }
+ mpool_put(t->bt_mp, h, 0);
+ }
+
+ /* Restore the stack. */
+ while (level--) {
+ /* Push the next level down onto the stack. */
+ bi = GETBINTERNAL(h, index);
+ 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);
+
+ index = NEXTINDEX(h) - 1;
+ BT_PUSH(t, pgno, index);
+ }
+ mpool_put(t->bt_mp, h, 0);
+ return (1);
+}
diff --git a/src/util/db2/btree/bt_seq.c b/src/util/db2/btree/bt_seq.c
new file mode 100644
index 0000000000..3e68c66a9c
--- /dev/null
+++ b/src/util/db2/btree/bt_seq.c
@@ -0,0 +1,490 @@
+/*-
+ * 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 "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 index;
+ 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;
+ index = c->pg.index;
+ if (++index == 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);
+ index = 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);
+ }
+ index = c->pg.index;
+ if (index == 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);
+ index = NEXTINDEX(h) - 1;
+ } else
+ --index;
+ break;
+ }
+
+ ep->page = h;
+ ep->index = index;
+ 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, index)
+ BTREE *t;
+ db_pgno_t pgno;
+ u_int index;
+{
+ /* 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 = index;
+ F_SET(&t->bt_cursor, CURS_INIT);
+}
diff --git a/src/util/db2/btree/bt_split.c b/src/util/db2/btree/bt_split.c
new file mode 100644
index 0000000000..0fc95baf3e
--- /dev/null
+++ b/src/util/db2/btree/bt_split.c
@@ -0,0 +1,827 @@
+/*-
+ * 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 >= 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;
+ 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/src/util/db2/btree/bt_utils.c b/src/util/db2/btree/bt_utils.c
new file mode 100644
index 0000000000..1a34598ad6
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/btree/btree.h b/src/util/db2/btree/btree.h
new file mode 100644
index 0000000000..171712749f
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/btree/extern.h b/src/util/db2/btree/extern.h
new file mode 100644
index 0000000000..9da8486e3a
--- /dev/null
+++ b/src/util/db2/btree/extern.h
@@ -0,0 +1,70 @@
+/*-
+ * 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
+ */
+
+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((PAGE *));
+int __bt_dump __P((DB *));
+#endif
+#ifdef STATISTICS
+int __bt_stat __P((DB *));
+#endif
diff --git a/src/util/db2/clib/memmove.c b/src/util/db2/clib/memmove.c
new file mode 100644
index 0000000000..e8384f7c81
--- /dev/null
+++ b/src/util/db2/clib/memmove.c
@@ -0,0 +1,138 @@
+/*-
+ * 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 */
+
+#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/src/util/db2/clib/mkstemp.c b/src/util/db2/clib/mkstemp.c
new file mode 100644
index 0000000000..07d4186a9d
--- /dev/null
+++ b/src/util/db2/clib/mkstemp.c
@@ -0,0 +1,119 @@
+/*
+ * 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 */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <ctype.h>
+
+static int _gettemp();
+
+mkstemp(path)
+ char *path;
+{
+ int fd;
+
+ return (_gettemp(path, &fd) ? fd : -1);
+}
+
+static
+_gettemp(path, doopen)
+ char *path;
+ register int *doopen;
+{
+ extern int errno;
+ 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, 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/src/util/db2/clib/strerror.c b/src/util/db2/clib/strerror.c
new file mode 100644
index 0000000000..53f374bdf7
--- /dev/null
+++ b/src/util/db2/clib/strerror.c
@@ -0,0 +1,67 @@
+/*
+ * 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 */
+
+#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/src/util/db2/configure.in b/src/util/db2/configure.in
new file mode 100644
index 0000000000..3d256c40b7
--- /dev/null
+++ b/src/util/db2/configure.in
@@ -0,0 +1,63 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(db/db.c)
+AC_CONFIG_HEADER(obj/db-config.h)
+dnl checks for programs
+AC_PROG_CC
+AC_PROG_RANLIB
+
+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)
+dnl checks for typedefs
+AC_TYPE_SIZE_T
+
+AC_CHECK_TYPE(ssize_t, int)
+
+AC_CHECK_TYPE(u_char, unsigned char)
+AC_CHECK_TYPE(u_short, unsigned short)
+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_CHECK_TYPE(int32_t, int)
+AC_CHECK_TYPE(u_int32_t, unsigned int)
+dnl checks for structures
+dnl checks for compiler characteristics
+AC_C_BIGENDIAN
+AC_C_CONST
+dnl checks for library functions
+AC_CHECK_FUNC(memmove,,MEMMOVE_OBJ=memmove.o)
+AC_CHECK_FUNC(mkstemp,,MKSTEMP_OBJ=mkstemp.o)
+AC_CHECK_FUNC(strerror,,STRERROR_OBJ=strerror.o)
+AC_SUBST(MEMMOVE_OBJ)
+AC_SUBST(MKSTEMP_OBJ)
+AC_SUBST(STRERROR_OBJ)
+AC_CHECK_FUNCS(memmove mkstemp strerror)
+dnl checks for system services
+AC_OUTPUT(Makefile obj/Makefile)
diff --git a/src/util/db2/db/Makefile.inc b/src/util/db2/db/Makefile.inc
new file mode 100644
index 0000000000..59478ba198
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/db/db.c b/src/util/db2/db/db.c
new file mode 100644
index 0000000000..dc38abdc4e
--- /dev/null
+++ b/src/util/db2/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 *
+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)
+
+ 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/src/util/db2/docs/btree.3.ps b/src/util/db2/docs/btree.3.ps
new file mode 100644
index 0000000000..c79c97232c
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/docs/dbopen.3.ps b/src/util/db2/docs/dbopen.3.ps
new file mode 100644
index 0000000000..c621bef97d
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/docs/hash.3.ps b/src/util/db2/docs/hash.3.ps
new file mode 100644
index 0000000000..18303cfb7c
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/docs/hash.usenix.ps b/src/util/db2/docs/hash.usenix.ps
new file mode 100644
index 0000000000..acdea09926
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/docs/libtp.usenix.ps b/src/util/db2/docs/libtp.usenix.ps
new file mode 100644
index 0000000000..5b5ba6e1b8
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/docs/mpool.3.ps b/src/util/db2/docs/mpool.3.ps
new file mode 100644
index 0000000000..816c9243c8
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/docs/recno.3.ps b/src/util/db2/docs/recno.3.ps
new file mode 100644
index 0000000000..8ffccfca90
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/hash/Makefile.inc b/src/util/db2/hash/Makefile.inc
new file mode 100644
index 0000000000..87746f721e
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/hash/dbm.c b/src/util/db2/hash/dbm.c
new file mode 100644
index 0000000000..a5a31f45bc
--- /dev/null
+++ b/src/util/db2/hash/dbm.c
@@ -0,0 +1,297 @@
+/*-
+ * 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 "hash.h"
+
+/*
+ *
+ * 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
+dbminit(file)
+ char *file;
+{
+ if (__cur_db != NULL)
+ (void)dbm_close(__cur_db);
+ if ((__cur_db = dbm_open(file, O_RDWR, 0)) != NULL)
+ return (0);
+ if ((__cur_db = dbm_open(file, O_RDONLY, 0)) != NULL)
+ return (0);
+ return (-1);
+}
+
+datum
+fetch(key)
+ datum key;
+{
+ datum item;
+
+ if (__cur_db == NULL) {
+ no_open_db();
+ item.dptr = 0;
+ return (item);
+ }
+ return (dbm_fetch(__cur_db, key));
+}
+
+datum
+firstkey()
+{
+ datum item;
+
+ if (__cur_db == NULL) {
+ no_open_db();
+ item.dptr = 0;
+ return (item);
+ }
+ return (dbm_firstkey(__cur_db));
+}
+
+datum
+nextkey(key)
+ datum key;
+{
+ datum item;
+
+ if (__cur_db == NULL) {
+ no_open_db();
+ item.dptr = 0;
+ return (item);
+ }
+ return (dbm_nextkey(__cur_db));
+}
+
+int
+delete(key)
+ datum key;
+{
+ if (__cur_db == NULL) {
+ no_open_db();
+ return (-1);
+ }
+ return (dbm_delete(__cur_db, key));
+}
+
+int
+store(key, dat)
+ datum key, dat;
+{
+ if (__cur_db == NULL) {
+ no_open_db();
+ return (-1);
+ }
+ return (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 *
+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)strcpy(path, file);
+ (void)strcat(path, DBM_SUFFIX);
+ return ((DBM *)__hash_open(path, flags, mode, &info, 0));
+}
+
+/*
+ * Returns:
+ * Nothing.
+ */
+void
+dbm_close(db)
+ DBM *db;
+{
+ (void)(db->close)(db);
+}
+
+/*
+ * Returns:
+ * DATUM on success
+ * NULL on failure
+ */
+datum
+dbm_fetch(db, key)
+ DBM *db;
+ datum key;
+{
+ datum retval;
+ int status;
+
+ status = (db->get)(db, (DBT *)&key, (DBT *)&retval, 0);
+ if (status) {
+ retval.dptr = NULL;
+ retval.dsize = 0;
+ }
+ return (retval);
+}
+
+/*
+ * Returns:
+ * DATUM on success
+ * NULL on failure
+ */
+datum
+dbm_firstkey(db)
+ DBM *db;
+{
+ int status;
+ datum retdata, retkey;
+
+ status = (db->seq)(db, (DBT *)&retkey, (DBT *)&retdata, R_FIRST);
+ if (status)
+ retkey.dptr = NULL;
+ return (retkey);
+}
+
+/*
+ * Returns:
+ * DATUM on success
+ * NULL on failure
+ */
+datum
+dbm_nextkey(db)
+ DBM *db;
+{
+ int status;
+ datum retdata, retkey;
+
+ status = (db->seq)(db, (DBT *)&retkey, (DBT *)&retdata, R_NEXT);
+ if (status)
+ retkey.dptr = NULL;
+ return (retkey);
+}
+
+/*
+ * Returns:
+ * 0 on success
+ * <0 failure
+ */
+int
+dbm_delete(db, key)
+ DBM *db;
+ datum key;
+{
+ int status;
+
+ status = (db->del)(db, (DBT *)&key, 0);
+ if (status)
+ return (-1);
+ else
+ return (0);
+}
+
+/*
+ * Returns:
+ * 0 on success
+ * <0 failure
+ * 1 if DBM_INSERT and entry exists
+ */
+int
+dbm_store(db, key, content, flags)
+ DBM *db;
+ datum key, content;
+ int flags;
+{
+ return ((db->put)(db, (DBT *)&key, (DBT *)&content,
+ (flags == DBM_INSERT) ? R_NOOVERWRITE : 0));
+}
+
+int
+dbm_error(db)
+ DBM *db;
+{
+ HTAB *hp;
+
+ hp = (HTAB *)db->internal;
+ return (hp->errno);
+}
+
+int
+dbm_clearerr(db)
+ DBM *db;
+{
+ HTAB *hp;
+
+ hp = (HTAB *)db->internal;
+ hp->errno = 0;
+ return (0);
+}
+
+int
+dbm_dirfno(db)
+ DBM *db;
+{
+ return(((HTAB *)db->internal)->fp);
+}
diff --git a/src/util/db2/hash/extern.h b/src/util/db2/hash/extern.h
new file mode 100644
index 0000000000..dd8a34e8ef
--- /dev/null
+++ b/src/util/db2/hash/extern.h
@@ -0,0 +1,76 @@
+/*-
+ * 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
+ */
+
+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/src/util/db2/hash/hash.c b/src/util/db2/hash/hash.c
new file mode 100644
index 0000000000..017138606a
--- /dev/null
+++ b/src/util/db2/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, 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 *, 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 *
+__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 = (char *)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, 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, (HASHINFO *)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;
+ 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;
+ db_pgno_t i;
+
+ /*
+ * 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.
+ */
+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);
+}
+
+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->errno = errno = EINVAL;
+ return (ERROR);
+ }
+ return (hash_access(hashp, HASH_GET, (DBT *)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->errno = errno = EINVAL;
+ return (ERROR);
+ }
+ if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
+ hashp->errno = errno = EPERM;
+ return (ERROR);
+ }
+ return (hash_access(hashp, flag == R_NOOVERWRITE ?
+ HASH_PUTNEW : HASH_PUT, (DBT *)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->errno = errno = EINVAL;
+ return (ERROR);
+ }
+ if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
+ hashp->errno = errno = EPERM;
+ return (ERROR);
+ }
+
+ return (hash_access(hashp, HASH_DELETE, (DBT *)key, NULL));
+}
+
+/*
+ * Assume that hashp has been set in wrapper routine.
+ */
+static int32_t
+hash_access(hashp, action, key, val)
+ HTAB *hashp;
+ ACTION action;
+ DBT *key, *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;
+}
+
+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->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);
+}
+
+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/src/util/db2/hash/hash.c.patch b/src/util/db2/hash/hash.c.patch
new file mode 100644
index 0000000000..b72cc0d26d
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/hash/hash.h b/src/util/db2/hash/hash.h
new file mode 100644
index 0000000000..973d543a85
--- /dev/null
+++ b/src/util/db2/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 */
+ 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 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_SIZE 4096
+#define DEF_BUCKET_SHIFT 12 /* log2(BUCKET) */
+#define DEF_SEGSIZE 256
+#define DEF_SEGSIZE_SHIFT 8 /* log2(SEGSIZE) */
+#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/src/util/db2/hash/hash_bigkey.c b/src/util/db2/hash/hash_bigkey.c
new file mode 100644
index 0000000000..689dc3db64
--- /dev/null
+++ b/src/util/db2/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 = (char *)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 = (char *)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 = (char *)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/src/util/db2/hash/hash_debug.c b/src/util/db2/hash/hash_debug.c
new file mode 100644
index 0000000000..ed99c69320
--- /dev/null
+++ b/src/util/db2/hash/hash_debug.c
@@ -0,0 +1,106 @@
+/*-
+ * 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"
+#include "compat.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/src/util/db2/hash/hash_func.c b/src/util/db2/hash/hash_func.c
new file mode 100644
index 0000000000..efa2a2843b
--- /dev/null
+++ b/src/util/db2/hash/hash_func.c
@@ -0,0 +1,196 @@
+/*-
+ * 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"
+
+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));
+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
+
+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))
+
+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.
+ */
+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);
+}
+
+/* Chris Torek's hash function. */
+u_int32_t
+hash4(key, len)
+ const void *key;
+ size_t len;
+{
+ u_int32_t h, loop;
+ u_int8_t *k;
+
+#define HASH4a h = (h << 5) - h + *k++;
+#define HASH4b h = (h << 5) + h + *k++;
+#define HASH4 HASH4b
+
+ h = 0;
+ k = (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/src/util/db2/hash/hash_log2.c b/src/util/db2/hash/hash_log2.c
new file mode 100644
index 0000000000..8604945e80
--- /dev/null
+++ b/src/util/db2/hash/hash_log2.c
@@ -0,0 +1,52 @@
+/*-
+ * 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"
+
+u_int32_t
+__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/src/util/db2/hash/hash_page.c b/src/util/db2/hash/hash_page.c
new file mode 100644
index 0000000000..8622075d17
--- /dev/null
+++ b/src/util/db2/hash/hash_page.c
@@ -0,0 +1,1380 @@
+/*-
+ * 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 stat;
+
+ stat = __get_item(hashp, cursorp, key, val, item_info);
+ cursorp->ndx++;
+ cursorp->pgndx++;
+ return (stat);
+}
+
+/*
+ * 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.
+ */
+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.
+ */
+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 (__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 (__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));
+}
+
+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);
+}
+
+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));
+ }
+}
+
+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);
+}
+
+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 */
+
+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/src/util/db2/hash/hsearch.c b/src/util/db2/hash/hsearch.c
new file mode 100644
index 0000000000..f257cd6eaa
--- /dev/null
+++ b/src/util/db2/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, 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/src/util/db2/hash/page.h b/src/util/db2/hash/page.h
new file mode 100644
index 0000000000..8ef8a2e294
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/hash/page.h.patch b/src/util/db2/hash/page.h.patch
new file mode 100644
index 0000000000..4a0311fea3
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/hash/search.h b/src/util/db2/hash/search.h
new file mode 100644
index 0000000000..4d3b9143e7
--- /dev/null
+++ b/src/util/db2/hash/search.h
@@ -0,0 +1,51 @@
+/*-
+ * 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;
+
+int hcreate __P((unsigned int));
+void hdestroy __P((void));
+ENTRY *hsearch __P((ENTRY, ACTION));
diff --git a/src/util/db2/include/db-int.h b/src/util/db2/include/db-int.h
new file mode 100644
index 0000000000..78be4c8a36
--- /dev/null
+++ b/src/util/db2/include/db-int.h
@@ -0,0 +1,208 @@
+/*-
+ * 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 "db.h"
+
+/* deal with autoconf-based stuff (db.h includes db-config.h) */
+
+#ifndef HAVE_MEMMOVE
+#define memmove my_memmove
+#endif
+
+#ifndef HAVE_MKSTEMP
+#define mkstemp my_mkstemp
+#endif
+
+#ifndef HAVE_STRERROR
+#define strerror my_strerror
+#endif
+
+#define DB_LITTLE_ENDIAN 1234
+#define DB_BIG_ENDIAN 4321
+
+#ifdef WORDS_BIGENDIAN
+#define DB_BYTE_ORDER DB_BIG_ENDIAN
+#else
+#define DB_BYTE_ORDER DB_LITTLE_ENDIAN
+#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>
+#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() */
+
+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
+
+#endif /* _DB_INT_H_ */
diff --git a/src/util/db2/include/db-ndbm.h b/src/util/db2/include/db-ndbm.h
new file mode 100644
index 0000000000..1bafb6c4bf
--- /dev/null
+++ b/src/util/db2/include/db-ndbm.h
@@ -0,0 +1,77 @@
+/*-
+ * 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
+
+__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 *));
+__END_DECLS
+
+#endif /* !_NDBM_H_ */
diff --git a/src/util/db2/include/db-queue.h b/src/util/db2/include/db-queue.h
new file mode 100644
index 0000000000..40d32ccb6e
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/include/db.h b/src/util/db2/include/db.h
new file mode 100644
index 0000000000..6b5c04e6b9
--- /dev/null
+++ b/src/util/db2/include/db.h
@@ -0,0 +1,170 @@
+/*-
+ * 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 UINT_MAX > 65535
+#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 */
+
+#if defined(__STDC__) || defined(__cplusplus)
+#define __P(protos) protos /* full-blown ANSI C */
+#else /* !(__STDC__ || __cplusplus) */
+#define __P(protos) () /* traditional C preprocessor */
+#endif
+
+/* 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
+
+__BEGIN_DECLS
+DB *dbopen __P((const char *, int, int, DBTYPE, const void *));
+__END_DECLS
+
+#endif /* !_DB_H_ */
diff --git a/src/util/db2/man/Makefile.inc b/src/util/db2/man/Makefile.inc
new file mode 100644
index 0000000000..f85cba1f81
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/man/db.man.ps b/src/util/db2/man/db.man.ps
new file mode 100644
index 0000000000..23feea6e5c
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/man/db_btree.3 b/src/util/db2/man/db_btree.3
new file mode 100644
index 0000000000..25e289f3cd
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/man/db_hash.3 b/src/util/db2/man/db_hash.3
new file mode 100644
index 0000000000..adb88fca7c
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/man/db_lock.3 b/src/util/db2/man/db_lock.3
new file mode 100644
index 0000000000..b18a38c60c
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/man/db_log.3 b/src/util/db2/man/db_log.3
new file mode 100644
index 0000000000..34c4d1f5d1
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/man/db_mpool.3 b/src/util/db2/man/db_mpool.3
new file mode 100644
index 0000000000..4b683b6185
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/man/db_open.3 b/src/util/db2/man/db_open.3
new file mode 100644
index 0000000000..f988ef9245
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/man/db_recno.3 b/src/util/db2/man/db_recno.3
new file mode 100644
index 0000000000..6b93b3f5a1
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/man/db_txn.3 b/src/util/db2/man/db_txn.3
new file mode 100644
index 0000000000..18ad64692e
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/man/spell.ok b/src/util/db2/man/spell.ok
new file mode 100644
index 0000000000..794b00bf87
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/mpool/Makefile.inc b/src/util/db2/mpool/Makefile.inc
new file mode 100644
index 0000000000..93210c89e2
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/mpool/README b/src/util/db2/mpool/README
new file mode 100644
index 0000000000..0f01fbcdb4
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/mpool/mpool.c b/src/util/db2/mpool/mpool.c
new file mode 100644
index 0000000000..12e557d031
--- /dev/null
+++ b/src/util/db2/mpool/mpool.c
@@ -0,0 +1,502 @@
+/*-
+ * 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 (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 (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/src/util/db2/mpool/mpool.h b/src/util/db2/mpool/mpool.h
new file mode 100644
index 0000000000..92bf7541d3
--- /dev/null
+++ b/src/util/db2/mpool/mpool.h
@@ -0,0 +1,107 @@
+/*-
+ * 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. */
+
+__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/src/util/db2/obj/Makefile.in b/src/util/db2/obj/Makefile.in
new file mode 100644
index 0000000000..5e60ef7961
--- /dev/null
+++ b/src/util/db2/obj/Makefile.in
@@ -0,0 +1,157 @@
+SHELL = /bin/sh
+
+LIBDB = libdb.a
+
+HASH_OBJS = hash.o hash_bigkey.o hash_debug.o hash_func.o hash_log2.o \
+ hash_page.o hsearch.o dbm.o
+BT_OBJS = 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
+DB_OBJS = db.o
+MPOOL_OBJS = mpool.o
+REC_OBJS = rec_close.o rec_delete.o rec_get.o rec_open.o rec_put.o \
+ rec_search.o rec_seq.o rec_utils.o
+
+MEMMOVE_OBJ = @MEMMOVE_OBJ@
+MKSTEMP_OBJ = @MKSTEMP_OBJ@
+STRERROR_OBJ = @STRERROR_OBJ@
+
+MISC_OBJS = $(MEMMOVE_OBJ) $(MKSTEMP_OBJ)
+
+ALL_OBJS = $(HASH_OBJS) $(BT_OBJS) $(DB_OBJS) $(MPOOL_OBJS) \
+ $(REC_OBJS) $(MISC_OBJS)
+
+TMPDIR = /tmp
+
+AR = ar
+CC = @CC@
+RANLIB = @RANLIB@
+FCTSH = @FCTSH@
+top_srcdir = @top_srcdir@
+srcdir = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+includedir = @includedir@
+libdir = @libdir@
+
+CDEBUGFLAGS = @CFLAGS@
+
+CFLAGS = $(CDEBUGFLAGS) @CPPFLAGS@ @DEFS@ \
+ -I. -I$(top_srcdir)/include -I$(top_srcdir)/mpool -I$(top_srcdir)/db \
+ -I$(top_srcdir)/hash -I$(top_srcdir)/btree -I$(top_srcdir)/recno
+
+all:: $(LIBDB) db.h
+
+$(LIBDB): $(ALL_OBJS)
+ $(AR) cru $@ $(ALL_OBJS)
+ $(RANLIB) $@
+
+db.h: $(top_srcdir)/include/db.h
+ ln -s $(top_srcdir)/include/db.h .
+
+dbtest: dbtest.o $(STRERROR_OBJ) $(LIBDB)
+ $(CC) -o $@ dbtest.o $(STRERROR_OBJ) $(LIBDB)
+
+check:: dbtest
+ TMPDIR=$(TMPDIR) $(FCTSH) $(top_srcdir)/test/run.test
+
+install::
+ cp $(LIBDB) $(libdir)
+ $(RANLIB) $(libdir)/$(LIBDB)
+ cp $(top_srcdir)/include/db.h $(includedir)
+ cp ../db-config.h $(includedir)
+
+clean::
+ rm -f $(ALL_OBJS) $(LIBDB) \
+ dbtest.o $(STRERROR_OBJ) dbtest \
+ core t1 t2 t3 *~
+
+## if VPATH worked everywhere, I could do this:
+##
+## VPATH = @top_srcdir@/db @top_srcdir@/mpool \
+## @top_srcdir@/hash @top_srcdir@/btree @top_srcdir@/recno \
+## @top_srcdir@/clib
+##
+## but it doesn't, so I do this instead:
+
+db.o: $(top_srcdir)/db/db.c
+ $(CC) $(CFLAGS) -c -o db.o $(top_srcdir)/db/db.c
+
+mpool.o: $(top_srcdir)/mpool/mpool.c
+ $(CC) $(CFLAGS) -c -o mpool.o $(top_srcdir)/mpool/mpool.c
+
+hash.o: $(top_srcdir)/hash/hash.c
+ $(CC) $(CFLAGS) -c -o hash.o $(top_srcdir)/hash/hash.c
+hash_bigkey.o: $(top_srcdir)/hash/hash_bigkey.c
+ $(CC) $(CFLAGS) -c -o hash_bigkey.o $(top_srcdir)/hash/hash_bigkey.c
+hash_debug.o: $(top_srcdir)/hash/hash_debug.c
+ $(CC) $(CFLAGS) -c -o hash_debug.o $(top_srcdir)/hash/hash_debug.c
+hash_func.o: $(top_srcdir)/hash/hash_func.c
+ $(CC) $(CFLAGS) -c -o hash_func.o $(top_srcdir)/hash/hash_func.c
+hash_log2.o: $(top_srcdir)/hash/hash_log2.c
+ $(CC) $(CFLAGS) -c -o hash_log2.o $(top_srcdir)/hash/hash_log2.c
+hash_page.o: $(top_srcdir)/hash/hash_page.c
+ $(CC) $(CFLAGS) -c -o hash_page.o $(top_srcdir)/hash/hash_page.c
+hsearch.o: $(top_srcdir)/hash/hsearch.c
+ $(CC) $(CFLAGS) -c -o hsearch.o $(top_srcdir)/hash/hsearch.c
+dbm.o: $(top_srcdir)/hash/dbm.c
+ $(CC) $(CFLAGS) -c -o dbm.o $(top_srcdir)/hash/dbm.c
+
+bt_close.o: $(top_srcdir)/btree/bt_close.c
+ $(CC) $(CFLAGS) -c -o bt_close.o $(top_srcdir)/btree/bt_close.c
+bt_conv.o: $(top_srcdir)/btree/bt_conv.c
+ $(CC) $(CFLAGS) -c -o bt_conv.o $(top_srcdir)/btree/bt_conv.c
+bt_debug.o: $(top_srcdir)/btree/bt_debug.c
+ $(CC) $(CFLAGS) -c -o bt_debug.o $(top_srcdir)/btree/bt_debug.c
+bt_delete.o: $(top_srcdir)/btree/bt_delete.c
+ $(CC) $(CFLAGS) -c -o bt_delete.o $(top_srcdir)/btree/bt_delete.c
+bt_get.o: $(top_srcdir)/btree/bt_get.c
+ $(CC) $(CFLAGS) -c -o bt_get.o $(top_srcdir)/btree/bt_get.c
+bt_open.o: $(top_srcdir)/btree/bt_open.c
+ $(CC) $(CFLAGS) -c -o bt_open.o $(top_srcdir)/btree/bt_open.c
+bt_overflow.o: $(top_srcdir)/btree/bt_overflow.c
+ $(CC) $(CFLAGS) -c -o bt_overflow.o $(top_srcdir)/btree/bt_overflow.c
+bt_page.o: $(top_srcdir)/btree/bt_page.c
+ $(CC) $(CFLAGS) -c -o bt_page.o $(top_srcdir)/btree/bt_page.c
+bt_put.o: $(top_srcdir)/btree/bt_put.c
+ $(CC) $(CFLAGS) -c -o bt_put.o $(top_srcdir)/btree/bt_put.c
+bt_search.o: $(top_srcdir)/btree/bt_search.c
+ $(CC) $(CFLAGS) -c -o bt_search.o $(top_srcdir)/btree/bt_search.c
+bt_seq.o: $(top_srcdir)/btree/bt_seq.c
+ $(CC) $(CFLAGS) -c -o bt_seq.o $(top_srcdir)/btree/bt_seq.c
+bt_split.o: $(top_srcdir)/btree/bt_split.c
+ $(CC) $(CFLAGS) -c -o bt_split.o $(top_srcdir)/btree/bt_split.c
+bt_stack.o: $(top_srcdir)/btree/bt_stack.c
+ $(CC) $(CFLAGS) -c -o bt_stack.o $(top_srcdir)/btree/bt_stack.c
+bt_utils.o: $(top_srcdir)/btree/bt_utils.c
+ $(CC) $(CFLAGS) -c -o bt_utils.o $(top_srcdir)/btree/bt_utils.c
+
+rec_close.o: $(top_srcdir)/recno/rec_close.c
+ $(CC) $(CFLAGS) -c -o rec_close.o $(top_srcdir)/recno/rec_close.c
+rec_delete.o: $(top_srcdir)/recno/rec_delete.c
+ $(CC) $(CFLAGS) -c -o rec_delete.o $(top_srcdir)/recno/rec_delete.c
+rec_get.o: $(top_srcdir)/recno/rec_get.c
+ $(CC) $(CFLAGS) -c -o rec_get.o $(top_srcdir)/recno/rec_get.c
+rec_open.o: $(top_srcdir)/recno/rec_open.c
+ $(CC) $(CFLAGS) -c -o rec_open.o $(top_srcdir)/recno/rec_open.c
+rec_put.o: $(top_srcdir)/recno/rec_put.c
+ $(CC) $(CFLAGS) -c -o rec_put.o $(top_srcdir)/recno/rec_put.c
+rec_search.o: $(top_srcdir)/recno/rec_search.c
+ $(CC) $(CFLAGS) -c -o rec_search.o $(top_srcdir)/recno/rec_search.c
+rec_seq.o: $(top_srcdir)/recno/rec_seq.c
+ $(CC) $(CFLAGS) -c -o rec_seq.o $(top_srcdir)/recno/rec_seq.c
+rec_utils.o: $(top_srcdir)/recno/rec_utils.c
+ $(CC) $(CFLAGS) -c -o rec_utils.o $(top_srcdir)/recno/rec_utils.c
+
+dbtest.o: $(top_srcdir)/test/dbtest.c
+ $(CC) $(CFLAGS) -c -o dbtest.o $(top_srcdir)/test/dbtest.c
+
+memmove.o: $(top_srcdir)/clib/memmove.c
+ $(CC) $(CFLAGS) -c -o memmove.o $(top_srcdir)/clib/memmove.c
+mkstemp.o: $(top_srcdir)/clib/mkstemp.c
+ $(CC) $(CFLAGS) -c -o mkstemp.o $(top_srcdir)/clib/mkstemp.c
+strerror.o: $(top_srcdir)/clib/strerror.c
+ $(CC) $(CFLAGS) -c -o strerror.o $(top_srcdir)/clib/strerror.c
+
+distclean:: clean
+ rm -f Makefile
diff --git a/src/util/db2/recno/Makefile.inc b/src/util/db2/recno/Makefile.inc
new file mode 100644
index 0000000000..e49e225522
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/recno/extern.h b/src/util/db2/recno/extern.h
new file mode 100644
index 0000000000..feed434453
--- /dev/null
+++ b/src/util/db2/recno/extern.h
@@ -0,0 +1,54 @@
+/*-
+ * 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"
+
+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/src/util/db2/recno/rec_close.c b/src/util/db2/recno/rec_close.c
new file mode 100644
index 0000000000..2e923070bd
--- /dev/null
+++ b/src/util/db2/recno/rec_close.c
@@ -0,0 +1,186 @@
+/*-
+ * 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/src/util/db2/recno/rec_delete.c b/src/util/db2/recno/rec_delete.c
new file mode 100644
index 0000000000..35ec7769ac
--- /dev/null
+++ b/src/util/db2/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
+ * index: index on current page to delete
+ *
+ * Returns:
+ * RET_SUCCESS, RET_ERROR.
+ */
+int
+__rec_dleaf(t, h, index)
+ BTREE *t;
+ PAGE *h;
+ u_int32_t index;
+{
+ 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, index);
+ 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[index];
+ for (cnt = &h->linp[index] - (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/src/util/db2/recno/rec_get.c b/src/util/db2/recno/rec_get.c
new file mode 100644
index 0000000000..230b2d4f54
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/recno/rec_open.c b/src/util/db2/recno/rec_open.c
new file mode 100644
index 0000000000..fccaacc90d
--- /dev/null
+++ b/src/util/db2/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, 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, S_IRUSR | S_IWUSR, &btopeninfo, dflags);
+ } else
+ dbp = __bt_open(NULL, O_RDWR, 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, "r")) == 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/src/util/db2/recno/rec_put.c b/src/util/db2/recno/rec_put.c
new file mode 100644
index 0000000000..25452f15f8
--- /dev/null
+++ b/src/util/db2/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 index, 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;
+ index = 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:
+ ++index;
+ break;
+ case R_IBEFORE:
+ break;
+ default:
+ if (nrec < t->bt_nrecs &&
+ __rec_dleaf(t, h, index) == 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, index);
+ if (status == RET_SUCCESS)
+ ++t->bt_nrecs;
+ return (status);
+ }
+
+ if (index < (nxtindex = NEXTINDEX(h)))
+ memmove(h->linp + index + 1, h->linp + index,
+ (nxtindex - index) * sizeof(indx_t));
+ h->lower += sizeof(indx_t);
+
+ h->linp[index] = 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/src/util/db2/recno/rec_search.c b/src/util/db2/recno/rec_search.c
new file mode 100644
index 0000000000..0be9563b8f
--- /dev/null
+++ b/src/util/db2/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 index;
+ 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 (index = 0, top = NEXTINDEX(h);;) {
+ r = GETRINTERNAL(h, index);
+ if (++index == top || total + r->nrecs > recno)
+ break;
+ total += r->nrecs;
+ }
+
+ BT_PUSH(t, pg, index - 1);
+
+ pg = r->pgno;
+ switch (op) {
+ case SDELETE:
+ --GETRINTERNAL(h, (index - 1))->nrecs;
+ mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+ break;
+ case SINSERT:
+ ++GETRINTERNAL(h, (index - 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/src/util/db2/recno/rec_seq.c b/src/util/db2/recno/rec_seq.c
new file mode 100644
index 0000000000..e150333cb1
--- /dev/null
+++ b/src/util/db2/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.
+ */
+
+#ifndef 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/src/util/db2/recno/rec_utils.c b/src/util/db2/recno/rec_utils.c
new file mode 100644
index 0000000000..f757a724f5
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/recno/recno.h b/src/util/db2/recno/recno.h
new file mode 100644
index 0000000000..bec772c2fa
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/test/Makefile b/src/util/db2/test/Makefile
new file mode 100644
index 0000000000..a5dd08ae58
--- /dev/null
+++ b/src/util/db2/test/Makefile
@@ -0,0 +1,23 @@
+# @(#)Makefile 8.15 (Berkeley) 7/28/94
+
+PROG= dbtest
+OBJS= dbtest.o strerror.o
+
+# 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}
+
+dbtest: ${OBJS} ${PORTDIR}/libdb.a
+ ${CC} -o $@ ${OBJS} ${PORTDIR}/libdb.a
+
+strerror.o: ${PORTDIR}/clib/strerror.c
+ ${CC} -c ${PORTDIR}/clib/strerror.c
+
+clean:
+ rm -f dbtest.core gmon.out ${OBJS} ${PROG} t1 t2 t3
+
+${OBJS}: Makefile
diff --git a/src/util/db2/test/README b/src/util/db2/test/README
new file mode 100644
index 0000000000..0c0cd13d8f
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/test/SEQ_TEST/data b/src/util/db2/test/SEQ_TEST/data
new file mode 100644
index 0000000000..37a518537e
--- /dev/null
+++ b/src/util/db2/test/SEQ_TEST/data
@@ -0,0 +1,8 @@
+A000027875A000135891
+A000059165A000130168
+A000060256A000133490
+A040025906A000136770
+A040027881A000135829
+A040028611A000137873
+A040032413A000056974
+A040050163A000126233
diff --git a/src/util/db2/test/SEQ_TEST/mbox b/src/util/db2/test/SEQ_TEST/mbox
new file mode 100644
index 0000000000..9d5d49d073
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/test/SEQ_TEST/t.c b/src/util/db2/test/SEQ_TEST/t.c
new file mode 100644
index 0000000000..ac0fef71ec
--- /dev/null
+++ b/src/util/db2/test/SEQ_TEST/t.c
@@ -0,0 +1,86 @@
+/* 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>
+
+extern int errno;
+
+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, 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 > 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/src/util/db2/test/btree.tests/main.c b/src/util/db2/test/btree.tests/main.c
new file mode 100644
index 0000000000..02f1b96286
--- /dev/null
+++ b/src/util/db2/test/btree.tests/main.c
@@ -0,0 +1,765 @@
+/*-
+ * 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;
+
+void append __P((DB *, char **));
+void bstat __P((DB *, char **));
+void cursor __P((DB *, char **));
+void delcur __P((DB *, char **));
+void delete __P((DB *, char **));
+void dump __P((DB *, char **));
+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 **));
+void load __P((DB *, char **));
+void mstat __P((DB *, char **));
+void next __P((DB *, char **));
+int parse __P((char *, char **, int));
+void previous __P((DB *, char **));
+void show __P((DB *, char **));
+void usage __P((void));
+void user __P((DB *));
+
+cmd_table commands[] = {
+ "?", 0, 0, help, "help", NULL,
+ "a", 2, 1, append, "append key def", "append key with data def",
+ "b", 0, 0, bstat, "bstat", "stat btree",
+ "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",
+ "d", 0, 0, dump, "dump", "dump database",
+ "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",
+ "loa", 1, 0, load, "load file", NULL,
+ "loc", 1, 1, get, "get key", NULL,
+ "m", 0, 0, mstat, "mstat", "stat memory pool",
+ "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",
+ "sh", 1, 0, show, "show page", "dump a page",
+ { NULL },
+};
+
+int recno; /* use record numbers */
+char *dict = "words"; /* default dictionary */
+char *progname;
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ DB *db;
+ BTREEINFO b;
+
+ progname = *argv;
+
+ 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:ru")) != EOF) {
+ switch (c) {
+ case 'b':
+ b.lorder = 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 = LITTLE_ENDIAN;
+ break;
+ case 'p':
+ b.psize = atoi(optarg);
+ break;
+ case 'r':
+ recno = 1;
+ break;
+ case 'u':
+ b.flags = 0;
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (recno)
+ db = dbopen(*argv == NULL ? NULL : *argv, O_RDWR,
+ 0, DB_RECNO, NULL);
+ else
+ db = dbopen(*argv == NULL ? NULL : *argv, O_CREAT|O_RDWR,
+ 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) == 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);
+}
+
+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;
+ }
+}
+
+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;
+ }
+}
+
+void
+dump(db, argv)
+ DB *db;
+ char **argv;
+{
+ __bt_dump(db);
+}
+
+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);
+ }
+ if (status == RET_ERROR)
+ perror("list/seq");
+}
+
+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);
+}
+
+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;
+ }
+}
+
+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(h);
+ mpool_put(t->bt_mp, h, 0);
+}
+
+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);
+}
+
+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 [-bdlu] [-c cache] [-i file] [-p page] [file]\n",
+ progname);
+ exit (1);
+}
diff --git a/src/util/db2/test/dbtest.c b/src/util/db2/test/dbtest.c
new file mode 100644
index 0000000000..f49228165b
--- /dev/null
+++ b/src/util/db2/test/dbtest.c
@@ -0,0 +1,753 @@
+/*-
+ * 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.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1992, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+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"
+
+enum S { COMMAND, COMPARE, GET, PUT, REMOVE, SEQ, SEQFLAG, KEY, DATA };
+
+void compare __P((DBT *, DBT *));
+DBTYPE dbtype __P((char *));
+void dump __P((DB *, int));
+void err __P((const char *, ...));
+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;
+ sflag = 0;
+ while ((ch = getopt(argc, argv, "f:i:lo:s")) != EOF)
+ 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(*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",
+ db1->size, db2->size);
+
+ len = MIN(db1->size, db2->size);
+ for (p1 = db1->data, p2 = db2->data; len--;)
+ if (*p1++ != *p2++) {
+ printf("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);
+ else
+ (void)fprintf(stderr, "%d: %.*s: %s",
+ lineno, MIN(kp->size, 20), 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, "%d: %.*s: %s",
+ lineno, MIN(kp->size, 20), kp->data, NOSUCHKEY);
+ else
+ (void)fprintf(stderr,
+ "%d: 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, "%d: %.*s: %s",
+ lineno, MIN(kp->size, 20), kp->data, NOSUCHKEY);
+ else
+ (void)fprintf(stderr,
+ "%d: seq (%s) failed\n", lineno, sflags(flags));
+#undef NOSUCHKEY
+ break;
+ }
+}
+
+void
+dump(dbp, rev)
+ DB *dbp;
+ int rev;
+{
+ DBT key, data;
+ int flags, nflags;
+
+ if (rev) {
+ flags = R_LAST;
+ nflags = R_PREV;
+ } else {
+ flags = R_FIRST;
+ nflags = R_NEXT;
+ }
+ for (;; flags = nflags)
+ switch (dbp->seq(dbp, &key, &data, flags)) {
+ 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(*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(flags)
+ int flags;
+{
+ switch (flags) {
+ 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(type, s)
+ DBTYPE 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(*eq))
+ err("%s: structure set statement must be a number", s);
+
+ switch (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(*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);
+}
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void
+#if __STDC__
+err(const char *fmt, ...)
+#else
+err(fmt, va_alist)
+ char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+#if __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/src/util/db2/test/hash1.tests/Makefile b/src/util/db2/test/hash1.tests/Makefile
new file mode 100644
index 0000000000..348a8f818b
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/test/hash1.tests/driver2.c b/src/util/db2/test/hash1.tests/driver2.c
new file mode 100644
index 0000000000..074f9eae06
--- /dev/null
+++ b/src/util/db2/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, 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/src/util/db2/test/hash1.tests/makedb.sh b/src/util/db2/test/hash1.tests/makedb.sh
new file mode 100644
index 0000000000..15901de193
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/test/hash1.tests/tcreat3.c b/src/util/db2/test/hash1.tests/tcreat3.c
new file mode 100644
index 0000000000..3aaab99cbf
--- /dev/null
+++ b/src/util/db2/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, 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/src/util/db2/test/hash1.tests/tdel.c b/src/util/db2/test/hash1.tests/tdel.c
new file mode 100644
index 0000000000..b542d8ef3d
--- /dev/null
+++ b/src/util/db2/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, 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/src/util/db2/test/hash1.tests/testit b/src/util/db2/test/hash1.tests/testit
new file mode 100644
index 0000000000..c80dc4e69b
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/test/hash1.tests/thash4.c b/src/util/db2/test/hash1.tests/thash4.c
new file mode 100644
index 0000000000..b0d4b42e36
--- /dev/null
+++ b/src/util/db2/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, 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/src/util/db2/test/hash1.tests/tread2.c b/src/util/db2/test/hash1.tests/tread2.c
new file mode 100644
index 0000000000..44acaa93dd
--- /dev/null
+++ b/src/util/db2/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, 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/src/util/db2/test/hash1.tests/tseq.c b/src/util/db2/test/hash1.tests/tseq.c
new file mode 100644
index 0000000000..5eee5de61c
--- /dev/null
+++ b/src/util/db2/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, 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/src/util/db2/test/hash1.tests/tverify.c b/src/util/db2/test/hash1.tests/tverify.c
new file mode 100644
index 0000000000..a5a5dfd183
--- /dev/null
+++ b/src/util/db2/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, 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/src/util/db2/test/hash2.tests/README b/src/util/db2/test/hash2.tests/README
new file mode 100644
index 0000000000..f29ccf7e1b
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/test/hash2.tests/bigtest.c b/src/util/db2/test/hash2.tests/bigtest.c
new file mode 100644
index 0000000000..e6d4108b72
--- /dev/null
+++ b/src/util/db2/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, 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/src/util/db2/test/hash2.tests/passtest.c b/src/util/db2/test/hash2.tests/passtest.c
new file mode 100644
index 0000000000..d6277ca52d
--- /dev/null
+++ b/src/util/db2/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, 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, 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, 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, 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/src/util/db2/test/hash2.tests/passwd/genpass.c b/src/util/db2/test/hash2.tests/passwd/genpass.c
new file mode 100644
index 0000000000..da37676878
--- /dev/null
+++ b/src/util/db2/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/src/util/db2/test/run.test b/src/util/db2/test/run.test
new file mode 100644
index 0000000000..393aedcad2
--- /dev/null
+++ b/src/util/db2/test/run.test
@@ -0,0 +1,717 @@
+#!/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
+ else
+ echo 'run.test: no dictionary'
+ exit 1
+ fi
+
+ 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
+}
+
+# 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"
+ sed 200q $DICT > $TMP1
+ for type in btree hash; do
+ rm -f $TMP2 $TMP3
+ for i in `sed 200q $DICT`; 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
+ sed 200q $DICT |
+ awk '{
+ ++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 "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 `sed 200q $DICT`; 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 /bin with their paths as their keys.
+test3()
+{
+ echo "Test 3: hash: small key, big data pairs"
+ rm -f $TMP1
+ (find /bin -type f -exec test -r {} \; -print | xargs cat) > $TMP1
+ for type in hash; do
+ rm -f $TMP2 $TMP3
+ for i in `find /bin -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 /bin -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 /bin -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, hash: 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
+ $PROG btree $TMP1
+# $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
+ 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 `sed 20000q $DICT | 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"
+ sed 50q $DICT > $TMP1
+ for order in 1234 4321; do
+ for type in btree hash; do
+ rm -f byte.file $TMP2 $TMP3
+ for i in `sed 50q $DICT`; 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 `sed 50q $DICT`; 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()
+{
+ 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
+ sed 10000q $DICT |
+ 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
+ sed 10000q $DICT |
+ 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/src/util/dyn/ChangeLog b/src/util/dyn/ChangeLog
new file mode 100644
index 0000000000..9fac926656
--- /dev/null
+++ b/src/util/dyn/ChangeLog
@@ -0,0 +1,13 @@
+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
+
+Tue Jul 9 19:30:40 1996 Marc Horowitz <marc@mit.edu>
+
+ * configure.in (DEPLIBS): AC_SUBST() it, to hack around an
+ incorrect assumption in aclocal.m4
+ * Makefile.in (DONE): add rules and macros to support shared
+ libraries
+
+
diff --git a/src/util/dyn/Imakefile b/src/util/dyn/Imakefile
new file mode 100644
index 0000000000..471cf5bc81
--- /dev/null
+++ b/src/util/dyn/Imakefile
@@ -0,0 +1,26 @@
+# This file is part of libdyn.a, the C Dynamic Object library. It
+# contains the Imakefile.
+#
+# 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.
+
+SRCS = dyn_create.c dyn_put.c dyn_debug.c dyn_delete.c dyn_size.c \
+ dyn_append.c dyn_realloc.c dyn_paranoid.c dyn_insert.c \
+ dyn_initzero.c
+OBJS = dyn_create.o dyn_put.o dyn_debug.o dyn_delete.o dyn_size.o \
+ dyn_append.o dyn_realloc.o dyn_paranoid.o dyn_insert.o \
+ dyn_initzero.o
+HDRS = dyn.h dynP.h
+
+DEST = libdyn.a
+
+StageLibrary($(DEST), $(OBJS))
+StageIncludes(dyn.h,)
+
+Program(test, test.o, $(DEST), $(DEST))
+
+Depend(,, $(SRCS) $(HDRS))
diff --git a/src/util/dyn/Makefile.in b/src/util/dyn/Makefile.in
new file mode 100644
index 0000000000..e2c4255bd8
--- /dev/null
+++ b/src/util/dyn/Makefile.in
@@ -0,0 +1,65 @@
+CFLAGS = $(CCOPTS) $(DEFS)
+
+##DOSBUILDTOP = ..\..
+##DOSLIBNAME=libdyn.lib
+
+.c.o:
+ $(CC) $(CFLAGS) -c $(srcdir)/$*.c
+@SHARED_RULE@
+
+SRCS = $(srcdir)/dyn_create.c \
+ $(srcdir)/dyn_put.c \
+ $(srcdir)/dyn_debug.c \
+ $(srcdir)/dyn_delete.c \
+ $(srcdir)/dyn_size.c \
+ $(srcdir)/dyn_append.c \
+ $(srcdir)/dyn_realloc.c \
+ $(srcdir)/dyn_paranoid.c \
+ $(srcdir)/dyn_insert.c \
+ $(srcdir)/dyn_initzero.c
+
+OBJS = dyn_create.$(OBJEXT) \
+ dyn_put.$(OBJEXT) \
+ dyn_debug.$(OBJEXT) \
+ dyn_delete.$(OBJEXT) \
+ dyn_size.$(OBJEXT) \
+ dyn_append.$(OBJEXT) \
+ dyn_realloc.$(OBJEXT) \
+ dyn_paranoid.$(OBJEXT) \
+ dyn_insert.$(OBJEXT) \
+ dyn_initzero.$(OBJEXT)
+
+LIB_SUBDIRS= .
+LIBDONE= DONE
+
+all-unix:: shared includes $(OBJS)
+all-mac:: $(OBJS)
+all-windows:: $(OBJS)
+
+shared:
+ mkdir shared
+
+check-windows::
+
+clean-unix::
+ $(RM) shared/*
+
+clean-mac::
+clean-windows::
+
+DONE:: $(OBJS)
+ $(RM) DONE
+ echo $(OBJS) >DONE
+
+libdyn.$(STEXT): $(OBJS)
+ $(RM) $@
+ $(ARADD) $@ $(OBJS)
+ $(RANLIB) $@
+
+install:: libdyn.a
+ $(INSTALL_DATA) libdyn.a $(DESTDIR)$(KRB5_LIBDIR)/libdyn.a
+ $(RANLIB) $(DESTDIR)$(KRB5_LIBDIR)/libdyn.a
+
+clean::
+ $(RM) libdyn.$(LIBEXT) libdyn.bak DONE
+
diff --git a/src/util/dyn/README b/src/util/dyn/README
new file mode 100644
index 0000000000..0c08ac5c62
--- /dev/null
+++ b/src/util/dyn/README
@@ -0,0 +1,32 @@
+libdyn.a -- Release 1.0
+
+A C Dynamic Object is an array that takes care of resizing itself as
+elements are added and deleted from it. It can be of any type for
+which sizeof is defined and for which an address of a variable of that
+type can be passed to a function.
+
+To build libdyn.a, simply type "make depend all" (if you don't have
+the program makedepend, of course, leave out the "depend" part). If
+your system's bcopy() cannot handle overlapping regions, you'll need
+to write one that can. (Left as an excercise for the reader..)
+
+The library should compile and work without modification on a vast
+number of systems. It only uses 5 external functions: malloc,
+realloc, free, bcopy, and fprintf (to stderr). Of these, only bcopy
+should need to be changed for other systems (such as MS-DOS) and it
+could probably be done with a -D flag to the compiler.
+
+The test/demo program is built by "make all". This program produces
+the library's debugging output (to stderr) as well as some of its own
+output (to stdout).
+
+The library has been tested (with test.c) on a VAX VSII, VAXstation
+3100, DECstation 3100, and IBM RT all running BSD4.3 (except for the
+DECstation, which was running Ultrix V2.1).
+
+An earlier version of this library was posted to alt.sources. This
+version contains one new function (DynInsert) and slightly cleaner
+code, but no bugfixes (no bugs were found).
+
+Author: Barr3y Jaspan, Student Information Processing Board (SIPB) and
+MIT-Project Athena, bjaspan@athena.mit.edu, 1990
diff --git a/src/util/dyn/TODO b/src/util/dyn/TODO
new file mode 100644
index 0000000000..d5a242b981
--- /dev/null
+++ b/src/util/dyn/TODO
@@ -0,0 +1,3 @@
+o be able to get obj->size
+o be able to get array without DynAdd (so you can just use DynPut)
+o be able to specify bzero on realloc
diff --git a/src/util/dyn/configure.in b/src/util/dyn/configure.in
new file mode 100644
index 0000000000..6ba8e6d24a
--- /dev/null
+++ b/src/util/dyn/configure.in
@@ -0,0 +1,14 @@
+AC_INIT(dyn.h)
+CONFIG_RULES
+AC_PROG_ARCHIVE
+AC_PROG_ARCHIVE_ADD
+AC_PROG_RANLIB
+AC_PROG_INSTALL
+AC_CHECK_FUNCS(memmove)
+V5_SHARED_LIB_OBJS
+V5_MAKE_SHARED_LIB(libdyn,1.0,../../lib, ../util/dyn)
+dnl DEPLIBS is normally set by KRB5_LIBRARIES, but that makes assumptions
+dnl which fail for libdyn.
+AC_SUBST(DEPLIBS)
+CopySrcHeader(dyn.h,[$](BUILDTOP)/include)
+V5_AC_OUTPUT_MAKEFILE
diff --git a/src/util/dyn/dyn.3m b/src/util/dyn/dyn.3m
new file mode 100644
index 0000000000..21ae70bb2f
--- /dev/null
+++ b/src/util/dyn/dyn.3m
@@ -0,0 +1,198 @@
+
+
+
+15 March 1990 DYN(3M)
+
+
+
+NAME
+ dyn - the C Dynamic Object library
+
+
+DESCRIPTION
+ A C Dynamic Object is an array that takes care of resizing
+ itself as you add and delete elements from it. It can be of
+ any type for which sizeof is defined and for which an
+ address of a variable of that type can be passed to a func-
+ tion. The library containing the functions described below
+ is called _l_i_b_d_y_n._a, and the necessary declarations to use
+ them are in <_d_y_n._h>.
+
+ A DynObject is actually a structure that contains an array
+ and a couple of integers to maintain necessary state infor-
+ mation. When a Dyn function is said to operate on "the
+ object" or "the array", it is operating on the array stored
+ in the structure while at the same time updating internal
+ state information.
+
+
+LIST OF FUNCTIONS
+ DynObject DynCreate(size, increment)
+ int size, increment;
+
+ _R_e_q_u_i_r_e_s: _s_i_z_e and _i_n_c_r_e_m_e_n_t are greater than zero.
+
+ _E_f_f_e_c_t_s: Creates a new DynObject that will store elements of
+ size _s_i_z_e and will allocate memory in blocks large enough to
+ hold exactly _i_n_c_r_e_m_e_n_t elements. For example, if you are
+ storing 8-byte double precision numbers and _i_n_c_r_e_m_e_n_t is 5,
+ each 5th element you add to the object will cause it to
+ request 40 more bytes (8 * 5) from the operating system. If
+ _i_n_c_r_e_m_e_n_t is zero, a default value is used (currently 100).
+ This is the only time the programmer deals with a dynamic
+ object's memory allocation.
+
+ _R_e_t_u_r_n_s: DynCreate returns the new DynObject, or NULL if
+ there is insufficient memory.
+
+ int DynDestroy(obj)
+ DynObject obj;
+
+ _M_o_d_i_f_i_e_s: obj
+
+ _E_f_f_e_c_t_s: Frees all memory associated with _o_b_j. The results
+ of calling any Dyn function on a destroyed object are unde-
+ fined (except for DynCreate, which resets the object).
+
+ _R_e_t_u_r_n_s: DynDestroy returns DYN_OK.
+
+
+
+
+
+ 1
+
+
+
+
+
+
+DYN(3M) 15 March 1990
+
+
+
+ int DynAdd(obj, el)
+ DynObject obj;
+ DynPtr el;
+
+ _M_o_d_i_f_i_e_s: obj
+
+ _E_f_f_e_c_t_s: Adds the element pointed to by _e_l to the object
+ _o_b_j, resizing the object if necessary. The new element
+ becomes the last element in obj's array.
+
+ _R_e_t_u_r_n_s: DynAdd returns DYN_OK on success or DYN_NOMEM if
+ there is insufficient memory.
+
+ int DynInsert(obj, index, els, num)
+ DynObject obj;
+ DynPtr els;
+ int index, num;
+
+ _M_o_d_i_f_i_e_s: obj
+
+ _E_f_f_e_c_t_s: Inserts the array of _n_u_m elements, pointed to by
+ _e_l_s, into the object _o_b_j starting at the array location
+ _i_n_d_e_x, resizing the object if necessary. Order is
+ preserved; if you have the array "1 2 3 4 5" and insert "10
+ 11 12" at the third position, you will have the array "1 2
+ 10 11 12 3 4 5".
+
+ _R_e_t_u_r_n_s: DynInsert returns DYN_BADINDEX if _i_n_d_e_x is not
+ between 0 and DynSize(obj); DYN_BADVALUE if _n_u_m is less than
+ 1; DYN_NOMEM if there is insufficient memory.
+
+ int DynGet(obj, index)
+ DynObject obj;
+ int index;
+
+ _E_f_f_e_c_t_s: Returns the address of the element _i_n_d_e_x in the
+ array of _o_b_j. This pointer can be treated as a normal array
+ of the type specified to DynCreate. The order of elements
+ in this array is the order in which they were added to the
+ object. The returned pointer is guaranteed to be valid only
+ until obj is modified.
+
+ _R_e_t_u_r_n_s: DynGet returns NULL if _i_n_d_e_x is larger than the
+ number of elements in the array of less than zero.
+
+ int DynDelete(obj, index)
+ DynObject obj;
+ int index;
+
+ _M_o_d_i_f_i_e_s: obj
+
+
+
+
+
+2
+
+
+
+
+
+
+15 March 1990 DYN(3M)
+
+
+
+ _E_f_f_e_c_t_s: The element _i_n_d_e_x is deleted from the object _o_b_j.
+ Note that the element is actually removed permanently from
+ the array. If you have the array "1 2 3 4 5" and delete the
+ third element, you will have the array "1 2 4 5". The order
+ of elements in not affected.
+
+ _R_e_t_u_r_n_s: DynDelete will return DYN_OK on success or
+ DYN_BADINDEX if the element _i_n_d_e_x does not exist in the
+ array or is less than zero.
+
+ int DynSize(obj)
+ DynObject obj;
+
+ _E_f_f_e_c_t_s: Returns the number of elements in the object _o_b_j.
+
+ int DynHigh(obj)
+ DynObject obj;
+
+ _E_f_f_e_c_t_s: Returns the index of the highest element in the
+ object _o_b_j. In this version, DynHigh is macro that expands
+ to DynSize - 1.
+
+ int DynLow(obj)
+ DynObject obj;
+
+ _E_f_f_e_c_t_s: Returns the index of the lowest element in the
+ object _o_b_j. In this version, DynLow is macro that expands
+ to 0.
+
+ int DynDebug(obj, state)
+ DynObject obj;
+ int state;
+
+ _M_o_d_i_f_i_e_s: obj
+
+ _E_f_f_e_c_t_s: Sets the debugging state of _o_b_j to _s_t_a_t_e and prints
+ a message on stderr saying what state debugging was set to.
+ Any non-zero value for _s_t_a_t_e turns debugging ``on''. When
+ debugging is on, all Dyn functions will produce (hopefully
+ useful) output to stderr describing what is going on.
+
+ _R_e_t_u_r_n_s: DynDebug returns DYN_OK.
+
+AUTHOR
+ Barr3y Jaspan, Student Information Processing Board (SIPB)
+ and MIT-Project Athena, bjaspan@athena.mit.edu
+
+
+
+
+
+
+
+
+
+ 3
+
+
+
diff --git a/src/util/dyn/dyn_append.c b/src/util/dyn/dyn_append.c
new file mode 100644
index 0000000000..81403ece70
--- /dev/null
+++ b/src/util/dyn/dyn_append.c
@@ -0,0 +1,26 @@
+/*
+ * This file is part of libdyn.a, the C Dynamic Object library. It
+ * contains the source code for the function DynAppend().
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+
+#include "dynP.h"
+
+/*
+ * 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);
+}
diff --git a/src/util/dyn/dyn_initzero.c b/src/util/dyn/dyn_initzero.c
new file mode 100644
index 0000000000..3949f30ec4
--- /dev/null
+++ b/src/util/dyn/dyn_initzero.c
@@ -0,0 +1,26 @@
+/*
+ * This file is part of libdyn.a, the C Dynamic Object library. It
+ * contains the source code for the function DynInitZero().
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+
+#include "dynP.h"
+
+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;
+}
diff --git a/src/util/dyn/dyn_insert.c b/src/util/dyn/dyn_insert.c
new file mode 100644
index 0000000000..5654e935d1
--- /dev/null
+++ b/src/util/dyn/dyn_insert.c
@@ -0,0 +1,70 @@
+/*
+ * This file is part of libdyn.a, the C Dynamic Object library. It
+ * contains the source code for the function DynInsert().
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include "dynP.h"
+
+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 %d + %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,
+ (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 %d to %d + %d\n",
+ obj->el_size*num, els, obj->array, obj->el_size*idx);
+
+#ifdef HAVE_MEMMOVE
+ memmove(obj->array + obj->el_size*idx, els, 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;
+}
diff --git a/src/util/dyn/dyn_paranoid.c b/src/util/dyn/dyn_paranoid.c
new file mode 100644
index 0000000000..7eb750a21a
--- /dev/null
+++ b/src/util/dyn/dyn_paranoid.c
@@ -0,0 +1,26 @@
+/*
+ * This file is part of libdyn.a, the C Dynamic Object library. It
+ * contains the source code for the function DynDebug().
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+
+#include "dynP.h"
+
+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;
+}
diff --git a/src/util/dyn/dyn_realloc.c b/src/util/dyn/dyn_realloc.c
new file mode 100644
index 0000000000..31e3975b57
--- /dev/null
+++ b/src/util/dyn/dyn_realloc.c
@@ -0,0 +1,88 @@
+/*
+ * This file is part of libdyn.a, the C Dynamic Object library. It
+ * contains the source code for the internal function _DynRealloc().
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "dynP.h"
+
+/*
+ * Resize the array so that element req exists.
+ */
+int _DynResize(obj, req)
+ DynObjectP obj;
+ int req;
+{
+ int cnt, 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;
+
+ while (size <= req)
+ size <<= 1;
+
+ 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, 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;
+}
diff --git a/src/util/et/ChangeLog b/src/util/et/ChangeLog
index 34cc96338a..233b5b9d7a 100644
--- a/src/util/et/ChangeLog
+++ b/src/util/et/ChangeLog
@@ -14,6 +14,10 @@ Mon Jun 10 21:54:09 1996 Theodore Ts'o <tytso@rsts-11.mit.edu>
* 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
diff --git a/src/util/et/et_c.awk b/src/util/et/et_c.awk
index 8067e71905..ac1321cd06 100644
--- a/src/util/et/et_c.awk
+++ b/src/util/et/et_c.awk
@@ -120,7 +120,18 @@ c2n["_"]=63
table_item_count = 0
}
+(continuation == 1) && ($0 ~ /\\[ \t]*$/) {
+ text=substr($0,1,length($0)-1);
+ printf "\t\t\"%s\"\n", text > outfile
+}
+
+(continuation == 1) && ($0 ~ /"[ \t]*$/) {
+ printf "\t\t\"%s,\n", $0 > outfile
+ continuation = 0;
+}
+
/^[ \t]*(error_code|ec)[ \t]+[A-Z_0-9]+,[ \t]*$/ {
+ table_item_count++
skipone=1
next
}
@@ -135,10 +146,28 @@ c2n["_"]=63
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
+ continuation++;
+}
+
+/^[ \t]*".*\\[ \t]*$/ {
+ if (skipone) {
+ text=substr($0,1,length($0)-1);
+ printf "\t%s\"\n", text > outfile
+ continuation++;
+ }
+ skipone=0
+}
+
{
if (skipone) {
printf "\t%s,\n", $0 > outfile
- table_item_count++
}
skipone=0
}