]> git.sur5r.net Git - openldap/commitdiff
Initial revision
authorKurt Zeilenga <kurt@openldap.org>
Sun, 9 Aug 1998 00:43:13 +0000 (00:43 +0000)
committerKurt Zeilenga <kurt@openldap.org>
Sun, 9 Aug 1998 00:43:13 +0000 (00:43 +0000)
644 files changed:
ANNOUNCEMENT [new file with mode: 0644]
CHANGES [new file with mode: 0644]
COPYRIGHT [new file with mode: 0644]
INSTALL [new file with mode: 0644]
Make-common [new file with mode: 0644]
Make-common.um [new file with mode: 0644]
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
build/Make-append [new file with mode: 0644]
build/Make-template [new file with mode: 0644]
build/PORTS [new file with mode: 0644]
build/README-unproto [new file with mode: 0644]
build/db.1.85.patch [new file with mode: 0644]
build/install.sh [new file with mode: 0755]
build/mkdep [new file with mode: 0755]
build/platforms/Make-setup [new file with mode: 0644]
build/platforms/Makefile [new file with mode: 0644]
build/platforms/aix-cc/Make-platform [new file with mode: 0644]
build/platforms/aix-gcc/Make-platform [new file with mode: 0644]
build/platforms/freebsd-gcc/Make-platform [new file with mode: 0644]
build/platforms/hpux-c89/Make-platform [new file with mode: 0644]
build/platforms/hpux-cc/Make-platform [new file with mode: 0644]
build/platforms/hpux-gcc/Make-platform [new file with mode: 0644]
build/platforms/irix-cc/Make-platform [new file with mode: 0644]
build/platforms/irix-gcc/Make-platform [new file with mode: 0644]
build/platforms/linux-gcc/Make-platform [new file with mode: 0644]
build/platforms/ncr-mp-ras-2-cc/Make-platform [new file with mode: 0644]
build/platforms/netbsd-cc/Make-platform [new file with mode: 0644]
build/platforms/netbsd-gcc/Make-platform [new file with mode: 0644]
build/platforms/nextstep-cc/Make-platform [new file with mode: 0644]
build/platforms/osf1-cc/Make-platform [new file with mode: 0644]
build/platforms/sco-cc/Make-platform [new file with mode: 0644]
build/platforms/sco-gcc/Make-platform [new file with mode: 0644]
build/platforms/sunos4-cc/Make-platform [new file with mode: 0644]
build/platforms/sunos4-gcc/Make-platform [new file with mode: 0644]
build/platforms/sunos5-cc/Make-platform [new file with mode: 0644]
build/platforms/sunos5-gcc/Make-platform [new file with mode: 0644]
build/platforms/ultrix-cc/Make-platform [new file with mode: 0644]
build/platforms/ultrix-gcc/Make-platform [new file with mode: 0644]
build/platforms/vms/Makefile [new file with mode: 0644]
build/platforms/vms/make.com [new file with mode: 0644]
build/uname.sh [new file with mode: 0644]
build/unproto/Makefile [new file with mode: 0644]
build/unproto/README [new file with mode: 0644]
build/unproto/acc.sh [new file with mode: 0755]
build/unproto/cpp.sh [new file with mode: 0755]
build/unproto/error.c [new file with mode: 0644]
build/unproto/error.h [new file with mode: 0644]
build/unproto/example.c [new file with mode: 0644]
build/unproto/example.out [new file with mode: 0644]
build/unproto/hash.c [new file with mode: 0644]
build/unproto/stdarg.h [new file with mode: 0644]
build/unproto/stddef.h [new file with mode: 0644]
build/unproto/stdlib.h [new file with mode: 0644]
build/unproto/strsave.c [new file with mode: 0644]
build/unproto/symbol.c [new file with mode: 0644]
build/unproto/symbol.h [new file with mode: 0644]
build/unproto/tok_class.c [new file with mode: 0644]
build/unproto/tok_io.c [new file with mode: 0644]
build/unproto/tok_pool.c [new file with mode: 0644]
build/unproto/token.h [new file with mode: 0644]
build/unproto/unproto.1 [new file with mode: 0644]
build/unproto/unproto.c [new file with mode: 0644]
build/unproto/varargs.c [new file with mode: 0644]
build/unproto/vstring.c [new file with mode: 0644]
build/unproto/vstring.h [new file with mode: 0644]
build/version [new file with mode: 0644]
clients/Make-template [new file with mode: 0644]
clients/fax500/Make-template [new file with mode: 0644]
clients/fax500/README [new file with mode: 0644]
clients/fax500/Version.c [new file with mode: 0644]
clients/fax500/Versionrp.c [new file with mode: 0644]
clients/fax500/faxtotpc.c [new file with mode: 0644]
clients/fax500/main.c [new file with mode: 0644]
clients/fax500/rp500.c [new file with mode: 0644]
clients/fax500/xrpcomp [new file with mode: 0644]
clients/finger/Make-template [new file with mode: 0644]
clients/finger/Version.c [new file with mode: 0644]
clients/finger/main.c [new file with mode: 0644]
clients/gopher/Make-template [new file with mode: 0644]
clients/gopher/README [new file with mode: 0644]
clients/gopher/Version.c [new file with mode: 0644]
clients/gopher/Versiongw.c [new file with mode: 0644]
clients/gopher/detach.c [new file with mode: 0644]
clients/gopher/go500.c [new file with mode: 0644]
clients/gopher/go500gw.c [new file with mode: 0644]
clients/gopher/go500gw.help [new file with mode: 0644]
clients/gopher/setproctitle.c [new file with mode: 0644]
clients/mail500/Make-template [new file with mode: 0644]
clients/mail500/README [new file with mode: 0644]
clients/mail500/Version.c [new file with mode: 0644]
clients/mail500/main.c [new file with mode: 0644]
clients/mail500/sendmail.cf [new file with mode: 0644]
clients/rcpt500/Make-template [new file with mode: 0644]
clients/rcpt500/README [new file with mode: 0644]
clients/rcpt500/Version.c [new file with mode: 0644]
clients/rcpt500/cmds.c [new file with mode: 0644]
clients/rcpt500/help.c [new file with mode: 0644]
clients/rcpt500/main.c [new file with mode: 0644]
clients/rcpt500/query.c [new file with mode: 0644]
clients/rcpt500/rcpt500.h [new file with mode: 0644]
clients/rcpt500/rcpt500.help [new file with mode: 0644]
clients/tools/Make-template [new file with mode: 0644]
clients/tools/Versionldd.c [new file with mode: 0644]
clients/tools/Versionldm.c [new file with mode: 0644]
clients/tools/Versionldr.c [new file with mode: 0644]
clients/tools/Versionlds.c [new file with mode: 0644]
clients/tools/ldapdelete.c [new file with mode: 0644]
clients/tools/ldapmodify.c [new file with mode: 0644]
clients/tools/ldapmodrdn.c [new file with mode: 0644]
clients/tools/ldapsearch.c [new file with mode: 0644]
clients/ud/Make-template [new file with mode: 0644]
clients/ud/README [new file with mode: 0644]
clients/ud/Version.c [new file with mode: 0644]
clients/ud/auth.c [new file with mode: 0644]
clients/ud/edit.c [new file with mode: 0644]
clients/ud/etc.ud.conf [new file with mode: 0644]
clients/ud/find.c [new file with mode: 0644]
clients/ud/globals.c [new file with mode: 0644]
clients/ud/group.c [new file with mode: 0644]
clients/ud/help.c [new file with mode: 0644]
clients/ud/main.c [new file with mode: 0644]
clients/ud/mod.c [new file with mode: 0644]
clients/ud/print.c [new file with mode: 0644]
clients/ud/string_to_key.c [new file with mode: 0644]
clients/ud/ud.h [new file with mode: 0644]
clients/ud/util.c [new file with mode: 0644]
contrib/README [new file with mode: 0644]
contrib/saucer/Make-template [new file with mode: 0644]
contrib/saucer/README [new file with mode: 0644]
contrib/saucer/main.c [new file with mode: 0644]
contrib/saucer/sample.saucerrc [new file with mode: 0644]
contrib/saucer/saucer.1 [new file with mode: 0644]
contrib/web500gw/README [new file with mode: 0644]
contrib/whois++/BUGS [new file with mode: 0644]
contrib/whois++/INSTALL [new file with mode: 0644]
contrib/whois++/Makefile [new file with mode: 0644]
contrib/whois++/README [new file with mode: 0644]
contrib/whois++/TODO [new file with mode: 0644]
contrib/whois++/command.c [new file with mode: 0644]
contrib/whois++/config.c [new file with mode: 0644]
contrib/whois++/describe.c [new file with mode: 0644]
contrib/whois++/help.c [new file with mode: 0644]
contrib/whois++/helpfiles/english/command [new file with mode: 0644]
contrib/whois++/helpfiles/english/commands [new file with mode: 0644]
contrib/whois++/helpfiles/english/constraints [new file with mode: 0644]
contrib/whois++/helpfiles/english/describe [new file with mode: 0644]
contrib/whois++/helpfiles/english/general [new file with mode: 0644]
contrib/whois++/helpfiles/english/help [new file with mode: 0644]
contrib/whois++/helpfiles/english/list [new file with mode: 0644]
contrib/whois++/helpfiles/english/search [new file with mode: 0644]
contrib/whois++/helpfiles/english/show [new file with mode: 0644]
contrib/whois++/helpfiles/english/version [new file with mode: 0644]
contrib/whois++/output.c [new file with mode: 0644]
contrib/whois++/root.Makefile.diff [new file with mode: 0644]
contrib/whois++/template.c [new file with mode: 0644]
contrib/whois++/templates/applicationentity [new file with mode: 0644]
contrib/whois++/templates/organizationalrole [new file with mode: 0644]
contrib/whois++/templates/organizationalunit [new file with mode: 0644]
contrib/whois++/templates/person [new file with mode: 0644]
contrib/whois++/util.c [new file with mode: 0644]
contrib/whois++/version.c [new file with mode: 0644]
contrib/whois++/whois++.c [new file with mode: 0644]
contrib/whois++/whois++.h [new file with mode: 0644]
contrib/whois++/whois++d.man [new file with mode: 0644]
contrib/whois++/whois++dtailor [new file with mode: 0644]
doc/Make-template [new file with mode: 0644]
doc/guides/Make-template [new file with mode: 0644]
doc/man/Make-template [new file with mode: 0644]
doc/man/man1/Make-template [new file with mode: 0644]
doc/man/man1/ldapdelete.1 [new file with mode: 0644]
doc/man/man1/ldapmodify.1 [new file with mode: 0644]
doc/man/man1/ldapmodify.1.links [new file with mode: 0644]
doc/man/man1/ldapmodrdn.1 [new file with mode: 0644]
doc/man/man1/ldapsearch.1 [new file with mode: 0644]
doc/man/man1/ud.1 [new file with mode: 0644]
doc/man/man3/Make-template [new file with mode: 0644]
doc/man/man3/cldap_close.3 [new file with mode: 0644]
doc/man/man3/cldap_open.3 [new file with mode: 0644]
doc/man/man3/cldap_search_s.3 [new file with mode: 0644]
doc/man/man3/cldap_setretryinfo.3 [new file with mode: 0644]
doc/man/man3/lber-decode.3 [new file with mode: 0644]
doc/man/man3/lber-encode.3 [new file with mode: 0644]
doc/man/man3/ldap.3 [new file with mode: 0644]
doc/man/man3/ldap.3.links [new file with mode: 0644]
doc/man/man3/ldap_abandon.3 [new file with mode: 0644]
doc/man/man3/ldap_add.3 [new file with mode: 0644]
doc/man/man3/ldap_add.3.links [new file with mode: 0644]
doc/man/man3/ldap_bind.3 [new file with mode: 0644]
doc/man/man3/ldap_bind.3.links [new file with mode: 0644]
doc/man/man3/ldap_cache.3 [new file with mode: 0644]
doc/man/man3/ldap_cache.3.links [new file with mode: 0644]
doc/man/man3/ldap_charset.3 [new file with mode: 0644]
doc/man/man3/ldap_charset.3.links [new file with mode: 0644]
doc/man/man3/ldap_compare.3 [new file with mode: 0644]
doc/man/man3/ldap_compare.3.links [new file with mode: 0644]
doc/man/man3/ldap_delete.3 [new file with mode: 0644]
doc/man/man3/ldap_delete.3.links [new file with mode: 0644]
doc/man/man3/ldap_disptmpl.3 [new file with mode: 0644]
doc/man/man3/ldap_disptmpl.3.links [new file with mode: 0644]
doc/man/man3/ldap_entry2text.3 [new file with mode: 0644]
doc/man/man3/ldap_entry2text.3.links [new file with mode: 0644]
doc/man/man3/ldap_error.3 [new file with mode: 0644]
doc/man/man3/ldap_error.3.links [new file with mode: 0644]
doc/man/man3/ldap_first_attribute.3 [new file with mode: 0644]
doc/man/man3/ldap_first_attribute.3.links [new file with mode: 0644]
doc/man/man3/ldap_first_entry.3 [new file with mode: 0644]
doc/man/man3/ldap_first_entry.3.links [new file with mode: 0644]
doc/man/man3/ldap_friendly.3 [new file with mode: 0644]
doc/man/man3/ldap_friendly.3.links [new file with mode: 0644]
doc/man/man3/ldap_get_dn.3 [new file with mode: 0644]
doc/man/man3/ldap_get_dn.3.links [new file with mode: 0644]
doc/man/man3/ldap_get_values.3 [new file with mode: 0644]
doc/man/man3/ldap_get_values.3.links [new file with mode: 0644]
doc/man/man3/ldap_getfilter.3 [new file with mode: 0644]
doc/man/man3/ldap_getfilter.3.links [new file with mode: 0644]
doc/man/man3/ldap_modify.3 [new file with mode: 0644]
doc/man/man3/ldap_modify.3.links [new file with mode: 0644]
doc/man/man3/ldap_modrdn.3 [new file with mode: 0644]
doc/man/man3/ldap_modrdn.3.links [new file with mode: 0644]
doc/man/man3/ldap_open.3 [new file with mode: 0644]
doc/man/man3/ldap_open.3.links [new file with mode: 0644]
doc/man/man3/ldap_result.3 [new file with mode: 0644]
doc/man/man3/ldap_result.3.links [new file with mode: 0644]
doc/man/man3/ldap_search.3 [new file with mode: 0644]
doc/man/man3/ldap_search.3.links [new file with mode: 0644]
doc/man/man3/ldap_searchprefs.3 [new file with mode: 0644]
doc/man/man3/ldap_searchprefs.3.links [new file with mode: 0644]
doc/man/man3/ldap_sort.3 [new file with mode: 0644]
doc/man/man3/ldap_sort.3.links [new file with mode: 0644]
doc/man/man3/ldap_ufn.3 [new file with mode: 0644]
doc/man/man3/ldap_ufn.3.links [new file with mode: 0644]
doc/man/man3/ldap_url.3 [new file with mode: 0644]
doc/man/man3/ldap_url.3.links [new file with mode: 0644]
doc/man/man3/regex.3 [new file with mode: 0644]
doc/man/man5/Make-template [new file with mode: 0644]
doc/man/man5/ldapfilter.conf.5 [new file with mode: 0644]
doc/man/man5/ldapfriendly.5 [new file with mode: 0644]
doc/man/man5/ldapsearchprefs.conf.5 [new file with mode: 0644]
doc/man/man5/ldaptemplates.conf.5 [new file with mode: 0644]
doc/man/man5/ldif.5 [new file with mode: 0644]
doc/man/man5/slapd.conf.5 [new file with mode: 0644]
doc/man/man5/slapd.replog.5 [new file with mode: 0644]
doc/man/man5/ud.conf.5 [new file with mode: 0644]
doc/man/man8/Make-template [new file with mode: 0644]
doc/man/man8/centipede.8 [new file with mode: 0644]
doc/man/man8/chlog2replog.8 [new file with mode: 0644]
doc/man/man8/edb2ldif.8 [new file with mode: 0644]
doc/man/man8/go500.8 [new file with mode: 0644]
doc/man/man8/go500gw.8 [new file with mode: 0644]
doc/man/man8/in.xfingerd.8 [new file with mode: 0644]
doc/man/man8/ldapd.8 [new file with mode: 0644]
doc/man/man8/ldbmcat.8 [new file with mode: 0644]
doc/man/man8/ldif.8 [new file with mode: 0644]
doc/man/man8/ldif2ldbm.8 [new file with mode: 0644]
doc/man/man8/ldif2ldbm.8.links [new file with mode: 0644]
doc/man/man8/mail500.8 [new file with mode: 0644]
doc/man/man8/mail500.8.links [new file with mode: 0644]
doc/man/man8/rcpt500.8 [new file with mode: 0644]
doc/man/man8/slapd.8 [new file with mode: 0644]
doc/man/man8/slurpd.8 [new file with mode: 0644]
doc/rfc/Make-template [new file with mode: 0644]
doc/rfc/rfc1558.txt [new file with mode: 0644]
doc/rfc/rfc1777.txt [new file with mode: 0644]
doc/rfc/rfc1778.txt [new file with mode: 0644]
doc/rfc/rfc1779.txt [new file with mode: 0644]
doc/rfc/rfc1798.txt [new file with mode: 0644]
doc/rfc/rfc1823.txt [new file with mode: 0644]
include/Make-template [new file with mode: 0644]
include/avl.h [new file with mode: 0644]
include/disptmpl.h [new file with mode: 0644]
include/lber.h [new file with mode: 0644]
include/ldap.h [new file with mode: 0644]
include/ldapconfig.h.edit [new file with mode: 0644]
include/ldapconfig.h.um [new file with mode: 0644]
include/ldbm.h [new file with mode: 0644]
include/ldif.h [new file with mode: 0644]
include/lthread.h [new file with mode: 0644]
include/portable.h [new file with mode: 0644]
include/proto-lber.h [new file with mode: 0644]
include/proto-ldap.h [new file with mode: 0644]
include/regex.h [new file with mode: 0644]
include/srchpref.h [new file with mode: 0644]
include/sysexits-compat.h [new file with mode: 0644]
libraries/Make-template [new file with mode: 0644]
libraries/libavl/Make-template [new file with mode: 0644]
libraries/libavl/Version.c [new file with mode: 0644]
libraries/libavl/avl.c [new file with mode: 0644]
libraries/libavl/testavl.c [new file with mode: 0644]
libraries/liblber/Make-template [new file with mode: 0644]
libraries/liblber/Version.c [new file with mode: 0644]
libraries/liblber/bprint.c [new file with mode: 0644]
libraries/liblber/decode.c [new file with mode: 0644]
libraries/liblber/dtest.c [new file with mode: 0644]
libraries/liblber/encode.c [new file with mode: 0644]
libraries/liblber/etest.c [new file with mode: 0644]
libraries/liblber/idtest.c [new file with mode: 0644]
libraries/liblber/io.c [new file with mode: 0644]
libraries/libldap/Make-template [new file with mode: 0644]
libraries/libldap/Version.c [new file with mode: 0644]
libraries/libldap/abandon.c [new file with mode: 0644]
libraries/libldap/add.c [new file with mode: 0644]
libraries/libldap/addentry.c [new file with mode: 0644]
libraries/libldap/bind.c [new file with mode: 0644]
libraries/libldap/cache.c [new file with mode: 0644]
libraries/libldap/charset.c [new file with mode: 0644]
libraries/libldap/cldap.c [new file with mode: 0644]
libraries/libldap/compare.c [new file with mode: 0644]
libraries/libldap/delete.c [new file with mode: 0644]
libraries/libldap/disptmpl.c [new file with mode: 0644]
libraries/libldap/dsparse.c [new file with mode: 0644]
libraries/libldap/error.c [new file with mode: 0644]
libraries/libldap/free.c [new file with mode: 0644]
libraries/libldap/friendly.c [new file with mode: 0644]
libraries/libldap/getattr.c [new file with mode: 0644]
libraries/libldap/getdn.c [new file with mode: 0644]
libraries/libldap/getdxbyname.c [new file with mode: 0644]
libraries/libldap/getentry.c [new file with mode: 0644]
libraries/libldap/getfilter.c [new file with mode: 0644]
libraries/libldap/getvalues.c [new file with mode: 0644]
libraries/libldap/kbind.c [new file with mode: 0644]
libraries/libldap/ldap-int.h [new file with mode: 0644]
libraries/libldap/ldapfilter.conf [new file with mode: 0644]
libraries/libldap/ldapfriendly [new file with mode: 0644]
libraries/libldap/ldapsearchprefs.conf [new file with mode: 0644]
libraries/libldap/ldaptemplates.conf [new file with mode: 0644]
libraries/libldap/modify.c [new file with mode: 0644]
libraries/libldap/modrdn.c [new file with mode: 0644]
libraries/libldap/open.c [new file with mode: 0644]
libraries/libldap/os-ip.c [new file with mode: 0644]
libraries/libldap/regex.c [new file with mode: 0644]
libraries/libldap/request.c [new file with mode: 0644]
libraries/libldap/result.c [new file with mode: 0644]
libraries/libldap/sbind.c [new file with mode: 0644]
libraries/libldap/search.c [new file with mode: 0644]
libraries/libldap/sort.c [new file with mode: 0644]
libraries/libldap/srchpref.c [new file with mode: 0644]
libraries/libldap/test.c [new file with mode: 0644]
libraries/libldap/tmplout.c [new file with mode: 0644]
libraries/libldap/tmpltest.c [new file with mode: 0644]
libraries/libldap/ufn.c [new file with mode: 0644]
libraries/libldap/unbind.c [new file with mode: 0644]
libraries/libldap/url.c [new file with mode: 0644]
libraries/libldbm/Make-template [new file with mode: 0644]
libraries/libldbm/Version.c [new file with mode: 0644]
libraries/libldbm/ldbm.c [new file with mode: 0644]
libraries/libldif/Make-template [new file with mode: 0644]
libraries/libldif/Version.c [new file with mode: 0644]
libraries/libldif/line64.c [new file with mode: 0644]
libraries/liblthread/Make-template [new file with mode: 0644]
libraries/liblthread/Version.c [new file with mode: 0644]
libraries/liblthread/stack.c [new file with mode: 0644]
libraries/liblthread/thread.c [new file with mode: 0644]
libraries/macintosh/Make-template [new file with mode: 0644]
libraries/macintosh/README [new file with mode: 0644]
libraries/macintosh/getopt.c [new file with mode: 0644]
libraries/macintosh/kerberos-macos.c [new file with mode: 0644]
libraries/macintosh/macos-ip.c [new file with mode: 0644]
libraries/macintosh/macos.h [new file with mode: 0644]
libraries/macintosh/strings.c [new file with mode: 0644]
libraries/macintosh/tcp/AddressXlation.h [new file with mode: 0644]
libraries/macintosh/tcp/GetMyIPAddr.h [new file with mode: 0644]
libraries/macintosh/tcp/MacTCPCommonTypes.h [new file with mode: 0644]
libraries/macintosh/tcp/MiscIPPB.h [new file with mode: 0644]
libraries/macintosh/tcp/TCPPB.h [new file with mode: 0644]
libraries/macintosh/tcp/UDPPB.h [new file with mode: 0644]
libraries/macintosh/tcp/dnr.c [new file with mode: 0644]
libraries/macintosh/tcp/tcp.c [new file with mode: 0644]
libraries/macintosh/tcp/tcp.h [new file with mode: 0644]
libraries/msdos/Make-template [new file with mode: 0644]
libraries/msdos/README [new file with mode: 0644]
libraries/msdos/README.CSA [new file with mode: 0644]
libraries/msdos/README.NFS [new file with mode: 0644]
libraries/msdos/README.WSA [new file with mode: 0644]
libraries/msdos/lp.c [new file with mode: 0644]
libraries/msdos/makefile.msc [new file with mode: 0644]
libraries/msdos/makefile.nfs [new file with mode: 0644]
libraries/msdos/makelber.msc [new file with mode: 0644]
libraries/msdos/makelber.nfs [new file with mode: 0644]
libraries/msdos/makeldap.msc [new file with mode: 0644]
libraries/msdos/makeldap.nfs [new file with mode: 0644]
libraries/msdos/makeud.msc [new file with mode: 0644]
libraries/msdos/msdos.c [new file with mode: 0644]
libraries/msdos/msdos.h [new file with mode: 0644]
libraries/msdos/opendos.c [new file with mode: 0644]
libraries/msdos/protoud.h [new file with mode: 0644]
libraries/msdos/winsock/include/file.h [new file with mode: 0644]
libraries/msdos/winsock/include/filio.h [new file with mode: 0644]
libraries/msdos/winsock/include/in.h [new file with mode: 0644]
libraries/msdos/winsock/include/ioctl.h [new file with mode: 0644]
libraries/msdos/winsock/include/krb/des.h [new file with mode: 0644]
libraries/msdos/winsock/include/krb/krb.h [new file with mode: 0644]
libraries/msdos/winsock/include/krb/mit/arpa/nameser.h [new file with mode: 0644]
libraries/msdos/winsock/include/krb/mit/conf-pc.h [new file with mode: 0644]
libraries/msdos/winsock/include/krb/mit/conf.h [new file with mode: 0644]
libraries/msdos/winsock/include/krb/mit/hesiod.h [new file with mode: 0644]
libraries/msdos/winsock/include/krb/mit/lsh_pwd.h [new file with mode: 0644]
libraries/msdos/winsock/include/krb/mit/mit_copy.h [new file with mode: 0644]
libraries/msdos/winsock/include/krb/mit/osconf.h [new file with mode: 0644]
libraries/msdos/winsock/include/krb/mit/resolv.h [new file with mode: 0644]
libraries/msdos/winsock/include/krb/mit/wshelper.h [new file with mode: 0644]
libraries/msdos/winsock/include/net/_sys/filio.h [new file with mode: 0644]
libraries/msdos/winsock/include/net/_sys/ioctl.h [new file with mode: 0644]
libraries/msdos/winsock/include/net/netdb.h [new file with mode: 0644]
libraries/msdos/winsock/include/param.h [new file with mode: 0644]
libraries/msdos/winsock/include/select.h [new file with mode: 0644]
libraries/msdos/winsock/include/socket.h [new file with mode: 0644]
libraries/msdos/winsock/include/time.h [new file with mode: 0644]
libraries/msdos/winsock/include/wsa.h [new file with mode: 0644]
libraries/msdos/winsock/include/wsa/errno.c [new file with mode: 0644]
libraries/msdos/winsock/include/wsa/errno.rc [new file with mode: 0644]
libraries/msdos/winsock/include/wsa/winsock.def [new file with mode: 0644]
libraries/msdos/winsock/include/wsa/winsock.h [new file with mode: 0644]
libraries/msdos/winsock/kerberos.c [new file with mode: 0644]
libraries/msdos/winsock/ldap32.def [new file with mode: 0644]
libraries/msdos/winsock/ldap32.mak [new file with mode: 0644]
libraries/msdos/winsock/ldap32.mdp [new file with mode: 0644]
libraries/msdos/winsock/libldap.def [new file with mode: 0644]
libraries/msdos/winsock/libldap.mak [new file with mode: 0644]
libraries/msdos/winsock/libldap.rc [new file with mode: 0644]
libraries/msdos/winsock/ltest/console.c [new file with mode: 0644]
libraries/msdos/winsock/ltest/console.h [new file with mode: 0644]
libraries/msdos/winsock/ltest/inpdlg.dlg [new file with mode: 0644]
libraries/msdos/winsock/ltest/inpdlg.h [new file with mode: 0644]
libraries/msdos/winsock/ltest/ltest.def [new file with mode: 0644]
libraries/msdos/winsock/ltest/ltest.mak [new file with mode: 0644]
libraries/msdos/winsock/ltest/ltest.rc [new file with mode: 0644]
libraries/msdos/winsock/ltest/ltest32.mak [new file with mode: 0644]
libraries/msdos/winsock/ltest/ltest32.mdp [new file with mode: 0644]
libraries/msdos/winsock/ltest/textwind.c [new file with mode: 0644]
libraries/msdos/winsock/ltest/textwind.h [new file with mode: 0644]
libraries/msdos/winsock/makefile [new file with mode: 0644]
libraries/msdos/winsock/openwsa.c [new file with mode: 0644]
libraries/msdos/winsock/setupwsa.bat [new file with mode: 0644]
libraries/msdos/winsock/unsetupwsa.bat [new file with mode: 0644]
libraries/msdos/winsock/winkit/help/ldap32.hlp [new file with mode: 0644]
libraries/msdos/winsock/winkit/help/ldap32.hpj [new file with mode: 0644]
libraries/msdos/winsock/winkit/help/libldap.hlp [new file with mode: 0644]
libraries/msdos/winsock/winkit/help/libldap.hpj [new file with mode: 0644]
libraries/msdos/winsock/winkit/readme.txt [new file with mode: 0644]
libraries/msdos/winsock/winkit/windowskit.cmd [new file with mode: 0644]
libraries/msdos/winsock/winkit/windowskit.mak [new file with mode: 0644]
libraries/msdos/winsock/wsa.c [new file with mode: 0644]
libraries/msdos/winsock/wsa/errno.c [new file with mode: 0644]
libraries/msdos/winsock/wsa/errno.rc [new file with mode: 0644]
libraries/msdos/winsock/wsa/winsock.def [new file with mode: 0644]
libraries/msdos/winsock/wsa/winsock.h [new file with mode: 0644]
libraries/msdos/winsock/wsockip.c [new file with mode: 0644]
libraries/vms/Make-template [new file with mode: 0644]
libraries/vms/README.VMS [new file with mode: 0644]
libraries/vms/getopt.c [new file with mode: 0644]
libraries/vms/strings.c [new file with mode: 0644]
libraries/vms/ucx_select.h [new file with mode: 0644]
servers/Make-template [new file with mode: 0644]
servers/ldapd/Make-template [new file with mode: 0644]
servers/ldapd/Version.c [new file with mode: 0644]
servers/ldapd/abandon.c [new file with mode: 0644]
servers/ldapd/add.c [new file with mode: 0644]
servers/ldapd/association.c [new file with mode: 0644]
servers/ldapd/bind.c [new file with mode: 0644]
servers/ldapd/certificate.c [new file with mode: 0644]
servers/ldapd/common.h [new file with mode: 0644]
servers/ldapd/compare.c [new file with mode: 0644]
servers/ldapd/delete.c [new file with mode: 0644]
servers/ldapd/detach.c [new file with mode: 0644]
servers/ldapd/error.c [new file with mode: 0644]
servers/ldapd/kerberos.c [new file with mode: 0644]
servers/ldapd/ldap.py [new file with mode: 0644]
servers/ldapd/main.c [new file with mode: 0644]
servers/ldapd/message.c [new file with mode: 0644]
servers/ldapd/modify.c [new file with mode: 0644]
servers/ldapd/modrdn.c [new file with mode: 0644]
servers/ldapd/proto-ldapd.h [new file with mode: 0644]
servers/ldapd/request.c [new file with mode: 0644]
servers/ldapd/result.c [new file with mode: 0644]
servers/ldapd/search.c [new file with mode: 0644]
servers/ldapd/setproctitle.c [new file with mode: 0644]
servers/ldapd/syntax.c [new file with mode: 0644]
servers/ldapd/util.c [new file with mode: 0644]
servers/slapd/Make-template [new file with mode: 0644]
servers/slapd/Version.c [new file with mode: 0644]
servers/slapd/abandon.c [new file with mode: 0644]
servers/slapd/acl.c [new file with mode: 0644]
servers/slapd/aclparse.c [new file with mode: 0644]
servers/slapd/add.c [new file with mode: 0644]
servers/slapd/attr.c [new file with mode: 0644]
servers/slapd/ava.c [new file with mode: 0644]
servers/slapd/back-ldbm/Make-template [new file with mode: 0644]
servers/slapd/back-ldbm/Version.c [new file with mode: 0644]
servers/slapd/back-ldbm/abandon.c [new file with mode: 0644]
servers/slapd/back-ldbm/add.c [new file with mode: 0644]
servers/slapd/back-ldbm/attr.c [new file with mode: 0644]
servers/slapd/back-ldbm/back-ldbm.h [new file with mode: 0644]
servers/slapd/back-ldbm/bind.c [new file with mode: 0644]
servers/slapd/back-ldbm/cache.c [new file with mode: 0644]
servers/slapd/back-ldbm/close.c [new file with mode: 0644]
servers/slapd/back-ldbm/compare.c [new file with mode: 0644]
servers/slapd/back-ldbm/config.c [new file with mode: 0644]
servers/slapd/back-ldbm/dbcache.c [new file with mode: 0644]
servers/slapd/back-ldbm/delete.c [new file with mode: 0644]
servers/slapd/back-ldbm/dn2id.c [new file with mode: 0644]
servers/slapd/back-ldbm/filterindex.c [new file with mode: 0644]
servers/slapd/back-ldbm/id2children.c [new file with mode: 0644]
servers/slapd/back-ldbm/id2entry.c [new file with mode: 0644]
servers/slapd/back-ldbm/idl.c [new file with mode: 0644]
servers/slapd/back-ldbm/index.c [new file with mode: 0644]
servers/slapd/back-ldbm/init.c [new file with mode: 0644]
servers/slapd/back-ldbm/kerberos.c [new file with mode: 0644]
servers/slapd/back-ldbm/modify.c [new file with mode: 0644]
servers/slapd/back-ldbm/modrdn.c [new file with mode: 0644]
servers/slapd/back-ldbm/nextid.c [new file with mode: 0644]
servers/slapd/back-ldbm/proto-back-ldbm.h [new file with mode: 0644]
servers/slapd/back-ldbm/search.c [new file with mode: 0644]
servers/slapd/back-ldbm/unbind.c [new file with mode: 0644]
servers/slapd/back-passwd/Make-template [new file with mode: 0644]
servers/slapd/back-passwd/Version.c [new file with mode: 0644]
servers/slapd/back-passwd/config.c [new file with mode: 0644]
servers/slapd/back-passwd/search.c [new file with mode: 0644]
servers/slapd/back-shell/Make-template [new file with mode: 0644]
servers/slapd/back-shell/Version.c [new file with mode: 0644]
servers/slapd/back-shell/abandon.c [new file with mode: 0644]
servers/slapd/back-shell/add.c [new file with mode: 0644]
servers/slapd/back-shell/bind.c [new file with mode: 0644]
servers/slapd/back-shell/compare.c [new file with mode: 0644]
servers/slapd/back-shell/config.c [new file with mode: 0644]
servers/slapd/back-shell/delete.c [new file with mode: 0644]
servers/slapd/back-shell/fork.c [new file with mode: 0644]
servers/slapd/back-shell/init.c [new file with mode: 0644]
servers/slapd/back-shell/modify.c [new file with mode: 0644]
servers/slapd/back-shell/modrdn.c [new file with mode: 0644]
servers/slapd/back-shell/result.c [new file with mode: 0644]
servers/slapd/back-shell/search.c [new file with mode: 0644]
servers/slapd/back-shell/searchexample.conf [new file with mode: 0644]
servers/slapd/back-shell/searchexample.sh [new file with mode: 0644]
servers/slapd/back-shell/shell.h [new file with mode: 0644]
servers/slapd/back-shell/unbind.c [new file with mode: 0644]
servers/slapd/backend.c [new file with mode: 0644]
servers/slapd/bind.c [new file with mode: 0644]
servers/slapd/ch_malloc.c [new file with mode: 0644]
servers/slapd/charray.c [new file with mode: 0644]
servers/slapd/compare.c [new file with mode: 0644]
servers/slapd/config.c [new file with mode: 0644]
servers/slapd/configinfo.c [new file with mode: 0644]
servers/slapd/connection.c [new file with mode: 0644]
servers/slapd/daemon.c [new file with mode: 0644]
servers/slapd/delete.c [new file with mode: 0644]
servers/slapd/detach.c [new file with mode: 0644]
servers/slapd/dn.c [new file with mode: 0644]
servers/slapd/entry.c [new file with mode: 0644]
servers/slapd/filter.c [new file with mode: 0644]
servers/slapd/filterentry.c [new file with mode: 0644]
servers/slapd/init.c [new file with mode: 0644]
servers/slapd/lock.c [new file with mode: 0644]
servers/slapd/main.c [new file with mode: 0644]
servers/slapd/modify.c [new file with mode: 0644]
servers/slapd/modrdn.c [new file with mode: 0644]
servers/slapd/monitor.c [new file with mode: 0644]
servers/slapd/operation.c [new file with mode: 0644]
servers/slapd/phonetic.c [new file with mode: 0644]
servers/slapd/proto-slap.h [new file with mode: 0644]
servers/slapd/regex.c [new file with mode: 0644]
servers/slapd/repl.c [new file with mode: 0644]
servers/slapd/result.c [new file with mode: 0644]
servers/slapd/schema.c [new file with mode: 0644]
servers/slapd/schemaparse.c [new file with mode: 0644]
servers/slapd/search.c [new file with mode: 0644]
servers/slapd/shell-backends/Make-template [new file with mode: 0644]
servers/slapd/shell-backends/passwd-shell.c [new file with mode: 0644]
servers/slapd/shell-backends/passwd-shell.h [new file with mode: 0644]
servers/slapd/shell-backends/pwd-Version.c [new file with mode: 0644]
servers/slapd/shell-backends/shellutil.c [new file with mode: 0644]
servers/slapd/shell-backends/shellutil.h [new file with mode: 0644]
servers/slapd/slap.h [new file with mode: 0644]
servers/slapd/slapd.at.conf [new file with mode: 0644]
servers/slapd/slapd.conf [new file with mode: 0644]
servers/slapd/slapd.oc.conf [new file with mode: 0644]
servers/slapd/str2filter.c [new file with mode: 0644]
servers/slapd/strdup.c [new file with mode: 0644]
servers/slapd/tempnam.c [new file with mode: 0644]
servers/slapd/tools/Make-template [new file with mode: 0644]
servers/slapd/tools/Vers-edb2.c [new file with mode: 0644]
servers/slapd/tools/centipede.c [new file with mode: 0644]
servers/slapd/tools/chlog2replog.c [new file with mode: 0644]
servers/slapd/tools/edb2ldif.c [new file with mode: 0644]
servers/slapd/tools/ldapsyntax.c [new file with mode: 0644]
servers/slapd/tools/ldapsyntax.h [new file with mode: 0644]
servers/slapd/tools/ldbmcat.c [new file with mode: 0644]
servers/slapd/tools/ldbmtest.c [new file with mode: 0644]
servers/slapd/tools/ldif.c [new file with mode: 0644]
servers/slapd/tools/ldif2id2children.c [new file with mode: 0644]
servers/slapd/tools/ldif2id2entry.c [new file with mode: 0644]
servers/slapd/tools/ldif2index.c [new file with mode: 0644]
servers/slapd/tools/ldif2ldbm.c [new file with mode: 0644]
servers/slapd/tools/sizecount.c [new file with mode: 0644]
servers/slapd/unbind.c [new file with mode: 0644]
servers/slapd/value.c [new file with mode: 0644]
servers/slurpd/DESIGN [new file with mode: 0644]
servers/slurpd/Make-template [new file with mode: 0644]
servers/slurpd/Version.c [new file with mode: 0644]
servers/slurpd/admin.c [new file with mode: 0644]
servers/slurpd/args.c [new file with mode: 0644]
servers/slurpd/ch_malloc.c [new file with mode: 0644]
servers/slurpd/config.c [new file with mode: 0644]
servers/slurpd/detach.c [new file with mode: 0644]
servers/slurpd/fm.c [new file with mode: 0644]
servers/slurpd/globals.c [new file with mode: 0644]
servers/slurpd/globals.h [new file with mode: 0644]
servers/slurpd/ldap_op.c [new file with mode: 0644]
servers/slurpd/lock.c [new file with mode: 0644]
servers/slurpd/main.c [new file with mode: 0644]
servers/slurpd/re.c [new file with mode: 0644]
servers/slurpd/reject.c [new file with mode: 0644]
servers/slurpd/replica.c [new file with mode: 0644]
servers/slurpd/replog.c [new file with mode: 0644]
servers/slurpd/ri.c [new file with mode: 0644]
servers/slurpd/rq.c [new file with mode: 0644]
servers/slurpd/sanity.c [new file with mode: 0644]
servers/slurpd/slurp.h [new file with mode: 0644]
servers/slurpd/st.c [new file with mode: 0644]
servers/slurpd/tsleep.c [new file with mode: 0644]
tests/Make-template [new file with mode: 0644]
tests/README [new file with mode: 0644]
tests/data/acl.out.master [new file with mode: 0644]
tests/data/modify.out.master [new file with mode: 0644]
tests/data/search.out.master [new file with mode: 0644]
tests/data/slapd-acl.conf [new file with mode: 0644]
tests/data/slapd-master.conf [new file with mode: 0644]
tests/data/slapd-repl-master.conf [new file with mode: 0644]
tests/data/slapd-repl-slave.conf [new file with mode: 0644]
tests/data/slapd.at.conf [new file with mode: 0644]
tests/data/slapd.oc.conf [new file with mode: 0644]
tests/data/test-ordered.ldif [new file with mode: 0644]
tests/data/test.ldif [new file with mode: 0644]
tests/scripts/all [new file with mode: 0755]
tests/scripts/defines.sh [new file with mode: 0755]
tests/scripts/makeldbm.sh [new file with mode: 0755]
tests/scripts/test001-ldif2ldbm [new file with mode: 0755]
tests/scripts/test001-slapadd [new file with mode: 0755]
tests/scripts/test002-populate [new file with mode: 0755]
tests/scripts/test003-search [new file with mode: 0755]
tests/scripts/test004-modify [new file with mode: 0755]
tests/scripts/test005-modrdn [new file with mode: 0755]
tests/scripts/test006-acls [new file with mode: 0755]
tests/scripts/test007-replication [new file with mode: 0755]

diff --git a/ANNOUNCEMENT b/ANNOUNCEMENT
new file mode 100644 (file)
index 0000000..0075060
--- /dev/null
@@ -0,0 +1,90 @@
+                       A N N O U N C E M E N T
+
+                              LDAP 3.3
+
+    The University of Michigan is pleased to announce release 3.3 of
+    UM-LDAP, an implementation of the Lightweight Directory Access
+    Protocol. LDAP is a draft Internet standard directory service
+    protocol that runs over TCP/IP. It can be used to provide a
+    stand-alone directory service, or to provide lightweight access to
+    the X.500 directory.  LDAP is defined by RFC 1777 and RFC 1778.
+
+    This release includes the following components:
+
+       - slapd - a stand-alone LDAP directory server
+       - slurpd - a stand-alone LDAP replication server
+       - ldapd - an LDAP-to-X.500 gateway server
+       - centipede - an LDAP centroid generation and maintenance program
+       - libldap - an LDAP client library
+       - liblber - a lightweight BER/DER encoding/decoding library
+       - ldif tools - data conversion tools for use with slapd
+       - in.xfingerd - a finger-to-LDAP gateway server
+       - go500 - a gopher-to-LDAP gateway server for searching
+       - go500gw - a gopher-to-LDAP gateway server for searching and browsing
+       - rcpt500 - an email-to-LDAP query responder
+       - mail500 - an LDAP-capable mailer
+       - fax500 - an LDAP-capable mailer that supports remote printing
+       - LDAP tools - A collection of shell-based LDAP utility programs
+
+    In addition, there are some contributed components:
+
+       - web500 - an HTTP-to-LDAP gateway
+       - whois++d - a WHOIS++-to-LDAP gateway
+       - saucer - a simple command-line oriented client program
+
+CHANGES
+
+    Changes since release 3.2 of LDAP include
+
+       - slurpd has been rewritten as a single process threaded daemon
+       - ldaptools (ldapsearch, etc) now support the LDIF format
+       - support for LDAP URLs added to libldap
+       - improved support for LDAP referrals in libldap
+       - preliminary test scripts included
+       - support for additional platforms
+       - various bug fixes and build fixes
+
+    See the CHANGES file in the distribution for more details.
+
+AVAILABILITY
+
+    This software is freely available to anyone for any lawful purpose,
+    subject to the U-M copyright notice and disclaimer.  The software is
+    available for anonymous ftp from the following location:
+
+       ftp://terminator.rs.itd.umich.edu/ldap/ldap-3.3.tar.Z
+
+SUPPORT
+
+    The software is provided as is without any express or implied
+    warranty, but there is a bug reporting mail address which is
+    responded to on a best-effort basis:
+
+       ldap-support@umich.edu
+
+    In addition, there is a discussion list for issues relating to this
+    implementation of ldap:
+
+       ldap@umich.edu                  -- discussion list
+       ldap-request@umich.edu          -- to join the list
+
+    Comments or questions about the LDAP protocol in general should be
+    sent to the IETF ASID discussion group:
+
+       ietf-asid@umich.edu             -- discussion list
+       ietf-asid-request@umich.edu     -- to join the list
+
+    An LDAP home page containing lots of interesting information and
+    online documentation is available at this URL:
+
+        http://www.umich.edu/~rsug/ldap/
+
+SUPPORTED PLATFORMS
+
+    This release has been ported to many UNIX platforms, including
+    SunOS 4.1.x, Solaris 2.x, Ultrix 4.3, HP-UX 9.05, AIX 3.2.5,
+    SCO, FreeBSD, NetBSD, LINUX, IRIX, Digital Unix (OSF/1), and
+    NeXTSTEP 3.2.  This release has also been ported to VMS.
+
+    The client libraries and some clients have also been ported to
+    MacOS 7.x, MSDOS (some TCP stacks), and MS Windows 3.1/95/NT.
diff --git a/CHANGES b/CHANGES
new file mode 100644 (file)
index 0000000..924b505
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,545 @@
+Changes since 3.3b1
+
+Various Make-template files    - update by doing 'make depend'
+
+include/disptmpl.h             - add LDAP_DISP_OPT_HTMLBODYONLY option
+
+libraries/liblber/io.c         - under MacOS, limit tcpwrite() calls to a
+                                 maximum of 64K bytes; ber_flush() int/long fix
+
+libraries/libldap/friendly.c   - don't use errno on MacOS or DOS
+libraries/libldap/regex.c      - fix re_exec() to that ".*" matches ""
+libraries/libldap/result.c     - eliminate memory leak in wait4msg()
+libraries/libldap/request.c    - eliminate double-free impurity
+libraries/libldap/tmplout.c    - add LDAP_DISP_OPT_HTMLBODYONLY option
+libraries/libldap/ufn.c                - purify: avoid bad frees; plug memory leaks
+
+libraries/libldif/line64.c     - str_parse_line() now 0-terminates base64 vals.
+
+libraries/macintosh/*          - tcpwrite()/OpenTransport bug fixes
+                               - better error checking for MacTCP driver opens
+                               - don't use old routine names any more
+
+libraries/msdos/winsock/*      - various bugs fixes & improvements
+
+servers/slapd/modify.c         - fix bug causing unnormalized attr names
+servers/slapd/monitor.c                - return new "version" attribute
+servers/slapd/regex.c          - fix re_exec() to that ".*" matches ""
+servers/slapd/tools/ldbmcat.c  - make -n option work (don't open file "-n" )
+servers/slapd/tools/ldif2id2entry.c    - include ids in stored entries
+servers/slapd/schema.c         - log some information useful in tracking
+                                 down schema-check problems
+servers/slapd/dn.c             - dn_upcase() was not returning anything (doh!)
+servers/slapd/backend.c                - pass unbind request to all backends
+servers/slapd/unbind.c         - pass unbind request to all backends
+servers/slapd/Version.c                - remove leading spaces from Versionstr[]
+
+servers/slapd/back-ldbm/unbind.c - make arguments consistent
+servers/slapd/back-ldbm/bind.c - fix bug which allowed anyone to bind as
+                                 anyone else using kerberos, if there was
+                                 at least one krbName in an entry
+
+servers/slurpd/replog.c                - do all replog copying with buffered i/o
+servers/slurpd/fm.c            - fix inconsistency in arguments
+servers/slurpd/main.c          - fix inconsistency in arguments
+
+clients/tools/ldapdelete.c     - add -K flag - only does LDAP_AUTH_KRBV41
+clients/tools/ldapmodify.c     - add -K flag - only does LDAP_AUTH_KRBV41
+clients/tools/ldapmodrdn.c     - add -K flag - only does LDAP_AUTH_KRBV41
+clients/tools/ldapsearch.c     - add -K flag - only does LDAP_AUTH_KRBV41
+
+doc/man/man1/ldapdelete.1      - add -K flag - only does LDAP_AUTH_KRBV41
+doc/man/man1/ldapmodify.1      - add -K flag - only does LDAP_AUTH_KRBV41
+doc/man/man1/ldapmodrdn.1      - add -K flag - only does LDAP_AUTH_KRBV41
+doc/man/man1/ldapsearch.1      - add -K flag - only does LDAP_AUTH_KRBV41
+doc/man/man3/ldap_entry2text.3 - document LDAP_DISP_OPT_HTMLBODYONLY option
+doc/man/man8/slapd.8           - add BUGS section and document modrdn bug
+
+----------------------------------------------------------------------------
+Changes since 3.2
+
+Makefile                       - added support for IRIX (SGI)
+                               - make depend improvements
+
+tests/                         - all new test scripts -- make test
+
+include/lber.h                 - use short include file names #ifdef WINSOCK
+include/ldap.h                 - change LDAPCache struct definition to reduce
+                                 cache overhead
+                               - use short include file names #ifdef WINSOCK
+                               - LDAP URL support
+                               - add lr_conn to LDAPRequest (needed by abandon)
+                               - add LDAP_OPT_RESTART for select() restart
+                               - revised Debug() macro #ifdef WINSOCK
+include/ldbm.h                 - under NDBM, use O_RDWR instead of O_CREAT
+                               -   in LDBM_WRCREAT and LDBM_NEWDB
+include/proto-lber.h           - changes for WIN32
+include/proto-ldap.h           - changes for WIN32
+                               - added LDAP URL routines
+include/disptmpl.h             - changes for WIN32
+include/ldif.h                 - includes for new libldif library
+include/srchpref.h             - changes for WIN32
+libraries/liblber/decode.c     - vararg changes for WIN32
+libraries/liblber/encode.c     - vararg changes for WIN32
+libraries/libldap/abandon.c    - make ldap_abandon() work with referrals
+libraries/libldap/bind.c       - added new ldap_set_rebind_proc() routine
+libraries/libldap/cache.c      - reduce cache overhead
+                               - fix small cache size infinite loop bug
+                               - clarify debugging messages
+libraries/libldap/charset.c    - new routines: ldap_translate_from_t61,
+                                   ldap_translate_to_t61,
+                                   ldap_enable_translation
+libraries/libldap/cldap.c      - changes to support referral re-bind w/auth
+libraries/libldap/getfilter.c  - ldap_build_filter:  don't use NULL value
+libraries/libldap/kbind.c      - changes to support referral re-bind w/auth
+libraries/libldap/ldap-int.h   - changes to support referral re-bind w/auth
+                               - rename do_select() to do_ldap_select()
+libraries/libldap/open.c       - changes to support referral re-bind w/auth
+                               - ld_options = LDAP_OPT_REFERRALS by default 
+libraries/libldap/os-ip.c      - include <sys/time.h> to fix HP/UX gcc builds
+                               - rename do_select() to do_ldap_select()
+libraries/libldap/result.c     - wait4msg debugging now shows timeout values
+                               - changes to support referral re-bind w/auth
+                               - rename do_select() to do_ldap_select()
+                               - buf fix in ldap_msgdelete() -- update prev
+                               - support LDAP_OPT_RESTART option
+libraries/libldap/request.c    - changes to support referral re-bind w/auth
+                               - initialize new lr_conn field (for abandon)
+libraries/libldap/test.c       - changes to support referral re-bind w/auth
+libraries/libldap/tmplout.c    - searchact uses "-dnt" and "-dnb", not "-dn"
+libraries/libldap/url.c                - new routines: ldap_is_ldap_url,
+                                   ldap_parse_url, ldap_url_search
+                                   ldap_url_search_s, ldap_url_search_st
+
+libraries/libldif/             - new library that contains line64 routines
+
+clients/tools/ldapmodify.c     - preferred input format is now slapd.replog
+clients/tools/ldapsearch.c     - added -L option (output in LDIF format)
+                               - don't print initial blank line when -f used
+                               - support "-f -" for reading filters from stdin
+clients/ud/*.c                 - various bug fixes & auth. streamlining
+
+doc/man/man3/ldap.3            - add several new routines
+doc/man/man3/ldap_bind.3/.links        - add new ldap_set_rebind_proc() routine
+doc/man/man3/ldap_charset.3/.links     - add new routines
+doc/man/man3/ldap_disptmpl.3   - added missing *'s in ldap_init... arg. lists
+doc/man/man3/ldap_result.3     - add details r.e. timeout parameter
+doc/man/man3/ldap_open.3       - document LDAP_OPT_REFERRALS default to on
+doc/man/man3/ldap_url.3/.links - document new LDAP URL routines
+
+Make-common.dist and .um       - add LDBMINCLUDE variable
+                               - use ISODEPACKAGE and ICRELEASE in place of
+                                 ICR1 and XTISODE defines
+                               - remove LDAP_DNS stuff
+
+build/Make-append              - add LDBMINCLUDE variable
+                               - add NO_SETPROCTITLE to SERVERDEFS
+                               - use ISODEPACKAGE and ICRELEASE in place of
+                                 ICR1 and XTISODE defines
+build/mkdep                    - use compiler passed in, not always cc
+                               - remove system dependencies when gcc is used
+build/platforms/attsvr4-cc/    - AT&T SVR4 support
+build/platforms/irix-cc/       - SGI IRIX support
+build/platforms/irix-gcc/      - SGI IRIX support
+
+servers/ldapd/common.h         - add missing extern function declarations
+servers/ldapd/association.c    - use ISODEPACKAGE test instead of ICR1, etc.
+servers/ldapd/certificate.c    - add missing extern declaration
+servers/ldapd/error.c          - use ISODEPACKAGE test instead of ICR1, etc.
+servers/ldapd/kerberos.c       - use ISODEPACKAGE test instead of ICR1, etc.
+servers/ldapd/request.c                - use ISODEPACKAGE test instead of ICR1, etc.
+servers/ldapd/main.c           - set proctitle to calling host (bug fix)
+                               - CLDAP: don't timeout/exit prematurely
+servers/ldapd/proctitle.c      - don't compile file if NO_SETPROCTITLE is on
+servers/ldapd/Make-template    - don't try to make depend if don't have isode
+servers/ldap                   - bug fixes, support ICR3
+
+servers/slapd/tools/ldif.c     - use correct pointer when calling realloc
+servers/slapd/tools/edb2ldif.c - properly #ifdef code to handle potential
+                                 lack of file_attr_dir and turbo disk stuff
+                               - add RDN attribute values to entries
+                               - don't pre-pend './' to EDB files on cmd. line
+servers/slapd/tools/ldapsyntax.c- use static buffer to speed things up
+servers/slapd/tools/Make-template      - don't try to make depend some tools
+                                       - if we don't have isode
+servers/slapd                  - fix acl handling
+servers/slapd                  - fix race condition setting o_dn
+servers/slapd                  - bug fixes
+
+servers/slurpd                 - complete re-write
+
+tests/                         - new - test scripts to verify basic
+                                 functionality of libraries, slapd, slurpd
+
+----------------------------------------------------------------------------
+Changes since 3.2b3
+
+slapd admin guide              - document ldbmtest changes
+                               - clarify quick-start instructions
+
+include/ldapconfig.h.dist      - move likely-to-change things to top
+
+Make-common.dist               - add phonetic algorithm config lines
+build/Make-append              - add def for phonetic algorithm config lines
+
+libraries/libldbm/ldbm.c       - fix bug with gdbm cache size handling
+
+libraries/liblber/encode.c     - cap lengths at 32-bits for Alpha compatibility
+
+libraries/libldap/disptmpl.c   - recognize both "addact" and "adddnact"
+libraries/libldap/getdn.c      - handle \ escapes in DNs better
+
+clients/tools/ldapsearch.c     - added -S option to sort results
+                               - print results as they are received (if no -S)
+
+servers/slapd/*                        - added function prototypes
+servers/slapd/phonetic.c       - make phonetic alg settable in Make-common
+servers/slapd/tools/ldbmtest.c - fix bugs, use dbcache routines (like slapd)
+                               - add 'b' and 'B' commands
+servers/slapd/tools/edb2ldif.c - include quipu/config.h & quipu/entry.h
+                               - this fixes TURBO_DISK problems
+servers/ldapd/*                        - misc. fixes for VMS and OSF/1
+                               - added function prototypes
+
+----------------------------------------------------------------------------
+Changes since 3.2b2
+
+servers/slapd/*                        - lots of changes/fixes/improvements
+servers/slapd/tools/*          - add ldif program
+                               - add centipede program
+                               - numerous fixes/improvements
+
+clients/tools/ldapmodify.c     - add -b option (read binary vals from a file)
+                               - add trailing \ feature for iattr, etc.
+clients/tools/ldapsearch.c     - add -z sizelimit and -l timelimit options
+                               - add -B (allow non-ascii values_ option
+                               - change /tmp template used with -t
+
+include/lber.h                 - add LBER_MAX_INCOMING_SIZE option
+
+libraries/liblber/io.c         - support LBER_MAX_INCOMING_SIZE option
+                               - new ber_init() and ber_reset() routines
+
+libraries/libldap/*            - various improvements to LDAP_REFERRALS code
+                               - minor changes for Mac re-port
+
+libraries/libldap/disptmpl.c   - "addact" is now "adddnact"
+libraries/libldap/cache.c      - we now cache compare results that have error
+                                       of LDAP_NO_SUCH_ATTRIBUTE
+libraries/libldap/open.c       - support :port on ldap_open() hosts
+libraries/libldap/charset.c    - new T.61 to ISO-8859 conversion support
+                               - thanks to enrique.silvestre@uv.es
+
+libraries/libldap/kbind.c      - a few changes for MS Windows
+
+libraries/msdos/winsock/*      - a few changes for Kerberos support
+
+servers/ldapd/modify.c         - added support for JPEG non-file attrs.
+                               - added support for octetstring attrs.
+
+servers/ldapd/syntax.c         - DN syntax fixes (OID. and replace {ASN} w/#)
+                               - don't escape '$' in DeliveryMethod attrs.
+                               - added support for JPEG non-file attrs.
+                               - added support for octetstring attrs.
+
+----------------------------------------------------------------------------
+Changes since 3.2b1
+
+servers/slapd/                 - add better database concurrency
+                               - remove multiple dn support
+                               - add stats logging
+                               - fix syslogging
+                               - add include config file option
+                               - add dbcachesize option
+                               - add abandon
+                               - add lastmod/creator attrs
+                               - add monitoring capability
+                               - normalize dns properly
+                               - base 64 value encoding support
+                               - add schema checking
+                               - fix various bugs
+                               - add srvtab config option
+servers/slapd/tools            - whole new set of db creation/conversion tools
+
+clients/finger/main.c          - added -c option & use of FINGER_RDNCOUNT
+clients/gopher/go500.c         - added -c option & use of GO500_RDNCOUNT
+clients/gopher/go500gw.c       - added -c option & use of GO500GW_RDNCOUNT
+                               - removed non-functional -s option
+clients/rcpt500/main.c         - added -c option & use of RCPT500_RDNCOUNT
+clients/rcpt500/query.c                - use rdncount instead of hard-coded 2
+
+include/ldapconfig.h.edit      - added _RDNCOUNT #defines
+
+libraries/libldap/tmplout.c    - made rdncount of 0 show all DN components
+
+libraries/libldap/getdn.c      - added ldap_is_dns_dn() routine
+
+libraries/libldap/*            - many #ifndef NO_REFERRALS changes
+                               - new ldap_init() routine
+
+----------------------------------------------------------------------------
+Changes since 3.1 final
+
+General/various files          - incorporated changes for Borland C 3.1
+
+Makefile                       - added support for NeXTSTEP
+
+libraries/liblber/io.c         - add ability to save ldap session to a file
+include/lber.h                 - add ability to save ldap session to a file
+
+
+build/platforms/nextstep-cc/Make-platform
+                               - added -all_load option for ld
+build/platforms/sunos5-cc/Make-platform
+                               - define SYSEXITSPATH as for sunos5-gcc
+
+build/uname.sh                 - new replacement uname for NeXTSTEP, etc.
+
+clients/finger/main.c          - don't use fprintf for entry2text
+clients/gopher/go500.c         - use GO500_HOSTNAME (bug fix)
+                               - don't use fprintf for entry2text
+clients/gopher/go500gw.c       - use GO500GW_HOSTNAME (bug fix)
+                               - don't use fprintf for entry2text
+clients/mail500/main.c         - improved error logging
+                               - fixed "errors-to is a group" bug
+                               - don't look in people space for groups
+                               - don't bounce loop messages back to sender
+                               - misc. fixes
+clients/tools/ldapdelete.c     - add -c option to continue after errors occur
+clients/tools/ldapmodify.c     - add -c option to continue after errors occur
+clients/tools/ldapmodrdn.c     - add -c option to continue after errors occur
+clients/tools/ldapsearch.c     - added -t option to write values to tmp files
+                               - added -A option for "attributes only"
+clients/ud/print.c             - make sure ldap_count_values() returns > 0
+                               -   before trying to use returned values
+
+doc/man/man1/ldapdelete.1      - updated to mention new -c option
+doc/man/man1/ldapmodify.1      - updated to mention new -c option
+doc/man/man1/ldapmodrdn.1      - updated to mention new -c option
+doc/man/man1/ldapsearch.1      - updated to mention new -A & -t options
+doc/man/man3/ldap_friendly.3   - fixed typo in ldap_free_friendlymap()
+doc/man/man5/ldapfilter.conf.5 - add missing part of example config file
+
+include/disptmpl.h             - appended 'L' to long #defined contants
+                               - added entry2html family of routines
+include/lber.h                 - added sb_options to allow copy to file
+                               - added ber_wptr to re-start partial writes
+include/ldap.h                 - added debug levels for sldapd
+                               - added LDAP_SYSLOG to send debug using syslog
+include/ldapconfig.h.edit      - added GO500GW_HOSTNAME
+include/ldapconfig.h.dist      - added GO500GW_HOSTNAME
+include/portable.h             - select() macro fix for HP/UX /bin/cc
+include/proto-lber.h           - Borland C fixes
+                               - added ber_bvdup() prototype
+include/sysexits-compat.h      - new file, in case we ever need it
+
+libraries/libavl/*             - new library; used in sldapd
+libraries/liblber/decode.c     - new 'o' feature for ber_scanf()
+                               - new ber_bvdup() routine
+                               - Borland C fixes
+libraries/liblber/encode.c     - Borland C fixes
+libraries/liblber/io.c         - ensure that write size <= 64K under VMS
+                               - use ber_wptr to restart partial writes
+                               - added LBER_TO_FILE/FILE_ONLY option support
+libraries/libldap/abandon.c    - use correct message id in abandon requests
+libraries/libldap/cache.c      - use time() in a more portable manner
+libraries/libldap/cldap.c      - retry correct number of times (off by one)
+libraries/libldap/error.c      - define empty ldap_perror if NO_USERINTERFACE
+libraries/libldap/getdn.c      - ldap_dn2ufn() now returns dn if no '='
+                               - ldap_explode_dn handles DNs without '='
+libraries/libldap/open.c       - "host" can now be a space-separated list
+libraries/libldap/sort.c       - make function declarations more portable
+libraries/libldap/srchpref.c   - fixed memory leak in options parsing
+libraries/libldap/test.c       - added -t & -T options for ber output to file
+                               - added 'E' command to explode a DN
+libraries/libldap/tmplout.c    - added entry2html()
+                               - added entry2html_search()
+                               - added entry2vals()
+                               - remove extraneous ber_free when not using tmpl
+                               - fix non-ASCII core dump bugs
+libraries/libldap/ldapfriendly - added EE & RU
+libraries/libldap/ldapfilter.conf
+                               - remove '\' inside [] in reg exprs.
+                               - add web500gw to filter tags
+                               - added xax500-auth section
+libraries/libldap/ldapsearchprefs.conf
+                               - changed xax500 tags
+libraries/libldap/ldaptemplates.conf
+                               - added co to Country template
+                               - add missing types & options to comments
+                               - add "Last Modified" attrs. to all templates
+                               - make "Last Modified" attrs. read-only
+libraries/libldbm/*            - new library; used in sldapd
+libraries/liblthread/*         - new library; used in sldapd
+libraries/msdos/README.WSA     - updated to include Borland C instructions
+libraries/vms/README.VMS       - fixed pathname typo
+
+servers/ldapd/add.c            - make BER tags unsigned long everywhere
+servers/ldapd/certificate.c    - make parsing consistent with printing code
+servers/ldapd/main.c           - moved openlog() after detach() call
+servers/ldapd/modify.c         - correct tag usage in ber_first/next loop
+                               - output all debugging to stderr
+                               - pass and use Sockbuf * in modify_result() call
+servers/ldapd/result.c         - change to always use DER encoding
+servers/ldapd/search.c         - change to always use DER encoding
+servers/ldapd/syntax.c         - add support for telexNumber
+servers/sldapd                 - all new "standalone LDAP server"
+
+
+
+----------------------------------------------------------------------------
+Changes since 3.1b8
+
+Make-common                    - added note r.e. -DNO_USERINTERFACE
+servers/ldapd/association.c    - don't include filio.h under AIX
+build/platforms/aix-cc and -gcc        - add _BSD to defines
+include/portable.h             - define OPENLOG_OPTIONS
+clients/*/*.c                  - use OPENLOG_OPTIONS
+servers/ldapd/main.c           - use OPENLOG_OPTIONS
+servers/ldapd/syntax.c         - add iattr support (from craig watkins)
+
+----------------------------------------------------------------------------
+Changes since 3.1b7
+
+Many System V portability fixes....
+A few fixes for VMS....
+
+Makefile                       - support Linux & NetBSD
+Make-common                    - add support for NEXOR version of isode
+                               - add ISODEBASELIBS
+
+include/Make-template          - make ldapconfig.h depend on Makefile
+include/ldapconfig.h.edit      - add RCPT500_LISTLIMIT, RCPT500_UFN
+                               - add GO500_TIMEOUT, GO500_UFN
+                               - add FINGER_UFN, FINGER_TIMEOUT,
+                               - add GO500GW_UFN
+                               - change *_DEREF to be LDAP_DEREF_FINDING
+include/regex.h                        - use NEED_BSDREGEX
+include/portable.h             - SYSV changes & general re-vamping
+include/disptmpl.h             - fix typo in ldap_name2template() prototype
+                               - add LDAP_SYN_RFC822ADDR
+
+libraries/liblber/io.c         - make ber_alloc actually use BER
+
+libraries/libldap/cldap.c      - preserve old log DN if NULL is passed
+libraries/libldap/regex.c      - use NEED_BSDREGEX
+libraries/libldap/disptmpl.c   - add support for LDAP_SYN_RFC822ADDR
+libraries/libldap/tmplout.c    - add support for LDAP_SYN_RFC822ADDR
+libraries/libldap/getfilter.c  - always #include "regex.h"
+
+servers/ldapd/main.c           - don't check openlog return code
+servers/ldapd/request.c                - only do syslog if dosyslog is set
+servers/ldapd/syntax.c         - add support for user certificates (from ER)
+servers/ldapd/certificate.c    - add support for user certificates (new file)
+
+clients/finger/main.c          - add -t disptmplfile option
+                               - add -p port option
+                               - add ufn support
+
+clients/gopher/go500.c         - add -t disptmplfile option
+                               - add ufn support
+
+clients/gopher/go500gw.c       - add -t disptmplfile option
+                               - add ufn support
+
+clients/mail500/main.c         - add -t disptmplfile option
+                               - add support for mail to -owner
+
+clients/rcpt500/main.c,query.c - add support for RCPT500_LISTLIMIT
+                               - support -p ldapport option
+                               - add ufn support
+
+clients/tools/ldapsearch.c     - recognize -w option properly
+clients/tools/ldapdelete.c     - recognize -k option properly
+clients/tools/ldapmodrdn.c     - new program
+
+clients/ud/edit.c              - use execlp() instead of execle()
+clients/ud/main.c              - include sys/ioctl.h under NetBSD
+clients/ud/print.c             - updated time2text() from libldap/tmplout.c
+
+contrib/saucer                 - new contributed client from Eric Rosenquist
+
+build/platforms                        - added netbsd-cc & netbsd-gcc
+                               - updated sunos5-cc and sunos5-gcc
+                               - added missing CC=gcc in hpux-gcc
+                               - added vms
+build/Make-append              - change ISODELIBS
+
+doc/man/man8/rcpt500.8         - new manual page
+doc/man/man3/ldap.3            - add (3) to routine names in INDEX section
+doc/man/man3/ldap_search.3     - remove reference to ldap_parse(3)
+doc/man/man3/ldap_modrdn.3     - new manual page
+doc/man/man3/ldap_modrdn.3.links- new links file
+doc/man/man3/ldap_disptmpl.3   - re-word ldap_octemplate description
+                               - document LDAP_SYN_RFC822ADDR
+doc/man/man5/ldap_searchprefs.5        - fix formatting
+doc/man/man5/ldaptemplatesconf.5- document "mail" syntax type
+doc/man/*                      - use ETCDIR everywhere (was %ETCDIR%)
+
+
+
+-------
+ldap-3.1b7 CHANGES file - summary of major changes to each component
+since the last release
+
+source tree    - completely reorganized for your convenience
+               - makes full use of ansi-style prototypes
+               - supports non-ansi compilers through unproto utility
+
+configuration  - all client configuration has been moved to ldapconfig.h.edit
+                 (no need to edit multiple source code files)
+
+build procedure        - completely revamped for your convenience
+               - automaticly figures out your platform/compiler
+               - supports multiple objects from a single source tree
+
+liblbdap       - added support for display templates
+               - added support for search preferences
+               - added ldap_sort routines for sorting entries
+               - rearranged some routines/source files to allow
+                 better incremental linking to reduce code bloat
+               - added support for CLDAP
+
+liblber                - added O option to ber_scanf: allocate octet string w/length
+               - big tags (greater than 31) now supported
+               - distinguished encoding rules supported (runtime choice
+                 between ber and der)
+
+in.xfingerd    - now uses display template routines
+               - now uses ldap sorting routines
+               - editable configuration info moved to ldapconfig.h.edit
+
+go500          - now uses display template routines
+               - now uses ldap sorting routines
+               - editable configuration info moved to ldapconfig.h.edit
+
+go500gw                - now uses display template routines
+               - now uses ldap sorting routines
+               - editable configuration info moved to ldapconfig.h.edit
+
+rcpt500                - now uses display template routines
+               - now uses ldap sorting routines
+               - editable configuration info moved to ldapconfig.h.edit
+
+mail500                - addition of a new "vacation" feature
+               - editable configuration info moved to ldapconfig.h.edit
+
+ldap tools     - new addition of some shell-based tools
+
+whois++ g/w    - moved to contrib/ directory
+
+web500         - new addition, in contrib/ directory
+
+ldapd          - lots of bug fixes
+               - bring CLDAP code in line with latest Internet Draft
+
+documentation  - library man pages have been completely re-done, split
+                 into separate manuals, with new pages for each set of
+                 routines.
+               - new man pages for most client programs (more on the way)
+
+windows ldap   - support for Win32 (unfinished?)
+               - added VERSIONINFO resource to dll
+               - check for > 64K response packet and don't crash
+
+macintosh ldap - support Apple's new Universal Header files
diff --git a/COPYRIGHT b/COPYRIGHT
new file mode 100644 (file)
index 0000000..ea961e7
--- /dev/null
+++ b/COPYRIGHT
@@ -0,0 +1,9 @@
+Copyright (c) 1992-1996 Regents of the University of Michigan.
+All rights reserved.
+
+Redistribution and use in source and binary forms are permitted
+provided that this notice is preserved and that due credit is given
+to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..958d72e
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,136 @@
+Making and Installing the U-M LDAP Distribution
+
+** It is recommended that you read or at least skim through ALL of the
+** instructions in this file before attempting to build the software.
+
+If you want to build binaries for more than one platform from a single
+source tree, skip ahead to the "Building LDAP For More Than One Platform"
+section near the end of this file. If you are planning to run slapd,
+you should read the "SLAPD and SLURPD Administrator's Guide", found in
+the doc/guides/ directory within the distribution.
+
+If you simply want to build LDAP for a single machine platform, follow
+these steps:
+
+ 1. untar the distribution and cd to the top:
+
+       % zcat ldap-3.3.tar.Z | tar xf -
+       % cd ldap-3.3
+
+    If you are reading this file, you probably have already done this!
+
+
+ 2. edit the files Make-common and include/ldapconfig.h.edit to configure
+    the software for your site (the files are well-commented):
+
+       % vi Make-common
+       % vi include/ldapconfig.h.edit
+
+    Note that you should NOT need to edit the Makefile located at the
+    top of the distribution.
+
+    If you just want to see if things will build, you can leave the
+    configuration alone and change it later.
+
+    If you have the ISODE package built and want to build the
+    LDAP-to-X.500 server (ldapd), be sure to uncomment the appropriate
+    lines near the end of the Make-common file.  By default only the
+    stand-alone server, LDAP libraries and client software are built.
+
+ 3. make the software:
+
+       % make
+
+    If all goes well, then make will figure out what platform you are on,
+    pick a compiler to use, construct Makefiles, and build everything.
+    If you see a message like "unknown platform..." LDAP has probably not
+    been set up to build on your machine.  See the file build/PORTS for
+    hints on what to do in that case.
+
+    Note that if your make does not use the Bourne (sh) shell by
+    default when executing internal scripts (reportedly the case on SGI
+    machines at least), you will need to run the make explicitly from
+    within a Bourne shell.  If you a syntax error such as "Missing ]"
+    when you do the make under your usual shell, try this:
+
+       % sh
+       $ make
+
+    If you don't like the some of the platform-specific options chosen
+    by the automatic build process (such as the compiler to use, etc),
+    you can intervene and edit them before anything is actually compiled
+    by explicitly doing a "make platform" step, editing the .make-platform
+    file (actually a link to the file to be edited), and then doing a
+    regular make:
+
+       % make platform
+       % vi .make-platform
+       % make
+
+    If you want to choose the build platform yourself from among those that
+    the distribution supports, cd to the appropriate directory underneath
+    build/platforms and make from there.  For example, if you are on a
+    machine running SunOS 4.1.4 and you want to force the use of the cc
+    compiler, you would do this:
+
+       % cd build/platforms/sunos4-cc
+       % make
+
+    If you want to run some simple tests after the build is complete, you
+    can do this:
+
+       % make test
+
+ 4. install the binaries and man pages.  You may need to be superuser to
+    do this (depending on where you are installing things):
+
+       % su
+       # make install
+
+    That's it!  See the man pages for the individual clients for information
+    on configuring and using them.  Eventually you will probably want to
+    edit the configuration files used by the various clients (installed in
+    the LDAP etc directory).  The files are:
+
+       ldapfilter.conf      - search filter configuration
+       ldapfriendly         - mapping of X.500 names to human-friendly names
+       ldapsearchprefs.conf - search object definitions
+       ldaptemplates.conf   - display template definitions
+
+    There are section 5 man pages for all of these files.
+
+
+Building LDAP For More Than One Platform
+
+It is now possible to build LDAP for more than one platform from the same
+source tree.  This is accomplished by some rules in the Makefiles that
+create a shadow (linked) directory tree where the binaries are placed.
+
+Follow these steps for each different platform:
+
+ 1. move to the directory that matches the platform and compiler you
+    want to build for and type make.  The directories are all located
+    underneath the build/platforms directory.  If your platform is not
+    there, you may need to do a port - see the build/PORTS file for
+    more information.  For a Sun running SunOS 4.1.4, you might do
+    this:
+
+       % cd build/platforms/sunos4-cc
+       % make links
+
+    This will create a linked source area.
+
+
+ 2. move to the new directory and make as for a single platform.  Follow steps
+    1-4 above to accomplish this.  For example:
+
+       % cd obj-sunos4-cc
+       % make
+
+    That's all there is to it.  You can also create the linked source area(s)
+    by just typing "make links" at the top of the distribution, in which case
+    the Makefile will try to automatically determine the platform and
+    compiler.
+
+
+End of LDAP INSTALL file.
diff --git a/Make-common b/Make-common
new file mode 100644 (file)
index 0000000..32683c7
--- /dev/null
@@ -0,0 +1,200 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1994 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP common Make defines (included in all but top-level Makefile)
+#
+#-----------------------------------------------------------------------------
+
+#############################################################################
+## Edit the following variables to have appropriate values for your system ##
+#############################################################################
+
+#############################################################################
+## LDAP install paths                                                      ##
+#############################################################################
+#
+# by default, everything is installed below INSTROOT
+# servers, config files, etc. are put in ETCDIR
+# include files get put in INCLUDEDIR
+# libraries are put in LIBDIR
+# man pages are put under MANDIR
+# programs end-users will run are put in BINDIR
+#
+INSTROOT=/usr/local
+ETCDIR= $(INSTROOT)/etc
+INCLUDEDIR= $(INSTROOT)/include
+LIBDIR= $(INSTROOT)/lib
+MANDIR= $(INSTROOT)/man
+BINDIR= $(INSTROOT)/bin
+#
+# if you want things to run in a different directory from where they
+# are installed, set this accordingly (this path gets compiled into a
+# few binaries). otherwise, leave it alone.
+RUNTIMEETCDIR= $(ETCDIR)
+
+#############################################################################
+## General compiler options                                                ##
+#############################################################################
+# Passed to every compile (cc or gcc).  This is where you put -O or -g, etc.
+#EXTRACFLAGS=-g
+# Passed to every link (ld).  Include -g here if you did in EXTRACFLAGS.
+#EXTRALDFLAGS=-g
+
+#############################################################################
+## If you are NOT using Kerberos authentication, you can skip this section.##
+#############################################################################
+#
+# Otherwise, to enable kerberos authentication, uncomment KERBEROS (and
+# AFSKERBEROS if you are running the AFS version of kerberos).  Also
+# uncomment and change the various KRB* lines to point to where the
+# kerberos libraries and include files are installed at your site.
+#
+#KERBEROS=-DKERBEROS
+#AFSKERBEROS=-DAFSKERBEROS
+#KRBINCLUDEFLAG        = -I/usr/local/kerberos/include
+#KRBLIBFLAG    = -L/usr/local/kerberos/lib
+#KRBLIBS               = -lkrb -ldes
+
+#############################################################################
+## ISODE is required ONLY to build the ldap <-> X.500 server (ldapd)       ##
+## If you don't want to build it, you can skip this section.               ##
+#############################################################################
+#
+# To build the ldap server, uncomment the HAVEISODE line,
+# and the section describing build settings for your version of isode.
+#
+#HAVEISODE = yes
+# If you compiled ISODE with TURBO_DISK defined, uncomment this
+#ISODETURBOLIBS        = -lgdbm
+# uncomment these to have ldapd "pretty print" protocol elements w/debugging
+#PEPSY_DUMP=-DPEPSY_DUMP
+#PEPSY=/usr/local/ic/bin/pepsy
+# uncommment this line to have ldapd load PP syntax handlers
+# you'll also need to add -lpp to ISODEBASELIBS below
+#LDAP_USE_PP=-DLDAP_USE_PP
+# uncomment NO_SETPROCTITLE to have ldapd NOT change its title
+#NO_SETPROCTITLE=-DNOSETPROCTITLE
+#
+# ISODE Consortium release build settings
+# You should change the next line so that ICRELEASE matches the (integer)
+# version number of whatever IC release you have, e.g. 1, 2, or 3 and
+# also uncomment the next 5 lines.
+#ICRELEASE=-DICRELEASE=1
+#ISODEPACKAGE=-DISODEPACKAGE=IC
+#ISODEINCLUDEFLAG= -I/usr/local/ic/include/isode -I/usr/local/ic/include
+#ISODELIBFLAG  = -L/usr/local/ic/lib
+#ISODEBASELIBS = -lisode
+#
+# Freely available ISODE 8.0 release build settings (uncomment the next 4 lines)
+#ISODEPACKAGE=-DISODEPACKAGE
+#ISODEINCLUDEFLAG= -I/usr/local/isode/include
+#ISODELIBFLAG  = -L/usr/local/isode/lib
+#ISODEBASELIBS = -ldsap -lisode
+#
+# NEXOR ISODE release build settings (uncomment the next 4 lines)
+#ISODEPACKAGE=-DISODEPACKAGE=XT
+#ISODEINCLUDEFLAG= -I/usr/include/isode
+#ISODELIBFLAG  = -L/usr/local/lib -L/usr/sunlink/osi/lib
+#ISODEBASELIBS = -lxtpp -lresolv -lxtdsap -lxtisode -losi
+
+#############################################################################
+## If you don't want to run slapd, skip this section.                      ##
+#############################################################################
+#
+# To build slapd (the stand-alone ldap daemon), uncomment the MAKESLAPD
+# line and select the SLAPD_BACKENDS you want to use. If you enable the
+# LDBM backend, also select one of the LDBM backends.
+MAKESLAPD= yes
+#
+# remove the defines for backends you don't want to enable 
+SLAPD_BACKENDS= -DLDAP_LDBM -DLDAP_SHELL -DLDAP_PASSWD
+#
+# If you have included -DLDAP_LDBM in the SLAPD_BACKENDS line you need
+# to specify which low-level database package to use.  There are
+# four choices: Berkeley db b-tree, Berkeley db hash, GNU dbm, or ndbm.
+#
+# berkeley db btree package
+#LDBMBACKEND=-DLDBM_USE_DBBTREE
+#LDBMINCLUDE=-I/usr/local/db/include
+#LDBMLIB=-ldb
+# berkeley db hash package
+#LDBMBACKEND=-DLDBM_USE_DBHASH
+#LDBMINCLUDE=-I/usr/local/db/include
+#LDBMLIB=-ldb
+# gnu dbm (gdbm)
+#LDBMBACKEND=-DLDBM_USE_GDBM
+#LDBMINCLUDE=-I/usr/local/gdbm/include
+#LDBMLIB=-lgdbm
+# standard unix ndbm
+LDBMBACKEND=-DLDBM_USE_NDBM
+#
+# if you want to use a non-default threads package change these lines
+#THREADS=-DNO_THREADS
+#THREADSLIB=
+
+#############################################################################
+## The following options are used by the xax500 client.  If you haven't    ##
+## retrieved the xax500 source and dropped it into the "clients"           ##
+## directory, you can skip this section.                                   ##
+#############################################################################
+#
+# location of your X include files
+#XINCLUDES= -I/usr/X11/include
+#
+# location of your X libraries
+#XLIBDIRS=-L/usr/X11/lib
+#
+# include any extra X libraries you need here
+# the following works with sunos 4 and X11R5
+#XLIBS = $(XLIBDIRS) -lXm -lXt -lX11
+# the following has been known to work with Solaris 2.4 and X11R6
+#XLIBS = $(XLIBDIRS) -lXm -lXext -lSM -lICE -lXpm -lXt -lX11
+
+#############################################################################
+## If you don't want to do auto-translation of character sets, skip this   ##
+#############################################################################
+#
+# Otherwise, uncomment this line and set the following options.
+#STR_TRANSLATION=-DSTR_TRANSLATION
+# 
+# remove the defines for LDAP client library T.61 character translation
+# you do not need.  If you use LDAP_CHARSET_8859, replace the '1' in "88591"
+# with the number of the particular character set you use.  E.g., use "88594"
+# if you use the ISO 8859-4 chracter set.
+#LIBLDAP_CHARSETS=-DLDAP_CHARSET_8859="88591"
+# 
+# uncomment one these lines to enable automatic T.61 translation by default
+#LIBLDAP_DEF_CHARSET=-DLDAP_DEFAULT_CHARSET=LDAP_CHARSET_8859
+
+#############################################################################
+## General options                                                         ##
+#############################################################################
+# uncomment this line to enable debugging code (a good idea)
+LDAP_DEBUG=-DLDAP_DEBUG
+
+# uncomment this line to turn on a few U of Michigan specific things
+#UOFM=-DUOFM
+
+# uncomment this line to delete a few printfs in the lber and ldap libraries.
+#NO_USERINTERFACE=-DNO_USERINTERFACE
+
+# uncomment this line to include Connectionless LDAP support
+#CLDAP=-DCLDAP
+
+# uncomment this line to eliminate local caching support in the libldap
+#NO_CACHE=-DNO_CACHE
+
+# uncomment this line to enable support for LDAP referrals in libldap
+LDAP_REFERRALS=-DLDAP_REFERRALS
+
+# uncomment this line to use soundex for approximate matches in slapd.
+# the default is to use the metaphone algorithm.
+#PHONETIC=-DSOUNDEX
diff --git a/Make-common.um b/Make-common.um
new file mode 100644 (file)
index 0000000..6fa3121
--- /dev/null
@@ -0,0 +1,200 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1994 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP common Make defines (included in all but top-level Makefile)
+#
+#-----------------------------------------------------------------------------
+
+#############################################################################
+## Edit the following variables to have appropriate values for your system ##
+#############################################################################
+
+#############################################################################
+## LDAP install paths                                                      ##
+#############################################################################
+#
+# by default, everything is installed below INSTROOT
+# servers, config files, etc. are put in ETCDIR
+# include files get put in INCLUDEDIR
+# libraries are put in LIBDIR
+# man pages are put under MANDIR
+# programs end-users will run are put in BINDIR
+#
+INSTROOT=/usr/local
+ETCDIR= $(INSTROOT)/etc
+INCLUDEDIR= $(INSTROOT)/include
+LIBDIR= $(INSTROOT)/lib
+MANDIR= $(INSTROOT)/man
+BINDIR= $(INSTROOT)/bin
+#
+# if you want things to run in a different directory from where they
+# are installed, set this accordingly (this path gets compiled into a
+# few binaries). otherwise, leave it alone.
+RUNTIMEETCDIR= $(ETCDIR)
+
+#############################################################################
+## General compiler options                                                ##
+#############################################################################
+# Passed to every compile (cc or gcc).  This is where you put -O or -g, etc.
+EXTRACFLAGS=-g
+# Passed to every link (ld).  Include -g here if you did in EXTRACFLAGS.
+EXTRALDFLAGS=-g
+
+#############################################################################
+## If you are NOT using Kerberos authentication, you can skip this section.##
+#############################################################################
+#
+# Otherwise, to enable kerberos authentication, uncomment KERBEROS (and
+# AFSKERBEROS if you are running the AFS version of kerberos).  Also
+# uncomment and change the various KRB* lines to point to where the
+# kerberos libraries and include files are installed at your site.
+#
+KERBEROS=-DKERBEROS
+AFSKERBEROS=-DAFSKERBEROS
+KRBINCLUDEFLAG = -I/usr/local/kerberos/include
+KRBLIBFLAG     = -L/usr/local/kerberos/lib
+KRBLIBS                = -lkrb -ldes
+
+#############################################################################
+## ISODE is required ONLY to build the ldap <-> X.500 server (ldapd)       ##
+## If you don't want to build it, you can skip this section.               ##
+#############################################################################
+#
+# To build the ldap server, uncomment the HAVEISODE line,
+# and the section describing build settings for your version of isode.
+#
+HAVEISODE = yes
+# If you compiled ISODE with TURBO_DISK defined, uncomment this
+#ISODETURBOLIBS        = -lgdbm
+# uncomment these to have ldapd "pretty print" protocol elements w/debugging
+PEPSY_DUMP=-DPEPSY_DUMP
+PEPSY=/usr/local/ic/bin/pepsy
+# uncommment this line to have ldapd load PP syntax handlers
+# you'll also need to add -lpp to ISODEBASELIBS below
+#LDAP_USE_PP=-DLDAP_USE_PP
+# uncomment NO_SETPROCTITLE to have ldapd NOT change its title
+#NO_SETPROCTITLE=-DNOSETPROCTITLE
+#
+# ISODE Consortium release build settings
+# You should change the next line so that ICRELEASE matches the (integer)
+# version number of whatever IC release you have, e.g. 1, 2, or 3 and
+# also uncomment the next 5 lines.
+ICRELEASE=-DICRELEASE=2
+ISODEPACKAGE=-DISODEPACKAGE=IC
+ISODEINCLUDEFLAG= -I/usr/local/ic/include
+ISODELIBFLAG   = -L/usr/local/ic/lib
+ISODEBASELIBS  = -lisode
+#
+# Freely available ISODE 8.0 release build settings (uncomment the next 4 lines)
+#ISODEPACKAGE=-DISODEPACKAGE
+#ISODEINCLUDEFLAG= -I/usr/local/isode/include
+#ISODELIBFLAG  = -L/usr/local/isode/lib
+#ISODEBASELIBS = -ldsap -lisode
+#
+# NEXOR ISODE release build settings (uncomment the next 4 lines)
+#ISODEPACKAGE=-DISODEPACKAGE=XT
+#ISODEINCLUDEFLAG= -I/usr/include/isode
+#ISODELIBFLAG  = -L/usr/local/lib -L/usr/sunlink/osi/lib
+#ISODEBASELIBS = -lxtpp -lresolv -lxtdsap -lxtisode -losi
+
+#############################################################################
+## If you don't want to run slapd, skip this section.                      ##
+#############################################################################
+#
+# To build slapd (the stand-alone ldap daemon), uncomment the MAKESLAPD
+# line and select the SLAPD_BACKENDS you want to use. If you enable the
+# LDBM backend, also select one of the LDBM backends.
+MAKESLAPD= yes
+#
+# remove the defines for backends you don't want to enable 
+SLAPD_BACKENDS= -DLDAP_LDBM -DLDAP_SHELL -DLDAP_PASSWD
+#
+# If you have included -DLDAP_LDBM in the SLAPD_BACKENDS line you need
+# to specify which low-level database package to use.  There are
+# four choices: Berkeley db b-tree, Berkeley db hash, GNU dbm, or ndbm.
+#
+# berkeley db btree package
+LDBMBACKEND=-DLDBM_USE_DBBTREE
+LDBMINCLUDE=-I/usr/local/include
+LDBMLIB=-ldb
+# berkeley db hash package
+#LDBMBACKEND=-DLDBM_USE_DBHASH
+#LDBMINCLUDE=-I/usr/local/include
+#LDBMLIB=-ldb
+# gnu dbm (gdbm)
+#LDBMBACKEND=-DLDBM_USE_GDBM
+#LDBMINCLUDE=-I/usr/local/include
+#LDBMLIB=-lgdbm
+# standard unix ndbm
+#LDBMBACKEND=-DLDBM_USE_NDBM
+#
+# if you want to use a non-default threads package change these lines
+#THREADS=-DNO_THREADS
+#THREADSLIB=
+
+#############################################################################
+## The following options are used by the xax500 client.  If you haven't    ##
+## retrieved the xax500 source and dropped it into the "clients"           ##
+## directory, you can skip this section.                                   ##
+#############################################################################
+#
+# location of your X include files
+#XINCLUDES= -I/usr/local/X11/include
+#
+# location of your X libraries
+#XLIBDIRS=-L/usr/local/X11/lib
+#
+# include any extra X libraries you need here
+# the following works with sunos 4 and X11R5
+#XLIBS = $(XLIBDIRS) -lXm -lXt -lX11
+# the following has been known to work with Solaris 2.4 and X11R6
+#XLIBS = $(XLIBDIRS) -lXm -lXext -lSM -lICE -lXpm -lXt -lX11
+
+#############################################################################
+## If you don't want to do auto-translation of character sets, skip this   ##
+#############################################################################
+#
+# Otherwise, uncomment this line and set the following options.
+#STR_TRANSLATION=-DSTR_TRANSLATION
+# 
+# remove the defines for LDAP client library T.61 character translation
+# you do not need.  If you use LDAP_CHARSET_8859, replace the '1' in "88591"
+# with the number of the particular character set you use.  E.g., use "88594"
+# if you use the ISO 8859-4 chracter set.
+#LIBLDAP_CHARSETS=-DLDAP_CHARSET_8859="88591"
+# 
+# uncomment one these lines to enable automatic T.61 translation by default
+#LIBLDAP_DEF_CHARSET=-DLDAP_DEFAULT_CHARSET=LDAP_CHARSET_8859
+
+#############################################################################
+## General options                                                         ##
+#############################################################################
+# uncomment this line to enable debugging code (a good idea)
+LDAP_DEBUG=-DLDAP_DEBUG
+
+# uncomment this line to turn on a few U of Michigan specific things
+UOFM=-DUOFM
+
+# uncomment this line to delete a few printfs in the lber and ldap libraries.
+#NO_USERINTERFACE=-DNO_USERINTERFACE
+
+# uncomment this line to include Connectionless LDAP support
+CLDAP=-DCLDAP
+
+# uncomment this line to eliminate local caching support in the libldap
+#NO_CACHE=-DNO_CACHE
+
+# uncomment this line to enable support for LDAP referrals in libldap
+LDAP_REFERRALS=-DLDAP_REFERRALS
+
+# uncomment this line to use soundex for approximate matches in slapd.
+# the default is to use the metaphone algorithm.
+#PHONETIC=-DSOUNDEX
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..a8103f2
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,392 @@
+#
+# You will usually NOT need to edit this file at all:  instead, edit the
+# Make-common file.  See the LDAP INSTALL file for more information.
+#
+#-----------------------------------------------------------------------------
+# Copyright (c) 1994 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP lightweight X.500 Directory access top level makefile
+#
+#-----------------------------------------------------------------------------
+#
+############################################################################
+#                                                                          #
+# Usually you will not need to edit anything in this file                  #
+#                                                                          #
+############################################################################
+#
+# Note that these definitions of standard Unix utilities are only used
+# in this Makefile.  The Make-common (and .make-platform) files have a
+# similar set of definitions that are used in all the other LDAP Makefiles.
+#
+RM=rm -f
+MV=mv -f
+CP=cp
+CAT=cat
+PWD=pwd
+TAIL=tail
+CHMOD=chmod
+FIND=find
+SED=sed
+LN=ln -s
+MKDIR=mkdir
+GREP=grep
+DIRNAME=dirname
+BASENAME=basename
+TAR=tar
+COMPRESS=compress
+CO=co
+CI=ci
+
+
+SRCDIRS= include libraries clients servers doc
+TESTDIR= tests
+
+#
+# LDAPSRC is used by the links rule
+#
+LDAPSRC= ..
+
+
+#
+# rules to make the software
+#
+
+all: makeconfig
+       @echo "making all"
+       @for i in $(SRCDIRS); do \
+           echo; echo "  cd $$i; $(MAKE) $(MFLAGS) all"; \
+           ( cd $$i; $(MAKE) $(MFLAGS) all ); \
+       done
+
+lib-only: makeconfig
+       @echo "making libraries only"
+       @echo "  cd include; $(MAKE) $(MFLAGS) all"; \
+               cd include; $(MAKE) $(MFLAGS) all
+       @echo "  cd libraries; $(MAKE) $(MFLAGS) all"; \
+               cd libraries; $(MAKE) $(MFLAGS) all
+
+
+#
+# rules to install the software
+#
+
+install:       makeconfig
+       @for i in $(SRCDIRS); do \
+           echo; echo "cd $$i; $(MAKE) $(MFLAGS) install"; \
+           ( cd $$i; $(MAKE) $(MFLAGS) install ); \
+       done
+
+inst-lib:      makeconfig
+       @echo "cd libraries; $(MAKE) $(MFLAGS) install"
+       @( cd libraries; $(MAKE) $(MFLAGS) install )
+
+
+#
+# rules to test the LDAP software
+#
+test:  all
+       @echo " cd $(TESTDIR); $(MAKE) $(MFLAGS) all"; \
+       ( cd $(TESTDIR); $(MAKE) $(MFLAGS) all );
+
+#
+# rules to make clean
+#
+
+clean: FORCE
+       @if [ -f .makefiles ]; then \
+           for i in $(SRCDIRS) $(TESTDIR); do \
+               echo; echo "cd $$i; $(MAKE) $(MFLAGS) clean"; \
+               ( cd $$i; $(MAKE) $(MFLAGS) clean ); \
+           done; \
+       fi; \
+       ( for d in ./obj-*; do \
+           if [ $$d != "./obj-*" ]; then \
+               ( echo "making clean in $$d..."; \
+                 cd $$d; $(MAKE) $(MFLAGS) clean; ) \
+           else \
+               exit 0; \
+           fi; \
+       done )
+
+veryclean:     FORCE
+       @echo; echo "cd build; $(MAKE) $(MFLAGS) -f Make-template veryclean"; \
+       ( cd build; $(MAKE) $(MFLAGS) -f Make-template veryclean ); \
+       if [ -f .makefiles ]; then \
+           for i in $(SRCDIRS) $(TESTDIR); do \
+               echo; echo "cd $$i; $(MAKE) $(MFLAGS) veryclean"; \
+               ( cd $$i; $(MAKE) $(MFLAGS) veryclean ); \
+           done; \
+           echo "finding and removing Makefiles..."; \
+           for i in `$(FIND) . -type d -print`; do \
+               if [ -f $$i/Make-template ]; then \
+                   echo "removing file $$i/Makefile"; \
+                   $(RM) $$i/Makefile; \
+               fi; \
+           done; \
+           echo "removing file .makefiles"; \
+           $(RM) .makefiles; \
+       fi; \
+       ( for d in ./obj-*; do \
+           if [ $$d != "./obj-*" ]; then \
+               echo "removing $$d..."; $(RM) -r $$d; \
+           else \
+               exit 0; \
+           fi; \
+       done ); \
+       if [ -f .make-platform ]; then \
+           echo "removing link .make-platform"; \
+           $(RM) .make-platform; \
+       else \
+           exit 0; \
+       fi
+
+
+#
+# rules to make depend
+#
+#
+depend:        makeconfig
+       @echo "making depend everywhere"; \
+       echo "  cd include; $(MAKE) $(MFLAGS) all"; \
+               ( cd include; $(MAKE) $(MFLAGS) all ); \
+       for i in $(SRCDIRS); do \
+           echo; echo "cd $$i; $(MAKE) $(MFLAGS) depend"; \
+           ( cd $$i; $(MAKE) $(MFLAGS) depend ); \
+       done; \
+       $(MAKE) $(MFLAGS) makefiles
+
+#
+# rules to check out and in Make-template files
+#
+co-mktmpls:    FORCE
+       @echo "checking out Make-template files..."; \
+       for mkfile in `$(FIND) . -name Make-template -type f -print`; do \
+           $(CO) -l $$mkfile; \
+       done
+
+ci-mktmpls:    FORCE
+       @echo "enter a one-word log message:"; \
+       read logmsg; \
+       echo "checking in Make-template files..."; \
+       for mkfile in `$(FIND) . -name Make-template -type f -print`; do \
+           $(CI) -m$$logmsg -u $$mkfile; \
+       done
+
+
+lib-depend:    makeconfig
+       @echo "cd libraries; $(MAKE) $(MFLAGS) depend"
+       @( cd libraries; $(MAKE) $(MFLAGS) depend )"
+
+#
+# rules to cut a new ldap distribution
+#
+distribution:  makeconfig checkin tar
+
+checkin:       FORCE
+       @-VERSION=V`cat ./build/version | $(SED) -e 's/\.//'` ; \
+       echo "Checking in version $$VERSION"; \
+       for i in `$(FIND) . -name \*,v -print | \
+               $(SED) -e 's%RCS/%%' -e 's%,v%%'`; \
+           do ( \
+               ci -m"pre-version $$VERSION check-in" -u $$i; \
+               rcs -N$$VERSION: $$i ) \
+           done
+
+tar:   veryclean
+       @PWD=`pwd`; \
+       $(RM) ./Make-common;  \
+       $(CP) ./Make-common.dist ./Make-common; \
+       $(CHMOD) 644 ./Make-common; \
+       $(RM) ./include/ldapconfig.h.edit; \
+       $(CP) ./include/ldapconfig.h.dist ./include/ldapconfig.h.edit; \
+       $(CHMOD) 644 ./include/ldapconfig.h.edit; \
+       BASE=`$(BASENAME) $$PWD`; XFILE=/tmp/ldap-x.$$$$; \
+       ( cd .. ; $(CAT) $$BASE/exclude >$$XFILE; \
+         $(FIND) $$BASE -name RCS -print >> $$XFILE ; \
+         $(FIND) $$BASE -name obj-\* -print >> $$XFILE ; \
+         $(FIND) $$BASE -name tags -print >> $$XFILE ; \
+         $(TAR) cvfX ./$$BASE.tar $$XFILE $$BASE; \
+       ); \
+       $(RM) $$XFILE; \
+       echo "compressing ../$$BASE.tar..."; \
+       $(COMPRESS) ../$$BASE.tar 
+
+#
+# rule to force check for change of platform
+#
+platform:      FORCE
+       @if [ -f .make-platform ]; then \
+           echo "removing old link .make-platform"; \
+           $(RM) .make-platform; \
+       fi; \
+       $(MAKE) $(MFLAGS) .make-platform
+
+
+makeconfig:    .makefiles buildtools
+
+.make-platform:
+       @if [ -f /usr/bin/swconfig ]; then \
+           UNAME=./build/uname.sh; \
+       elif [ -f /bin/uname ]; then \
+           UNAME=/bin/uname; \
+       elif [ -f /usr/bin/uname ]; then \
+           UNAME=/usr/bin/uname; \
+       else \
+           UNAME=./build/uname.sh; \
+       fi; \
+       if [ -z "$$UNAME" ]; then \
+           echo "unknown platform (no $$UNAME or /usr/bin/uname)"; \
+           echo "see the file  build/PORTS  for more information."; \
+           exit 1; \
+       else \
+           OS=`$$UNAME -s` ; OSRELEASE=`$$UNAME -r` ; \
+           OSVERSION=`$$UNAME -v` ; \
+           case $$OS in \
+           SunOS) \
+               if [ $$OSRELEASE -gt "5" -o $$OSRELEASE -lt "4" ]; then \
+                   echo "SunOS release $$OSRELEASE unknown..."; exit 1; \
+               fi; \
+               if [ $$OSRELEASE -ge "5" ]; then \
+                   PLATFORM="sunos5"; \
+               else \
+                   PLATFORM="sunos4"; \
+               fi; \
+               ;; \
+           ULTRIX) \
+               PLATFORM="ultrix" \
+               ;; \
+           OSF1) \
+               PLATFORM="osf1" \
+               ;; \
+           AIX) \
+               PLATFORM="aix" \
+               ;; \
+           HP-UX) \
+               PLATFORM="hpux" \
+               ;; \
+           Linux) \
+               PLATFORM="linux" \
+               ;; \
+           NetBSD) \
+               PLATFORM="netbsd" \
+               ;; \
+           FreeBSD) \
+               PLATFORM="freebsd" \
+               ;; \
+           NeXTSTEP) \
+               PLATFORM="nextstep" \
+               ;; \
+           SCO) \
+               PLATFORM="sco" \
+               ;; \
+           IRIX|IRIX64) \
+               PLATFORM="irix" \
+               ;; \
+           *) echo "unknown platform ($$OS $$OSVERSION $$OSRELEASE)..."; \
+              echo "see the file  build/PORTS  for more information."; \
+               exit 1; \
+               ;; \
+           esac; \
+       fi; \
+       CC=$(CC); \
+       OLDIFS="$$IFS"; \
+       IFS=":"; \
+       for dir in $$PATH; do \
+           if [ -f $$dir/gcc ]; then \
+               CC=gcc; \
+               break; \
+           fi; \
+       done; \
+       IFS="$$OLDIFS"; \
+       $(LN) ./build/platforms/$$PLATFORM-$$CC/Make-platform .make-platform; \
+       echo ""; \
+       echo "** Set platform to $$PLATFORM with compiler $$CC..."; \
+       echo ""
+
+#
+# rule to build Makefiles by concatenating Make-template file in each
+# subdirectory with global Make-common, .make-platform, and
+# build/Make-append files
+#
+.makefiles:    Make-common .make-platform build/Make-append
+       @echo "making Makefiles..."; \
+       HDRFILE=/tmp/Makehdr.$$$$; \
+       DEFSFILE=/tmp/Makedefs.$$$$; \
+       $(CAT) build/Make-append ./.make-platform ./Make-common > $$DEFSFILE; \
+       echo "# --------------------------------------------------------" >  $$HDRFILE; \
+       echo "#  This file was automatically generated.  Do not edit it."  >> $$HDRFILE; \
+       echo "#  Instead, edit the Make-common file (located in the root"  >> $$HDRFILE; \
+       echo "#  (of the LDAP distribution).  See the LDAP INSTALL file"   >> $$HDRFILE; \
+       echo "#  for more information." >> $$HDRFILE; \
+       echo "# --------------------------------------------------------" >> $$HDRFILE; \
+       echo "#" >> $$HDRFILE; \
+       for i in `$(FIND) . -type d -print`; do \
+           if [ -f $$i/Make-template ]; then \
+               echo "  creating $$i/Makefile"; \
+               $(RM) $$i/Makefile; \
+               $(CAT) $$HDRFILE $$i/Make-template $$DEFSFILE > $$i/Makefile; \
+               $(CHMOD) 444 $$i/Makefile; \
+           fi; \
+       done; \
+       $(RM) .makefiles; \
+       touch .makefiles; \
+       $(RM) $$HDRFILE $$DEFSFILE
+
+#
+# rule to always build makefiles
+#
+makefiles:     FORCE
+       $(RM) .makefiles
+       $(MAKE) $(MFLAGS) .makefiles
+
+#
+# rule to create any tools we need to build everything else
+#
+buildtools:    FORCE
+       @echo "making buildtools"
+       @echo "  cd build; $(MAKE) $(MFLAGS)"
+       @( cd build; $(MAKE) $(MFLAGS) )
+
+#
+# rule to make a shadow (linked) build area
+#
+links: FORCE
+       @if [ -f /usr/bin/swconfig ]; then \
+           UNAME=./build/uname.sh; \
+       elif [ -f /bin/uname ]; then \
+           UNAME=/bin/uname; \
+       elif [ -f /usr/bin/uname ]; then \
+           UNAME=/usr/bin/uname; \
+       else \
+           UNAME=./build/uname.sh; \
+       fi; \
+       if [ ! -z "$(DEST)" ]; then \
+           DEST="$(DEST)"; \
+       else \
+           DEST=./obj-`$$UNAME -s`-`$$UNAME -r` ; \
+       fi; \
+       echo "making links in $$DEST..."; \
+       LINKLIST=/tmp/ldaplinklist.$$$$; \
+       $(RM) $$LINKLIST; \
+       $(MKDIR) $$DEST; \
+       cd $$DEST; $(LN) $(LDAPSRC) .src; \
+       $(LN) .src/Makefile . ; \
+       $(CP) .src/Make-common . ; $(CHMOD) 644 ./Make-common; \
+       for d in build $(SRCDIRS) $(TESTDIR); do \
+               ( $(MKDIR) $$d; cd $$d; $(LN) ../.src/$$d .src; \
+                 $(LN) .src/Make-template . ; \
+                 $(MAKE) $(MFLAGS) MKDIR="$(MKDIR)" LN="$(LN)" \
+                       -f Make-template links ) ; \
+       done; \
+       echo ""; echo "Now type:"; echo "  cd $$DEST"; echo "and make there"
+
+FORCE:
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..fb8dd8a
--- /dev/null
+++ b/README
@@ -0,0 +1,59 @@
+UM-LDAP 3.3 README file
+
+    This is the UM-LDAP version 3.3 distribution.  For a description of
+    what this distribution contains, see the ANNOUNCEMENT file in this
+    directory.  For a description of changes from previous releases,
+    see the CHANGES file in this directory.  For a more detailed
+    description of how to make and install the distribution, see the
+    INSTALL file in this directory.  For more information on making and
+    installing slapd, see the "SLAPD and SLURPD Administrator's Guide"
+    in the doc/guides/ directory.
+
+MAKING AND INSTALLING THE DISTRIBUTION
+
+    You should be able to make and install the distribution with a pretty
+    standard default configuration by typing the following commands
+
+       % make
+       % su
+       # make install
+
+    in this directory.  This should produce something that basically
+    works.
+
+    You will probably want to do a little configuration to suit your
+    site, though.  There are two files you might want to edit:
+
+       Make-common                This file contains definitions for
+                                  where things will be installed, where
+                                  to find various things, etc.  If you
+                                  want to build an ldap server, you'll
+                                  definitely need to edit this file
+
+       include/ldapconfig.h.edit  This file contains #defines used
+                                  by many parts of the distribution.
+                                  You'll at least want to change
+                                  DEFAULT_BASE.
+
+    See the INSTALL file in this directory for more information.
+
+DOCUMENTATION
+
+    There are man pages for most programs in the distribution and
+    routines in the various libraries.  See ldap(3) for details.
+
+    There is a postscript version of an administrator's guide for
+    slapd in doc/guides/slapd.ps.
+
+    There is an LDAP homepage available that contains the latest
+    LDAP news, releases announcements, pointers to other LDAP resources,
+    etc. You can access it at this URL:
+
+       http://www.umich.edu/~rsug/ldap/
+
+FEEDBACK / PROBLEM REPORTS
+
+    We would appreciate any feedback you can provide.  If you have
+    problems, report them to this address:
+
+       ldap-support@umich.edu
diff --git a/build/Make-append b/build/Make-append
new file mode 100644 (file)
index 0000000..67a2f29
--- /dev/null
@@ -0,0 +1,78 @@
+#
+# Do NOT edit this file -- it is automatically appended to all Makefiles
+# except the LDAP top-level Makefile. See the LDAP INSTALL file for more
+# information.
+#
+#-----------------------------------------------------------------------------
+# Copyright (c) 1994 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP standard Make defines (appended to all but top-level Makefile)
+#
+#-----------------------------------------------------------------------------
+
+# DEFS are included in CFLAGS
+DEFS   = $(PLATFORMCFLAGS) $(LDAP_DEBUG) $(KERBEROS) $(AFSKERBEROS) \
+               $(UOFM) $(UOFA) $(NO_USERINTERFACE) $(CLDAP) $(NO_CACHE) \
+               $(LDAP_REFERRALS) $(LDAP_DNS) $(STR_TRANSLATION) \
+               $(LIBLDAP_CHARSETS) $(LIBLDAP_DEF_CHARSET) \
+               $(SLAPD_BACKENDS) $(LDBMBACKEND) $(LDBMINCLUDE) $(PHONETIC)
+
+# SERVERDEFS are added to server builds CFLAGS (in addition to DEFS)
+SERVERDEFS     = $(ISODEPACKAGE) $(ICRELEASE) $(LDAP_USE_PP) \
+                       $(NO_SETPROCTITLE) $(PEPSY_DUMP)
+
+#
+# ISODELIBS are used in server/ldapd builds
+#
+ISODELIBS      = $(ISODEBASELIBS) -lm $(ISODETURBOLIBS)
+
+# ACFLAGS are added to CFLAGS but not passed to mkdep, lint, etc
+ACFLAGS                = $(EXTRACFLAGS) $(UNPROTOCFLAGS)
+
+# ALDFLAGS are always placed near the beginning of all linker (cc -o) commands
+ALDFLAGS       = $(EXTRALDFLAGS) $(PLATFORMLDFLAGS)
+
+# ALIBS are always placed at the end of all linker (cc -o) commands
+ALIBS          = $(PLATFORMLIBS)
+
+#
+# default definitions for Unix utilities (may be over-ridden in Make-platform)
+CC     = cc
+MAKE   = make
+RANLIB = ranlib
+AR     = ar
+RM     = rm -f
+MV     = mv -f
+CP     = cp
+CHMOD  = chmod
+CAT    = cat
+LN     = ln -s
+HARDLN = ln
+TAIL   = tail
+SED    = sed
+LINT   = lint
+5LINT  = lint
+MKDIR  = mkdir
+INSTALL        = install
+INSTALLFLAGS = -c
+BASENAME= basename
+DIRNAME        = dirname
+MKDEP  = $(LDAPSRC)/build/mkdep -s -f Make-template
+PWD    = pwd
+DATE   = date
+HOSTNAME= hostname
+
+
+#
+# empty target used to force rules to be invoked
+#
+FORCE:
+
diff --git a/build/Make-template b/build/Make-template
new file mode 100644 (file)
index 0000000..28055d9
--- /dev/null
@@ -0,0 +1,38 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1994 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP buildtools makefile
+#
+#-----------------------------------------------------------------------------
+
+all:   FORCE
+       @if [ ! -z "$(NEEDUNPROTO)" ]; then \
+           cd unproto; $(MAKE) $(MFLAGS) CC=$(CC); \
+       else \
+           exit 0; \
+       fi
+
+install:       FORCE
+
+clean:
+       cd unproto; $(MAKE) $(MFLAGS) clean
+       cd platforms; $(MAKE) $(MFLAGS) clean
+
+veryclean:
+       cd unproto; $(MAKE) $(MFLAGS) clean
+       cd platforms; $(MAKE) $(MFLAGS) veryclean
+
+links:
+       @echo "making links in `$(PWD)`"; \
+       $(LN) .src/version .src/platforms .src/Make-append .src/install.sh . ; \
+       ( $(MKDIR) unproto; cd unproto; $(LN) ../.src/unproto .src; \
+         $(LN) .src/Makefile .src/*.[ch] . )
+
diff --git a/build/PORTS b/build/PORTS
new file mode 100644 (file)
index 0000000..b51ba12
--- /dev/null
@@ -0,0 +1,98 @@
+This file gives some helpful hints for building LDAP on various machines.
+
+LDAP has been built and tested on the following platforms.  It will
+probably build fine under similar versions of the OS (e.g. it has
+been built and tested under SunOS 4.1.4, but probably builds fine
+under all SunOS 4.1.x systems).
+
+If you port LDAP to a new platform, let us know so we can add it here.
+See the end of this file for some hints on doing a port.  The following
+tables give some indication of the level of support there is for various
+platforms where the LDAP release has been built.  Key:
+
+    X - all pieces are known to build and work
+    B - all pieces build and are believed to work
+    S - some pieces build and work
+    O - an older LDAP release has been ported here; current status unknown
+    ? - unknown
+    - - does not build and/or work at all
+
+** Unix and Unix-like platforms:
+
+ OS Version     libraries   clients    ldapd    slapd    slurpd
+ ----------     ---------   -------    -----    -----    ------
+ AIX 3.2.5          X          X         B        B        -(1)
+
+ HP-UX 9.05         X          X         ?        B        -(1)
+
+ Linux 1.3.76       X          X         O        X        -(1)
+
+ FreeBSD 2.0.5      X          X         ?        B        ?
+
+ NETBSD 0.9a        O          O         ?        ?        ?
+
+ NeXTSTEP 3.2       O          O         ?        ?        ?
+
+ SunOS 4.1.4        X          X         X        X        X
+
+ SunOS 5.5          X          X         B        X        X
+ (Solaris 2.5)
+
+ Ultrix 4.3         X          X         B        B        ?
+
+ OSF/1 3.2          X          X         X        X        ?
+
+ IRIX 5.x/6.x       B          B         ?        B        ?
+
+ NCR MP-RAS 2.3     X          X         ?        ?        ?
+
+(1) - required threads support not provided by vendor
+
+** Non-Unix Platforms:
+
+ OS Version     libraries   clients    ldapd    slapd    slurpd
+ ----------     ---------   -------    -----    -----    ------
+ MacOS 7.5          X          -         -        -        -
+     (see the file libraries/macintosh/README for build instructions)
+
+ MSDOS              O          S         -        -        -
+     (see the file libraries/msdos/README for build instructions)
+
+ MS-Windows 3.x     O          -         -        -        -
+     (see the file libraries/msdos/README.WSA for build instructions)
+
+ MS-Win NT & 95     O          ?         ?        ?        ?
+
+ VMS                X          S         X        X        ?
+     (see the file libraries/vms/README.VMS for build instructions)
+
+
+** Hints on Porting LDAP to a New Platform
+
+If your platform is not listed here, you will need to do a port.  The
+place to start for Unix systems is by creating a new directory under
+the LDAP build/platforms directory and creating an appropriate
+Make-platform file.  It is probably easiest to start by duplicating a
+directory there that is for a platform similar to yours.
+
+Variables commonly set in the Make-platform files include:
+
+CC              - compiler to use, e.g. CC=cc or CC=gcc
+PLATFORMCFLAGS  - flags added to every compile
+PLATFORMLDFLAGS - flags added to every link
+PLATFORMLIBS    - extra libraries needed (added to the end of all link commands)
+LDBMLIB         - ndbm library, needed if not in libc (e.g. LDBMLIB=-lndbm)
+NEEDUNPROTO=yes - set if your compiler doesn't understand prototypes; see the
+                      sunos4-cc and hpux-cc files for example usage
+INSTALL         - BSD-like install command; if necessary, you can use a script
+                      we provide:  INSTALL=$(LDAPSRC)/build/install.sh
+RANLIB          - command to convert libraries for efficient random access;
+                      if your system has no ranlib, use RANLIB = ""
+other commands  - see the file build/Make-append for a list
+
+You will also need to modify the top-level LDAP Makefile .make-platform
+rule to know about your platform.  Finally, you should look through the
+include/portable.h file and make any necessary adjustments.
+
+Please send changes via e-mail to:  ldap-support@umich.edu so they can be
+incorporated into future releases.
diff --git a/build/README-unproto b/build/README-unproto
new file mode 100644 (file)
index 0000000..05def5e
--- /dev/null
@@ -0,0 +1,3 @@
+The unproto code was obtained from:
+
+    ftp://ftp.win.tue.nl/pub/unix/unproto5.shar.Z
diff --git a/build/db.1.85.patch b/build/db.1.85.patch
new file mode 100644 (file)
index 0000000..b6e227b
--- /dev/null
@@ -0,0 +1,158 @@
+*** ./hash/hash.h.bak  Fri May 12 11:00:42 1995
+--- ./hash/hash.h      Fri May 12 11:01:07 1995
+***************
+*** 103,109 ****
+       BUFHEAD         *cpage;         /* Current page */
+       int             cbucket;        /* Current bucket */
+       int             cndx;           /* Index of next item on cpage */
+!      int             errno;          /* Error Number -- for DBM 
+                                        * compatability */
+       int             new_file;       /* Indicates if fd is backing store 
+                                        * or no */
+--- 103,109 ----
+       BUFHEAD         *cpage;         /* Current page */
+       int             cbucket;        /* Current bucket */
+       int             cndx;           /* Index of next item on cpage */
+!      int             h_errno;        /* Error Number -- for DBM 
+                                        * compatability */
+       int             new_file;       /* Indicates if fd is backing store 
+                                        * or no */
+*** ./hash/hash.c.bak  Fri May 12 11:02:03 1995
+--- ./hash/hash.c      Fri May 12 11:02:42 1995
+***************
+*** 505,511 ****
+       else
+               if (wsize != sizeof(HASHHDR)) {
+                       errno = EFTYPE;
+!                      hashp->errno = errno;
+                       return (-1);
+               }
+       for (i = 0; i < NCACHED; i++)
+--- 505,511 ----
+       else
+               if (wsize != sizeof(HASHHDR)) {
+                       errno = EFTYPE;
+!                      hashp->h_errno = errno;
+                       return (-1);
+               }
+       for (i = 0; i < NCACHED; i++)
+***************
+*** 536,542 ****
+  
+       hashp = (HTAB *)dbp->internal;
+       if (flag) {
+!              hashp->errno = errno = EINVAL;
+               return (ERROR);
+       }
+       return (hash_access(hashp, HASH_GET, (DBT *)key, data));
+--- 536,542 ----
+  
+       hashp = (HTAB *)dbp->internal;
+       if (flag) {
+!              hashp->h_errno = errno = EINVAL;
+               return (ERROR);
+       }
+       return (hash_access(hashp, HASH_GET, (DBT *)key, data));
+***************
+*** 553,563 ****
+  
+       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 ?
+--- 553,563 ----
+  
+       hashp = (HTAB *)dbp->internal;
+       if (flag && flag != R_NOOVERWRITE) {
+!              hashp->h_errno = errno = EINVAL;
+               return (ERROR);
+       }
+       if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
+!              hashp->h_errno = errno = EPERM;
+               return (ERROR);
+       }
+       return (hash_access(hashp, flag == R_NOOVERWRITE ?
+***************
+*** 574,584 ****
+  
+       hashp = (HTAB *)dbp->internal;
+       if (flag && flag != R_CURSOR) {
+!              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));
+--- 574,584 ----
+  
+       hashp = (HTAB *)dbp->internal;
+       if (flag && flag != R_CURSOR) {
+!              hashp->h_errno = errno = EINVAL;
+               return (ERROR);
+       }
+       if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
+!              hashp->h_errno = errno = EPERM;
+               return (ERROR);
+       }
+       return (hash_access(hashp, HASH_DELETE, (DBT *)key, NULL));
+***************
+*** 729,735 ****
+  
+       hashp = (HTAB *)dbp->internal;
+       if (flag && flag != R_FIRST && flag != R_NEXT) {
+!              hashp->errno = errno = EINVAL;
+               return (ERROR);
+       }
+  #ifdef HASH_STATISTICS
+--- 729,735 ----
+  
+       hashp = (HTAB *)dbp->internal;
+       if (flag && flag != R_FIRST && flag != R_NEXT) {
+!              hashp->h_errno = errno = EINVAL;
+               return (ERROR);
+       }
+  #ifdef HASH_STATISTICS
+*** ./hash/ndbm.c.bak  Fri May 12 11:02:06 1995
+--- ./hash/ndbm.c      Fri May 12 11:02:54 1995
+***************
+*** 180,186 ****
+       HTAB *hp;
+  
+       hp = (HTAB *)db->internal;
+!      return (hp->errno);
+  }
+  
+  extern int
+--- 180,186 ----
+       HTAB *hp;
+  
+       hp = (HTAB *)db->internal;
+!      return (hp->h_errno);
+  }
+  
+  extern int
+***************
+*** 190,196 ****
+       HTAB *hp;
+  
+       hp = (HTAB *)db->internal;
+!      hp->errno = 0;
+       return (0);
+  }
+  
+--- 190,196 ----
+       HTAB *hp;
+  
+       hp = (HTAB *)db->internal;
+!      hp->h_errno = 0;
+       return (0);
+  }
+  
diff --git a/build/install.sh b/build/install.sh
new file mode 100755 (executable)
index 0000000..b9ac07f
--- /dev/null
@@ -0,0 +1,45 @@
+#!/bin/sh
+# simple BSD-like install replacement
+#
+# Copyright (c) 1994 The Regents of the University of Michigan
+#
+
+MODE=0755
+USAGE="usage: $0 [-c] [-m mode] file dir"
+
+while [ $# != 0 ]; do
+    case "$1" in
+    -c)
+       ;;
+    -m)
+       MODE=$2
+       shift
+       ;;
+    -*)
+       echo "$USAGE"
+       exit 1
+       ;;
+    *)
+       break
+       ;;
+    esac
+    shift
+done
+
+if [ $# != 2 ]; then
+    echo "$USAGE"
+    exit 1
+fi
+
+FILE=$1
+DIR=$2
+
+cp $FILE $DIR
+if [ -d $DIR ]; then
+    chmod $MODE $DIR/`basename $FILE`
+else
+#
+# DIR is really the destination file
+#
+    chmod $MODE $DIR
+fi
diff --git a/build/mkdep b/build/mkdep
new file mode 100755 (executable)
index 0000000..006f05a
--- /dev/null
@@ -0,0 +1,133 @@
+#!/bin/sh -
+#
+# 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.
+#
+#      @(#)mkdep.sh    5.12 (Berkeley) 6/30/88
+#
+# We now use whatever path is already set by the invoker
+#PATH=/bin:/usr/bin:/usr/ucb
+#export PATH
+
+set -e                         # exit immediately if any errors occur
+
+MAKE=Makefile                  # default makefile name is "Makefile"
+NOSLASH="no"                   # by default, / dependencies are included
+CC=cc                          # default compiler is cc
+
+while :
+       do case "$1" in
+               # -f allows you to select a makefile name
+               -f)
+                       MAKE=$2
+                       shift; shift ;;
+
+               # -c allows you to select a compiler to use (default is cc)
+               -c)
+                       CC=$2
+                       shift; shift ;;
+
+               # the -p flag produces "program: program.c" style dependencies
+               # so .o's don't get produced
+               -p)
+                       SED='s;\.o;;'
+                       shift ;;
+
+               # the -s flag removes dependencies to files that begin with /
+               -s)
+                       NOSLASH=yes;
+                       shift ;;
+
+#              -*)     shift ;;
+
+               *)
+                       break ;;
+       esac
+done
+
+if [ $# = 0 ] ; then
+       echo 'usage: mkdep [-p] [-f makefile] [flags] file ...'
+       exit 1
+fi
+
+if [ ! -w $MAKE ]; then
+       echo "mkdep: no writeable file \"$MAKE\""
+       exit 1
+fi
+
+TMP=/tmp/mkdep$$
+
+trap 'rm -f $TMP ; exit 1' 1 2 3 13 15
+
+cp $MAKE ${MAKE}.bak
+
+sed -e '/DO NOT DELETE THIS LINE/,$d' < $MAKE > $TMP
+
+cat << _EOF_ >> $TMP
+# DO NOT DELETE THIS LINE -- mkdep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+_EOF_
+
+# If your compiler doesn't have -M, add it.  If you can't, the next two
+# lines will try and replace the "cc -M".  The real problem is that this
+# hack can't deal with anything that requires a search path, and doesn't
+# even try for anything using bracket (<>) syntax.
+#
+# egrep '^#include[    ]*".*"' /dev/null $* |
+# sed -e 's/:[^"]*"\([^"]*\)".*/: \1/' -e 's/\.c/.o/' |
+
+$CC -M $* |
+sed "
+       s; \./; ;g
+       $SED" |
+awk '
+$1 ~ /:/ {
+       filenm=$1
+       dep=$2
+}
+$1 !~ /:/ {
+       dep=$1
+}
+/.*/ {
+       if ( noslash = "yes" && dep ~ /^\// ) next
+       if (filenm != prev) {
+               if (rec != "")
+                       print rec;
+               rec = filenm " " dep;
+               prev = filenm;
+       }
+       else {
+               if (length(rec dep) > 78) {
+                       print rec;
+                       rec = filenm " " dep;
+               }
+               else
+                       rec = rec " " dep
+       }
+    }
+END {
+       print rec
+}' noslash="$NOSLASH" >> $TMP
+
+cat << _EOF_ >> $TMP
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
+_EOF_
+
+# copy to preserve permissions
+cp $TMP $MAKE
+rm -f ${MAKE}.bak $TMP
+exit 0
diff --git a/build/platforms/Make-setup b/build/platforms/Make-setup
new file mode 100644 (file)
index 0000000..9e09919
--- /dev/null
@@ -0,0 +1,68 @@
+#
+# You should NOT need to edit this file at all:  if you just type make
+# in this directory, LDAP will be built for this platform using this
+# compiler.  If you type   make links  a build area will be created for
+# you under ./obj.  You should # cd in there and edit the Make-common file
+# before building.  See the LDAP INSTALL file for more information.
+#
+#-----------------------------------------------------------------------------
+# Copyright (c) 1994 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP lightweight X.500 Directory access platform setup makefile
+#
+#-----------------------------------------------------------------------------
+#
+############################################################################
+#                                                                          #
+# You should not have to edit anything in this file                        #
+#                                                                          #
+############################################################################
+LN=ln -s
+RM=rm -f
+SED=sed
+PWD=pwd
+
+LDAPSRC= ../../..
+
+all:   platform
+       ( cd $(LDAPSRC); $(MAKE) $(MFLAGS) )
+
+install: platform
+       ( cd $(LDAPSRC); $(MAKE) $(MFLAGS) install )
+
+platform:      FORCE
+       @PWD=`$(PWD)`; \
+       PLATFORMCC=`basename $$PWD`; \
+       PLATFORM=`echo $$PLATFORMCC | $(SED) 's/-.*$$//'`; \
+       CC=`echo $$PLATFORMCC | $(SED) 's/^.*-//'`; \
+       echo "** Setting platform to $$PLATFORM and compiler $$CC"; \
+       ( cd $(LDAPSRC); \
+         $(RM) .make-platform; \
+         $(LN) build/platforms/$$PLATFORMCC/Make-platform .make-platform )
+
+links: FORCE
+       @PWD=`$(PWD)`; \
+       PLATFORMCC=`basename $$PWD`; \
+       DEST=./obj-$$PLATFORMCC; \
+       PLATFORM=`echo $$PLATFORMCC | $(SED) 's/-.*$$//'`; \
+       CC=`echo $$PLATFORMCC | $(SED) 's/^.*-//'`; \
+       echo "** Setting platform to $$PLATFORM and compiler $$CC"; \
+       ( cd $(LDAPSRC); $(MAKE) $(MFLAGS) DEST=$$DEST links; \
+         cd $$DEST; \
+         $(LN) .src/build/platforms/$$PLATFORMCC/Make-platform .make-platform ); \
+       $(LN) $(LDAPSRC)/$$DEST .
+
+clean: FORCE
+
+veryclean:
+       -$(RM) -r ./obj-*
+
+FORCE: 
diff --git a/build/platforms/Makefile b/build/platforms/Makefile
new file mode 100644 (file)
index 0000000..38f3194
--- /dev/null
@@ -0,0 +1,46 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1994 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP build/platforms Makefile
+#
+#-----------------------------------------------------------------------------
+
+############################################################################
+#                                                                          #
+# You should not have to edit anything below this point                    #
+#                                                                          #
+############################################################################
+
+all:   FORCE
+
+
+install:       FORCE
+
+clean: FORCE
+       @echo "making clean in `pwd`"
+       @for i in *; do \
+           if [ -d $$i -a $$i != "RCS" ]; then \
+               echo; echo "  cd $$i; $(MAKE) $(MFLAGS) clean"; \
+               ( cd $$i; $(MAKE) $(MFLAGS) clean ); \
+           fi; \
+       done
+
+veryclean:     FORCE
+       @echo "making veryclean in `pwd`"
+       @for i in *; do \
+           if [ -d $$i -a $$i != "RCS" ]; then \
+               echo; echo "  cd $$i; $(MAKE) $(MFLAGS) veryclean"; \
+               ( cd $$i; $(MAKE) $(MFLAGS) veryclean ); \
+           fi; \
+       done
+
+FORCE:
+
diff --git a/build/platforms/aix-cc/Make-platform b/build/platforms/aix-cc/Make-platform
new file mode 100644 (file)
index 0000000..cb2e2fd
--- /dev/null
@@ -0,0 +1,18 @@
+#
+# LDAP AIX standard cc Make-platform file
+#
+
+
+#
+# add any platform-specific overrides below here
+#
+
+#
+# -------------------------------------------------------------------------
+# you will probably not need to edit anything below this point
+# -------------------------------------------------------------------------
+
+# install with BSD semantics
+INSTALL=/usr/ucb/install
+
+PLATFORMCFLAGS=        -Daix
diff --git a/build/platforms/aix-gcc/Make-platform b/build/platforms/aix-gcc/Make-platform
new file mode 100644 (file)
index 0000000..29a7774
--- /dev/null
@@ -0,0 +1,19 @@
+#
+# LDAP AIX standard cc Make-platform file
+#
+
+
+#
+# add any platform-specific overrides below here
+#
+
+#
+# -------------------------------------------------------------------------
+# you will probably not need to edit anything below this point
+# -------------------------------------------------------------------------
+CC     = gcc
+
+# install with BSD commandline
+INSTALL=/usr/ucb/install
+
+PLATFORMCFLAGS=        -Daix
diff --git a/build/platforms/freebsd-gcc/Make-platform b/build/platforms/freebsd-gcc/Make-platform
new file mode 100644 (file)
index 0000000..895b32f
--- /dev/null
@@ -0,0 +1,16 @@
+#
+# LDAP FreeBSD GNU C Make-platform file
+#
+
+
+#
+# add any platform-specific overrides below here
+#
+
+#
+# -------------------------------------------------------------------------
+# you will probably not need to edit anything below this point
+# -------------------------------------------------------------------------
+CC     = gcc
+
+PLATFORMCFLAGS=        -Dfreebsd
diff --git a/build/platforms/hpux-c89/Make-platform b/build/platforms/hpux-c89/Make-platform
new file mode 100644 (file)
index 0000000..f3d502e
--- /dev/null
@@ -0,0 +1,27 @@
+#
+# HP-UX optional c89 Make-platform file
+#
+
+#
+# add any platform-specific overrides below here
+#
+
+#
+# -------------------------------------------------------------------------
+# you will probably not need to edit anything below this point
+# -------------------------------------------------------------------------
+CC=c89
+
+# ranlib not needed under HP-UX
+RANLIB  = ""
+
+# install under HP-UX is not like on BSD systems, so we use our own script
+INSTALL=$(LDAPSRC)/build/install.sh
+
+# we need to link a separate library to get ndbm routines under HP/UX
+LDBMLIB=-lndbm
+
+# we need to link in the V3 library to get sigset()
+PLATFORMLIBS= -lV3
+
+PLATFORMCFLAGS= -Dhpux -Aa -D_HPUX_SOURCE
diff --git a/build/platforms/hpux-cc/Make-platform b/build/platforms/hpux-cc/Make-platform
new file mode 100644 (file)
index 0000000..3c81367
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# LDAP HP-UX standard cc Make-platform file
+#
+
+#
+# add any platform-specific overrides below here
+#
+
+
+#
+# -------------------------------------------------------------------------
+# you will probably not need to edit anything below this point
+# -------------------------------------------------------------------------
+# ranlib not needed under HP-UX
+RANLIB = ""
+
+# install under HP-UX is not like on BSD systems, so we use our own script
+INSTALL=$(LDAPSRC)/build/install.sh
+
+# we need to link a separate library to get ndbm routines under HP/UX 
+LDBMLIB=-lndbm
+
+PLATFORMCFLAGS= -Dhpux
+
+# we need to link in the V3 library to get sigset()
+PLATFORMLIBS= -lV3
+
+#
+# the HP-UX cc compiler doesn't understand function prototypes, so we
+# need the unproto preprocessor
+#
+NEEDUNPROTO=yes
+UNPROTOCFLAGS=-tp,$(LDAPSRC)/build/unproto/cpp
diff --git a/build/platforms/hpux-gcc/Make-platform b/build/platforms/hpux-gcc/Make-platform
new file mode 100644 (file)
index 0000000..2c3d77d
--- /dev/null
@@ -0,0 +1,28 @@
+#
+# LDAP HP-UX gcc Make-platform file
+#
+
+#
+# add any platform-specific overrides below here
+#
+
+
+#
+# -------------------------------------------------------------------------
+# you will probably not need to edit anything below this point
+# -------------------------------------------------------------------------
+CC=gcc
+
+# ranlib not needed under HP-UX
+RANLIB = ""
+
+# install under HP-UX is not like on BSD systems, so we use our own script
+INSTALL=$(LDAPSRC)/build/install.sh
+
+# we need to link a separate library to get ndbm routines under HP/UX 
+LDBMLIB=-lndbm
+
+# we need to link in the V3 library to get sigset()
+PLATFORMLIBS= -lV3
+
+PLATFORMCFLAGS= -Dhpux
diff --git a/build/platforms/irix-cc/Make-platform b/build/platforms/irix-cc/Make-platform
new file mode 100644 (file)
index 0000000..c4b1955
--- /dev/null
@@ -0,0 +1,29 @@
+#
+# LDAP IRIX standard cc Make-platform file
+#
+
+#
+# add any platform-specific overrides below here
+#
+
+
+#
+# -------------------------------------------------------------------------
+# you will probably not need to edit anything below this point
+# -------------------------------------------------------------------------
+# ranlib not needed under IRIX
+RANLIB = ""
+
+# be explicit about which CC to use
+CC=cc
+
+# give full path to hostname since it may not be in user's path
+HOSTNAME=/usr/bsd/hostname
+
+# don't count on a BSD install being present or first in path
+INSTALL=$(LDAPSRC)/build/install.sh
+
+PLATFORMCFLAGS=-DUSE_WAITPID
+PLATFORMLIBS=
+THREADS=
+THREADSLIB=
diff --git a/build/platforms/irix-gcc/Make-platform b/build/platforms/irix-gcc/Make-platform
new file mode 100644 (file)
index 0000000..96f698d
--- /dev/null
@@ -0,0 +1,29 @@
+#
+# LDAP IRIX standard cc Make-platform file
+#
+
+#
+# add any platform-specific overrides below here
+#
+
+
+#
+# -------------------------------------------------------------------------
+# you will probably not need to edit anything below this point
+# -------------------------------------------------------------------------
+# ranlib not needed under IRIX
+RANLIB = ""
+
+# be explicit about which CC to use
+CC=gcc
+
+# give full path to hostname since it may not be in user's path
+HOSTNAME=/usr/bsd/hostname
+
+# don't count on a BSD install being present or first in path
+INSTALL=$(LDAPSRC)/build/install.sh
+
+PLATFORMCFLAGS=-DUSE_WAITPID
+PLATFORMLIBS=
+THREADS=
+THREADSLIB=
diff --git a/build/platforms/linux-gcc/Make-platform b/build/platforms/linux-gcc/Make-platform
new file mode 100644 (file)
index 0000000..45f3823
--- /dev/null
@@ -0,0 +1,17 @@
+#
+# LDAP Linux GNU C Make-platform file
+#
+
+#
+# add any platform-specific overrides below here
+#
+
+
+#
+# -------------------------------------------------------------------------
+# you will probably not need to edit anything below this point
+# -------------------------------------------------------------------------
+CC     = gcc
+RANLIB = "ranlib"
+
+PLATFORMCFLAGS=        -Dlinux
diff --git a/build/platforms/ncr-mp-ras-2-cc/Make-platform b/build/platforms/ncr-mp-ras-2-cc/Make-platform
new file mode 100644 (file)
index 0000000..ce98b2c
--- /dev/null
@@ -0,0 +1,34 @@
+#
+# LDAP SVR4 standard cc Make-platform file
+#
+# Uses the std SVR4 stuff whenever possible.  
+# Some references to the BSD compatibility required.
+#
+
+#
+# add any platform-specific overrides below here
+#
+
+# compiler to use, e.g. CC=cc or CC=gcc
+CC = cc
+
+# flags added to every compile
+# Use the BSD include files but only after the SVR4 files.
+PLATFORMCFLAGS=        -DSYSV -DSVR4 -I/usr/include -I/usr/ucbinclude 
+
+# flags added to every link
+PLATFORMLDFLAGS = 
+
+# extra libraries needed (added to the end of all link commands)
+PLATFORMLIBS =  -lnsl -lnet -lsocket
+
+# ndbm library, needed if not in libc (e.g. LDBMLIB=-lndbm)
+LDBMLIB = -L/usr/ucblib -lucb
+
+# BSD-like install command; if necessary, you can use a script
+INSTALL = /usr/ucb/install
+
+# command to convert libraries for efficient random access;
+RANLIB = ""
+
+# other commands  - see the file build/Make-append for a list
diff --git a/build/platforms/netbsd-cc/Make-platform b/build/platforms/netbsd-cc/Make-platform
new file mode 100644 (file)
index 0000000..e176e6d
--- /dev/null
@@ -0,0 +1,17 @@
+#
+# LDAP NetBSD cc Make-platform file
+# on NetBSD, cc is gcc
+#
+
+
+#
+# add any platform-specific overrides below here
+#
+
+#
+# -------------------------------------------------------------------------
+# you will probably not need to edit anything below this point
+# -------------------------------------------------------------------------
+CC     = gcc
+
+PLATFORMCFLAGS=        -Dnetbsd
diff --git a/build/platforms/netbsd-gcc/Make-platform b/build/platforms/netbsd-gcc/Make-platform
new file mode 100644 (file)
index 0000000..b66f830
--- /dev/null
@@ -0,0 +1,16 @@
+#
+# LDAP NetBSD GNU C Make-platform file
+#
+
+
+#
+# add any platform-specific overrides below here
+#
+
+#
+# -------------------------------------------------------------------------
+# you will probably not need to edit anything below this point
+# -------------------------------------------------------------------------
+CC     = gcc
+
+PLATFORMCFLAGS=        -Dnetbsd
diff --git a/build/platforms/nextstep-cc/Make-platform b/build/platforms/nextstep-cc/Make-platform
new file mode 100644 (file)
index 0000000..1105e6c
--- /dev/null
@@ -0,0 +1,15 @@
+#
+# LDAP NeXTSTEP cc Make-platform file
+#
+
+
+#
+# add any platform-specific overrides below here
+#
+
+#
+# -------------------------------------------------------------------------
+# you will probably not need to edit anything below this point
+# -------------------------------------------------------------------------
+PLATFORMCFLAGS=        -Dnextstep
+PLATFORMLDFLAGS= -all_load
diff --git a/build/platforms/osf1-cc/Make-platform b/build/platforms/osf1-cc/Make-platform
new file mode 100644 (file)
index 0000000..2fd6b20
--- /dev/null
@@ -0,0 +1,24 @@
+#
+# LDAP OSF1 standard cc Make-platform file
+#
+
+#
+# add any platform-specific overrides below here
+#
+
+
+#
+# -------------------------------------------------------------------------
+# you will probably not need to edit anything below this point
+# -------------------------------------------------------------------------
+
+# Even though prototypes are supported by the compiler, OSF's CC doesn't
+# seem to define __STDC__ so we explicitly defined NEEDPROTOS here.
+PLATFORMCFLAGS=        -Dosf1 -DNEEDPROTOS
+PLATFORMLDFLAGS=
+
+THREADS= -DTHREAD_DCE_PTHREADS
+THREADSLIB= -lpthreads
+
+# the BSD-like install under OSF/1 is called installbsd
+INSTALL=installbsd
diff --git a/build/platforms/sco-cc/Make-platform b/build/platforms/sco-cc/Make-platform
new file mode 100644 (file)
index 0000000..31ff05d
--- /dev/null
@@ -0,0 +1,23 @@
+#
+# LDAP SCO standard cc Make-platform file
+#
+
+#
+# add any platform-specific overrides below here
+#
+
+#
+# -------------------------------------------------------------------------
+# you will probably not need to edit anything below this point
+# -------------------------------------------------------------------------
+# ranlib not needed under SCO
+RANLIB  = ""
+
+# be explicit about which CC to use
+CC=/bin/cc
+
+# don't count on /usr/ucb/install being present or first in path
+INSTALL=$(LDAPSRC)/build/install.sh
+
+PLATFORMCFLAGS= -DSCO -DNEED_BSDREGEX -DSYSV -DNOTERMCAP
+PLATFORMLIBS= -lsocket -lnsl_s
diff --git a/build/platforms/sco-gcc/Make-platform b/build/platforms/sco-gcc/Make-platform
new file mode 100644 (file)
index 0000000..1abaa79
--- /dev/null
@@ -0,0 +1,22 @@
+#
+# LDAP SCO gcc Make-platform file
+#
+
+#
+# add any platform-specific overrides below here
+#
+
+#
+# -------------------------------------------------------------------------
+# you will probably not need to edit anything below this point
+# -------------------------------------------------------------------------
+# ranlib not needed under SCO
+RANLIB  = ""
+
+CC=gcc
+
+# don't count on /usr/ucb/install being present or first in path
+INSTALL=$(LDAPSRC)/build/install.sh
+
+PLATFORMCFLAGS= -DSCO -DNEED_BSDREGEX -DSYSV -DNOTERMCAP
+PLATFORMLIBS= -lsocket -lnsl_s
diff --git a/build/platforms/sunos4-cc/Make-platform b/build/platforms/sunos4-cc/Make-platform
new file mode 100644 (file)
index 0000000..6f94bd4
--- /dev/null
@@ -0,0 +1,25 @@
+#
+# LDAP SunOS standard cc Make-platform file
+#
+
+#
+# add any platform-specific overrides below here
+#
+
+
+#
+# -------------------------------------------------------------------------
+# you will probably not need to edit anything below this point
+# -------------------------------------------------------------------------
+5LINT  = /usr/5bin/lint
+
+PLATFORMCFLAGS= -Dsunos4
+THREADS= -DTHREAD_SUNOS4_LWP
+THREADSLIB=-llwp
+
+#
+# the SunOS 4 cc compiler doesn't understand function prototypes, so we
+# need the unproto preprocessor
+#
+NEEDUNPROTO=yes
+UNPROTOCFLAGS=-Qpath $(LDAPSRC)/build/unproto
diff --git a/build/platforms/sunos4-gcc/Make-platform b/build/platforms/sunos4-gcc/Make-platform
new file mode 100644 (file)
index 0000000..81c97f9
--- /dev/null
@@ -0,0 +1,19 @@
+#
+# LDAP SunOS GNU C Make-platform file
+#
+
+
+#
+# add any platform-specific overrides below here
+#
+
+#
+# -------------------------------------------------------------------------
+# you will probably not need to edit anything below this point
+# -------------------------------------------------------------------------
+CC     = gcc
+5LINT  = /usr/5bin/lint
+
+PLATFORMCFLAGS=        -Dsunos4
+THREADS= -DTHREAD_SUNOS4_LWP
+THREADSLIB=-llwp
diff --git a/build/platforms/sunos5-cc/Make-platform b/build/platforms/sunos5-cc/Make-platform
new file mode 100644 (file)
index 0000000..beaad9f
--- /dev/null
@@ -0,0 +1,29 @@
+#
+# LDAP SunOS5 standard cc Make-platform file
+#
+
+#
+# add any platform-specific overrides below here
+#
+
+
+#
+# -------------------------------------------------------------------------
+# you will probably not need to edit anything below this point
+# -------------------------------------------------------------------------
+# ranlib not needed under SunOS5
+RANLIB = ""
+
+# be explicit about which CC to use
+CC=cc
+
+# give full path to hostname since it may not be in user's path
+HOSTNAME=/usr/ucb/hostname
+
+# don't count on /usr/ucb/install being present or first in path
+INSTALL=$(LDAPSRC)/build/install.sh
+
+PLATFORMCFLAGS=        -Dsunos5 -D_REENTRANT
+PLATFORMLIBS= -lsocket -lnsl -lgen
+THREADS= -DTHREAD_SUNOS5_LWP
+THREADSLIB=-lthread
diff --git a/build/platforms/sunos5-gcc/Make-platform b/build/platforms/sunos5-gcc/Make-platform
new file mode 100644 (file)
index 0000000..20c5e47
--- /dev/null
@@ -0,0 +1,28 @@
+#
+# LDAP SunOS5 GNU C Make-platform file
+#
+
+#
+# add any platform-specific overrides below here
+#
+
+
+#
+# -------------------------------------------------------------------------
+# you will probably not need to edit anything below this point
+# -------------------------------------------------------------------------
+CC     = gcc
+
+# ranlib not needed under SunOS5
+RANLIB = ""
+
+# give full path to hostname since it may not be in user's path
+HOSTNAME=/usr/ucb/hostname
+
+# don't count on /usr/ucb/install being present or first in path
+INSTALL=$(LDAPSRC)/build/install.sh
+
+PLATFORMCFLAGS=        -Dsunos5 -D_REENTRANT
+PLATFORMLIBS= -lsocket -lnsl -lgen
+THREADS= -DTHREAD_SUNOS5_LWP
+THREADSLIB=-lthread
diff --git a/build/platforms/ultrix-cc/Make-platform b/build/platforms/ultrix-cc/Make-platform
new file mode 100644 (file)
index 0000000..8139f5f
--- /dev/null
@@ -0,0 +1,16 @@
+#
+# LDAP Ultrix standard cc Make-platform file
+#
+
+#
+# add any platform-specific overrides below here
+#
+
+
+#
+# -------------------------------------------------------------------------
+# you will probably not need to edit anything below this point
+# -------------------------------------------------------------------------
+
+PLATFORMCFLAGS=        -Dultrix -YSYSTEM_FIVE
+PLATFORMLDFLAGS= -YSYSTEM_FIVE
diff --git a/build/platforms/ultrix-gcc/Make-platform b/build/platforms/ultrix-gcc/Make-platform
new file mode 100644 (file)
index 0000000..976e069
--- /dev/null
@@ -0,0 +1,16 @@
+#
+# LDAP Ultrix standard gcc Make-platform file
+#
+
+#
+# add any platform-specific overrides below here
+#
+
+
+#
+# -------------------------------------------------------------------------
+# you will probably not need to edit anything below this point
+# -------------------------------------------------------------------------
+
+CC= gcc
+PLATFORMCFLAGS=        -Dultrix
diff --git a/build/platforms/vms/Makefile b/build/platforms/vms/Makefile
new file mode 100644 (file)
index 0000000..65467d2
--- /dev/null
@@ -0,0 +1,31 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1994 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP build/platforms/vms Makefile (do nothing)
+#
+#-----------------------------------------------------------------------------
+#
+############################################################################
+#                                                                          #
+# You should not have to edit anything in this file                        #
+#                                                                          #
+############################################################################
+LDAPSRC= ../../..
+
+all:   FORCE
+
+links: FORCE
+
+clean: FORCE
+
+veryclean:     FORCE
+
+FORCE: 
diff --git a/build/platforms/vms/make.com b/build/platforms/vms/make.com
new file mode 100644 (file)
index 0000000..01fe326
--- /dev/null
@@ -0,0 +1,95 @@
+$! 30-Nov-1995  ldap V3.2  Craig Watkins  Innosoft International, Inc.
+$!
+$! This is a crude make procedure to build the ldap libraries and the test
+$! program.  This should work with DECC or VAXC compilers.
+$!
+$! This links with UCX libraries so that it should work on any TCP/IP
+$! package that has UCX emulation.  This has been tested with MultiNet.
+$! You may have to change the LINK to find your copy of UCX$IPC.OLB.
+$!
+$ ARCH = "VAX"
+$ if f$getsyi("hw_model") .GE. 1024 then ARCH = "ALPHA"
+$ !
+$ ! If we are on an alpha/axp, we need to use DECC -- otherwise, your choice
+$ COMPILER = "VAXC"
+$ if ARCH .eqs. "ALPHA" then COMPILER = "DECC"
+$ !
+$ if COMPILER .eqs. "VAXC"
+$ then
+$   define arpa sys$library:
+$   define sys sys$library:
+$   define netinet sys$library:
+$! This assumes your default compiler is VAXC; if not, add /VAXC below 
+$   cc_switches = "/include=([---.include],[---.libraries.vms])/define=(LDAP_DEBUG,CLDAP,LDAP_REFERRALS,STR_TRANSLATION,LDAP_CHARSET_8859=88591)"
+$!
+$ else
+$!
+$   cc_switches = "/decc/standard=vaxc/include=([---.include],[---.libraries.vms])/define=(__STDC__,LDAP_DEBUG,CLDAP,LDAP_REFERRALS,STR_TRANSLATION,LDAP_CHARSET_8859=88591)
+$ endif
+$ !
+$ cc 'CC_SWITCHES' 'P1'  [---.libraries.liblber]io
+$ cc 'CC_SWITCHES' 'P1'  [---.libraries.liblber]encode
+$ cc 'CC_SWITCHES' 'P1'  [---.libraries.liblber]decode
+$ cc 'CC_SWITCHES' 'P1'  [---.libraries.liblber]version
+$ !
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]ABANDON        
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]ADD            
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]ADDENTRY       
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]BIND           
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]CACHE          
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]CHARSET
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]CLDAP          
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]COMPARE        
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]DELETE         
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]DISPTMPL       
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]DSPARSE        
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]ERROR          
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]FREE           
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]FRIENDLY       
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]GETATTR        
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]GETDN          
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]GETDXBYNAME
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]GETENTRY       
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]GETFILTER      
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]GETVALUES      
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]KBIND          
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]MODIFY         
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]MODRDN         
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]OPEN           
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]OS-IP
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]REGEX          
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]REQUEST          
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]RESULT         
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]SBIND          
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]SEARCH         
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]SORT           
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]SRCHPREF       
+$ cc 'CC_SWITCHES' 'P1' /define="TEMPLATEFILE=""LDAP_ETC:ldaptemplates.conf""" -
+                       [---.libraries.libldap]TMPLOUT        
+$!CC 'CC_SWITCHES' 'P1' [---.libraries.libldap]TMPLTEST       
+$ cc 'CC_SWITCHES' 'P1' /define="FILTERFILE=""LDAP_ETC:ldapfilter.conf""" -
+                       [---.libraries.libldap]UFN            
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]UNBIND         
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]VERSION        
+$ !
+$ cc 'CC_SWITCHES' 'P1'  [---.libraries.vms]getopt
+$ cc 'CC_SWITCHES' 'P1'  [---.libraries.vms]strings
+$ !
+$ library/create/log ldap.olb *.obj
+$ !
+$ cc 'CC_SWITCHES' 'P1' [---.libraries.libldap]TEST           
+$ !
+$ if COMPILER .eqs. "VAXC"
+$ then
+$!
+$  link test, sys$input/opt
+ldap.olb/lib
+sys$library:ucx$ipc.olb/lib
+sys$share:vaxcrtl.exe/share
+$!
+$ else
+$!
+$  link test, sys$input/opt
+ldap.olb/lib
+$ endif
+$!
diff --git a/build/uname.sh b/build/uname.sh
new file mode 100644 (file)
index 0000000..fbb58dd
--- /dev/null
@@ -0,0 +1,109 @@
+#!/bin/sh
+# simple BSD-like uname replacement for those systems without it
+#
+# Copyright (c) 1995 The Regents of the University of Michigan
+#
+
+
+#
+# if /bin/uname or /usr/bin/uname exists, just use it
+# ...unless we are on SCO, where the provided uname is bad
+#
+if  [ ! -f /usr/bin/swconfig ]; then
+    if [ -f /bin/uname ]; then
+       exec /bin/uname $*
+    fi
+
+    if [ -f /usr/bin/uname ]; then
+       exec /usr/bin/uname $*
+    fi
+fi
+
+
+#
+# flags to keep track of what to output
+#
+PRINT_SYSTEM=0
+PRINT_VERSION=0
+PRINT_RELEASE=0
+
+#
+# process arguments
+#
+USAGE="usage: $0 [-s] [-v] [-r]"
+
+while [ $# != 0 ]; do
+    case "$1" in
+    -s)
+       PRINT_SYSTEM=1
+       ;;
+    -v)
+       PRINT_VERSION=1
+       ;;
+    -r)
+       PRINT_RELEASE=1
+       ;;
+    *)
+       echo "$USAGE"
+       exit 1
+       ;;
+    esac
+    shift
+done
+
+
+#
+# print system name by default
+#
+if [ $PRINT_VERSION = "0" -a $PRINT_RELEASE = "0" ]; then
+    PRINT_SYSTEM=1
+fi
+
+
+#
+# default to unknown everything...
+#
+SYSTEM="Unknown-System"
+VERSION="Unknown-Version"
+RELEASE="Unknown-Release"
+
+#
+# check to see if we are on a machine that runs NextSTEP or SCO
+#
+if [ -r /NextApps ]; then
+    SYSTEM="NeXTSTEP"
+elif [ -f /usr/bin/swconfig ]; then
+    SYSTEM="SCO"
+fi
+
+
+#
+# output requested information
+#
+OUTPUT=0
+if [ $PRINT_SYSTEM = "1" ]; then
+    echo -n "$SYSTEM"
+    OUTPUT=1
+fi
+
+if [ $PRINT_VERSION = "1" ]; then
+    if [ $OUTPUT = "1" ]; then
+       echo -n " $VERSION"
+    else
+       echo -n "$VERSION"
+       OUTPUT=1
+    fi
+fi
+
+if [ $PRINT_RELEASE = "1" ]; then
+    if [ $OUTPUT = "1" ]; then
+       echo -n " $RELEASE"
+    else
+       echo -n "$RELEASE"
+       OUTPUT=1
+    fi
+fi
+
+echo
+
+exit 0
diff --git a/build/unproto/Makefile b/build/unproto/Makefile
new file mode 100644 (file)
index 0000000..2d7a98c
--- /dev/null
@@ -0,0 +1,123 @@
+# @(#) Makefile 1.6 93/06/18 22:29:40
+
+## BEGIN CONFIGURATION STUFF
+
+# In the unlikely case that your compiler has no hooks for alternate
+# compiler passes, use a "cc cflags -E file.c | unproto >file.i"
+# pipeline, then "cc cflags -c file.i" to compile the resulting
+# intermediate file.
+# 
+# Otherwise, the "/lib/cpp | unproto" pipeline can be packaged as an
+# executable shell script (see the provided "cpp.sh" script) that should
+# be installed as "/whatever/cpp". This script should then be specified
+# to the C compiler as a non-default preprocessor.
+#
+# PROG = unproto
+# PIPE =
+
+# The overhead and problems of shell script interpretation can be
+# eliminated by having the unprototyper program itself open the pipe to
+# the preprocessor.  In that case, define the PIPE_THROUGH_CPP macro as
+# the path name of the default C preprocessor (usually "/lib/cpp"),
+# install the unprototyper as "/whatever/cpp" and specify that to the C
+# compiler as a non-default preprocessor.
+#
+PROG   = cpp
+PIPE   = -DPIPE_THROUGH_CPP=\"/lib/cpp\"
+
+# Some compilers complain about some #directives. The following is only a
+# partial solution, because the directives are still seen by /lib/cpp.
+# Be careful with filtering out #pragma, because some pre-ANSI compilers
+# (SunOS) rely on its use.
+#
+# SKIP = -DIGNORE_DIRECTIVES=\"pragma\",\"foo\",\"bar\"
+#
+SKIP   =
+
+# The bell character code depends on the character set. With ASCII, it is
+# 7. Specify a string constant with exactly three octal digits. If you
+# change this definition, you will have to update the example.out file.
+#
+BELL   = -DBELL=\"007\"
+
+# Some C compilers have problems with "void".  The nature of the problems
+# depends on the age of the compiler.
+#
+# If your compiler does not understand "void" at all, compile with
+# -DMAP_VOID. The unprototyper will replace "void *" by "char *", a
+# (void) argument list by an empty one, and will replace all other
+# instances of "void" by "int".
+#
+# If your compiler has problems with "void *" only, compile with
+# -DMAP_VOID_STAR. The unprototyper will replace "void *" by "char *",
+# and will replace a (void) argument list by an empty one. All other
+# instances of "void" will be left alone.
+#
+# If neither of these are defined, (void) argument lists will be replaced
+# by empty ones.
+#
+# MAP  = -DMAP_VOID_STAR
+
+# Now that we have brought up the subject of antique C compilers, here's
+# a couple of aliases that may be useful, too.
+#
+# ALIAS        = -Dstrchr=index
+
+# If you need support for functions that implement ANSI-style variable
+# length argument lists, edit the stdarg.h file provided with this
+# package so that it contains the proper definitions for your machine.
+
+## END CONFIGURATION STUFF
+
+SHELL  = /bin/sh
+
+CFILES = unproto.c tok_io.c tok_class.c tok_pool.c vstring.c symbol.c error.c \
+       hash.c strsave.c
+HFILES = error.h token.h vstring.h symbol.h
+SCRIPTS        = cpp.sh acc.sh
+SAMPLES        = stdarg.h stddef.h stdlib.h varargs.c example.c example.out
+SOURCES        = README $(CFILES) $(HFILES) Makefile $(SCRIPTS) $(SAMPLES)
+FILES  = $(SOURCES) unproto.1
+OBJECTS        = tok_io.o tok_class.o tok_pool.o unproto.o vstring.o symbol.o error.o \
+       hash.o strsave.o
+
+CFLAGS = -O $(PIPE) $(SKIP) $(BELL) $(MAP) $(ALIAS)
+#CFLAGS        = -O $(PIPE) $(SKIP) $(BELL) $(MAP) $(ALIAS) -p -Dstatic=
+#CFLAGS        = -g $(PIPE) $(SKIP) $(BELL) $(MAP) $(ALIAS) -DDEBUG
+
+$(PROG): $(OBJECTS)
+       $(CC) $(CFLAGS) -o $@ $(OBJECTS) $(MALLOC)
+
+# For linting, enable all bells and whistles.
+
+lint:
+       lint -DPIPE_THROUGH_CPP=\"foo\" -DIGNORE_DIRECTIVES=\"foo\",\"bar\" \
+       $(BELL) -DMAP_VOID $(ALIAS) $(CFILES)
+
+# Testing requires that the program is compiled with -DDEBUG.
+
+test:  $(PROG) cpp example.c example.out
+       ./cpp example.c >example.tmp
+       @echo the following diff command should produce no output
+       diff -b example.out example.tmp
+       rm -f example.tmp
+
+shar:  $(FILES)
+       @shar $(FILES)
+
+archive:
+       $(ARCHIVE) $(SOURCES)
+
+clean:
+       rm -f *.o core cpp unproto mon.out varargs.o varargs example.tmp
+
+error.o : error.c token.h error.h Makefile
+hash.o : hash.c Makefile
+strsave.o : strsave.c error.h Makefile
+symbol.o : symbol.c error.h token.h symbol.h Makefile
+tok_class.o : tok_class.c error.h vstring.h token.h symbol.h Makefile
+tok_io.o : tok_io.c token.h vstring.h error.h Makefile
+tok_pool.o : tok_pool.c token.h vstring.h error.h Makefile
+unproto.o : unproto.c vstring.h stdarg.h token.h error.h symbol.h Makefile
+varargs.o : varargs.c stdarg.h Makefile
+vstring.o : vstring.c vstring.h Makefile
diff --git a/build/unproto/README b/build/unproto/README
new file mode 100644 (file)
index 0000000..1074874
--- /dev/null
@@ -0,0 +1,160 @@
+@(#) README 1.6 93/06/18 22:29:34
+
+unproto - Compile ANSI C with traditional UNIX C compiler
+
+Description:
+------------
+
+This is a filter that sits in between the UNIX C preprocessor and the
+next UNIX C compiler stage, on the fly transforming ANSI C syntax to
+old C syntax.  Line number information is preserved so that compiler
+diagnostics still make sense.  It runs at roughly the same speed as
+/lib/cpp, so it has negligible impact on compilation time.
+
+Typically, the program is invoked by the native UNIX C compiler as an
+alternate preprocessor. The unprototyper in turn invokes the native C
+preprocessor and massages its output.  Similar tricks can be used with
+the lint(1) command. Details are given below.
+
+The filter rewrites ANSI-style function headings, function pointer
+types and type casts, function prototypes, and combinations thereof.
+Unlike some other unprototypers, this one is fully recursive and does
+not depend on source file layout (see the example.c file).
+
+Besides the rewriting of argument lists, the program does the following
+transformations:  string concatenation, conversion of \a and \x escape
+sequences to their octal equivalents, translation of the __TIME__ and
+__DATE__ macros, optional mapping of `void *' to `char *', and optional
+mapping of plain `void' to `int'. 
+
+The unprototyper provides hooks for compilers that require special
+tricks for variadic functions (fortunately, many don't). <stdarg.h>
+support is provided for sparc, mips, mc68k, 80x86, vax, and others.
+
+The program has been tested with SunOS 4.1.1 (sparc), Ultrix 4.0 and
+4.2 (mips), and Microport System V Release 2 (80286). It should work
+with almost every PCC-based UNIX C compiler.
+
+Restrictions:
+-------------
+
+A description of restrictions and workarounds can be found in the
+unproto.1 manual page.
+
+Problems fixed with this release:
+---------------------------------
+
+Prototypes and definitions of functions returning pointer to function
+were not rewritten to old style.
+
+Operation:
+----------
+
+This package implements a non-default C preprocessor (the output from
+the default C preprocessor being piped through the unprototyper).  How
+one tells the C compiler to use a non-default preprocessor program is
+somewhat compiler-dependent:
+
+    SunOS 4.x:  cc -Qpath directory_with_alternate_cpp ...
+
+    Ultrix 4.x: cc -tp -hdirectory_with_alternate_cpp -B ...
+
+    System V.2: cc -Bdirectory_with_alternate_cpp/ -tp ...
+
+Examples of these, and others, can be found in the acc.sh shell script
+that emulates an ANSI C compiler.  Your C compiler manual page should
+provide the necessary information.
+
+A more portable, but less efficient, approach relies on the observation
+that almost every UNIX C compiler supports the -E (write preprocessor
+output to stdout) and -P options (preprocess file.c into file.i). Just
+add the following lines to your Makefiles:
+
+    .c.o:
+           $(CC) $(CFLAGS) -E $*.c | unproto >$*.i # simulate -P option
+           $(CC) $(CFLAGS) -c $*.i
+           rm -f $*.i
+
+On some systems the lint(1) command is just a shell script, and writing
+a version that uses the unprototyper should not be too hard. With SunOS
+4.x, /usr/bin/lint is not a shell script, but it does accept the same
+syntax as the cc(1) command for the specification of a non-default
+compiler pass. 
+
+You may have to do some research on the lint command provided with your
+own machine.
+
+Configuration:
+--------------
+
+Check the contents of the `stdarg.h' file provided with this package.
+This file serves a dual purpose: (1) on systems that do not provide a
+stdarg.h file, it should be included by C source files that implements
+ANSI-style variadic functions; (2) it is also used to configure the
+unprototyper so that it emits the proper magic when it sees `...'.
+
+The `stdarg.h' file has support for sparc, mips, and for compilers that
+pass arguments via the stack (typical for 80*86, mc68k and vax). It
+gives general hints for other compilers.
+
+The other sample header files (stddef.h and stdlib.h) are not required
+to build the unprototyper.
+
+The `varargs.c' file provided with this package can be used to verify
+that the `stdarg.h' file has been set up correctly.
+
+If your C compiler has no hooks for an alternate preprocessor (the
+unprototyper will be used as: `cc cflags -E file.c | unproto >file.i'),
+build the `unproto' executable without the `PIPE_THROUGH_CPP' feature.
+Details are given in the Makefile.
+
+Otherwise, the `cpp.sh' shell script can be used to set up the pipe
+between the native C preprocessor and the unprototyper command.  The
+script assumes that the unprototyper binary is called `unproto', and
+that it was compiled without the `PIPE_THROUGH_CPP' feature.  See the
+Makefile and the `cpp.sh' script for details and for a description of
+possible problems with this approach.
+
+The overhead and problems of shell-script interpretation can be avoided
+by letting the unprototyper itself pipe its standard input through the
+C preprocessor.  For this mode of operation, the unprototyper binary
+should be called `cpp', and the `unproto.c' source file should be
+compiled with the `PIPE_THROUGH_CPP' macro defined as the absolute
+pathname of the native C preprocessor (usually `/lib/cpp').  See the
+Makefile for details.
+
+Installation:
+-------------
+
+Install the `unproto.1' manual page in a suitable place. If your system
+does not provide a `stdarg.h' file, find a suitable place for the one
+provided with the unprototyper and install it there. The same goes for
+the sample stddef.h and stdlib.h files; make sure that the definitions
+in there apply to your environment. Most or all of the latter files are
+already part of Ultrix 4.x and SunOS 4.1.1.
+
+The ANSI float.h and limits.h files can be generated with the config
+program by Steve Pemberton (comp.sources.misc volume 10, issue 62,
+available from ftp.uu.net as comp.sources.misc/volume10/config42.Z).
+
+If you run the unprototyper with "cc -E" just install the `unproto'
+binary; the `cpp' and `acc' shell scripts will not be needed.
+
+If you use the `cpp' shell script to pipe the preprocessor output
+through the unprototyper program, install the `unproto' binary in a
+place where the `cpp' shell script can find it, and install the `cpp'
+shell script in a suitable place. Edit the `acc' shell script and
+install it in a suitable place. From now on, type `acc' instead of
+`cc'.
+
+If the unprototyper itself opens the pipe to the C preprocessor (i.e.
+the unprototyper was built with the `PIPE_THROUGH_CPP' macro defined),
+install the `cpp' unprototyper binary in a suitable place. Edit the
+`acc' shell script and install it in a suitable place. From now on,
+type `acc' instead of `cc'.
+
+       Wietse Venema
+       wietse@wzv.win.tue.nl
+       Mathematics and Computing Science
+       Eindhoven University of Technology
+       The Netherlands
diff --git a/build/unproto/acc.sh b/build/unproto/acc.sh
new file mode 100755 (executable)
index 0000000..124e700
--- /dev/null
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+# @(#) acc.sh 1.1 93/06/18 22:29:42
+#
+# Script to emulate most of an ANSI C compiler with a traditional UNIX
+# C compiler.
+
+# INCDIR should be the directory with auxiliary include files from the
+# unproto source distribution (stdarg.h, stdlib.h, stddef.h, and other
+# stuff that is missing from your compilation environment). With Ultrix
+# 4.[0-2] you need unproto's stdarg.h even though the system provides
+# one.
+#
+INCDIR=.
+
+# CPPDIR should be the directory with the unprototypeing cpp filter
+# (preferably the version with the PIPE_THROUGH_CPP feature).
+#
+CPPDIR=.
+
+# DEFINES: you will want to define volatile and const, and maybe even
+# __STDC__.
+#
+DEFINES="-Dvolatile= -Dconst= -D__STDC__"
+
+# Possible problem: INCDIR should be listed after the user-specified -I
+# command-line options, not before them as we do here. This is a problem
+# only if you attempt to redefine system libraries.
+#
+# Choose one of the commands below that is appropriate for your system.
+#
+exec cc -Qpath ${CPPDIR} -I${INCDIR} ${DEFINES} "$@"   # SunOS 4.x
+exec cc -tp -h${CPPDIR} -B -I${INCDIR} ${DEFINES} "$@" # Ultrix 4.2
+exec cc -Yp,${CPPDIR} -I${INCDIR} ${DEFINES} "$@"      # M88 SysV.3
+exec cc -B${CPPDIR}/ -tp -I${INCDIR} ${DEFINES} "$@"   # System V.2
diff --git a/build/unproto/cpp.sh b/build/unproto/cpp.sh
new file mode 100755 (executable)
index 0000000..a039146
--- /dev/null
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+# @(#) cpp.sh 1.3 92/01/15 21:53:22
+
+# Unprototypeing preprocessor for pre-ANSI C compilers.  On some systems,
+# this script can be as simple as:
+#
+#      /lib/cpp "$@" | unproto
+#
+# However, some cc(1) drivers specify output file names on the
+# preprocessor command line, so this shell script must be prepared to
+# intercept them.  Depending on the driver program, the cpp options may
+# even go before or after the file name argument(s). The script below
+# tries to tackle all these cases.
+#
+# You may want to add -Ipath_to_stdarg.h_file, -Dvoid=, -Dvolatile=, 
+# and even -D__STDC__.
+
+cpp_args=""
+
+while :
+do
+       case $1 in
+       "")     break;;
+       -*)     cpp_args="$cpp_args $1";;
+        *)     cpp_args="$cpp_args $1"
+               case $2 in
+               ""|-*)  ;;
+                   *)  exec 1> $2 || exit 1; shift;;
+               esac;;
+       esac
+       shift
+done
+
+/lib/cpp $cpp_args | unproto
diff --git a/build/unproto/error.c b/build/unproto/error.c
new file mode 100644 (file)
index 0000000..667d978
--- /dev/null
@@ -0,0 +1,97 @@
+/*++
+/* NAME
+/*     error 3
+/* SUMMARY
+/*     diagnostics
+/* PACKAGE
+/*     unproto
+/* SYNOPSIS
+/*     #include "error.h"
+/*
+/*     int errcount;
+/*
+/*     void error(text)
+/*     char *text;
+/*
+/*     void error_where(path, line, text)
+/*     char *path;
+/*     int line;
+/*     char *text;
+/*
+/*     void fatal(text)
+/*     char *text;
+/* DESCRIPTION
+/*     The routines in this file print a diagnostic (text). Some also
+/*     terminate the program. Upon each error*() call, the errcount variable
+/*     is incremented.
+/*
+/*     error() provides a default context, i.e. the source-file
+/*     coordinate of the last read token.
+/*
+/*     error_where() allows the caller to explicitly specify context: path
+/*     is a source-file name, and line is a line number.
+/*
+/*     fatal() is like error() but terminates the program with a non-zero
+/*     exit status.
+/*
+/*     context is ignored if the line number is zero or if the path
+/*     is an empty string.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     Eindhoven University of Technology
+/*     Department of Mathematics and Computer Science
+/*     Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
+/* LAST MODIFICATION
+/*     92/01/15 21:53:10
+/* VERSION/RELEASE
+/*     1.2
+/*--*/
+
+static char error_sccsid[] = "@(#) error.c 1.2 92/01/15 21:53:10";
+
+/* C library */
+
+#include <stdio.h>
+
+extern void exit();
+
+/* Application-specific stuff */
+
+#include "token.h"
+#include "error.h"
+
+int     errcount = 0;                  /* error counter */
+
+/* error - report problem (implicit context) */
+
+void    error(text)
+char   *text;
+{
+    error_where(in_path, in_line, text);
+}
+
+/* error_where - report problem (explicit context) */
+
+void    error_where(path, line, text)
+char   *path;
+int     line;
+char   *text;
+{
+    errcount++;
+
+    /* Suppress context info if there is none. */
+
+    if (line && path[0])
+       fprintf(stderr, "%s, line %d: ", path, line);
+
+    fprintf(stderr, "%s\n", text);
+}
+
+/* fatal - report problem and terminate unsuccessfully */
+
+void    fatal(text)
+char   *text;
+{
+    error(text);
+    exit(1);
+}
diff --git a/build/unproto/error.h b/build/unproto/error.h
new file mode 100644 (file)
index 0000000..dfb27e9
--- /dev/null
@@ -0,0 +1,6 @@
+/* @(#) error.h 1.2 92/01/15 21:53:14 */
+
+extern int errcount;                   /* error counter */
+extern void error();                   /* default context */
+extern void error_where();             /* user-specified context */
+extern void fatal();                   /* fatal error */
diff --git a/build/unproto/example.c b/build/unproto/example.c
new file mode 100644 (file)
index 0000000..bf2f838
--- /dev/null
@@ -0,0 +1,222 @@
+ /*
+  * @(#) example.c 1.5 93/06/18 22:29:46
+  * 
+  * Examples of things that can be done with the unproto package
+  */
+
+typedef char *charstar;
+
+ /*
+  * New-style argument list with structured argument, one field being pointer
+  * to function returning pointer to function with function-pointer argument
+  */
+
+x(struct {
+    struct {
+       int (*(*foo) (int (*arg1) (double))) (float arg2);
+    } foo;
+} baz) {
+    return (0);
+}
+
+ /* New-style function-pointer declaration. */
+
+int (*(*bar0) (float)) (int);
+
+ /* Old-style argument list with new-style argument type. */
+
+baz0(bar)
+int (*(*bar) (float)) (int);
+{}
+
+ /*
+  * New-style argument list with new-style argument type, declaration
+  * embedded within block. Plus a couple assignments with function calls that
+  * look like casts.
+  */
+
+foo(int (*(*bar) (float)) (int))
+{
+    int     (*baz) (int) = (int (*) (int)) 0,
+           y = (y * (*baz) (y)),
+           *(*z) (int) = (int *(*) (int)) 0;
+
+    struct { int (*foo)(int); } *(*s)(int) = 
+       (struct { int (*foo)(int); } *(*)(int)) 0;
+
+    {
+       y = (y * (*baz) (y));
+    }
+    {
+       z = (int *(*) (int)) 0;
+    }
+    {
+       s = (struct { int (*foo)(int); } *(*)(int)) 0;
+    }
+
+    return (0);
+}
+
+/* Multiple declarations in one statement */
+
+test1()
+{
+       int foo2,*(*(*bar)(int))(float),*baz(double);
+}
+
+/* Discriminate declarations from executable statements */
+
+test2(charstar y)
+{
+       int foo = 5,atoi(charstar);
+
+       foo = 5,atoi(y);
+}
+
+/* Declarations without explicit type */
+
+test3,test4(int);
+
+test5(int y)
+{
+       {
+               test3;
+       }
+       {
+               test4(y);
+       }
+}
+
+test6[1],test7(int);
+
+test7(int x)
+{
+       {
+               test6[1];
+       }
+       {
+               test7(x);
+       }
+}
+
+/* Checking a complicated cast */
+
+struct {
+    struct {
+       int (*f)(int), o;
+    } bar;
+} (*baz2)(int) = (struct { struct { int (*f)(int), o; } bar; } (*)(int)) 0;
+
+/* Distinguish things with the same shape but with different meaning */
+
+test8(x)
+{
+    {
+       struct {
+           int     foo;
+       } bar(charstar);
+    }
+    {
+       do {
+           int     foo;
+       } while (x);
+    }
+}
+
+/* Do not think foo(*bar) is a function pointer declaration */
+
+test9(char *bar)
+{
+    foo(*bar);
+}
+
+/* another couple of special-cased words. */
+
+test10(int x)
+{
+    {
+       int test10(int);
+       do  test10(x);
+       while (x);
+    }
+    {
+       return test10(x);
+    }
+}
+
+test11(int *x)
+{
+       while (*x)
+           (putchar(*x++));
+}
+
+test11a(int *x)
+{
+       for (*x;;)
+           (putchar(*x++));
+}
+
+/* #include directive between stuff that requires lookahead */
+
+test12()
+{
+       char *x = "\xf\0002\002\02\2" /* foo */
+#include "/dev/null"
+               "\abar";
+
+       printf("foo" /* 1 */ "bar" /* 2 */ "baz");
+
+       *x = '\a';
+       *x = '\xff';
+}
+
+int test13(void);
+
+/* line continuations in the middle of tokens */
+
+te\
+st14();
+charstar test15 = "foo\
+bar";
+char test16 = "foo\\
+abar";
+
+/* Array dimensions with unexpanded macros */
+
+test17(charstar foo[bar]){}
+
+int (*(*test18[bar])(charstar))(charstar) = \
+       (int (*(*[bar])(charstar))(charstar)) 0;
+
+/* Function returning pointer to function */
+
+int (*(*test19(long))(int))(double);
+
+/* GCC accepts the following stuff, K&R C does not... */
+
+void test20(int test21(double)) {}
+
+void test22(struct { int foo; } test23(short)) {}
+
+/* Do not blindly rewrite (*name(stuff))(otherstuff) */
+
+void    test23()
+{
+    int     (*test24(int)) (int),
+            y = (*test24(2)) (3),
+            z = ((*test24(2)) (3));
+}
+
+/* Function returning pointer to function */
+
+int (*(*test25(long foo))(int bar))(double baz){ /* body */ }
+
+int (*(*test26(foo))())()
+long foo;
+{ /* body */ }
+
+#define ARGSTR()   struct {int l; char c[1];}
+
+void functie(ARGSTR() *cmdlin, ARGSTR() *c1)
+{
+}
diff --git a/build/unproto/example.out b/build/unproto/example.out
new file mode 100644 (file)
index 0000000..0b14e1b
--- /dev/null
@@ -0,0 +1,271 @@
+# 1 "example.c" 
+
+
+
+
+
+typedef char *charstar;
+
+
+
+
+
+x(
+
+
+
+baz)
+# 14 "example.c"
+struct {
+    struct {
+       int (*(*foo)())();
+    } foo;
+} baz;
+# 18 "example.c"
+{/*1*/
+    /* end dcls */return (0);
+}/*1*/
+
+
+int (*(*bar0)())();
+
+
+baz0(bar)
+int (*(*bar)())();
+{/*1*/}/*1*/
+
+
+
+
+
+
+foo(bar)
+# 38 "example.c"
+int (*(*bar)())();
+{/*1*/
+    int     (*baz)()= (int (*)()) 0,
+           y = (y * (*baz)(y)),
+           *(*z)()= (int *(*)()) 0;
+
+    struct {/*2*/ int (*foo)(); }/*2*/ *(*s)()= 
+       (struct { int (*foo)(); } *(*)()) 0;
+
+    /* end dcls */{/*2*/
+       y /* end dcls */= (y * (*baz)(y));
+    }/*2*/
+    {/*2*/
+       z /* end dcls */= (int *(*)()) 0;
+    }/*2*/
+    {/*2*/
+       s /* end dcls */= (struct { int (*foo)(); } *(*)()) 0;
+    }/*2*/
+
+    return (0);
+}/*1*/
+
+
+
+test1()
+{/*1*/
+       int foo2,*(*(*bar)())(),*baz();
+}/*1*/
+
+
+
+test2(y)
+# 69 "example.c"
+charstar y;
+{/*1*/
+       int foo = 5,atoi();
+
+       foo /* end dcls */= 5,atoi(y);
+}/*1*/
+
+
+
+test3,test4();
+
+test5(y)
+# 80 "example.c"
+int y;
+{/*1*/
+       /* end dcls */{/*2*/
+               test3/* end dcls */;
+       }/*2*/
+       {/*2*/
+               test4/* end dcls */(y);
+       }/*2*/
+}/*1*/
+
+test6[1],test7();
+
+test7(x)
+# 92 "example.c"
+int x;
+{/*1*/
+       /* end dcls */{/*2*/
+               test6/* end dcls */[1];
+       }/*2*/
+       {/*2*/
+               test7/* end dcls */(x);
+       }/*2*/
+}/*1*/
+
+
+
+struct {/*1*/
+    struct {/*2*/
+       int (*f)(), o;
+    }/*2*/ bar;
+}/*1*/ (*baz2)()= (struct { struct { int (*f)(), o; } bar; } (*)()) 0;
+
+
+
+test8(x)
+{/*1*/
+    /* end dcls */{/*2*/
+       struct {/*3*/
+           int     foo;
+       }/*3*/ bar();
+    }/*2*/
+    {/*2*/
+       /* end dcls */do {/*3*/
+           int     foo;
+       }/*3*/ while (x);
+    }/*2*/
+}/*1*/
+
+
+
+test9(bar)
+# 128 "example.c"
+char *bar;
+{/*1*/
+    foo/* end dcls */(*bar);
+}/*1*/
+
+
+
+test10(x)
+# 135 "example.c"
+int x;
+{/*1*/
+    /* end dcls */{/*2*/
+       int test10();
+       /* end dcls */do  test10(x);
+       while (x);
+    }/*2*/
+    {/*2*/
+       /* end dcls */return test10(x);
+    }/*2*/
+}/*1*/
+
+test11(x)
+# 147 "example.c"
+int *x;
+{/*1*/
+       /* end dcls */while (*x)
+           (putchar(*x++));
+}/*1*/
+
+test11a(x)
+# 153 "example.c"
+int *x;
+{/*1*/
+       /* end dcls */for (*x;;)
+           (putchar(*x++));
+}/*1*/
+
+
+
+test12()
+{/*1*/
+       char *x = 
+# 1 "/dev/null" 1
+# 165 "example.c" 2
+# 163 "example.c"
+"\017\0002\002\002\002\007bar" 
+
+               ;
+
+       printf/* end dcls */("foobarbaz"    );
+
+       *x = '\007';
+       *x = '\377';
+}/*1*/
+
+int test13();
+
+
+
+test14();
+
+charstar test15 = "foobar";
+
+char test16 = "foo\007bar";
+
+
+
+
+test17(foo)
+# 186 "example.c"
+charstar foo[bar];
+# 186 "example.c"
+{/*1*/}/*1*/
+
+int (*(*test18[bar])())()=     (int (*(*[bar])())()) 0;
+
+
+
+
+int (*(*test19())())();
+
+
+
+void test20(test21)
+# 197 "example.c"
+int test21();
+# 197 "example.c"
+{/*1*/}/*1*/
+
+void test22(test23)
+# 199 "example.c"
+struct { int foo; } test23();
+# 199 "example.c"
+{/*1*/}/*1*/
+
+
+
+void    test23()
+{/*1*/
+    int     (*test24())(),
+            y = (*test24(2)) (3),
+            z = ((*test24(2))(3));
+}/*1*/
+
+
+
+int (*(*test25(foo))())()
+# 212 "example.c"
+long foo;
+# 212 "example.c"
+{/*1*/  }/*1*/
+
+int (*(*test26(foo))())()
+long foo;
+{/*1*/  }/*1*/
+
+
+
+void functie(cmdlin,c1)
+# 220 "example.c"
+struct {int l; char c[1];} *cmdlin;
+# 220 "example.c"
+struct {int l; char c[1];} *c1;
+{/*1*/
+}/*1*/
diff --git a/build/unproto/hash.c b/build/unproto/hash.c
new file mode 100644 (file)
index 0000000..153f6b7
--- /dev/null
@@ -0,0 +1,54 @@
+/*++
+/* NAME
+/*     hash 3
+/* SUMMARY
+/*     compute hash value for string
+/* SYNOPSIS
+/*     int hash(string, size)
+/*     char *string;
+/*     int size;
+/* DESCRIPTION
+/*     This function computes for the given null-terminated string an
+/*     integer hash value in the range 0..size-1.
+/* SEE ALSO
+/* .fi
+/*     Alfred V. Aho, Ravi Sethi and Jeffrey D. Ullman: Compilers: 
+/*     principles, techniques and tools; Addison-Wesley, Amsterdam, 1986.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     Eindhoven University of Technology
+/*     Department of Mathematics and Computer Science
+/*     Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
+/*
+/*     Originally written by: P. J. Weinberger at Bell Labs.
+/* LAST MODIFICATION
+/*     92/01/15 21:53:12
+/* VERSION/RELEASE
+/*     %I
+/*--*/
+
+static char hash_sccsid[] = "@(#) hash.c 1.1 92/01/15 21:53:12";
+
+/* hash - hash a string; original author: P. J. Weinberger at Bell Labs. */
+
+int     hash(s, size)
+register char *s;
+unsigned size;
+{
+    register unsigned long h = 0;
+    register unsigned long g;
+
+    /*
+     * For a performance comparison with the hash function presented in K&R,
+     * first edition, see the "Dragon" book by Aho, Sethi and Ullman.
+     */
+
+    while (*s) {
+       h = (h << 4) + *s++;
+       if (g = (h & 0xf0000000)) {
+           h ^= (g >> 24);
+           h ^= g;
+       }
+    }
+    return (h % size);
+}
diff --git a/build/unproto/stdarg.h b/build/unproto/stdarg.h
new file mode 100644 (file)
index 0000000..20f6fe7
--- /dev/null
@@ -0,0 +1,90 @@
+ /*
+  * @(#) stdarg.h 1.4 93/06/18 22:29:44
+  * 
+  * Sample stdarg.h file for use with the unproto filter.
+  * 
+  * This file serves two purposes.
+  * 
+  * 1 - On systems that do not have a /usr/include/stdarg.h file, it should be
+  * included by C source files that implement ANSI-style variadic functions.
+  * Ultrix 4.[0-2] comes with stdarg.h but still needs the one that is
+  * provided with the unproto filter.
+  * 
+  * 2 - To configure the unprototyper itself. If the _VA_ALIST_ macro is
+  * defined, its value will appear in the place of the "..." at the end of
+  * argument lists of variadic function *definitions* (not declarations).
+  * Some compilers (such as Greenhills m88k) have a non-empty va_dcl
+  * definition in the system header file varargs.h. If that is the case,
+  * define "_VA_DCL_" with the same value as va_dcl. If _VA_DCL_ is defined,
+  * the unprototyper will emit its value just before the opening "{".
+  * 
+  * Compilers that always pass arguments via the stack can use the default code
+  * at the end of this file (this usually applies for the vax, mc68k and
+  * 80*86 architectures).
+  * 
+  * Special tricks are needed for compilers that pass some or all function
+  * arguments via registers. Examples of the latter are given for the mips
+  * and sparc architectures. Usually the compiler special-cases an argument
+  * declaration such as "va_alist" or "__builtin_va_alist". For inspiration,
+  * see the local /usr/include/varargs.h file.
+  * 
+  * You can use the varargs.c program provided with the unproto package to
+  * verify that the stdarg.h file has been set up correctly.
+  */
+
+#ifdef sparc /* tested with SunOS 4.1.1 */
+
+#define _VA_ALIST_             "__builtin_va_alist"
+typedef char *va_list;
+#define va_start(ap, p)                (ap = (char *) &__builtin_va_alist)
+#define va_arg(ap, type)       ((type *) __builtin_va_arg_incr((type *) ap))[0]
+#define va_end(ap)
+
+#else
+#ifdef mips /* tested with Ultrix 4.0 and 4.2 */
+
+#define _VA_ALIST_             "va_alist"
+#include "/usr/include/stdarg.h"
+
+#else
+#ifdef m88k /* Motorola SYSTEM V/88 R32V3 */
+
+#define _VA_ALIST_             "va_alist"
+#define _VA_DCL_               "va_type va_alist;"
+typedef struct _va_struct {
+    int va_narg;
+    int *va_stkaddr;
+    int *va_iregs;
+} va_list;
+#define va_start(ap, p) \
+((ap).va_narg=(int *)&va_alist-va_stkarg, \
+ (ap).va_stkaddr=va_stkarg, \
+ (ap).va_iregs=(int *)va_intreg)
+#define va_end(p)
+#if defined(LittleEndian)
+#define va_arg(p,mode) \
+    (*(mode *)_gh_va_arg(&p, va_align(mode), va_regtyp(mode), sizeof(mode)))
+#else /* defined(LittleEndian) */
+#define va_arg(p,mode) ( \
+    (p).va_narg += ((p).va_narg & (va_align(mode) == 8)) + \
+                      (sizeof(mode)+3)/4, \
+    ((mode *)((va_regtyp(mode) && (p).va_narg <= 8 ? \
+             (p).va_iregs: \
+             (p).va_stkaddr) + (p).va_narg))[-1])
+#endif /* defined(LittleEndian) */
+
+#else
+#ifdef hpux
+#include <stdarg.h>
+
+#else /* vax, mc68k, 80*86 */
+
+typedef char *va_list;
+#define va_start(ap, p)                (ap = (char *) (&(p)+1))
+#define va_arg(ap, type)       ((type *) (ap += sizeof(type)))[-1]
+#define va_end(ap)
+
+#endif /* hpux */
+#endif /* m88k */
+#endif /* mips */
+#endif /* sparc */
diff --git a/build/unproto/stddef.h b/build/unproto/stddef.h
new file mode 100644 (file)
index 0000000..97dbc01
--- /dev/null
@@ -0,0 +1,23 @@
+/* @(#) stddef.h 1.1 92/02/15 17:25:46 */
+
+#ifndef _stddef_h_
+#define _stddef_h_
+
+/* NULL is also defined in <stdio.h> */
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* Structure member offset - some compilers barf on this. */
+
+#define offsetof(type, member) ((size_t) &((type *)0)->member)
+
+/* Some of the following types may already be defined in <sys/types.h>. */
+
+/* #include <sys/types.h> */
+/* typedef long ptrdiff_t;             /* type of pointer difference */
+/* typedef unsigned short wchar_t;     /* wide character type */
+/* typedef unsigned size_t;            /* type of sizeof */
+
+#endif /* _stddef_h_ */
diff --git a/build/unproto/stdlib.h b/build/unproto/stdlib.h
new file mode 100644 (file)
index 0000000..78d99dd
--- /dev/null
@@ -0,0 +1,53 @@
+/* @(#) stdlib.h 1.1 92/02/15 17:25:45 */
+
+#ifndef _stdlib_h_
+#define _stdlib_h_
+
+/* NULL is also defined in <stdio.h> */
+
+#ifndef NULL
+#define NULL   0
+#endif
+
+/*
+ * Some functions in this file will be missing from the typical pre-ANSI
+ * UNIX library. Some pre-ANSI UNIX library functions have return types
+ * that differ from what ANSI requires.
+ */
+
+extern double atof();
+extern int atoi();
+extern long atol();
+extern double strtod();
+extern long strtol();
+extern unsigned long strtoul();
+extern int rand();
+extern void srand();
+extern char *calloc();
+extern char *malloc();
+extern char *realloc();
+extern void free();
+extern void abort();
+extern void exit();
+extern int atextit();
+extern int system();
+extern char *getenv();
+extern char *bsearch();
+extern void qsort();
+extern int abs();
+extern long labs();
+
+typedef struct {
+    int     quot;
+    int     rem;
+} div_t;
+
+typedef struct {
+    long    quot;
+    long    rem;
+} ldiv_t;
+
+extern div_t div();
+extern ldiv_t ldiv();
+
+#endif /* _stdlib_h_ */
diff --git a/build/unproto/strsave.c b/build/unproto/strsave.c
new file mode 100644 (file)
index 0000000..c2a4b15
--- /dev/null
@@ -0,0 +1,71 @@
+/*++
+/* NAME
+/*     strsave 3
+/* SUMMARY
+/*     maintain unique copy of a string
+/* SYNOPSIS
+/*     char *strsave(string)
+/*     char *string;
+/* DESCRIPTION
+/*     This function returns a pointer to an unique copy of its
+/*     argument.
+/* DIAGNOSTISC
+/*     strsave() calls fatal() when it runs out of memory.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     Eindhoven University of Technology
+/*     Department of Mathematics and Computer Science
+/*     Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
+/* LAST MODIFICATION
+/*     92/01/15 21:53:13
+/* VERSION/RELEASE
+/*     1.1
+/*--*/
+
+static char strsave_sccsid[] = "@(#) strsave.c 1.1 92/01/15 21:53:13";
+
+/* C library */
+
+extern char *strcpy();
+extern char *malloc();
+
+/* Application-specific stuff */
+
+#include "error.h"
+
+#define        STR_TABSIZE     100
+
+struct string {
+    char   *strval;                    /* unique string copy */
+    struct string *next;               /* next one in hash chain */
+};
+
+static struct string *str_tab[STR_TABSIZE] = {0,};
+
+/* More string stuff. Maybe it should go to an #include file. */
+
+#define        STREQ(x,y)      (*(x) == *(y) && strcmp((x),(y)) == 0)
+
+/* strsave - save unique copy of string */
+
+char   *strsave(str)
+register char *str;
+{
+    register struct string *s;
+    register int where = hash(str, STR_TABSIZE);
+
+    /* Look for existing entry. */
+
+    for (s = str_tab[where]; s; s = s->next)
+       if (STREQ(str, s->strval))
+           return (s->strval);
+
+    /* Add new entry. */
+
+    if ((s = (struct string *) malloc(sizeof(*s))) == 0
+       || (s->strval = malloc(strlen(str) + 1)) == 0)
+       fatal("out of memory");
+    s->next = str_tab[where];
+    str_tab[where] = s;
+    return (strcpy(s->strval, str));
+}
diff --git a/build/unproto/symbol.c b/build/unproto/symbol.c
new file mode 100644 (file)
index 0000000..ce9f7d9
--- /dev/null
@@ -0,0 +1,144 @@
+/*++
+/* NAME
+/*     symbol 3
+/* SUMMARY
+/*     rudimentary symbol table package
+/* SYNOPSIS
+/*     #include "symbol.h"
+/*
+/*     void sym_init()
+/*
+/*     void sym_enter(name, type)
+/*     char *name;
+/*     int type;
+/*
+/*     struct symbol *sym_find(name)
+/*     char *name;
+/* DESCRIPTION
+/*     This is a rudimentary symbol-table package, just enough to
+/*     keep track of a couple of C keywords.
+/*
+/*     sym_init() primes the table with C keywords. At present, most of
+/*     the keywords that have to do with types are left out.
+/*     We need a different strategy to detect type definitions because
+/*     we do not keep track of typedef names.
+/*
+/*     sym_enter() adds an entry to the symbol table.
+/*
+/*     sym_find() locates a symbol table entry (it returns 0 if
+/*     it is not found).
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     Eindhoven University of Technology
+/*     Department of Mathematics and Computer Science
+/*     Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
+/* LAST MODIFICATION
+/*     92/02/15 18:59:56
+/* VERSION/RELEASE
+/*     1.4
+/*--*/
+
+static char symbol_sccsid[] = "@(#) symbol.c 1.4 92/02/15 18:59:56";
+
+/* C library */
+
+extern char *strcpy();
+extern char *malloc();
+
+/* Application-specific stuff */
+
+#include "error.h"
+#include "token.h"
+#include "symbol.h"
+
+#define        SYM_TABSIZE     20
+
+static struct symbol *sym_tab[SYM_TABSIZE] = {0,};
+
+/* More string stuff. Maybe it should go to an #include file. */
+
+#define        STREQ(x,y)      (*(x) == *(y) && strcmp((x),(y)) == 0)
+
+/* sym_enter - enter symbol into table */
+
+void    sym_enter(name, type)
+char   *name;
+int     type;
+{
+    struct symbol *s;
+    int     where;
+
+    if ((s = (struct symbol *) malloc(sizeof(*s))) == 0
+       || (s->name = malloc(strlen(name) + 1)) == 0)
+       fatal("out of memory");
+    (void) strcpy(s->name, name);
+    s->type = type;
+
+    where = hash(name, SYM_TABSIZE);
+    s->next = sym_tab[where];
+    sym_tab[where] = s;
+}
+
+/* sym_find - locate symbol definition */
+
+struct symbol *sym_find(name)
+register char *name;
+{
+    register struct symbol *s;
+
+    /*
+     * This function is called for almost every "word" token, so it better be
+     * fast.
+     */
+
+    for (s = sym_tab[hash(name, SYM_TABSIZE)]; s; s = s->next)
+       if (STREQ(name, s->name))
+           return (s);
+    return (0);
+}
+
+ /*
+  * Initialization data for symbol table. We do not enter keywords for types.
+  * We use a different strategy to detect type declarations because we do not
+  * keep track of typedef names.
+  */
+
+struct sym {
+    char   *name;
+    int     tokno;
+};
+
+static struct sym syms[] = {
+    "if", TOK_CONTROL,
+    "else", TOK_CONTROL,
+    "for", TOK_CONTROL,
+    "while", TOK_CONTROL,
+    "do", TOK_CONTROL,
+    "switch", TOK_CONTROL,
+    "case", TOK_CONTROL,
+    "default", TOK_CONTROL,
+    "return", TOK_CONTROL,
+    "continue", TOK_CONTROL,
+    "break", TOK_CONTROL,
+    "goto", TOK_CONTROL,
+    "struct", TOK_COMPOSITE,
+    "union", TOK_COMPOSITE,
+    "__DATE__", TOK_DATE,
+    "__TIME__", TOK_TIME,
+#if defined(MAP_VOID_STAR) || defined(MAP_VOID)
+    "void", TOK_VOID,
+#endif
+    "asm", TOK_OTHER,
+    0,
+};
+
+/* sym_init - enter known keywords into symbol table */
+
+void    sym_init()
+{
+    register struct sym *p;
+
+    for (p = syms; p->name; p++)
+       sym_enter(p->name, p->tokno);
+}
+
diff --git a/build/unproto/symbol.h b/build/unproto/symbol.h
new file mode 100644 (file)
index 0000000..0711c1f
--- /dev/null
@@ -0,0 +1,11 @@
+/* @(#) symbol.h 1.1 91/09/22 21:21:42 */
+
+struct symbol {
+    char   *name;                      /* symbol name */
+    int     type;                      /* symbol type */
+    struct symbol *next;
+};
+
+extern void sym_enter();               /* add symbol to table */
+extern struct symbol *sym_find();      /* locate symbol */
+extern void sym_init();                        /* prime the table */
diff --git a/build/unproto/tok_class.c b/build/unproto/tok_class.c
new file mode 100644 (file)
index 0000000..38ccd0d
--- /dev/null
@@ -0,0 +1,432 @@
+/*++
+/* NAME
+/*     tok_class 3
+/* SUMMARY
+/*     token classification
+/* PACKAGE
+/*     unproto
+/* SYNOPSIS
+/*     #include "token.h"
+/*
+/*     void tok_unget(t)
+/*     struct token *t;
+/*
+/*     struct token *tok_class()
+/* DESCRIPTION
+/*     tok_class() collects single and composite tokens, and
+/*     recognizes keywords.
+/*     At present, the only composite tokens are ()-delimited,
+/*     comma-separated lists, and non-whitespace tokens with attached
+/*     whitespace or comment tokens.
+/*
+/*     Source transformations are: __DATE__ and __TIME__ are rewritten
+/*     to string constants with the current date and time, respectively.
+/*     Multiple string constants are concatenated. Optionally, "void *" 
+/*     is mapped to "char *", and plain "void" to "int".
+/*
+/*     tok_unget() implements an arbitrary amount of token pushback.
+/*     Only tokens obtained through tok_class() should be given to
+/*     tok_unget(). This function accepts a list of tokens in 
+/*     last-read-first order.
+/* DIAGNOSTICS
+/*     The code complains if input terminates in the middle of a list.
+/* BUGS
+/*     Does not preserve white space at the beginning of a list element
+/*     or after the end of a list.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     Eindhoven University of Technology
+/*     Department of Mathematics and Computer Science
+/*     Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
+/* LAST MODIFICATION
+/*     92/01/15 21:53:02
+/* VERSION/RELEASE
+/*     1.4
+/*--*/
+
+static char class_sccsid[] = "@(#) tok_class.c 1.4 92/01/15 21:53:02";
+
+/* C library */
+
+#include <stdio.h>
+
+extern char *strcpy();
+extern long time();
+extern char *ctime();
+
+/* Application-specific stuff */
+
+#include "error.h"
+#include "vstring.h"
+#include "token.h"
+#include "symbol.h"
+
+static struct token *tok_list();
+static void tok_list_struct();
+static void tok_list_append();
+static void tok_strcat();
+static void tok_time();
+static void tok_date();
+static void tok_space_append();
+
+#if defined(MAP_VOID_STAR) || defined(MAP_VOID)
+static void tok_void();                        /* rewrite void keyword */
+#endif
+
+static struct token *tok_buf = 0;      /* token push-back storage */
+
+/* TOK_PREPEND - add token to LIFO queue, return head */
+
+#define TOK_PREPEND(list,t) (t->next = list, list = t)
+
+/* tok_space_append - append trailing space except at start of or after list */
+
+static void tok_space_append(list, t)
+register struct token *list;
+register struct token *t;
+{
+
+    /*
+     * The head/tail fields of a token do triple duty. They are used to keep
+     * track of the members that make up a (list); to keep track of the
+     * non-blank tokens that make up one list member; and, finally, to tack
+     * whitespace and comment tokens onto the non-blank tokens that make up
+     * one list member.
+     * 
+     * Within a (list), white space and comment tokens are always tacked onto
+     * the non-blank tokens to avoid parsing complications later on. For this
+     * reason, blanks and comments at the beginning of a list member are
+     * discarded because there is no token to tack them onto. (Well, we could
+     * start each list member with a dummy token, but that would mess up the
+     * whole unprototyper).
+     * 
+     * Blanks or comments that follow a (list) are discarded, because the
+     * head/tail fields of a (list) are already being used for other
+     * purposes.
+     * 
+     * Newlines within a (list) are discarded because they can mess up the
+     * output when we rewrite function headers. The output routines will
+     * regenerate discarded newlines, anyway.
+     */
+
+    if (list == 0 || list->tokno == TOK_LIST) {
+       tok_free(t);
+    } else {
+       tok_list_append(list, t);
+    }
+}
+
+/* tok_class - discriminate single tokens, keywords, and composite tokens */
+
+struct token *tok_class()
+{
+    register struct token *t;
+    register struct symbol *s;
+
+    /*
+     * Use push-back token, if available. Push-back tokens are already
+     * canonical and can be passed on to the caller without further
+     * inspection.
+     */
+
+    if (t = tok_buf) {
+       tok_buf = t->next;
+       t->next = 0;
+       return (t);
+    }
+    /* Read a new token and canonicalize it. */
+
+    if (t = tok_get()) {
+       switch (t->tokno) {
+       case '(':                               /* beginning of list */
+           t = tok_list(t);
+           break;
+       case TOK_WORD:                          /* look up keyword */
+           if ((s = sym_find(t->vstr->str))) {
+               switch (s->type) {
+               case TOK_TIME:                  /* map __TIME__ to string */
+                   tok_time(t);
+                   tok_strcat(t);              /* look for more strings */
+                   break;
+               case TOK_DATE:                  /* map __DATE__ to string */
+                   tok_date(t);
+                   tok_strcat(t);              /* look for more strings */
+                   break;
+#if defined(MAP_VOID_STAR) || defined(MAP_VOID)
+               case TOK_VOID:                  /* optionally map void types */
+                   tok_void(t);
+                   break;
+#endif
+               default:                        /* other keyword */
+                   t->tokno = s->type;
+                   break;
+               }
+           }
+           break;
+       case '"':                               /* string, look for more */
+           tok_strcat(t);
+           break;
+       }
+    }
+    return (t);
+}
+
+/* tok_list - collect ()-delimited, comma-separated list of tokens */
+
+static struct token *tok_list(t)
+struct token *t;
+{
+    register struct token *list = tok_alloc();
+    char   *filename;
+    int     lineno;
+
+    /* Save context of '(' for diagnostics. */
+
+    filename = t->path;
+    lineno = t->line;
+
+    list->tokno = TOK_LIST;
+    list->head = list->tail = t;
+    list->path = t->path;
+    list->line = t->line;
+#ifdef DEBUG
+    strcpy(list->vstr->str, "LIST");
+#endif
+
+    /*
+     * Read until the matching ')' is found, accounting for structured stuff
+     * (enclosed by '{' and '}' tokens). Break the list up at each ',' token,
+     * and try to preserve as much whitespace as possible. Newlines are
+     * discarded so that they will not mess up the layout when we rewrite
+     * argument lists. The output routines will regenerate discarded
+     * newlines.
+     */
+
+    while (t = tok_class()) {                  /* skip blanks */
+       switch (t->tokno) {
+       case ')':                               /* end of list */
+           tok_list_append(list, t);
+           return (list);
+       case '{':                               /* struct/union type */
+           tok_list_struct(list->tail, t);
+           break;
+       case TOK_WSPACE:                        /* preserve trailing blanks */
+           tok_space_append(list->tail->tail, t);      /* except after list */
+           break;
+       case '\n':                              /* fix newlines later */
+           tok_free(t);
+           break;
+       case ',':                               /* list separator */
+           tok_list_append(list, t);
+           break;
+       default:                                /* other */
+           tok_list_append(list->tail, t);
+           break;
+       }
+    }
+    error_where(filename, lineno, "unmatched '('");
+    return (list);                             /* do not waste any data */
+}
+
+/* tok_list_struct - collect structured type info within list */
+
+static void tok_list_struct(list, t)
+register struct token *list;
+register struct token *t;
+{
+    char   *filename;
+    int     lineno;
+
+    /*
+     * Save context of '{' for diagnostics. This routine is called by the one
+     * that collects list members. If the '}' is not found, the list
+     * collector will not see the closing ')' either.
+     */
+
+    filename = t->path;
+    lineno = t->line;
+
+    tok_list_append(list, t);
+
+    /*
+     * Collect tokens until the matching '}' is found. Try to preserve as
+     * much whitespace as possible. Newlines are discarded so that they do
+     * not interfere when rewriting argument lists. The output routines will
+     * regenerate discarded newlines.
+     */
+
+    while (t = tok_class()) {
+       switch (t->tokno) {
+       case TOK_WSPACE:                        /* preserve trailing blanks */
+           tok_space_append(list->tail, t);    /* except after list */
+           break;
+       case '\n':                              /* fix newlines later */
+           tok_free(t);
+           break;
+       case '{':                               /* recurse */
+           tok_list_struct(list, t);
+           break;
+       case '}':                               /* done */
+           tok_list_append(list, t);
+           return;
+       default:                                /* other */
+           tok_list_append(list, t);
+           break;
+       }
+    }
+    error_where(filename, lineno, "unmatched '{'");
+}
+
+/* tok_strcat - concatenate multiple string constants */
+
+static void tok_strcat(t1)
+register struct token *t1;
+{
+    register struct token *t2;
+    register struct token *lookahead = 0;
+
+    /*
+     * Read ahead past whitespace, comments and newlines. If we find a string
+     * token, concatenate it with the previous one and push back the
+     * intervening tokens (thus preserving as much information as possible).
+     * If we find something else, push back all lookahead tokens.
+     */
+
+#define PUSHBACK_AND_RETURN { if (lookahead) tok_unget(lookahead); return; }
+
+    while (t2 = tok_class()) {
+       switch (t2->tokno) {
+       case TOK_WSPACE:                        /* read past comments/blanks */
+       case '\n':                              /* read past newlines */
+           TOK_PREPEND(lookahead, t2);
+           break;
+       case '"':                               /* concatenate string tokens */
+           if (vs_strcpy(t1->vstr,
+                         t1->vstr->str + strlen(t1->vstr->str) - 1,
+                         t2->vstr->str + 1) == 0)
+               fatal("out of memory");
+           tok_free(t2);
+           PUSHBACK_AND_RETURN;
+       default:                                /* something else, push back */
+           tok_unget(t2);
+           PUSHBACK_AND_RETURN;
+       }
+    }
+    PUSHBACK_AND_RETURN;                       /* hit EOF */
+}
+
+#if defined(MAP_VOID_STAR) || defined(MAP_VOID)
+
+/* tok_void - support for compilers that have problems with "void" */
+
+static void tok_void(t)
+register struct token *t;
+{
+    register struct token *t2;
+    register struct token *lookahead = 0;
+
+    /*
+     * Look ahead beyond whitespace, comments and newlines until we see a '*'
+     * token. If one is found, replace "void" by "char". If we find something
+     * else, and if "void" should always be mapped, replace "void" by "int".
+     * Always push back the lookahead tokens.
+     * 
+     * XXX The code also replaces the (void) argument list; this must be
+     * accounted for later on. The alternative would be to add (in unproto.c)
+     * TOK_VOID cases all over the place and that would be too error-prone.
+     */
+
+#define PUSHBACK_AND_RETURN { if (lookahead) tok_unget(lookahead); return; }
+
+    while (t2 = tok_class()) {
+       switch (TOK_PREPEND(lookahead, t2)->tokno) {
+       case TOK_WSPACE:                        /* read past comments/blanks */
+       case '\n':                              /* read past newline */
+           break;
+       case '*':                               /* "void *" -> "char *" */
+           if (vs_strcpy(t->vstr, t->vstr->str, "char") == 0)
+               fatal("out of memory");
+           PUSHBACK_AND_RETURN;
+       default:
+#ifdef MAP_VOID                                        /* plain "void" -> "int" */
+           if (vs_strcpy(t->vstr, t->vstr->str, "int") == 0)
+               fatal("out of memory");
+#endif
+           PUSHBACK_AND_RETURN;
+       }
+    }
+    PUSHBACK_AND_RETURN;                       /* hit EOF */
+}
+
+#endif
+
+/* tok_time - rewrite __TIME__ to "hh:mm:ss" string constant */
+
+static void tok_time(t)
+struct token *t;
+{
+    long    now;
+    char   *cp;
+    char    buf[BUFSIZ];
+
+    /*
+     * Using sprintf() to select parts of a string is gross, but this should
+     * be fast enough.
+     */
+
+    (void) time(&now);
+    cp = ctime(&now);
+    sprintf(buf, "\"%.8s\"", cp + 11);
+    if (vs_strcpy(t->vstr, t->vstr->str, buf) == 0)
+       fatal("out of memory");
+    t->tokno = buf[0];
+}
+
+/* tok_date - rewrite __DATE__ to "Mmm dd yyyy" string constant */
+
+static void tok_date(t)
+struct token *t;
+{
+    long    now;
+    char   *cp;
+    char    buf[BUFSIZ];
+
+    /*
+     * Using sprintf() to select parts of a string is gross, but this should
+     * be fast enough.
+     */
+
+    (void) time(&now);
+    cp = ctime(&now);
+    sprintf(buf, "\"%.3s %.2s %.4s\"", cp + 4, cp + 8, cp + 20);
+    if (vs_strcpy(t->vstr, t->vstr->str, buf) == 0)
+       fatal("out of memory");
+    t->tokno = buf[0];
+}
+
+/* tok_unget - push back one or more possibly composite tokens */
+
+void    tok_unget(t)
+register struct token *t;
+{
+    register struct token *next;
+
+    do {
+       next = t->next;
+       TOK_PREPEND(tok_buf, t);
+    } while (t = next);
+}
+
+/* tok_list_append - append data to list */
+
+static void tok_list_append(h, t)
+struct token *h;
+struct token *t;
+{
+    if (h->head == 0) {
+       h->head = h->tail = t;
+    } else {
+       h->tail->next = t;
+       h->tail = t;
+    }
+}
diff --git a/build/unproto/tok_io.c b/build/unproto/tok_io.c
new file mode 100644 (file)
index 0000000..74ae6bc
--- /dev/null
@@ -0,0 +1,612 @@
+/*++
+/* NAME
+/*     tok_io 3
+/* SUMMARY
+/*     token I/O
+/* PACKAGE
+/*     unproto
+/* SYNOPSIS
+/*     #include "token.h"
+/*
+/*     struct token *tok_get()
+/*
+/*     void tok_flush(t)
+/*     struct token *t;
+/*
+/*     void tok_show(t)
+/*     struct token *t;
+/*
+/*     void tok_show_ch(t)
+/*     struct token *t;
+/*
+/*     void put_str(s)
+/*     char *s;
+/*
+/*     void put_ch(c)
+/*     int c;
+/*
+/*     void put_nl()
+/*
+/*     char *in_path;
+/*     int in_line;
+/* DESCRIPTION
+/*     These functions read from stdin and write to stdout. The
+/*     tokenizer keeps track of where the token appeared in the input
+/*     stream; on output, this information is used to preserve correct
+/*     line number information (even after lots of token lookahead or
+/*     after function-header rewriting) so that diagnostics from the
+/*     next compiler stage make sense.
+/*
+/*     tok_get() reads the next token from standard input. It returns
+/*     a null pointer when the end of input is reached.
+/*
+/*     tok_show() displays the contents of a (possibly composite) token
+/*     on the standard output.
+/*
+/*     tok_show_ch() displays the contents of a single-character token
+/*     on the standard output. The character should not be a newline.
+/*
+/*     tok_flush() displays the contents of a (possibly composite) token
+/*     on the standard output and makes it available for re-use.
+/*
+/*     put_str() writes a null-terminated string to standard output.
+/*     There should be no newline characters in the string argument.
+/*
+/*     put_ch() writes one character to standard output. The character
+/*     should not be a newline.
+/*
+/*     put_nl() outputs a newline character and adjusts the program's idea of
+/*     the current output line.
+/*
+/*     The in_path and in_line variables contain the file name and
+/*     line number of the most recently read token.
+/* BUGS
+/*     The tokenizer is just good enough for the unproto filter.
+/*     As a benefit, it is quite fast.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     Eindhoven University of Technology
+/*     Department of Mathematics and Computer Science
+/*     Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
+/* LAST MODIFICATION
+/*     92/01/15 21:52:59
+/* VERSION/RELEASE
+/*     1.3
+/*--*/
+
+static char io_sccsid[] = "@(#) tok_io.c 1.3 92/01/15 21:52:59";
+
+/* C library */
+
+#include <stdio.h>
+#include <ctype.h>
+
+extern char *strchr();
+extern char *malloc();
+extern char *realloc();
+extern char *strcpy();
+
+/* Application-specific stuff */
+
+#include "token.h"
+#include "vstring.h"
+#include "error.h"
+
+extern char *strsave();                        /* XXX need include file */
+
+/* Stuff to keep track of original source file name and position */
+
+static char def_path[] = "";           /* default path name */
+
+char   *in_path = def_path;            /* current input file name */
+int     in_line = 1;                   /* current input line number */
+
+static char *out_path = def_path;      /* last name in output line control */
+static int out_line = 1;               /* current output line number */
+int     last_ch;                       /* type of last output */
+
+/* Forward declarations */
+
+static int read_quoted();
+static void read_comment();
+static int backslash_newline();
+static char *read_hex();
+static char *read_octal();
+static void fix_line_control();
+
+ /*
+  * Character input with one level of pushback. The INPUT() macro recursively
+  * strips backslash-newline pairs from the input stream. The UNPUT() macro
+  * should be used only for characters obtained through the INPUT() macro.
+  * 
+  * After skipping a backslash-newline pair, the input line counter is not
+  * updated, and we continue with the same logical source line. We just
+  * update a counter with the number of backslash-newline sequences that must
+  * be accounted for (backslash_newline() updates the counter). At the end of
+  * the logical source line, an appropriate number of newline characters is
+  * pushed back (in tok_get()). I do not know how GCC handles this, but it
+  * seems to produce te same output.
+  * 
+  * Because backslash_newline() recursively calls itself (through the INPUT()
+  * macro), we will run out of stack space, given a sufficiently long
+  * sequence of backslash-newline pairs.
+  */
+
+static char in_char = 0;               /* push-back storage */
+static int in_flag = 0;                        /* pushback available */
+static int nl_compensate = 0;          /* line continuation kluge */
+
+#define INPUT(c) (in_flag ? (in_flag = 0, c = in_char) : \
+                   (c = getchar()) != '\\' ? c : \
+                   (c = getchar()) != '\n' ? (ungetc(c, stdin), c = '\\') : \
+                   (c = backslash_newline()))
+#define        UNPUT(c) (in_flag = 1, in_char = c)
+
+/* Directives that should be ignored. */
+
+#ifdef IGNORE_DIRECTIVES
+
+static char *ignore_directives[] = {
+    IGNORE_DIRECTIVES,
+    0,
+};
+
+#endif
+
+/* Modified string and ctype stuff. */
+
+#define        STREQUAL(x,y)   (*(x) == *(y) && strcmp((x),(y)) == 0)
+
+#define        ISALNUM(c)      (isalnum(c) || (c) == '_')
+#define        ISALPHA(c)      (isalpha(c) || (c) == '_')
+#define        ISSPACE(c)      (isspace(c) && c != '\n')
+#define        ISDOT(c)        (c == '.')
+#define        ISHEX(c)        (isdigit(c) || strchr("abcdefABCDEF", c) != 0)
+#define        ISOCTAL(c)      (isdigit(c) && (c) != '8' && (c) != '9')
+
+/* Collect all characters that satisfy one condition */
+
+#define        COLLECT(v,c,cond) { \
+                               register struct vstring *vs = v; \
+                               register char *cp = vs->str; \
+                               *cp++ = c; \
+                               while (INPUT(c) != EOF) { \
+                                   if (cond) { \
+                                       if (VS_ADDCH(vs, cp, c) == 0) \
+                                           fatal("out of memory"); \
+                                   } else { \
+                                       UNPUT(c); \
+                                       break; \
+                                   } \
+                               } \
+                               *cp = 0; \
+                           }
+
+/* Ensure that output line information is correct */
+
+#define        CHECK_LINE_CONTROL(p,l) { if (out_path != (p) || out_line != (l)) \
+                                       fix_line_control((p),(l)); }
+
+/* do_control - parse control line */
+
+static int do_control()
+{
+    struct token *t;
+    int     line;
+    char   *path;
+
+    /* Make sure that the directive shows up in the right place. */
+
+    CHECK_LINE_CONTROL(in_path, in_line);
+
+    while (t = tok_get()) {
+       switch (t->tokno) {
+
+       case TOK_WSPACE:
+           /* Ignore blanks after "#" token. */
+           tok_free(t);
+           break;
+
+       case TOK_NUMBER:
+
+           /*
+            * Line control is of the form: number pathname junk. Since we
+            * have no idea what junk the preprocessor may generate, we copy
+            * all line control tokens to stdout.
+            */
+
+           put_str("# ");
+           line = atoi(t->vstr->str);          /* extract line number */
+           tok_flush(t);
+           while ((t = tok_get()) && t->tokno == TOK_WSPACE)
+               tok_flush(t);                   /* copy white space */
+           if (t) {                            /* extract path name */
+               path = (t->tokno == '"') ? strsave(t->vstr->str) : in_path;
+               do {
+                   tok_flush(t);               /* copy until newline */
+               } while (t->tokno != '\n' && (t = tok_get()));
+           }
+           out_line = in_line = line;          /* synchronize */
+           out_path = in_path = path;          /* synchronize */
+           return;
+
+#ifdef IGNORE_DIRECTIVES
+
+       case TOK_WORD:
+
+           /*
+            * Optionally ignore other #directives. This is only a partial
+            * solution, because the preprocessor will still see them.
+            */
+           {
+               char  **cpp;
+               char   *cp = t->vstr->str;
+
+               for (cpp = ignore_directives; *cpp; cpp++) {
+                   if (STREQUAL(cp, *cpp)) {
+                       do {
+                           tok_free(t);
+                       } while (t->tokno != '\n' && (t = tok_get()));
+                       return;
+                   }
+               }
+           }
+           /* FALLTHROUGH */
+#endif
+       default:
+           /* Pass through. */
+           put_ch('#');
+           do {
+               tok_flush(t);
+           } while (t->tokno != '\n' && (t = tok_get()));
+           return;
+
+       case 0:
+           /* Hit EOF, punt. */
+           put_ch('#');
+           return;
+       }
+    }
+}
+
+/* backslash_newline - fix up things after reading a backslash-newline pair */
+
+static int backslash_newline()
+{
+    register int c;
+
+    nl_compensate++;
+    return (INPUT(c));
+}
+
+/* tok_get - get next token */
+
+static int last_tokno = '\n';
+
+struct token *tok_get()
+{
+    register struct token *t;
+    register int c;
+    int     d;
+
+    /*
+     * Get one from the pool and fill it in. The loop is here in case we hit
+     * a preprocessor control line, which happens in a minority of all cases.
+     * We update the token input path and line info *after* backslash-newline
+     * processing or the newline compensation would go wrong.
+     */
+
+    t = tok_alloc();
+
+    for (;;) {
+       if ((INPUT(c)) == EOF) {
+           tok_free(t);
+           return (0);
+       } else if ((t->line = in_line, t->path = in_path), !isascii(c)) {
+           t->vstr->str[0] = c;
+           t->vstr->str[1] = 0;
+           t->tokno = TOK_OTHER;
+           break;
+       } else if (ISSPACE(c)) {
+           COLLECT(t->vstr, c, ISSPACE(c));
+           t->tokno = TOK_WSPACE;
+           break;
+       } else if (ISALPHA(c)) {
+           COLLECT(t->vstr, c, ISALNUM(c));
+           t->tokno = TOK_WORD;
+           break;
+       } else if (isdigit(c)) {
+           COLLECT(t->vstr, c, isdigit(c));
+           t->tokno = TOK_NUMBER;
+           break;
+       } else if (c == '"' || c == '\'') {
+           t->tokno = read_quoted(t->vstr, c); /* detect missing end quote */
+           break;
+       } else if (ISDOT(c)) {
+           COLLECT(t->vstr, c, ISDOT(c));
+           t->tokno = TOK_OTHER;
+           break;
+       } else if (c == '#' && last_tokno == '\n') {
+           do_control();
+           continue;
+       } else {
+           t->vstr->str[0] = c;
+           if (c == '\n') {
+               in_line++;
+               if (nl_compensate > 0) {        /* compensation for bs-nl */
+                   UNPUT('\n');
+                   nl_compensate--;
+               }
+           } else if (c == '/') {
+               if ((INPUT(d)) == '*') {
+                   t->vstr->str[1] = d;        /* comment */
+                   read_comment(t->vstr);
+                   t->tokno = TOK_WSPACE;
+                   break;
+               } else {
+                   if (d != EOF)
+                       UNPUT(d);
+               }
+           } else if (c == '\\') {
+               t->vstr->str[1] = (INPUT(c) == EOF ? 0 : c);
+               t->vstr->str[2] = 0;
+               t->tokno = TOK_OTHER;
+               break;
+           }
+           t->vstr->str[1] = 0;
+           t->tokno = c;
+           break;
+       }
+    }
+    last_tokno = t->tokno;
+    t->end_line = in_line;
+    return (t);
+}
+
+/* read_quoted - read string or character literal, canonicalize escapes */
+
+static int read_quoted(vs, ch)
+register struct vstring *vs;
+int     ch;
+{
+    register char *cp = vs->str;
+    register int c;
+    int     ret = TOK_OTHER;
+
+    *cp++ = ch;
+
+    /*
+     * Clobber the token type in case of a premature newline or EOF. This
+     * prevents us from attempting to concatenate string constants with
+     * broken ones that have no closing quote.
+     */
+
+    while (INPUT(c) != EOF) {
+       if (c == '\n') {                        /* newline in string */
+           UNPUT(c);
+           break;
+       }
+       if (VS_ADDCH(vs, cp, c) == 0)           /* store character */
+           fatal("out of memory");
+       if (c == ch) {                          /* closing quote */
+           ret = c;
+           break;
+       }
+       if (c == '\\') {                        /* parse escape sequence */
+           if ((INPUT(c)) == EOF) {            /* EOF, punt */
+               break;
+           } else if (c == 'a') {              /* \a -> audible bell */
+               if ((cp = vs_strcpy(vs, cp, BELL)) == 0)
+                   fatal("out of memory");
+           } else if (c == 'x') {              /* \xhh -> \nnn */
+               cp = read_hex(vs, cp);
+           } else if (ISOCTAL(c) && ch != '\'') {
+               cp = read_octal(vs, cp, c);     /* canonicalize \octal */
+           } else {
+               if (VS_ADDCH(vs, cp, c) == 0)   /* \other: leave alone */
+                   fatal("out of memory");
+           }
+       }
+    }
+    *cp = 0;
+    return (ret);
+}
+
+/* read_comment - stuff a whole comment into one huge token */
+
+static void read_comment(vs)
+register struct vstring *vs;
+{
+    register char *cp = vs->str + 2;   /* skip slash star */
+    register int c;
+    register int d;
+
+    while (INPUT(c) != EOF) {
+       if (VS_ADDCH(vs, cp, c) == 0)
+           fatal("out of memory");
+       if (c == '*') {
+           if ((INPUT(d)) == '/') {
+               if (VS_ADDCH(vs, cp, d) == 0)
+                   fatal("out of memory");
+               break;
+           } else {
+               if (d != EOF)
+                   UNPUT(d);
+           }
+       } else if (c == '\n') {
+           in_line++;
+       } else if (c == '\\') {
+           if ((INPUT(d)) != EOF && VS_ADDCH(vs, cp, d) == 0)
+               fatal("out of memory");
+       }
+    }
+    *cp = 0;
+}
+
+/* read_hex - rewrite hex escape to three-digit octal escape */
+
+static char *read_hex(vs, cp)
+struct vstring *vs;
+register char *cp;
+{
+    register int c;
+    register int i;
+    char    buf[BUFSIZ];
+    int     len;
+    unsigned val;
+
+    /*
+     * Eat up all subsequent hex digits. Complain later when there are too
+     * many.
+     */
+
+    for (i = 0; i < sizeof(buf) && (INPUT(c) != EOF) && ISHEX(c); i++)
+       buf[i] = c;
+    buf[i] = 0;
+
+    if (i < sizeof(buf) && c)
+       UNPUT(c);
+
+    /*
+     * Convert hex form to three-digit octal form. The three-digit form is
+     * used so that strings can be concatenated without problems. Complain
+     * about malformed input; truncate the result to at most three octal
+     * digits.
+     */
+
+    if (i == 0) {
+       error("\\x escape sequence without hexadecimal digits");
+       if (VS_ADDCH(vs, cp, 'x') == 0)
+           fatal("out of memory");
+    } else {
+       (void) sscanf(buf, "%x", &val);
+       sprintf(buf, "%03o", val);
+       if ((len = strlen(buf)) > 3)
+           error("\\x escape sequence yields non-character value");
+       if ((cp = vs_strcpy(vs, cp, buf + len - 3)) == 0)
+           fatal("out of memory");
+    }
+    return (cp);
+}
+
+/* read_octal - convert octal escape to three-digit format */
+
+static char obuf[] = "00123";
+
+static char *read_octal(vs, cp, c)
+register struct vstring *vs;
+register char *cp;
+register int c;
+{
+    register int i;
+
+#define        buf_input (obuf + 2)
+
+    /* Eat up at most three octal digits. */
+
+    buf_input[0] = c;
+    for (i = 1; i < 3 && (INPUT(c) != EOF) && ISOCTAL(c); i++)
+       buf_input[i] = c;
+    buf_input[i] = 0;
+
+    if (i < 3 && c)
+       UNPUT(c);
+
+    /*
+     * Leave three-digit octal escapes alone. Convert one-digit and two-digit
+     * octal escapes to three-digit form by prefixing them with a suitable
+     * number of '0' characters. This is done so that strings can be
+     * concatenated without problems.
+     */
+
+    if ((cp = vs_strcpy(vs, cp, buf_input + i - 3)) == 0)
+       fatal("out of memory");
+    return (cp);
+}
+
+/* put_nl - emit newline and adjust output line count */
+
+void    put_nl()
+{
+    put_ch('\n');
+    out_line++;
+}
+
+/* fix_line_control - to adjust path and/or line count info in output */
+
+static void fix_line_control(path, line)
+register char *path;
+register int line;
+{
+
+    /*
+     * This function is called sporadically, so it should not be a problem
+     * that we repeat some of the tests that preceded this function call.
+     * 
+     * Emit a newline if we are not at the start of a line.
+     * 
+     * If we switch files, or if we jump backwards, emit line control. If we
+     * jump forward, emit the proper number of newlines to compensate.
+     */
+
+    if (last_ch != '\n')                       /* terminate open line */
+       put_nl();
+    if (path != out_path || line < out_line) { /* file switch or back jump */
+       printf("# %d %s\n", out_line = line, out_path = path);
+       last_ch = '\n';
+    } else {                                   /* forward jump */
+       while (line > out_line)
+           put_nl();
+    }
+}
+
+/* tok_show_ch - output single-character token (not newline) */
+
+void    tok_show_ch(t)
+register struct token *t;
+{
+    CHECK_LINE_CONTROL(t->path, t->line);
+
+    put_ch(t->tokno);                          /* show token contents */
+}
+
+/* tok_show - output (possibly composite) token */
+
+void    tok_show(t)
+register struct token *t;
+{
+    register struct token *p;
+
+    if (t->tokno == TOK_LIST) {
+       register struct token *s;
+
+       /*
+        * This branch is completely in terms of tok_xxx() primitives, so
+        * there is no need to check the line control information.
+        */
+
+       for (s = t->head; s; s = s->next) {
+           tok_show_ch(s);                     /* '(' or ',' or ')' */
+           for (p = s->head; p; p = p->next)
+               tok_show(p);                    /* show list element */
+       }
+    } else {
+       register char *cp = t->vstr->str;
+
+       /*
+        * Measurements show that it pays off to give special treatment to
+        * single-character tokens. Note that both types of token may cause a
+        * change of output line number.
+        */
+
+       CHECK_LINE_CONTROL(t->path, t->line);
+       if (cp[1] == 0) {
+           put_ch(*cp);                        /* single-character token */
+       } else {
+           put_str(cp);                        /* multi_character token */
+       }
+       out_line = t->end_line;                 /* may span multiple lines */
+       for (p = t->head; p; p = p->next)
+           tok_show(p);                        /* trailing blanks */
+    }
+}
diff --git a/build/unproto/tok_pool.c b/build/unproto/tok_pool.c
new file mode 100644 (file)
index 0000000..e2ed107
--- /dev/null
@@ -0,0 +1,103 @@
+/*++
+/* NAME
+/*     tok_pool 3
+/* SUMMARY
+/*     maintain pool of unused token structures
+/* PACKAGE
+/*     unproto
+/* SYNOPSIS
+/*     #include "token.h"
+/*
+/*     struct token *tok_alloc()
+/*
+/*     void tok_free(t)
+/*     struct token *t;
+/* DESCRIPTION
+/*     tok_alloc() and tok_free() maintain a pool of unused token
+/*     structures.
+/*
+/*     tok_alloc() takes the first free token structure from the pool
+/*     or allocates a new one if the pool is empty.
+/*
+/*     tok_free() adds a (possibly composite) token structure to the pool.
+/* BUGS
+/*     The pool never shrinks.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     Eindhoven University of Technology
+/*     Department of Mathematics and Computer Science
+/*     Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
+/* LAST MODIFICATION
+/*     92/01/15 21:53:04
+/* VERSION/RELEASE
+/*     1.2
+/*--*/
+
+static char pool_sccsid[] = "@(#) tok_pool.c 1.2 92/01/15 21:53:04";
+
+/* C library */
+
+extern char *malloc();
+
+/* Application-specific stuff */
+
+#include "token.h"
+#include "vstring.h"
+#include "error.h"
+
+#define        TOKLEN  5                       /* initial string buffer length */
+
+struct token *tok_pool = 0;            /* free token pool */
+
+/* tok_alloc - allocate token structure from pool or heap */
+
+struct token *tok_alloc()
+{
+    register struct token *t;
+
+    if (tok_pool) {                            /* re-use an old one */
+       t = tok_pool;
+       tok_pool = t->next;
+    } else {                                   /* create a new one */
+       if ((t = (struct token *) malloc(sizeof(struct token))) == 0
+           || (t->vstr = vs_alloc(TOKLEN)) == 0)
+           fatal("out of memory");
+    }
+    t->next = t->head = t->tail = 0;
+#ifdef DEBUG
+    strcpy(t->vstr->str, "BUSY");
+#endif
+    return (t);
+}
+
+/* tok_free - return (possibly composite) token to pool of free tokens */
+
+void    tok_free(t)
+register struct token *t;
+{
+#ifdef DEBUG
+    /* Check if we are freeing free token */
+
+    register struct token *p;
+
+    for (p = tok_pool; p; p = p->next)
+       if (p == t)
+           fatal("freeing free token");
+#endif
+
+    /* Free neighbours and subordinates first */
+
+    if (t->next)
+       tok_free(t->next);
+    if (t->head)
+       tok_free(t->head);
+
+    /* Free self */
+
+    t->next = tok_pool;
+    t->head = t->tail = 0;
+    tok_pool = t;
+#ifdef DEBUG
+    strcpy(t->vstr->str, "FREE");
+#endif
+}
diff --git a/build/unproto/token.h b/build/unproto/token.h
new file mode 100644 (file)
index 0000000..bb2f50a
--- /dev/null
@@ -0,0 +1,55 @@
+/* @(#) token.h 1.4 92/01/15 21:53:17 */
+
+struct token {
+    int     tokno;                     /* token value, see below */
+    char   *path;                      /* file name */
+    int     line;                      /* line number at token start */
+    int     end_line;                  /* line number at token end */
+    struct vstring *vstr;              /* token contents */
+    struct token *next;
+    struct token *head;
+    struct token *tail;
+};
+
+/* Special token values */
+
+#define        TOK_LIST        256             /* () delimited list */
+#define        TOK_WORD        257             /* keyword or identifier */
+#define        TOK_NUMBER      258             /* one or more digits */
+#define        TOK_WSPACE      259             /* comment, white space, not newline */
+#define        TOK_OTHER       260             /* other token */
+#define        TOK_CONTROL     261             /* flow control keyword */
+#define        TOK_COMPOSITE   262             /* struct or union keyword */
+#define        TOK_DATE        263             /* date: Mmm dd yyyy */
+#define        TOK_TIME        264             /* time: hh:mm:ss */
+#define        TOK_VOID        265             /* void keyword */
+
+/* Input/output functions and macros */
+
+extern struct token *tok_get();                /* read next single token */
+extern void tok_show();                        /* display (composite) token */
+extern struct token *tok_class();      /* classify tokens */
+extern void tok_unget();               /* stuff token back into input */
+extern void put_nl();                  /* print newline character */
+extern void tok_show_ch();             /* emit single-character token */
+
+#define        tok_flush(t)    (tok_show(t), tok_free(t))
+
+#ifdef DEBUG
+#define put_ch(c)      (putchar(last_ch = c),fflush(stdout))
+#define put_str(s)     (fputs(s,stdout),last_ch = 0,fflush(stdout))
+#else
+#define put_ch(c)      putchar(last_ch = c)
+#define put_str(s)     (fputs(s,stdout),last_ch = 0)
+#endif
+
+/* Memory management */
+
+struct token *tok_alloc();             /* allocate token storage */
+extern void tok_free();                        /* re-cycle storage */
+
+/* Context */
+
+extern char *in_path;                  /* current input path name */
+extern int in_line;                    /* current input line number */
+extern int last_ch;                    /* type of last output */
diff --git a/build/unproto/unproto.1 b/build/unproto/unproto.1
new file mode 100644 (file)
index 0000000..31490c3
--- /dev/null
@@ -0,0 +1,152 @@
+.TH UNPROTO 1 
+.ad
+.fi
+.SH NAME
+unproto
+\-
+compile ANSI C with traditional UNIX C compiler
+.SH PACKAGE
+.na
+.nf
+unproto
+.SH SYNOPSIS
+.na
+.nf
+/somewhere/cpp ...
+
+cc cflags -E file.c | unproto >file.i; cc cflags -c file.i
+.SH DESCRIPTION
+.ad
+.fi
+This document describes a filter that sits in between the UNIX
+C preprocessor and the next UNIX C compiler stage, on the fly rewriting
+ANSI-style syntax to old-style syntax. Typically, the program is
+invoked by the native UNIX C compiler as an alternate preprocessor.
+The unprototyper in turn invokes the native C preprocessor and
+massages its output. Similar tricks can be used with the lint(1)
+command.
+
+Language constructs that are always rewritten:
+.TP
+function headings, prototypes, pointer types
+ANSI-C style function headings, function prototypes, function
+pointer types and type casts are rewritten to old style.
+<stdarg.h> support is provided for functions with variable-length
+argument lists.
+.TP
+character and string constants
+The \\a and \\x escape sequences are rewritten to their (three-digit)
+octal equivalents.
+
+Multiple string tokens are concatenated; an arbitrary number of
+whitespace or comment tokens may appear between successive
+string tokens.
+
+Within string constants, octal escape sequences are rewritten to the
+three-digit \\ddd form, so that string concatenation produces correct
+results.
+.TP
+date and time
+The __DATE__ and __TIME__ tokens are replaced by string constants
+of the form "Mmm dd yyyy" and "hh:mm:ss", respectively. The result
+is subjected to string concatenation, just like any other string
+constant.
+.PP
+Language constructs that are rewritten only if the program has been
+configured to do so:
+.TP
+void types
+The unprototyper can be configured to rewrite "void *" to "char *",
+and even to rewrite plain "void" to "int".
+These features are configurable because many traditional UNIX C
+compilers do not need them.
+
+Note: (void) argument lists are always replaced by empty ones.
+.PP
+ANSI C constructs that are not rewritten because the traditional
+UNIX C preprocessor provides suitable workarounds:
+.TP
+const and volatile
+Use the "-Dconst=" and/or "-Dvolatile=" preprocessor directives to
+get rid of unimplemented keywords.
+.TP
+token pasting and stringizing
+The traditional UNIX C preprocessor provides excellent alternatives.
+For example:
+
+.nf
+.ne 2
+#define string(bar)     "bar"           /* instead of: # x */
+#define paste(x,y)      x/**\/y         /* instead of: x##y */
+.fi
+
+There is a good reason why the # and ## operators are not implemented
+in the unprototyper.
+After program text has gone through a non-ANSI C preprocessor, all
+information about the grouping of the operands of # and ## is lost.
+Thus, if the unprototyper were to perform these operations, it would
+produce correct results only in the most trivial cases. Operands
+with embedded blanks, operands that expand to null tokens, and nested
+use of # and/or ## would cause all kinds of obscure problems.
+.PP
+Unsupported ANSI features:
+.TP
+trigraphs and #pragmas
+Trigraphs are useful only for systems with broken character sets.
+If the local compiler chokes on #pragma, insert a blank before the
+"#" character, and enclose the offending directive between #ifdef
+and #endif.
+.SH SEE ALSO
+.na
+.nf
+.ad
+.fi
+cc(1), how to specify a non-default C preprocessor.
+Some versions of the lint(1) command are implemented as a shell
+script. It should require only minor modification for integration
+with the unprototyper. Other versions of the lint(1) command accept
+the same command syntax as the C compiler for the specification of a
+non-default preprocessor. Some research may be needed.
+.SH FILES
+.na
+.nf
+/wherever/stdarg.h, provided with the unproto filter.
+.SH DIAGNOSTICS
+.ad
+.fi
+Problems are reported on the standard error stream.
+A non-zero exit status means that there was a problem.
+.SH BUGS
+.ad
+.fi
+The unprototyper should be run on preprocessed source only:
+unexpanded macros may confuse the program.
+
+Declarations of (object) are misunderstood and will result in
+syntax errors: the objects between parentheses disappear.
+
+Sometimes does not preserve whitespace after parentheses and commas.
+This is a purely aesthetical matter, and the compiler should not care.
+Whitespace within string constants is, of course, left intact.
+
+Does not generate explicit type casts for function-argument
+expressions.  The lack of explicit conversions between integral
+and/or pointer argument types should not be a problem in environments
+where sizeof(int) == sizeof(long) == sizeof(pointer).  A more serious
+problem is the lack of automatic type conversions between integral and
+floating-point argument types.  Let lint(1) be your friend.
+.SH AUTHOR(S)
+.na
+.nf
+Wietse Venema (wietse@wzv.win.tue.nl)
+Eindhoven University of Technology
+Department of Mathematics and Computer Science
+Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
+.SH LAST MODIFICATION
+.na
+.nf
+93/06/18 22:29:37
+.SH VERSION/RELEASE
+.na
+.nf
+1.6
diff --git a/build/unproto/unproto.c b/build/unproto/unproto.c
new file mode 100644 (file)
index 0000000..2b2e764
--- /dev/null
@@ -0,0 +1,999 @@
+/*++
+/* NAME
+/*     unproto 1
+/* SUMMARY
+/*     compile ANSI C with traditional UNIX C compiler
+/* PACKAGE
+/*     unproto
+/* SYNOPSIS
+/*     /somewhere/cpp ...
+/*
+/*     cc cflags -E file.c | unproto >file.i; cc cflags -c file.i
+/* DESCRIPTION
+/*     This document describes a filter that sits in between the UNIX
+/*     C preprocessor and the next UNIX C compiler stage, on the fly rewriting
+/*     ANSI-style syntax to old-style syntax. Typically, the program is
+/*     invoked by the native UNIX C compiler as an alternate preprocessor.
+/*     The unprototyper in turn invokes the native C preprocessor and
+/*     massages its output. Similar tricks can be used with the lint(1)
+/*     command.
+/*
+/*     Language constructs that are always rewritten:
+/* .TP
+/* function headings, prototypes, pointer types
+/*     ANSI-C style function headings, function prototypes, function
+/*     pointer types and type casts are rewritten to old style.
+/*     <stdarg.h> support is provided for functions with variable-length
+/*     argument lists.
+/* .TP
+/* character and string constants
+/*     The \\a and \\x escape sequences are rewritten to their (three-digit)
+/*     octal equivalents.
+/*
+/*     Multiple string tokens are concatenated; an arbitrary number of
+/*     whitespace or comment tokens may appear between successive
+/*     string tokens.
+/*
+/*     Within string constants, octal escape sequences are rewritten to the
+/*     three-digit \\ddd form, so that string concatenation produces correct
+/*     results.
+/* .TP
+/* date and time
+/*     The __DATE__ and __TIME__ tokens are replaced by string constants
+/*     of the form "Mmm dd yyyy" and "hh:mm:ss", respectively. The result
+/*     is subjected to string concatenation, just like any other string
+/*     constant.
+/* .PP
+/*     Language constructs that are rewritten only if the program has been
+/*     configured to do so:
+/* .TP
+/* void types
+/*     The unprototyper can be configured to rewrite "void *" to "char *",
+/*     and even to rewrite plain "void" to "int".
+/*     These features are configurable because many traditional UNIX C
+/*     compilers do not need them.
+/*
+/*     Note: (void) argument lists are always replaced by empty ones.
+/* .PP
+/*     ANSI C constructs that are not rewritten because the traditional
+/*     UNIX C preprocessor provides suitable workarounds:
+/* .TP
+/* const and volatile
+/*     Use the "-Dconst=" and/or "-Dvolatile=" preprocessor directives to
+/*     get rid of unimplemented keywords.
+/* .TP
+/* token pasting and stringizing
+/*     The traditional UNIX C preprocessor provides excellent alternatives.
+/*     For example:
+/*
+/* .nf
+/* .ne 2
+/*     #define string(bar)     "bar"           /* instead of: # x */
+/*     #define paste(x,y)      x/**\/y         /* instead of: x##y */
+/* .fi
+/*
+/*     There is a good reason why the # and ## operators are not implemented
+/*     in the unprototyper.
+/*     After program text has gone through a non-ANSI C preprocessor, all
+/*     information about the grouping of the operands of # and ## is lost.
+/*     Thus, if the unprototyper were to perform these operations, it would
+/*     produce correct results only in the most trivial cases. Operands
+/*     with embedded blanks, operands that expand to null tokens, and nested
+/*     use of # and/or ## would cause all kinds of obscure problems.
+/* .PP
+/*     Unsupported ANSI features:
+/* .TP
+/* trigraphs and #pragmas
+/*     Trigraphs are useful only for systems with broken character sets.
+/*     If the local compiler chokes on #pragma, insert a blank before the
+/*     "#" character, and enclose the offending directive between #ifdef
+/*     and #endif.
+/* SEE ALSO
+/* .ad
+/* .fi
+/*     cc(1), how to specify a non-default C preprocessor.
+/*     Some versions of the lint(1) command are implemented as a shell
+/*     script. It should require only minor modification for integration
+/*     with the unprototyper. Other versions of the lint(1) command accept
+/*     the same command syntax as the C compiler for the specification of a
+/*     non-default preprocessor. Some research may be needed.
+/* FILES
+/*     /wherever/stdarg.h, provided with the unproto filter.
+/* DIAGNOSTICS
+/*     Problems are reported on the standard error stream.
+/*     A non-zero exit status means that there was a problem.
+/* BUGS
+/*     The unprototyper should be run on preprocessed source only:
+/*     unexpanded macros may confuse the program.
+/*
+/*     Declarations of (object) are misunderstood and will result in
+/*     syntax errors: the objects between parentheses disappear.
+/*
+/*     Sometimes does not preserve whitespace after parentheses and commas.
+/*     This is a purely aesthetical matter, and the compiler should not care.
+/*     Whitespace within string constants is, of course, left intact.
+/*
+/*     Does not generate explicit type casts for function-argument
+/*     expressions.  The lack of explicit conversions between integral
+/*     and/or pointer argument types should not be a problem in environments
+/*     where sizeof(int) == sizeof(long) == sizeof(pointer).  A more serious
+/*     problem is the lack of automatic type conversions between integral and
+/*     floating-point argument types.  Let lint(1) be your friend.
+/* AUTHOR(S)
+/*     Wietse Venema (wietse@wzv.win.tue.nl)
+/*     Eindhoven University of Technology
+/*     Department of Mathematics and Computer Science
+/*     Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
+/* LAST MODIFICATION
+/*     93/06/18 22:29:37
+/* VERSION/RELEASE
+/*     1.6
+/*--*/
+
+static char unproto_sccsid[] = "@(#) unproto.c 1.6 93/06/18 22:29:37";
+
+/* C library */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <errno.h>
+
+extern void exit();
+extern int optind;
+extern char *optarg;
+extern int getopt();
+
+/* Application-specific stuff */
+
+#include "vstring.h"
+#include "stdarg.h"
+#include "token.h"
+#include "error.h"
+#include "symbol.h"
+
+/* Forward declarations. */
+
+static struct token *dcl_flush();
+static void block_flush();
+static void block_dcls();
+static struct token *show_func_ptr_type();
+static struct token *show_struct_type();
+static void show_arg_name();
+static void show_type();
+static void pair_flush();
+static void check_cast();
+static void show_empty_list();
+
+#define        check_cast_flush(t)     (check_cast(t), tok_free(t))
+
+#ifdef PIPE_THROUGH_CPP
+static int pipe_stdin_through_cpp();
+#endif
+
+/* Disable debugging printfs while preserving side effects. */
+
+#ifdef DEBUG
+#define        DPRINTF printf
+#else
+#define        DPRINTF (void)
+#endif
+
+/* An attempt to make some complicated expressions a bit more readable. */
+
+#define        STREQ(x,y)              (*(x) == *(y) && !strcmp((x),(y)))
+
+#define        LAST_ARG_AND_EQUAL(s,c) ((s)->next && (s)->next->next == 0 \
+                               && (s)->head && ((s)->head == (s)->tail) \
+                               && (STREQ((s)->head->vstr->str, (c))))
+
+#define        LIST_BEGINS_WITH_STAR(s) (s->head->head && s->head->head->tokno == '*')
+
+#define        IS_FUNC_PTR_TYPE(s)     (s->tokno == TOK_LIST && s->next \
+                               && s->next->tokno == TOK_LIST \
+                               && LIST_BEGINS_WITH_STAR(s))
+
+/* What to look for to detect a (void) argument list. */
+
+#ifdef MAP_VOID
+#define        VOID_ARG        "int"           /* bare "void" is mapped to "int" */
+#else
+#define        VOID_ARG        "void"          /* bare "void" is left alone */
+#endif
+
+/* main - driver */
+
+int     main(argc, argv)
+int     argc;
+char  **argv;
+{
+    register struct token *t;
+#ifdef PIPE_THROUGH_CPP                        /* pipe through /lib/cpp */
+    int     cpp_status;
+    int     wait_pid;
+    int     cpp_pid;
+
+    cpp_pid = pipe_stdin_through_cpp(argv);
+#endif
+
+    sym_init();                                        /* prime the symbol table */
+
+    while (t = tok_class()) {
+       if (t = dcl_flush(t)) {                 /* try declaration */
+           if (t->tokno == '{') {              /* examine rejected token */
+               block_flush(t);                 /* body */
+           } else {
+               tok_flush(t);                   /* other, recover */
+           }
+       }
+    }
+
+#ifdef PIPE_THROUGH_CPP                        /* pipe through /lib/cpp */
+    while ((wait_pid = wait(&cpp_status)) != -1 && wait_pid != cpp_pid)
+        /* void */ ;
+    return (errcount != 0 || wait_pid != cpp_pid || cpp_status != 0);
+#else
+    return (errcount != 0);
+#endif
+}
+
+#ifdef PIPE_THROUGH_CPP                /* pipe through /lib/cpp */
+
+/* pipe_stdin_through_cpp - avoid shell script overhead */
+
+static int pipe_stdin_through_cpp(argv)
+char  **argv;
+{
+    int     pipefds[2];
+    int     pid;
+    char  **cpptr = argv;
+    int     i;
+    struct stat st;
+
+    /*
+     * The code that sets up the pipe requires that file descriptors 0,1,2
+     * are already open. All kinds of mysterious things will happen if that
+     * is not the case. The following loops makes sure that descriptors 0,1,2
+     * are set up properly. 
+     */
+
+    for (i = 0; i < 3; i++) {
+       if (fstat(i, &st) == -1 && open("/dev/null", 2) != i) {
+           perror("open /dev/null");
+           exit(1);
+       }
+    }
+
+    /*
+     * With most UNIX implementations, the second non-option argument to
+     * /lib/cpp specifies the output file. If an output file other than
+     * stdout is specified, we must force /lib/cpp to write to stdout, and we
+     * must redirect our own standard output to the specified output file.
+     */
+
+#define        IS_OPTION(cp) ((cp)[0] == '-' && (cp)[1] != 0)
+
+    /* Skip to first non-option argument, if any. */
+
+    while (*++cpptr && IS_OPTION(*cpptr))
+        /* void */ ;
+
+    /*
+     * Assume that the first non-option argument is the input file name. The
+     * next argument could be the output destination or an option (System V
+     * Release 2 /lib/cpp gets the options *after* the file arguments).
+     */
+
+    if (*cpptr && *++cpptr && **cpptr != '-') {
+
+       /*
+        * The first non-option argument is followed by another argument that
+        * is not an option ("-stuff") or a hyphen ("-"). Redirect our own
+        * standard output before we clobber the file name.
+        */
+
+       if (freopen(*cpptr, "w", stdout) == 0) {
+           perror(*cpptr);
+           exit(1);
+       }
+       /* Clobber the file name argument so that /lib/cpp writes to stdout */
+
+       *cpptr = "-";
+    }
+    /* Set up the pipe that connects /lib/cpp to our standard input. */
+
+    if (pipe(pipefds)) {
+       perror("pipe");
+       exit(1);
+    }
+    switch (pid = fork()) {
+    case -1:                                   /* error */
+       perror("fork");
+       exit(1);
+       /* NOTREACHED */
+    case 0:                                    /* child */
+       (void) close(pipefds[0]);               /* close reading end */
+       (void) close(1);                        /* connect stdout to pipe */
+       if (dup(pipefds[1]) != 1)
+           fatal("dup() problem");
+       (void) close(pipefds[1]);               /* close redundant fd */
+       (void) execv(PIPE_THROUGH_CPP, argv);
+       perror(PIPE_THROUGH_CPP);
+       exit(1);
+       /* NOTREACHED */
+    default:                                   /* parent */
+       (void) close(pipefds[1]);               /* close writing end */
+       (void) close(0);                        /* connect stdin to pipe */
+       if (dup(pipefds[0]) != 0)
+           fatal("dup() problem");
+       close(pipefds[0]);                      /* close redundant fd */
+       return (pid);
+    }
+}
+
+#endif
+
+/* show_arg_names - display function argument names */
+
+static void show_arg_names(t)
+register struct token *t;
+{
+    register struct token *s;
+
+    /* Do argument names, but suppress void and rewrite trailing ... */
+
+    if (LAST_ARG_AND_EQUAL(t->head, VOID_ARG)) {
+       show_empty_list(t);                     /* no arguments */
+    } else {
+       for (s = t->head; s; s = s->next) {     /* foreach argument... */
+           if (LAST_ARG_AND_EQUAL(s, "...")) {
+#ifdef _VA_ALIST_                              /* see ./stdarg.h */
+               tok_show_ch(s);                 /* ',' */
+               put_str(_VA_ALIST_);            /* varargs magic */
+#endif
+           } else {
+               tok_show_ch(s);                 /* '(' or ',' or ')' */
+               show_arg_name(s);               /* extract argument name */
+           }
+       }
+    }
+}
+
+/* show_arg_types - display function argument types */
+
+static void show_arg_types(t)
+register struct token *t;
+{
+    register struct token *s;
+
+    /* Do argument types, but suppress void and trailing ... */
+
+    if (!LAST_ARG_AND_EQUAL(t->head, VOID_ARG)) {
+       for (s = t->head; s; s = s->next) {     /* foreach argument... */
+           if (LAST_ARG_AND_EQUAL(s, "...")) {
+#ifdef _VA_DCL_                                        /* see ./stdarg.h */
+               put_str(_VA_DCL_);              /* varargs magic */
+               put_nl();                       /* make output look nicer */
+#endif
+           } else {
+               if (s->head != s->tail) {       /* really new-style argument? */
+                   show_type(s);               /* rewrite type info */
+                   put_ch(';');
+                   put_nl();                   /* make output look nicer */
+               }
+           }
+       }
+    }
+}
+
+/* header_flush - rewrite new-style function heading to old style */
+
+static void header_flush(t)
+register struct token *t;
+{
+    show_arg_names(t);                         /* show argument names */
+    put_nl();                                  /* make output look nicer */
+    show_arg_types(t);                         /* show argument types */
+    tok_free(t);                               /* discard token */
+}
+
+/* fpf_header_names - define func returning ptr to func, no argument types */
+
+static void fpf_header_names(list)
+struct token *list;
+{
+    register struct token *s;
+    register struct token *p;
+
+    /*
+     * Recurse until we find the argument list. Account for the rare case
+     * that list is a comma-separated list (which should be a syntax error).
+     * Display old-style fuction argument names.
+     */
+
+    for (s = list->head; s; s = s->next) {
+       tok_show_ch(s);                         /* '(' or ',' or ')' */
+       for (p = s->head; p; p = p->next) {
+           if (p->tokno == TOK_LIST) {
+               if (IS_FUNC_PTR_TYPE(p)) {      /* recurse */
+                   fpf_header_names(p);
+                   show_empty_list(p = p->next);
+               } else {                        /* display argument names */
+                   show_arg_names(p);
+               }
+           } else {                            /* pass through other stuff */
+               tok_show(p);
+           }
+       }
+    }
+}
+
+/* fpf_header_types - define func returning ptr to func, argument types only */
+
+static void fpf_header_types(list)
+struct token *list;
+{
+    register struct token *s;
+    register struct token *p;
+
+    /*
+     * Recurse until we find the argument list. Account for the rare case
+     * that list is a comma-separated list (which should be a syntax error).
+     * Display old-style function argument types.
+     */
+
+    for (s = list->head; s; s = s->next) {
+       for (p = s->head; p; p = p->next) {
+           if (p->tokno == TOK_LIST) {
+               if (IS_FUNC_PTR_TYPE(p)) {      /* recurse */
+                   fpf_header_types(p);
+                   p = p->next;
+               } else {                        /* display argument types */
+                   show_arg_types(p);
+               }
+           }
+       }
+    }
+}
+
+/* fpf_header - define function returning pointer to function */
+
+static void fpf_header(l1, l2)
+struct token *l1;
+struct token *l2;
+{
+    fpf_header_names(l1);                      /* strip argument types */
+    show_empty_list(l2);                       /* strip prototype */
+    put_nl();                                  /* nicer output */
+    fpf_header_types(l1);                      /* show argument types */
+}
+
+/* skip_enclosed - skip over enclosed tokens */
+
+static struct token *skip_enclosed(p, stop)
+register struct token *p;
+register int stop;
+{
+    register int start = p->tokno;
+
+    /* Always return a pointer to the last processed token, never NULL. */
+
+    while (p->next) {
+       p = p->next;
+       if (p->tokno == start) {
+           p = skip_enclosed(p, stop);         /* recurse */
+       } else if (p->tokno == stop) {
+           break;                              /* done */
+       }
+    }
+    return (p);
+}
+
+/* show_arg_name - extract argument name from argument type info */
+
+static void show_arg_name(s)
+register struct token *s;
+{
+    if (s->head) {
+       register struct token *p;
+       register struct token *t = 0;
+
+       /* Find the last interesting item. */
+
+       for (p = s->head; p; p = p->next) {
+           if (p->tokno == TOK_WORD) {
+               t = p;                          /* remember last word */
+           } else if (p->tokno == '{') {
+               p = skip_enclosed(p, '}');      /* skip structured stuff */
+           } else if (p->tokno == '[') {
+               break;                          /* dimension may be a macro */
+           } else if (IS_FUNC_PTR_TYPE(p)) {
+               t = p;                          /* or function pointer */
+               p = p->next;
+           }
+       }
+
+       /* Extract argument name from last interesting item. */
+
+       if (t) {
+           if (t->tokno == TOK_LIST)
+               show_arg_name(t->head);         /* function pointer, recurse */
+           else
+               tok_show(t);                    /* print last word */
+       }
+    }
+}
+
+/* show_type - rewrite type to old-style syntax */
+
+static void show_type(s)
+register struct token *s;
+{
+    register struct token *p;
+
+    /*
+     * Rewrite (*stuff)(args) to (*stuff)(). Rewrite word(args) to word(),
+     * but only if the word was preceded by a word, '*' or '}'. Leave
+     * anything else alone.
+     */
+
+    for (p = s->head; p; p = p->next) {
+       if (IS_FUNC_PTR_TYPE(p)) {
+           p = show_func_ptr_type(p, p->next); /* function pointer type */
+       } else {
+           register struct token *q;
+           register struct token *r;
+
+           tok_show(p);                        /* other */
+           if ((p->tokno == TOK_WORD || p->tokno == '*' || p->tokno == '}')
+               && (q = p->next) && q->tokno == TOK_WORD
+               && (r = q->next) && r->tokno == TOK_LIST) {
+               tok_show(q);                    /* show name */
+               show_empty_list(p = r);         /* strip args */
+           }
+       }
+    }
+}
+
+/* show_func_ptr_type - display function_pointer type using old-style syntax */
+
+static struct token *show_func_ptr_type(t1, t2)
+struct token *t1;
+struct token *t2;
+{
+    register struct token *s;
+
+    /*
+     * Rewrite (list1) (list2) to (list1) (). Account for the rare case that
+     * (list1) is a comma-separated list. That should be an error, but we do
+     * not want to waste any information.
+     */
+
+    for (s = t1->head; s; s = s->next) {
+       tok_show_ch(s);                         /* '(' or ',' or ')' */
+       show_type(s);                           /* recurse */
+    }
+    show_empty_list(t2);
+    return (t2);
+}
+
+/* show_empty_list - display opening and closing parentheses (if available) */
+
+static void show_empty_list(t)
+register struct token *t;
+{
+    tok_show_ch(t->head);                      /* opening paren */
+    if (t->tail->tokno == ')')
+       tok_show_ch(t->tail);                   /* closing paren */
+}
+
+/* show_struct_type - display structured type, rewrite function-pointer types */
+
+static struct token *show_struct_type(p)
+register struct token *p;
+{
+    tok_show(p);                               /* opening brace */
+
+    while (p->next) {                          /* XXX cannot return 0 */
+       p = p->next;
+       if (IS_FUNC_PTR_TYPE(p)) {
+           p = show_func_ptr_type(p, p->next); /* function-pointer member */
+       } else if (p->tokno == '{') {
+           p = show_struct_type(p);            /* recurse */
+       } else {
+           tok_show(p);                        /* other */
+           if (p->tokno == '}') {
+               return (p);                     /* done */
+           }
+       }
+    }
+    DPRINTF("/* missing '}' */");
+    return (p);
+}
+
+/* is_func_ptr_cast - recognize function-pointer type cast */
+
+static int is_func_ptr_cast(t)
+register struct token *t;
+{
+    register struct token *p;
+
+    /*
+     * Examine superficial structure. Require (list1) (list2). Require that
+     * list1 begins with a star.
+     */
+
+    if (!IS_FUNC_PTR_TYPE(t))
+       return (0);
+
+    /*
+     * Make sure that there is no name in (list1). Do not worry about
+     * unexpected tokens, because the compiler will complain anyway.
+     */
+
+    for (p = t->head->head; p; p = p->next) {
+       switch (p->tokno) {
+       case TOK_LIST:                          /* recurse */
+           return (is_func_ptr_cast(p));
+       case TOK_WORD:                          /* name in list */
+           return (0);
+       case '[':
+           return (1);                         /* dimension may be a macro */
+       }
+    }
+    return (1);                                        /* no name found */
+}
+
+/* check_cast - display ()-delimited, comma-separated list */
+
+static void check_cast(t)
+struct token *t;
+{
+    register struct token *s;
+    register struct token *p;
+
+    /*
+     * Rewrite function-pointer types and function-pointer casts. Do not
+     * blindly rewrite (*list1)(list2) to (*list1)(). Function argument lists
+     * are about the only thing we can discard without provoking diagnostics
+     * from the compiler.
+     */
+
+    for (s = t->head; s; s = s->next) {
+       tok_show_ch(s);                         /* '(' or ',' or ')' */
+       for (p = s->head; p; p = p->next) {
+           switch (p->tokno) {
+           case TOK_LIST:
+               if (is_func_ptr_cast(p)) {      /* not: IS_FUNC_PTR_TYPE(p) */
+                   p = show_func_ptr_type(p, p->next);
+               } else {
+                   check_cast(p);              /* recurse */
+               }
+               break;
+           case '{':
+               p = show_struct_type(p);        /* rewrite func. ptr. types */
+               break;
+           default:
+               tok_show(p);
+               break;
+           }
+       }
+    }
+}
+
+/* block_dcls - on the fly rewrite decls/initializers at start of block */
+
+static void block_dcls()
+{
+    register struct token *t;
+
+    /*
+     * Away from the top level, a declaration should be preceded by type or
+     * storage-class information. That is why inside blocks, structs and
+     * unions we insist on reading one word before passing the _next_ token
+     * to the dcl_flush() function.
+     * 
+     * Struct and union declarations look the same everywhere: we make an
+     * exception for these more regular constructs and pass the "struct" and
+     * "union" tokens to the type_dcl() function.
+     */
+
+    while (t = tok_class()) {
+       switch (t->tokno) {
+       case TOK_WSPACE:                        /* preserve white space */
+       case '\n':                              /* preserve line count */
+           tok_flush(t);
+           break;
+       case TOK_WORD:                          /* type declarations? */
+           tok_flush(t);                       /* advance to next token */
+           t = tok_class();                    /* null return is ok */
+           /* FALLTRHOUGH */
+       case TOK_COMPOSITE:                     /* struct or union */
+           if ((t = dcl_flush(t)) == 0)
+               break;
+           /* FALLTRHOUGH */
+       default:                                /* end of declarations */
+           DPRINTF("/* end dcls */");
+           /* FALLTRHOUGH */
+       case '}':                               /* end of block */
+           tok_unget(t);
+           return;
+       }
+    }
+}
+
+/* block_flush - rewrite struct, union or statement block on the fly */
+
+static void block_flush(t)
+register struct token *t;
+{
+    static int count = 0;
+
+    tok_flush(t);
+    DPRINTF("/*%d*/", ++count);
+
+    /*
+     * Rewrite function pointer types in declarations and function pointer
+     * casts in initializers at start of block.
+     */
+
+    block_dcls();
+
+    /* Remainder of block: only rewrite function pointer casts. */
+
+    while (t = tok_class()) {
+       if (t->tokno == TOK_LIST) {
+           check_cast_flush(t);
+       } else if (t->tokno == '{') {
+           block_flush(t);
+       } else {
+           tok_flush(t);
+           if (t->tokno == '}') {
+               DPRINTF("/*%d*/", count--);
+               return;
+           }
+       }
+    }
+    DPRINTF("/* missing '}' */");
+}
+
+/* pair_flush - on the fly rewrite casts in grouped stuff */
+
+static void pair_flush(t, start, stop)
+register struct token *t;
+register int start;
+register int stop;
+{
+    tok_flush(t);
+
+    while (t = tok_class()) {
+       if (t->tokno == start) {                /* recurse */
+           pair_flush(t, start, stop);
+       } else if (t->tokno == TOK_LIST) {      /* expression or cast */
+           check_cast_flush(t);
+       } else {                                /* other, copy */
+           tok_flush(t);
+           if (t->tokno == stop) {             /* done */
+               return;
+           }
+       }
+    }
+    DPRINTF("/* missing '%c' */", stop);
+}
+
+/* initializer - on the fly rewrite casts in initializer */
+
+static void initializer()
+{
+    register struct token *t;
+
+    while (t = tok_class()) {
+       switch (t->tokno) {
+       case ',':                               /* list separator */
+       case ';':                               /* list terminator */
+           tok_unget(t);
+           return;
+       case TOK_LIST:                          /* expression or cast */
+           check_cast_flush(t);
+           break;
+       case '[':                               /* array subscript, may nest */
+           pair_flush(t, '[', ']');
+           break;
+       case '{':                               /* structured data, may nest */
+           pair_flush(t, '{', '}');
+           break;
+       default:                                /* other, just copy */
+           tok_flush(t);
+           break;
+       }
+    }
+}
+
+/* func_ptr_dcl_flush - rewrite function pointer stuff */
+
+static struct token *func_ptr_dcl_flush(list)
+register struct token *list;
+{
+    register struct token *t;
+    register struct token *t2;
+
+    /*
+     * Ignore blanks and newlines because we are too lazy to maintain more
+     * than one token worth of lookahead. The output routines will regenerate
+     * discarded newline tokens.
+     */
+
+    while (t = tok_class()) {
+       switch (t->tokno) {
+       case TOK_WSPACE:
+       case '\n':
+           tok_free(t);
+           break;
+       case TOK_LIST:
+           /* Function pointer or function returning pointer to function. */
+           while ((t2 = tok_class())           /* skip blanks etc. */
+                  &&(t2->tokno == TOK_WSPACE || t2->tokno == '\n'))
+               tok_free(t2);
+           switch (t2 ? t2->tokno : 0) {
+           case '{':                           /* function heading (new) */
+               fpf_header(list, t);
+               break;
+           case TOK_WORD:                      /* function heading (old) */
+               tok_show(list);
+               tok_show(t);
+               break;
+           default:                            /* func pointer type */
+               (void) show_func_ptr_type(list, t);
+               break;
+           }
+           tok_free(list);
+           tok_free(t);
+           if (t2)
+               tok_unget(t2);
+           return (0);
+       default:                                /* not a declaration */
+           tok_unget(t);
+           return (list);
+       }
+    }
+
+    /* Hit EOF; must be mistake, but do not waste any information. */
+
+    return (list);
+}
+
+/* function_dcl_flush - rewrite function { heading, type declaration } */
+
+static struct token *function_dcl_flush(list)
+register struct token *list;
+{
+    register struct token *t;
+
+    /*
+     * Ignore blanks and newlines because we are too lazy to maintain more
+     * than one token worth of lookahead. The output routines will regenerate
+     * ignored newline tokens.
+     */
+
+    while (t = tok_class()) {
+       switch (t->tokno) {
+       case TOK_WSPACE:
+       case '\n':
+           tok_free(t);
+           break;
+       case '{':
+           /* Function heading: word (list) { -> old style heading */
+           header_flush(list);
+           tok_unget(t);
+           return (0);
+       case TOK_WORD:
+           /* Old-style function heading: word (list) word... */
+           tok_flush(list);
+           tok_unget(t);
+           return (0);
+       case TOK_LIST:
+           /* Function pointer: word (list1) (list2) -> word (list1) () */
+           tok_flush(list);
+           show_empty_list(t);
+           tok_free(t);
+           return (0);
+       case ',':
+       case ';':
+           /* Function type declaration: word (list) -> word () */
+           show_empty_list(list);
+           tok_free(list);
+           tok_unget(t);
+           return (0);
+       default:
+           /* Something else, reject the list. */
+           tok_unget(t);
+           return (list);
+       }
+    }
+
+    /* Hit EOF; must be mistake, but do not waste any information. */
+
+    return (list);
+}
+
+/* dcl_flush - parse declaration on the fly, return rejected token */
+
+static struct token *dcl_flush(t)
+register struct token *t;
+{
+    register int got_word;
+
+    /*
+     * Away from the top level, type or storage-class information is required
+     * for an (extern or forward) function type declaration or a variable
+     * declaration.
+     * 
+     * With our naive word-counting approach, this means that the caller should
+     * read one word before passing the next token to us. This is how we
+     * distinguish, for example, function declarations from function calls.
+     * 
+     * An exception are structs and unions, because they look the same at any
+     * level. The caller should give is the "struct" or "union" token.
+     */
+
+    for (got_word = 0; t; t = tok_class()) {
+       switch (t->tokno) {
+       case TOK_WSPACE:                        /* advance past blanks */
+       case '\n':                              /* advance past newline */
+       case '*':                               /* indirection: keep trying */
+           tok_flush(t);
+           break;
+       case TOK_WORD:                          /* word: keep trying */
+       case TOK_COMPOSITE:                     /* struct or union */
+           got_word = 1;
+           tok_flush(t);
+           break;
+       default:
+
+           /*
+            * Function pointer types can be preceded by zero or more words
+            * (at least one when not at the top level). Other stuff can be
+            * accepted only after we have seen at least one word (two words
+            * when not at the top level). See also the above comment on
+            * structs and unions.
+            */
+
+           if (t->tokno == TOK_LIST && LIST_BEGINS_WITH_STAR(t)) {
+               if (t = func_ptr_dcl_flush(t)) {
+                   return (t);                 /* reject token */
+               } else {
+                   got_word = 1;               /* for = and [ and , and ; */
+               }
+           } else if (got_word == 0) {
+               return (t);                     /* reject token */
+           } else {
+               switch (t->tokno) {
+               case TOK_LIST:                  /* function type */
+                   if (t = function_dcl_flush(t))
+                       return (t);             /* reject token */
+                   break;
+               case '[':                       /* dimension, does not nest */
+                   pair_flush(t, '[', ']');
+                   break;
+               case '=':                       /* initializer follows */
+                   tok_flush(t);
+                   initializer();              /* rewrite casts */
+                   break;
+               case '{':                       /* struct, union, may nest */
+                   block_flush(t);             /* use code for stmt blocks */
+                   break;
+               case ',':                       /* separator: keep trying */
+                   got_word = 0;
+                   tok_flush(t);
+                   break;
+               case ';':                       /* terminator: succeed */
+                   tok_flush(t);
+                   return (0);
+               default:                        /* reject token */
+                   return (t);
+               }
+           }
+       }
+    }
+    return (0);                                        /* hit EOF */
+}
diff --git a/build/unproto/varargs.c b/build/unproto/varargs.c
new file mode 100644 (file)
index 0000000..4ca56d8
--- /dev/null
@@ -0,0 +1,32 @@
+ /*
+  * @(#) varargs.c 1.1 91/09/01 23:08:45
+  * 
+  * This program can be used to verify that the stdarg.h file is set up
+  * correctly for your system. If it works, it should print one line with the
+  * text "stdarg.h works".
+  */
+
+#include <stdio.h>
+#include "stdarg.h"
+
+main(int argc, char *argv[])
+{
+    varargs_test("%s %s\n", "stdarg.h", "works");
+}
+
+varargs_test(char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    while (*fmt) {
+       if (strncmp("%s", fmt, 2) == 0) {
+           fputs(va_arg(ap, char *), stdout);
+           fmt += 2;
+       } else {
+           putchar(*fmt);
+           fmt++;
+       }
+    }
+    va_end(ap);
+}
diff --git a/build/unproto/vstring.c b/build/unproto/vstring.c
new file mode 100644 (file)
index 0000000..220bd53
--- /dev/null
@@ -0,0 +1,122 @@
+/*++
+/* NAME
+/*     vs_alloc(), VS_ADDCH()
+/* SUMMARY
+/*     auto-resizing string library
+/* PACKAGE
+/*     vstring
+/* SYNOPSIS
+/*     #include "vstring.h"
+/*
+/*     struct vstring *vs_alloc(len)
+/*     int len;
+/*
+/*     int VS_ADDCH(vs, wp, ch)
+/*     struct vstring *vs;
+/*     char *wp;
+/*     int ch;
+/*
+/*     char *vs_strcpy(vp, dst, src)
+/*     struct vstring *vp;
+/*     char *dst;
+/*     char *src;
+/* DESCRIPTION
+/*     These functions and macros implement a small library for
+/*     arbitrary-length strings that grow automatically when
+/*     they fill up. The allocation strategy is such that there
+/*     will always be place for the terminating null character.
+/*
+/*     vs_alloc() allocates storage for a variable-length string
+/*     of at least "len" bytes.
+/*
+/*     VS_ADDCH() adds a character to a variable-length string
+/*     and automagically extends the string if fills up.
+/*     \fIvs\fP is a pointer to a vstring structure; \fIwp\fP
+/*     the current write position in the corresponding character
+/*     array; \fIch\fP the character value to be written.
+/*     Note that VS_ADDCH() is a macro that evaluates some
+/*     arguments more than once.
+/*
+/*     vs_strcpy() appends a null-terminated string to a variable-length
+/*     string. \fIsrc\fP provides the data to be copied; \fIvp\fP is the
+/*     target, and \fIdst\fP the current write position within the target.
+/*     The result is null-terminated. The return value is the new write
+/*     position.
+/* DIAGNOSTICS
+/*     VS_ADDCH() returns zero if it was unable to dynamically
+/*     resize a string.
+/*
+/*     vs_alloc() returns a null pointer in case of problems.
+/*
+/*     vs_strcpy() returns a null pointer if the request failed.
+/* BUGS
+/*     Auto-resizing may change the address of the string data in
+/*     a vstring structure. Beware of dangling pointers.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     Eindhoven University of Technology
+/*     Department of Mathematics and Computer Science
+/*     Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
+/* LAST MODIFICATION
+/*     92/01/15 21:53:06
+/* VERSION/RELEASE
+/*     1.3
+/*--*/
+
+static char vstring_sccsid[] = "@(#) vstring.c 1.3 92/01/15 21:53:06";
+
+/* C library */
+
+extern char *malloc();
+extern char *realloc();
+
+/* Application-specific stuff */
+
+#include "vstring.h"
+
+/* vs_alloc - initial string allocation */
+
+struct vstring *vs_alloc(len)
+int     len;
+{
+    register struct vstring *vp;
+
+    if (len < 1 
+       || (vp = (struct vstring *) malloc(sizeof(struct vstring))) == 0
+       || (vp->str = malloc(len)) == 0)
+       return (0);
+    vp->last = vp->str + len - 1;
+    return (vp);
+}
+
+/* vs_realloc - extend string, update write pointer */
+
+char   *vs_realloc(vp, cp)
+register struct vstring *vp;
+char   *cp;
+{
+    int     where = cp - vp->str;
+    int     len = vp->last - vp->str + 1;
+
+    if ((vp->str = realloc(vp->str, len *= 2)) == 0)
+       return (0);
+    vp->last = vp->str + len - 1;
+    return (vp->str + where);
+}
+
+/* vs_strcpy - copy string */
+
+char   *vs_strcpy(vp, dst, src)
+register struct vstring *vp;
+register char *dst;
+register char *src;
+{
+    while (*src) {
+       if (VS_ADDCH(vp, dst, *src) == 0)
+           return (0);
+       src++;
+    }
+    *dst = '\0';
+    return (dst);
+}
+
diff --git a/build/unproto/vstring.h b/build/unproto/vstring.h
new file mode 100644 (file)
index 0000000..c2e1f88
--- /dev/null
@@ -0,0 +1,15 @@
+/* @(#) vstring.h 1.2 92/01/15 21:53:19 */
+
+struct vstring {
+    char   *str;                       /* string value */
+    char   *last;                      /* last position */
+};
+
+extern struct vstring *vs_alloc();     /* initial allocation */
+extern char *vs_realloc();             /* string extension */
+extern char *vs_strcpy();              /* copy string */
+
+/* macro to add one character to auto-resized string */
+
+#define        VS_ADDCH(vs,wp,c) \
+    ((wp < (vs)->last || (wp = vs_realloc(vs,wp))) ? (*wp++ = c) : 0)
diff --git a/build/version b/build/version
new file mode 100644 (file)
index 0000000..eb39e53
--- /dev/null
@@ -0,0 +1 @@
+3.3
diff --git a/clients/Make-template b/clients/Make-template
new file mode 100644 (file)
index 0000000..76a02d5
--- /dev/null
@@ -0,0 +1,84 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1994 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP clients Makefile
+#
+#-----------------------------------------------------------------------------
+
+############################################################################
+#                                                                          #
+# You should not have to edit anything below this point                    #
+#                                                                          #
+############################################################################
+
+all:   FORCE
+       @echo "making all in `$(PWD)`"
+       @for i in *; do \
+           if [ -d $$i -a $$i != "RCS" ]; then \
+               echo; echo "  cd $$i; $(MAKE) $(MFLAGS) all"; \
+               ( cd $$i; $(MAKE) $(MFLAGS) all ); \
+           fi; \
+       done
+
+
+#
+# rules to install the software
+#
+
+install:       FORCE
+       @echo "making install in `$(PWD)`"
+       @for i in *; do \
+           if [ -d $$i -a $$i != "RCS" ]; then \
+               echo; echo "  cd $$i; $(MAKE) $(MFLAGS) install"; \
+               ( cd $$i; $(MAKE) $(MFLAGS) install ); \
+           fi; \
+       done
+
+#
+# rules to make clean
+#
+
+clean: FORCE
+       @echo "making clean in `$(PWD)`"
+       @for i in *; do \
+           if [ -d $$i -a $$i != "RCS" ]; then \
+               echo; echo "  cd $$i; $(MAKE) $(MFLAGS) clean"; \
+               ( cd $$i; $(MAKE) $(MFLAGS) clean ); \
+           fi; \
+       done
+
+veryclean:     clean
+
+#
+# rules to make depend
+#
+#
+
+depend:        FORCE
+       @echo "making depend in `$(PWD)`"
+       @for i in *; do \
+           if [ -d $$i -a $$i != "RCS" ]; then \
+               echo; echo "  cd $$i; $(MAKE) $(MFLAGS) depend"; \
+               ( cd $$i; $(MAKE) $(MFLAGS) depend ); \
+           fi; \
+       done
+
+links:
+       @echo "making links in `$(PWD)`"; \
+       for i in .src/*; do \
+           if [ -d $$i -a $$i != ".src/RCS" ]; then \
+               d=`basename $$i`; \
+               ( $(MKDIR) $$d; cd $$d; $(LN) ../.src/$$d .src; \
+                 $(LN) ../.src/$$d/Make-template . ; \
+                 $(MAKE) $(MFLAGS) MKDIR="$(MKDIR)" LN="$(LN)" \
+                   -f Make-template links ) ; \
+           fi; \
+       done
diff --git a/clients/fax500/Make-template b/clients/fax500/Make-template
new file mode 100644 (file)
index 0000000..e3b224d
--- /dev/null
@@ -0,0 +1,87 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1994 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       X.500 ldap fax mailer makefile
+#
+#-----------------------------------------------------------------------------
+LDAPSRC = ../..
+HDIR    = $(LDAPSRC)/include
+LDIR  = $(LDAPSRC)/libraries
+VERSIONFILE = $(LDAPSRC)/build/version
+
+SRCS   = rp500.c main.c faxtotpc.c
+OBJS   = rp500.o main.o faxtotpc.o
+
+INCLUDES= -I$(HDIR)
+DEFINES        = $(DEFS)
+
+CFLAGS = $(INCLUDES) $(DEFINES) $(ACFLAGS)
+LIBS   = -lldap -llber $(KRBLIBFLAG) $(KRBLIBS) $(ALIBS)
+
+all:   rp500 fax500
+
+rp500: rpversion.o
+       $(CC) $(ALDFLAGS) -o $@ faxtotpc.o rp500.o rpversion.o \
+               -L$(LDIR) $(LIBS)
+
+fax500:        fax5version.o
+       $(CC) $(ALDFLAGS) -o $@ main.o fax5version.o faxtotpc.o \
+               -L$(LDIR) $(LIBS)
+
+rpversion.c:   faxtotpc.o rp500.o $(LDIR)/libldap.a
+       $(RM) $@
+       (u=$${USER-root} v=`$(CAT) $(VERSIONFILE)` d=`$(PWD)` h=`$(HOSTNAME)` \
+       t=`$(DATE)`; $(SED) -e "s|%WHEN%|$${t}|" \
+       -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+       -e "s|%VERSION%|$${v}|" \
+       < Versionrp.c > $@)
+
+fax5version.c: main.o faxtotpc.o $(LDIR)/libldap.a
+       $(RM) $@
+       (u=$${USER-root} v=`$(CAT) $(VERSIONFILE)` d=`$(PWD)` h=`$(HOSTNAME)` \
+        t=`$(DATE)`; $(SED) -e "s|%WHEN%|$${t}|" \
+       -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+       -e "s|%VERSION%|$${v}|" \
+       < Version.c > $@ )
+
+install:       rp500 xrpcomp fax500 FORCE
+               -$(MKDIR) -p $(ETCDIR) $(BINDIR)
+               $(INSTALL) $(INSTALLFLAGS) -m 755 rp500 $(ETCDIR)
+               $(SED) -e 's%ETCDIR%$(ETCDIR)%' xrpcomp > /tmp/xrpcomp.tmp
+               $(INSTALL) $(INSTALLFLAGS) -m 755 /tmp/xrpcomp.tmp $(BINDIR)/xrpcomp
+               $(RM) /tmp/xrpcomp.tmp
+               $(INSTALL) $(INSTALLFLAGS) -m 755 fax500 $(ETCDIR)
+
+lint:  FORCE
+       $(LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+5lint: FORCE
+       $(5LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+clean: FORCE
+       $(RM) *.o core a.out rpversion.c fax5version.c rp500 fax500
+
+depend:        FORCE
+       $(MKDEP) $(INCLUDES) $(DEFINES) $(SRCS)
+
+links:
+       @$(LN) .src/README .src/xrpcomp .src/*.[ch] .
+
+# DO NOT DELETE THIS LINE -- mkdep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+rp500.o: rp500.c ../../include/ldapconfig.h ../../include/lber.h
+rp500.o: ../../include/ldap.h
+main.o: main.c ../../include/ldapconfig.h ../../include/portable.h
+main.o: ../../include/lber.h ../../include/ldap.h
+faxtotpc.o: faxtotpc.c
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/clients/fax500/README b/clients/fax500/README
new file mode 100644 (file)
index 0000000..5b0e1a3
--- /dev/null
@@ -0,0 +1,104 @@
+README file for fax500
+
+xrpcomp
+-------
+
+This directory contains a modified version of the rpcomp program, used
+with the Internet remote-printing experiment.  More info on the experiment
+can be found in /mrose/tpc on ftp.ics.uci.edu.
+
+The xrpcomp program (it's a shell script) is like rpcomp, except that it
+will look in X.500 if no fax recipients are found in the .rpdb file.
+It still uses .rpdb to extract the originator information.
+
+There are a couple of things in rp500.c you will want to tailor to use
+xrpcomp at your site:
+
+       DAPUSER         This is the user the rp500 program, called from
+                       xrpcomp will bind to the directory as.  It can
+                       be set to NULL.
+
+       DEFAULT_BASE    This is the search base rp500 will use when looking
+                       in the directory for fax recipients.
+
+       DEFAULT_FILTERCONF
+                       Where to find the ldapfilter.conf file.  Should
+                       make setting this automatic, but for now...
+
+       PHONE_PREFIX    The prefix of phones in your local area.  If
+                       rp500 finds a fax number in the directory that is
+                       not fully qualified, it will append as many of
+                       these digits as necessary to make it fully
+                       qualified.  NB it assumes US-format numbers.
+
+       DEFAULT_LDAPHOST
+                       The host running the default ldap server to
+                       contact.
+
+Things to note:
+
+The rp500 program knows a little about the US phone number format, in
+an attempt to deal with (evil) people who have not put fully qualified
+international format (e.g. +1 ... ) phone numbers in their entry.  If
+your users do not have US-format phone numbers, you'll need to take a
+look at the fax2email() routine in rp500.c and change it around a bit.
+
+7/30/93  -- Tim
+
+
+fax500
+------
+
+This directory also contains the fax500 program.  fax500 is just like
+mail500, except that it looks up the facsimileTelephoneNumber
+attribute, constructs an appropriate "remote-printer@blah.tpc.int"
+address, and send the mail there.  For example, the facsimile number
+"+1 313 555 1212" corresponds to the address
+"remote-printer@2.1.2.1.5.5.5.3.1.3.1.tpc.int." For a complete
+explanation of the Internet remote-printing experiment, look in
+/mrose/tpc on ftp.ics.uci.edu, or send mail to tpc-faq@town.hall.org.
+
+The general idea is that you can set things up so that mail sent to
+"user@fax.domain" will get printed on the user's fax machine, if
+they've entered a fax number in their X.500 entry.
+
+NOTE: you will need to modify faxtotpc.c if you have any "abbreviated"
+phone number capabilities.  For example, our telephone switches allow
+you to dial only the last 5 digits of campus telephone numbers. People,
+therefore, tend to list the last 5 digits of their fax numbers.  The
+routine "munge_phone()" takes care of fixing up abbreviated phone
+numbers.  You may need to write your own code.
+
+fax500 is not yet complete.  In particular, the following work still needs
+to be done:
+
+- If the group entry itself has a fax number, don't send to all the members'
+  individual fax numbers.  Instead, just send to the group's fax number.
+- The -h flag for fax500 defines both the host name and the search base.
+  This causes problems because the host name we want is "fax.umich.edu"
+  but we need to search "umich.edu."  The workaround is to add an
+  Associated Domain corresponding to the domain you want for your fax
+  service to each X.500 group which is to be accessible.
+- We're working toward mail500 and fax500 being the same binary.  Depending
+  on what argv[0] is, you'll get different behavior.  Although this
+  binary should work just like mail500 if you name it "mail500" it's
+  not yet been tested.
+- fax500 currently assumes that incoming messages are plain text, and
+  therefore constructs a destination address like
+  "remote-printer.user_name@2.1.2.1.5.5.5.3.1.3.1.tpc.int".  If
+  the message is already MIME-compliant with an "application/remote-printing"
+  content type, we lose, since the remote-printing software assumes
+  that anything other than "remote-printer" on ther lhs of the address
+  means the message is plain text.  Not sure about the solution to this.
+- Regarding group support - typically, when we collect all the fax numbers
+  for a group, we'll end up either with (a) people who haven't registered
+  fax numbers, or (b) "email-only" group members who do not have entries
+  in X.500 (they only have an email address associated with the group).
+  The question is: what do you do with faxes for these folks?  You could
+  (1) bounce to the sender (current behavior) or you could (2) send
+  email to the members with no fax numbers, informing them that someone
+  tried to send them a fax.  I tend to prefer solution (2) for case (a),
+  and solution (1) for case (b).
+- A configuration file-driven "munge_phone()" would be nice.
+8/23/93 - Gordon
diff --git a/clients/fax500/Version.c b/clients/fax500/Version.c
new file mode 100644 (file)
index 0000000..8bc6c81
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 1993 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+char Version[] = "  fax500 v%VERSION% (%WHEN%)\n\t%WHOANDWHERE%\n";
diff --git a/clients/fax500/Versionrp.c b/clients/fax500/Versionrp.c
new file mode 100644 (file)
index 0000000..75d8dd7
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 1993 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+char Version[] = "  rp500 v%VERSION% (%WHEN%)\n\t%WHOANDWHERE%\n";
diff --git a/clients/fax500/faxtotpc.c b/clients/fax500/faxtotpc.c
new file mode 100644 (file)
index 0000000..d4631b4
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 1993 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ *
+ *
+ * Routines for parsing the facsimileTelephoneNumber field out of
+ * an X.500 entry and converting it to a "tpc.int" domain name.
+ *
+ * char *faxtotpc(str)
+ * char *str;
+ *
+ * faxtotpc() returns a pointer to a string allocated with malloc(3).
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+
+#ifdef ultrix
+extern char *strdup();
+#endif
+
+
+#define        TPCDOMAIN       "tpc.int"
+
+/*
+ * Remove everything from 'str' which is not a digit
+ */
+void strip_nonnum(str)
+char *str;
+{
+       char *p, *q;
+       p = q = str;
+       for (;;) {
+               if (*p == '\0') {
+                       *q = *p;
+                       return;
+               }
+
+               if (isdigit((u_char) *p)) {
+                       *q = *p;
+                       p++;
+                       q++;
+               } else {
+                       p++;
+               }
+       }
+}
+
+
+
+/* 
+ * Remove anything of the form (blah) where
+ * "blah" contains a non-numeric character.
+ */
+char *remove_parens(ibuf, obuf)
+char *ibuf;
+char *obuf;
+{
+       char *p = ibuf;
+       char *q = obuf;
+
+       while (*p != '\0') {
+               char *s;
+               char *t;
+               if (*p == '(') {
+                       /* look for a closing paren */
+                       if (( s = strchr(p, ')')) != NULL) {
+                               /* Check the string between p and s */
+                               /* for non-numeric characters       */
+                               t = p + 1;
+                               while (t < s) {
+                                       if (!isdigit((u_char) *t)) {
+                                               /* garbage, delete */
+                                               p = s + 1;
+                                               t = p;
+                                               break;
+                                       }
+                                       t++;
+                               }
+                               /* when we get here, p points to the first */
+                               /* thing we want to keep, t to the last.   */
+                               strncpy(q, p,  t - p);
+                               q += t - p;
+                               p = t;
+                       } else {
+                               /* no closing paren, what to do?  keep it */
+                               *q = *p;
+                               p++;
+                               q++;
+                       }
+               } else {
+                       /* not a paren - copy out */
+                       *q = *p;
+                       p++;
+                       q++;
+               }
+       }
+       *q = '\0';      /* terminate output string */
+       return(obuf);
+}
+
+
+
+
+/*
+ * Apply local fixups to phone numbers here.  Replace this routine
+ * with code to expand common "abbreviations" for phone numbers.  For
+ * example, on the U-M campus, it's only necessary to dial the last
+ * 5 digits of the telephone number, and hence people here tend to
+ * give only the last 5 digits of their fax numbers.
+ *
+ * Local U-M mods:
+ * If exactly 5 digits were provided, assume it's a campus
+ * phone number and prepend "1313nm" where "mn" are computed
+ * according to the following:
+ * first digit of 
+ * 5-digit "Local" 
+ * phone              mn
+ * -----              --
+ * 3                  76 e.g. "31234" -> "7631234"
+ * 4                  76
+ * 7                  74
+ * 6                  93
+ * 8                  99
+ */
+char *munge_phone(ibuf, obuf)
+char *ibuf;
+char *obuf;
+{
+#define        UMAREACODE      "1313"
+
+       char prefix[3];
+
+       if (strlen(ibuf) == 7) {
+               /* Assume local number w/o area code */
+               sprintf(obuf, "%s%s", UMAREACODE, ibuf);
+               return(obuf);
+       }
+       if (strlen(ibuf) == 10) {
+               /* Assume local number with area code */
+               sprintf(obuf, "%s%s", "1", ibuf);
+               return(obuf);
+       }
+       if (strlen(ibuf) != 5) {
+               /* Not 5 digits - leave alone */
+               strcpy(obuf, ibuf);
+               return(obuf);
+       }
+
+       switch (ibuf[0]) {
+         case '3'      :
+         case '4'      :       strcpy(prefix, "76");
+                               break;
+         case '7'      :       strcpy(prefix, "74");
+                               break;
+         case '6'      :       strcpy(prefix, "93");
+                               break;
+         case '8'      :       strcpy(prefix, "99");
+                               break;
+         default       :       /* Unknown, leave alone */
+                               strcpy(obuf, ibuf);
+                               return(obuf);
+       }
+       sprintf(obuf, "%s%s%s", UMAREACODE, prefix, ibuf);
+       return(obuf);
+}
+
+
+
+
+
+
+
+
+/* 
+ * Convert string to "tpc.int" domain name.
+ */
+char *faxtotpc(phone, userinfo)
+char *phone;
+char *userinfo;
+{
+       char *p;
+       char *q;
+       char ibuf[255];
+       char obuf[255];
+
+       /* nuke spaces */
+       strcpy(ibuf, phone);
+       for (p = ibuf, q = obuf; *p != '\0'; p++) {
+               if (*p != ' ') {
+                       *q = *p;
+                       q++;
+               }
+       }
+       *q = '\0';
+       strcpy(ibuf, obuf);
+
+       remove_parens(ibuf, obuf);
+       strcpy(ibuf, obuf);
+
+       /* Look for "+" - if followed by a number,
+          assume it's an international number and leave
+          it alone.
+       */
+       if ((p = strchr(ibuf, '+')) != NULL) {
+               if (isdigit((u_char) *(p + 1))) {
+                       /* strip any non-digits */
+                       strip_nonnum(ibuf);
+               }
+       } else {
+               strip_nonnum(ibuf);
+
+               /* Apply local munges */
+               munge_phone(ibuf, obuf);
+               strcpy(ibuf, obuf);
+       }
+
+       /* Convert string of form abcd to remote-printer@d.c.b.a.tpc.int */
+       q = obuf;
+       for (p = ibuf + strlen(ibuf) - 1; p >= ibuf; p--) {
+               *q++ = *p;
+               *q++ = '.';
+       }
+       *q = '\0';
+       strcpy(ibuf, obuf);
+       strcpy(obuf, "remote-printer");
+
+       /* include userinfo if present */
+       if (userinfo != NULL && strlen(userinfo)) {
+               strcat(obuf, ".");
+               strcat(obuf, userinfo);
+       }
+       strcat(obuf, "@");
+       strcat(obuf, ibuf);             /* tack on reversed phone number */
+       strcat(obuf, TPCDOMAIN);        /* tack on domain name */
+       p = strdup(obuf);
+       return(p);
+                               
+}
diff --git a/clients/fax500/main.c b/clients/fax500/main.c
new file mode 100644 (file)
index 0000000..7481d49
--- /dev/null
@@ -0,0 +1,1499 @@
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <memory.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <syslog.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <sysexits.h>
+#include <ldapconfig.h>
+#include "portable.h"
+
+#include "lber.h"
+#include "ldap.h"
+
+#define USER           0
+#define GROUP_ERRORS   1
+#define GROUP_REQUEST  2
+#define GROUP_MEMBERS  3
+
+#define ERRORS "errors"
+#define REQUEST        "request"
+#define MEMBERS        "members"
+
+LDAP   *ld;
+char   *errorsfrom = NULL;
+char   *mailfrom = NULL;
+char   *host = NULL;
+int    hostlen = 0;
+char   *faxtotpc();
+
+int    identity;
+#define        MAIL500 1       
+#define        FAX500  2
+
+typedef struct errs {
+       int             e_code;
+#define E_USERUNKNOWN          1
+#define E_AMBIGUOUS            2
+#define E_NOEMAIL              3
+#define E_NOREQUEST            4
+#define E_NOERRORS             5
+#define E_BADMEMBER            6
+#define E_JOINMEMBERNOEMAIL    7
+#define E_MEMBERNOEMAIL                8
+#define E_NOFAXNUM             9
+#define E_JOINMEMBERNOFAXNUM   10
+#define E_MEMBERNOFAXNUM       11
+#define        E_FAXTOEMAILMBR         12
+
+       char            *e_addr;
+       LDAPMessage     *e_msg;
+} Error;
+
+typedef struct groupto {
+       char    *g_dn;
+       char    *g_errorsto;
+       char    **g_members;
+} Group;
+
+typedef struct baseinfo {
+       char    *b_dn;          /* dn to start searching at */
+       char    b_rdnpref;      /* give rdn's preference when searching? */
+       char    *b_filter[3];   /* filter to apply - name substituted for %s */
+                               /* (up to three of them) */
+} Base;
+
+Base   base[] = 
+       { "ou=People, o=University of Michigan, c=US", 0,
+               "uid=%s", "cn=%s", NULL,
+         "ou=System Groups, ou=Groups, o=University of Michigan, c=US", 1,
+               "(&(cn=%s)(associatedDomain=%h))", NULL, NULL,
+         "ou=User Groups, ou=Groups, o=University of Michigan, c=US", 1,
+               "(&(cn=%s)(associatedDomain=%h))", NULL, NULL,
+         NULL
+       };
+
+char   *sendmailargs[] = { FAX_SENDMAIL, "-oMrX.500", "-odi", "-oi", "-f", NULL, NULL };
+
+static char    *attrs[] = { "objectClass", "title", "postaladdress",
+                       "telephoneNumber", "mail", "description",
+                       "errorsTo", "rfc822ErrorsTo", "requestsTo",
+                       "rfc822RequestsTo", "joinable", "cn", "member",
+                       "facsimileTelephoneNumber", NULL };
+
+static do_address();
+static do_group();
+static do_group_members();
+static send_message();
+static send_errors();
+static do_noemailorfax();
+static do_ambiguous();
+static add_to();
+static isgroup();
+static add_error();
+static add_group();
+static unbind_and_exit();
+static group_loop();
+static send_group();
+static has_attributes();
+static char **get_attributes_mail_dn();
+static char *canonical();
+
+main (argc, argv)
+int    argc;
+char   **argv;
+{
+       char            *myname;
+       char            **tolist;
+       Error           *errlist;
+       Group           *togroups;
+       int             numto, ngroups, numerr, nargs;
+       int             i, j;
+       FILE            *fp;
+       extern int      optind, errno;
+       extern char     *optarg;
+
+       while ( (i = getopt( argc, argv, "f:h:m:" )) != EOF ) {
+               switch( i ) {
+               case 'f':       /* who it's from & where errors should go */
+                       mailfrom = strdup( optarg );
+                       for ( j = 0; sendmailargs[j] != NULL; j++ ) {
+                               if ( strcmp( sendmailargs[j], "-f" ) == 0 ) {
+                                       sendmailargs[j+1] = mailfrom;
+                                       break;
+                               }
+                       }
+                       break;
+
+               case 'h':       /* hostname */
+                       host = strdup( optarg );
+                       hostlen = strlen(host);
+                       break;
+
+                               /* mailer-daemon address - who we should */
+               case 'm':       /* say errors come from */
+                       errorsfrom = strdup( optarg );
+                       break;
+
+               default:
+                       syslog( LOG_ALERT, "unknown option" );
+                       break;
+               }
+       }
+
+       if ( (myname = strrchr( argv[0], '/' )) == NULL )
+               myname = strdup( argv[0] );
+       else
+               myname = strdup( myname + 1 );
+       if (!strcmp(myname, "mail500")) {
+               identity = MAIL500;
+       } else if (!strcmp(myname, "fax500")) {
+               identity = FAX500;
+       } else {
+               /* I give up, I must be mail500 */
+               identity = MAIL500;
+       }
+
+#ifdef LOG_MAIL
+       openlog( myname, OPENLOG_OPTIONS, LOG_MAIL );
+#else
+       openlog( myname, OPENLOG_OPTIONS );
+#endif
+
+       if ( mailfrom == NULL ) {
+               syslog( LOG_ALERT, "required argument -f not present" );
+               exit( EX_TEMPFAIL );
+       }
+       if ( errorsfrom == NULL ) {
+               syslog( LOG_ALERT, "required argument -m not present" );
+               exit( EX_TEMPFAIL );
+       }
+       if ( host == NULL ) {
+               syslog( LOG_ALERT, "required argument -h not present" );
+               exit( EX_TEMPFAIL );
+       }
+
+       if ( connect_to_x500() != 0 )
+               exit( EX_TEMPFAIL );
+
+       setuid( geteuid() );
+/*
+{
+       char    buf[1024];
+       int     i;
+
+       strcpy( buf, argv[0] );
+       for ( i = 1; i < argc; i++ ) {
+               strcat( buf, " " );
+               strcat( buf, argv[i] );
+       }
+
+       syslog( LOG_ALERT, "args: (%s)", buf );
+}
+*/
+       numto = 0;
+       add_to( &tolist, &numto, sendmailargs );
+       nargs = numto;
+       ngroups = numerr = 0;
+       togroups = NULL;
+       errlist = NULL;
+       for ( i = optind; i < argc; i++ ) {
+               char    *s;
+               int     type;
+
+               for ( j = 0; argv[i][j] != '\0'; j++ ) {
+                       if ( argv[i][j] == '.' || argv[i][j] == '_' )
+                               argv[i][j] = ' ';
+               }
+
+               type = USER;
+               if ( (s = strrchr( argv[i], '-' )) != NULL ) {
+                       s++;
+
+                       if ( strcmp( s, ERRORS ) == 0 ) {
+                               type = GROUP_ERRORS;
+                               *(--s) = '\0';
+                       } else if ( strcmp( s, REQUEST ) == 0 ) {
+                               type = GROUP_REQUEST;
+                               *(--s) = '\0';
+                       } else if ( strcmp( s, MEMBERS ) == 0 ) {
+                               type = GROUP_MEMBERS;
+                               *(--s) = '\0';
+                       }
+               }
+
+               do_address( argv[i], &tolist, &numto, &togroups, &ngroups,
+                   &errlist, &numerr, type );
+       }
+
+       /*
+        * If we have both errors and successful deliveries to make or if
+        * if there are any groups to deliver to, we basically need to read
+        * the message twice.  So, we have to put it in a tmp file.
+        */
+
+       if ( numerr > 0 && numto > nargs || ngroups > 0 ) {
+               int     fd;
+               char    buf[BUFSIZ];
+
+               umask( 077 );
+               if ( (fp = tmpfile()) == NULL ) {
+                       syslog( LOG_ALERT, "could not open tmp file" );
+                       unbind_and_exit( EX_TEMPFAIL );
+               }
+
+               /* copy the message to a temp file */
+               while ( fgets( buf, sizeof(buf), stdin ) != NULL ) {
+                       if ( fputs( buf, fp ) == EOF ) {
+                               syslog( LOG_ALERT, "error writing tmpfile" );
+                               unbind_and_exit( EX_TEMPFAIL );
+                       }
+               }
+
+               if ( dup2( fileno( fp ), 0 ) == -1 ) {
+                       syslog( LOG_ALERT, "could not dup2 tmpfile" );
+                       unbind_and_exit( EX_TEMPFAIL );
+               }
+
+               fclose( fp );
+       }
+
+       /* deal with errors */
+       if ( numerr > 0 ) {
+               (void) rewind( stdin );
+               send_errors( errlist, numerr );
+       }
+
+       (void) ldap_unbind( ld );
+
+       /* send to groups with errorsTo */
+       if ( ngroups > 0 ) {
+               (void) rewind( stdin );
+               send_group( togroups, ngroups );
+       }
+
+       /* send to expanded aliases and groups w/o errorsTo */
+       if ( numto > nargs ) {
+               (void) rewind( stdin );
+               send_message( tolist );
+       }
+
+       return( EX_OK );
+}
+
+connect_to_x500()
+{
+       if ( (ld = ldap_open( LDAPHOST, LDAP_PORT )) == NULL ) {
+               syslog( LOG_ALERT, "ldap_open failed" );
+               return( -1 );
+       }
+       ld->ld_sizelimit = FAX_MAXAMBIGUOUS;
+       ld->ld_deref = LDAP_DEREF_ALWAYS;
+
+       if ( ldap_simple_bind_s( ld, FAX_BINDDN, NULL ) != LDAP_SUCCESS ) {
+               syslog( LOG_ALERT, "ldap_simple_bind_s failed" );
+               return( -1 );
+       }
+
+       return( 0 );
+}
+
+
+static
+do_address( name, to, nto, togroups, ngroups, err, nerr, type )
+    char       *name;
+    char       ***to;
+    int                *nto;
+    Group      **togroups;
+    int                *ngroups;
+    Error      **err;
+    int                *nerr;
+    int                type;
+{
+       int             rc, b, f, match;
+       LDAPMessage     *e, *res;
+       struct timeval  timeout;
+       char            *dn;
+       char            filter[1024];
+       char            **mail;
+       char            **fax;
+
+       /*
+        * Look up the name in X.500, add the appropriate addresses found
+        * to the to list, or to the err list in case of error.  Groups are
+        * handled by the do_group routine, individuals are handled here.
+        * When looking up name, we follow the bases hierarchy, looking
+        * in base[0] first, then base[1], etc.  For each base, there is
+        * a set of search filters to try, in order.  If something goes
+        * wrong here trying to contact X.500, we exit with EX_TEMPFAIL.
+        * If the b_rdnpref flag is set, then we give preference to entries
+        * that matched name because it's their rdn, otherwise not.
+        */
+
+       timeout.tv_sec = FAX_TIMEOUT;
+       timeout.tv_usec = 0;
+       for ( b = 0, match = 0; !match && base[b].b_dn != NULL; b++ ) {
+               for ( f = 0; base[b].b_filter[f] != NULL; f++ ) {
+                       char    *format, *p, *argv[3];
+                       int     argc;
+
+                       for ( argc = 0; argc < 3; argc++ ) {
+                               argv[argc] = NULL;
+                       }
+
+                       format = strdup( base[b].b_filter[f] );
+                       for ( argc = 0, p = format; *p; p++ ) {
+                               if ( *p == '%' ) {
+                                       switch ( *++p ) {
+                                       case 's':       /* %s is the name */
+                                               argv[argc] = name;
+                                               break;
+
+                                       case 'h':       /* %h is the host */
+                                               *p = 's';
+                                               argv[argc] = host;
+                                               break;
+
+                                       default:
+                                               syslog( LOG_ALERT,
+                                                   "unknown format %c", *p );
+                                               break;
+                                       }
+
+                                       argc++;
+                               }
+                       }
+
+                       /* three names ought to do... */
+                       sprintf( filter, format, argv[0], argv[1], argv[2] );
+                       free( format );
+
+                       res = NULL;
+                       rc = ldap_search_st( ld, base[b].b_dn,
+                           LDAP_SCOPE_SUBTREE, filter, attrs, 0, &timeout,
+                           &res );
+
+                       /* some other trouble - try again later */
+                       if ( rc != LDAP_SUCCESS &&
+                           rc != LDAP_SIZELIMIT_EXCEEDED ) {
+                               syslog( LOG_ALERT, "return %d from X.500", rc );
+                               unbind_and_exit( EX_TEMPFAIL );
+                       }
+
+                       if ( (match = ldap_count_entries( ld, res )) != 0 )
+                               break;
+
+                       ldap_msgfree( res );
+               }
+
+               if ( match )
+                       break;
+       }
+
+       /* trouble - try again later */
+       if ( match == -1 ) {
+               syslog( LOG_ALERT, "error parsing result from X.500" );
+               unbind_and_exit( EX_TEMPFAIL );
+       }
+
+       /* no matches - bounce with user unknown */
+       if ( match == 0 ) {
+               add_error( err, nerr, E_USERUNKNOWN, name, NULLMSG );
+               return;
+       }
+
+       /* more than one match - bounce with ambiguous user? */
+       if ( match > 1 ) {
+               LDAPMessage     *next, *tmpres = NULL;
+               char            *dn;
+               char            **xdn;
+
+               /* not giving rdn preference - bounce with ambiguous user */
+               if ( base[b].b_rdnpref == 0 ) {
+                       add_error( err, nerr, E_AMBIGUOUS, name, res );
+                       return;
+               }
+
+               /*
+                * giving rdn preference - see if any entries were matched
+                * because of their rdn.  If so, collect them to deal with
+                * later (== 1 we deliver, > 1 we bounce).
+                */
+
+               for ( e = ldap_first_entry( ld, res ); e != NULL; e = next ) {
+                       next = ldap_next_entry( ld, e );
+                       dn = ldap_get_dn( ld, e );
+                       xdn = ldap_explode_dn( dn, 1 );
+
+                       /* XXX bad, but how else can we do it? XXX */
+                       if ( strcasecmp( xdn[0], name ) == 0 ) {
+                               ldap_delete_result_entry( &res, e );
+                               ldap_add_result_entry( &tmpres, e );
+                       }
+
+                       ldap_value_free( xdn );
+                       free( dn );
+               }
+
+               /* nothing matched by rdn - go ahead and bounce */
+               if ( tmpres == NULL ) {
+                       add_error( err, nerr, E_AMBIGUOUS, name, res );
+                       return;
+
+               /* more than one matched by rdn - bounce with rdn matches */
+               } else if ( (match = ldap_count_entries( ld, tmpres )) > 1 ) {
+                       add_error( err, nerr, E_AMBIGUOUS, name, tmpres );
+                       return;
+
+               /* trouble... */
+               } else if ( match < 0 ) {
+                       syslog( LOG_ALERT, "error parsing result from X.500" );
+                       unbind_and_exit( EX_TEMPFAIL );
+               }
+
+               /* otherwise one matched by rdn - send to it */
+               ldap_msgfree( res );
+               res = tmpres;
+       }
+
+       /*
+        * if we get this far, it means that we found a single match for
+        * name.  for a user, we deliver to the mail attribute or bounce
+        * with address and phone if no mail attr.  for a group, we
+        * deliver to all members or bounce to rfc822ErrorsTo if no members.
+        */
+
+       /* trouble */
+       if ( (e = ldap_first_entry( ld, res )) == NULL ) {
+               syslog( LOG_ALERT, "error parsing entry from X.500" );
+               unbind_and_exit( EX_TEMPFAIL );
+       }
+
+       dn = ldap_get_dn( ld, e );
+
+       if ( type == GROUP_ERRORS ) {
+               /* sent to group-errors - resend to [rfc822]ErrorsTo attr */
+               do_group_errors( e, dn, to, nto, err, nerr );
+
+       } else if ( type == GROUP_REQUEST ) {
+               /* sent to group-request - resend to [rfc822]RequestsTo attr */
+               do_group_request( e, dn, to, nto, err, nerr );
+
+       } else if ( type == GROUP_MEMBERS ) {
+               /* sent to group-members - expand */
+               do_group_members( e, dn, to, nto, togroups, ngroups, err,
+                   nerr );
+
+       } else if ( isgroup( e ) ) {
+               /* 
+                * sent to group - resend from [rfc822]ErrorsTo if it's there,
+                * otherwise, expand the group
+                */
+
+               do_group( e, dn, to, nto, togroups, ngroups, err, nerr );
+
+               ldap_msgfree( res );
+
+       } else {
+               /*
+                * sent to user - mail attribute => add it to the to list,
+                * otherwise bounce
+                */
+               switch (identity) {
+               case FAX500 :   
+                       if ( (mail = ldap_get_values( ld, e, 
+                            "facsimileTelephoneNumber" )) != NULL ) {
+                               char *fdn;
+                               char **ufn;
+                               int i;
+
+                               fdn = ldap_get_dn( ld, e );
+                               ufn = ldap_explode_dn( fdn, 1 );
+                               /* Convert spaces to underscores for rp */
+                               for (i = 0; ufn[0][i] != '\0'; i++) {
+                                       if (ufn[0][i] == ' ') {
+                                               ufn[0][i] = '_';
+                                       }
+                               }
+                               *mail = faxtotpc(*mail, ufn[0]);
+                               
+                               add_to(to, nto, mail);
+
+                               if (fdn != NULL) {
+                                       free(fdn);
+                               }
+                               ldap_value_free( ufn );
+                               ldap_value_free( mail );
+                               ldap_msgfree( res );
+                       } else {
+                               add_error( err, nerr, E_NOFAXNUM, 
+                                          name, res );
+                       }
+                       break;
+               case MAIL500 :
+                       if ( (mail = ldap_get_values( ld, e, "mail" ))
+                            != NULL ) {
+                               add_to( to, nto, mail );
+
+                               ldap_value_free( mail );
+                               ldap_msgfree( res );
+                       } else {
+                               add_error( err, nerr, E_NOEMAIL, 
+                                          name, res );
+                       }
+                       break;
+               }
+       }
+
+       free( dn );
+
+       return;
+}
+
+static
+do_group( e, dn, to, nto, togroups, ngroups, err, nerr )
+    LDAPMessage        *e;
+    char       *dn;
+    char       ***to;
+    int                *nto;
+    Group      **togroups;
+    int                *ngroups;
+    Error      **err;
+    int                *nerr;
+{
+       /*
+        * If this group has an rfc822ErrorsTo attribute, we need to
+        * arrange for errors involving this group to go there, not
+        * to the sender.  Since sendmail only has the concept of a
+        * single sender, we arrange for errors to go to groupname-errors,
+        * which we then handle specially when (if) it comes back to us
+        * by expanding to all the rfc822ErrorsTo addresses.  If it has no
+        * rfc822ErrorsTo attribute, we call do_group_members() to expand
+        * the group.
+        */
+
+       if ( group_loop( dn ) ) {
+               return( -1 );
+       }
+
+       if ( has_attributes( e, "rfc822ErrorsTo", "errorsTo" ) ) {
+               add_group( dn, togroups, ngroups );
+
+               return( 0 );
+       }
+
+       do_group_members( e, dn, to, nto, togroups, ngroups, err, nerr );
+
+       return( 0 );
+}
+
+/* ARGSUSED */
+static
+do_group_members( e, dn, to, nto, togroups, ngroups, err, nerr )
+    LDAPMessage        *e;
+    char       *dn;
+    char       ***to;
+    int                *nto;
+    Group      **togroups;
+    int                *ngroups;
+    Error      **err;
+    int                *nerr;
+{
+       int             i, rc;
+       char            *ndn;
+       char            **mail, **member, **joinable;
+       char            filter[256];
+       LDAPMessage     *ee, *res;
+       struct timeval  timeout;
+
+       /*
+        * if all has gone according to plan, we've already arranged for
+        * errors to go to the [rfc822]ErrorsTo attributes (if they exist),
+        * so all we have to do here is arrange to send to the
+        * rfc822Mailbox attribute, the member attribute, and anyone who
+        * has joined the group by setting memberOfGroup equal to the
+        * group dn.
+        */
+
+       /* add members in the group itself - mail attribute */
+       if ( (mail = ldap_get_values( ld, e, "mail" )) != NULL ) {
+               /* 
+                * These are only email addresses - impossible 
+                * to have a fax number
+                */
+               switch (identity) {
+               case FAX500 :
+                       /* XXX How do we want to inform sender that the */
+                       /* group they sent to has email-only members? */
+                       break;
+               case MAIL500 :
+                       add_to( to, nto, mail );
+                       break;
+               }
+
+               ldap_value_free( mail ); 
+       }
+
+       /* add members in the group itself - member attribute */
+       if ( (member = ldap_get_values( ld, e, "member" )) != NULL ) {
+               for ( i = 0; member[i] != NULL; i++ ) {
+                       add_member( dn, member[i], to, nto, togroups,
+                           ngroups, err, nerr );
+               }
+
+               ldap_value_free( member );
+       }
+
+       /* add members who have joined by setting memberOfGroup */
+       if ( (joinable = ldap_get_values( ld, e, "joinable" )) != NULL ) {
+               if ( strcasecmp( joinable[0], "FALSE" ) == 0 ) {
+                       ldap_value_free( joinable );
+                       return;
+               }
+               ldap_value_free( joinable );
+
+               sprintf( filter, "(memberOfGroup=%s)", dn );
+
+               timeout.tv_sec = FAX_TIMEOUT;
+               timeout.tv_usec = 0;
+
+               /* for each subtree to look in... */
+               ld->ld_sizelimit = FAX_MAXMEMBERS;
+               for ( i = 0; base[i].b_dn != NULL; i++ ) {
+                       /* find entries that have joined this group... */
+                       rc = ldap_search_st( ld, base[i].b_dn,
+                           LDAP_SCOPE_SUBTREE, filter, attrs, 0, &timeout,
+                           &res );
+
+                       if ( rc == LDAP_SIZELIMIT_EXCEEDED ||
+                           rc == LDAP_TIMELIMIT_EXCEEDED ) {
+                               syslog( LOG_ALERT,
+                                   "group search limit exceeded %d", rc );
+                               unbind_and_exit( EX_TEMPFAIL );
+                       }
+
+                       if ( rc != LDAP_SUCCESS ) {
+                               syslog( LOG_ALERT, "group search bad return %d",
+                                   rc );
+                               unbind_and_exit( EX_TEMPFAIL );
+                       }
+
+                       /* for each entry that has joined... */
+                       for ( ee = ldap_first_entry( ld, res ); ee != NULL;
+                           ee = ldap_next_entry( ld, ee ) ) {
+                               if ( isgroup( ee ) ) {
+                                       ndn = ldap_get_dn( ld, ee );
+
+                                       if ( do_group( e, ndn, to, nto,
+                                           togroups, ngroups, err, nerr )
+                                           == -1 ) {
+                                               syslog( LOG_ALERT,
+                                                   "group loop (%s) (%s)",
+                                                   dn, ndn );
+                                       }
+
+                                       free( ndn );
+
+                                       continue;
+                               }
+
+                               /* add them to the to list */
+                               switch (identity) {
+                               case FAX500 :   
+                                       if ( (mail = ldap_get_values( ld, ee, 
+                                             "facsimileTelephoneNumber" )) 
+                                             != NULL ) {
+                                               char *fdn;
+                                               char **ufn;
+                                               int i;
+
+                                               fdn = ldap_get_dn( ld, ee );
+                                               ufn = ldap_explode_dn( fdn, 1 );
+                                               /* 
+                                                * Convert spaces to 
+                                                * underscores for rp
+                                                */
+                                               for (i = 0; ufn[0][i] != '\0'; 
+                                                    i++) {
+                                                       if (ufn[0][i] == ' ') {
+                                                               ufn[0][i] = '_';
+                                                       }
+                                               }
+                                               *mail = faxtotpc(*mail, ufn[0]);
+                                               add_to(to, nto, mail);
+
+                                               ldap_value_free( mail );
+                                               ldap_msgfree( res );
+                                       } else {
+                                               ndn = ldap_get_dn( ld, ee );
+
+                                               add_error( err, nerr,
+                                                   E_JOINMEMBERNOFAXNUM, ndn, 
+                                                   NULLMSG );
+
+                                               free( ndn );
+                                       }
+                                       break;
+                               case MAIL500 :
+                                       if ( (mail = ldap_get_values( ld, ee, 
+                                            "mail" )) != NULL ) {
+                                               add_to( to, nto, mail );
+
+                                               ldap_value_free( mail );
+
+                                       /* else generate a bounce */
+                                       } else {
+                                               ndn = ldap_get_dn( ld, ee );
+
+                                               add_error( err, nerr,
+                                                   E_JOINMEMBERNOEMAIL, ndn, 
+                                                   NULLMSG );
+
+                                               free( ndn );
+                                       }
+                                       break;
+                               }
+                       }
+
+                       ldap_msgfree( res );
+               }
+               ld->ld_sizelimit = FAX_MAXAMBIGUOUS;
+       }
+
+       return;
+}
+
+add_member( gdn, dn, to, nto, togroups, ngroups, err, nerr )
+    char       *gdn;
+    char       *dn;
+    char       ***to;
+    int                *nto;
+    Group      **togroups;
+    int                *ngroups;
+    Error      **err;
+    int                *nerr;
+{
+       char            *ndn;
+       char            **mail;
+       int             rc;
+       LDAPMessage     *res, *e;
+       struct timeval  timeout;
+
+       timeout.tv_sec = FAX_TIMEOUT;
+       timeout.tv_usec = 0;
+       if ( (rc = ldap_search_st( ld, dn, LDAP_SCOPE_BASE, "(objectclass=*)",
+           attrs, 0, &timeout, &res )) != LDAP_SUCCESS ) {
+               if ( rc == LDAP_NO_SUCH_OBJECT ) {
+                       add_error( err, nerr, E_BADMEMBER, dn, NULLMSG );
+
+                       return;
+               } else {
+                       syslog( LOG_ALERT, "member search bad return %d", rc );
+
+                       unbind_and_exit( EX_TEMPFAIL );
+               }
+       }
+
+       if ( (e = ldap_first_entry( ld, res )) == NULL ) {
+               syslog( LOG_ALERT, "member search error parsing entry" );
+
+               unbind_and_exit( EX_TEMPFAIL );
+       }
+       ndn = ldap_get_dn( ld, e );
+
+       /* allow groups within groups */
+       if ( isgroup( e ) ) {
+               if ( do_group( e, ndn, to, nto, togroups, ngroups, err, nerr )
+                   == -1 ) {
+                       syslog( LOG_ALERT, "group loop (%s) (%s)", gdn, ndn );
+               }
+
+               free( ndn );
+
+               return;
+       }
+
+       switch (identity) {
+       case FAX500 :   
+               if ( (mail = ldap_get_values( ld, e, 
+                    "facsimileTelephoneNumber" )) != NULL ) {
+                       char *fdn;
+                       char **ufn;
+                       int i;
+                       fdn = ldap_get_dn( ld, e );
+                       ufn = ldap_explode_dn( fdn, 1 );
+                       /* Convert spaces to underscores for rp */
+                       for (i = 0; ufn[0][i] != '\0'; i++) {
+                               if (ufn[0][i] == ' ') {
+                                       ufn[0][i] = '_';
+                               }
+                       }
+                       *mail = faxtotpc(*mail, ufn[0]);
+                       add_to(to, nto, mail);
+
+                       ldap_value_free( mail );
+                       ldap_msgfree( res );
+               } else {
+                       add_error( err, nerr, E_MEMBERNOFAXNUM, ndn, NULLMSG );
+               }
+               break;
+       case MAIL500 :
+               /* send to the member's mail attribute */
+               if ( (mail = ldap_get_values( ld, e, "mail" )) != NULL ) {
+                       add_to( to, nto, mail );
+
+                       ldap_value_free( mail );
+
+               /* else generate a bounce */
+               } else {
+                       add_error( err, nerr, E_MEMBERNOEMAIL, ndn, NULLMSG );
+               }
+
+               free( ndn );
+       }
+       return;
+}
+
+do_group_request( e, dn, to, nto, err, nerr )
+    LDAPMessage        *e;
+    char       *dn;
+    char       ***to;
+    int                *nto;
+    Error      **err;
+    int                *nerr;
+{
+       char            **requeststo;
+
+       if ( (requeststo = get_attributes_mail_dn( e, "rfc822RequestsTo",
+           "requestsTo" )) != NULL ) {
+               add_to( to, nto, requeststo );
+
+               ldap_value_free( requeststo );
+       } else {
+               add_error( err, nerr, E_NOREQUEST, dn, NULLMSG );
+       }
+
+       return;
+}
+
+do_group_errors( e, dn, to, nto, err, nerr )
+    LDAPMessage        *e;
+    char       *dn;
+    char       ***to;
+    int                *nto;
+    Error      **err;
+    int                *nerr;
+{
+       char            **errorsto;
+
+       if ( (errorsto = get_attributes_mail_dn( e, "rfc822ErrorsTo",
+           "errorsTo" )) != NULL ) {
+               add_to( to, nto, errorsto );
+
+               ldap_value_free( errorsto );
+       } else {
+               add_error( err, nerr, E_NOERRORS, dn, NULLMSG );
+       }
+
+       return;
+}
+
+static
+send_message( to )
+    char       **to;
+{
+       int     pid;
+#ifndef USE_WAITPID
+       WAITSTATUSTYPE  status;
+#endif
+
+
+       /* parent */
+       if ( pid = fork() ) {
+#ifdef USE_WAITPID
+               waitpid( pid, (int *) NULL, 0 );
+#else
+               wait4( pid, &status, WAIT_FLAGS, 0 );
+#endif
+       /* child */
+       } else {
+               /* to includes sendmailargs */
+               execv( FAX_SENDMAIL, to );
+
+               syslog( LOG_ALERT, "execv failed" );
+
+               exit( EX_TEMPFAIL );
+       }
+}
+
+static
+send_group( group, ngroup )
+    Group      *group;
+    int                ngroup;
+{
+       int     i, pid;
+       char    **argv;
+       int     argc;
+       char    *iargv[7];
+#ifndef USE_WAITPID
+       WAITSTATUSTYPE  status;
+#endif
+
+       for ( i = 0; i < ngroup; i++ ) {
+               (void) rewind( stdin );
+
+               iargv[0] = FAX_SENDMAIL;
+               iargv[1] = "-f";
+               iargv[2] = group[i].g_errorsto;
+               iargv[3] = "-oMrX.500";
+               iargv[4] = "-odi";
+               iargv[5] = "-oi";
+               iargv[6] = NULL;
+
+               argv = NULL;
+               argc = 0;
+               add_to( &argv, &argc, iargv );
+               add_to( &argv, &argc, group[i].g_members );
+
+
+               /* parent */
+               if ( pid = fork() ) {
+#ifdef USE_WAITPID
+                       waitpid( pid, (int *) NULL, 0 );
+#else
+                       wait4( pid, &status, WAIT_FLAGS, 0 );
+#endif
+               /* child */
+               } else {
+                       execv( FAX_SENDMAIL, argv );
+
+                       syslog( LOG_ALERT, "execv failed" );
+
+                       exit( EX_TEMPFAIL );
+               }
+       }
+
+       return;
+}
+
+static
+send_errors( err, nerr )
+    Error      *err;
+    int                nerr;
+{
+       int             i, namelen;
+       FILE            *fp;
+       char            buf[1024];
+
+       sprintf( buf, "%s -oMrX.500 -odi -oi -f %s %s", FAX_SENDMAIL, errorsfrom,
+           mailfrom );
+       if ( (fp = popen( buf, "w" )) == NULL ) {
+               syslog( LOG_ALERT, "could not popen sendmail for errs" );
+               return;
+       }
+
+       fprintf( fp, "To: %s\n", mailfrom );
+       fprintf( fp, "From: %s\n", errorsfrom );
+       fprintf( fp, "Subject: undeliverable mail\n" );
+       fprintf( fp, "\n" );
+       fprintf( fp, "The following errors occurred when trying to deliver the attached mail:\n" );
+       for ( i = 0; i < nerr; i++ ) {
+               namelen = strlen( err[i].e_addr );
+               fprintf( fp, "\n" );
+
+               switch ( err[i].e_code ) {
+               case E_USERUNKNOWN:
+                       fprintf( fp, "%s: User unknown\n", err[i].e_addr );
+                       break;
+
+               case E_BADMEMBER:
+                       fprintf( fp, "%s: Group member does not exist\n",
+                           err[i].e_addr );
+                       break;
+
+               case E_NOREQUEST:
+                       fprintf( fp, "%s: Group exists but has no request address\n",
+                           err[i].e_addr );
+                       break;
+
+               case E_NOERRORS:
+                       fprintf( fp, "%s: Group exists but has no errors-to address\n",
+                           err[i].e_addr );
+                       break;
+
+               case E_AMBIGUOUS:
+                       do_ambiguous( fp, &err[i], namelen );
+                       break;
+
+               case E_NOEMAIL:
+                       do_noemailorfax( fp, &err[i], namelen, E_NOEMAIL );
+                       break;
+
+               case E_MEMBERNOEMAIL:
+                       fprintf( fp, "%s: Group member exists but does not have an email address\n",
+                           err[i].e_addr );
+                       break;
+
+               case E_JOINMEMBERNOEMAIL:
+                       fprintf( fp, "%s: User has joined group but does not have an email address\n",
+                           err[i].e_addr );
+                       break;
+
+               case E_NOFAXNUM:
+                       do_noemailorfax( fp, &err[i], namelen, E_NOFAXNUM );
+                       break;
+
+               case E_MEMBERNOFAXNUM:
+                       fprintf( fp, "%s: Group member exists but does not have a fax number\n",
+                           err[i].e_addr );
+                       break;
+
+               case E_JOINMEMBERNOFAXNUM:
+                       fprintf( fp, "%s: User has joined group but does not have a fax number\n",
+                           err[i].e_addr );
+                       break;
+
+               default:
+                       syslog( LOG_ALERT, "unknown error %d", err[i].e_code );
+                       unbind_and_exit( EX_TEMPFAIL );
+                       break;
+               }
+       }
+
+       fprintf( fp, "\n------- The original message sent:\n\n" );
+
+       while ( fgets( buf, sizeof(buf), stdin ) != NULL ) {
+               fputs( buf, fp );
+       }
+
+       if ( pclose( fp ) == -1 ) {
+               syslog( LOG_ALERT, "pclose failed" );
+               unbind_and_exit( EX_TEMPFAIL );
+       }
+
+       return;
+}
+
+
+static
+do_noemailorfax( fp, err, namelen, errtype )
+    FILE       *fp;
+    Error      *err;
+    int                namelen;
+    int                errtype;
+{
+       int             i, last;
+       char            *dn, *rdn;
+       char            **ufn, **vals;
+
+       if (errtype == E_NOFAXNUM) {
+               fprintf(fp, "%s: User has no facsimile number registered.\n",
+                       err->e_addr );
+       } else if (errtype == E_NOEMAIL) {
+               fprintf(fp, "%s: User has no email address registered.\n",
+                       err->e_addr );
+       }
+       fprintf( fp, "%*s  Name, title, postal address and phone for '%s':\n\n",
+           namelen, " ", err->e_addr );
+
+       /* name */
+       dn = ldap_get_dn( ld, err->e_msg );
+       ufn = ldap_explode_dn( dn, 1 );
+       rdn = strdup( ufn[0] );
+       if ( strcasecmp( rdn, err->e_addr ) == 0 ) {
+               if ( (vals = ldap_get_values( ld, err->e_msg, "cn" ))
+                   != NULL ) {
+                       for ( i = 0; vals[i]; i++ ) {
+                               last = strlen( vals[i] ) - 1;
+                               if ( isdigit( vals[i][last] ) ) {
+                                       rdn = strdup( vals[i] );
+                                       break;
+                               }
+                       }
+
+                       ldap_value_free( vals );
+               }
+       }
+       fprintf( fp, "%*s  %s\n", namelen, " ", rdn );
+       free( dn );
+       free( rdn );
+       ldap_value_free( ufn );
+
+       /* titles or descriptions */
+       if ( (vals = ldap_get_values( ld, err->e_msg, "title" )) == NULL &&
+           (vals = ldap_get_values( ld, err->e_msg, "description" ))
+           == NULL ) {
+               fprintf( fp, "%*s  No title or description registered\n",
+                   namelen, " " );
+       } else {
+               for ( i = 0; vals[i] != NULL; i++ ) {
+                       fprintf( fp, "%*s  %s\n", namelen, " ", vals[i] );
+               }
+
+               ldap_value_free( vals );
+       }
+
+       /* postal address */
+       if ( (vals = ldap_get_values( ld, err->e_msg, "postalAddress" ))
+           == NULL ) {
+               fprintf( fp, "%*s  No postal address registered\n", namelen,
+                   " " );
+       } else {
+               fprintf( fp, "%*s  ", namelen, " " );
+               for ( i = 0; vals[0][i] != '\0'; i++ ) {
+                       if ( vals[0][i] == '$' ) {
+                               fprintf( fp, "\n%*s  ", namelen, " " );
+                               while ( isspace( vals[0][i+1] ) )
+                                       i++;
+                       } else {
+                               fprintf( fp, "%c", vals[0][i] );
+                       }
+               }
+               fprintf( fp, "\n" );
+
+               ldap_value_free( vals );
+       }
+
+       /* telephone number */
+       if ( (vals = ldap_get_values( ld, err->e_msg, "telephoneNumber" ))
+           == NULL ) {
+               fprintf( fp, "%*s  No phone number registered\n", namelen,
+                   " " );
+       } else {
+               for ( i = 0; vals[i] != NULL; i++ ) {
+                       fprintf( fp, "%*s  %s\n", namelen, " ", vals[i] );
+               }
+
+               ldap_value_free( vals );
+       }
+}
+
+/* ARGSUSED */
+static
+do_ambiguous( fp, err, namelen )
+    FILE       *fp;
+    Error      *err;
+    int                namelen;
+{
+       int             i, last;
+       char            *dn, *rdn;
+       char            **ufn, **vals;
+       LDAPMessage     *e;
+
+       i = ldap_result2error( ld, err->e_msg, 0 );
+
+       fprintf( fp, "%s: Ambiguous user.  %s%d matches found:\n\n",
+           err->e_addr, i == LDAP_SIZELIMIT_EXCEEDED ? "First " : "",
+           ldap_count_entries( ld, err->e_msg ) );
+
+       for ( e = ldap_first_entry( ld, err->e_msg ); e != NULL;
+           e = ldap_next_entry( ld, e ) ) {
+               dn = ldap_get_dn( ld, e );
+               ufn = ldap_explode_dn( dn, 1 );
+               rdn = strdup( ufn[0] );
+               if ( strcasecmp( rdn, err->e_addr ) == 0 ) {
+                       if ( (vals = ldap_get_values( ld, e, "cn" )) != NULL ) {
+                               for ( i = 0; vals[i]; i++ ) {
+                                       last = strlen( vals[i] ) - 1;
+                                       if ( isdigit( vals[i][last] ) ) {
+                                               rdn = strdup( vals[i] );
+                                               break;
+                                       }
+                               }
+
+                               ldap_value_free( vals );
+                       }
+               }
+
+               if ( isgroup( e ) ) {
+                       vals = ldap_get_values( ld, e, "description" );
+               } else {
+                       vals = ldap_get_values( ld, e, "title" );
+               }
+
+               fprintf( fp, "    %-20s %s\n", rdn, vals ? vals[0] : "" );
+               for ( i = 1; vals && vals[i] != NULL; i++ ) {
+                       fprintf( fp, "                         %s\n", vals[i] );
+               }
+
+               free( dn );
+               free( rdn );
+               ldap_value_free( ufn );
+               if ( vals != NULL )
+                       ldap_value_free( vals );
+       }
+}
+
+static
+count_values( list )
+    char       **list;
+{
+       int     i;
+
+       for ( i = 0; list && list[i] != NULL; i++ )
+               ;       /* NULL */
+
+       return( i );
+}
+
+static
+add_to( list, nlist, new )
+    char       ***list;
+    int                *nlist;
+    char       **new;
+{
+       int     i, nnew, oldnlist;
+
+       nnew = count_values( new );
+
+       oldnlist = *nlist;
+       if ( *list == NULL || *nlist == 0 ) {
+               *list = (char **) malloc( (nnew + 1) * sizeof(char *) );
+               *nlist = nnew;
+       } else {
+               *list = (char **) realloc( *list, *nlist * sizeof(char *) +
+                   nnew * sizeof(char *) + sizeof(char *) );
+               *nlist += nnew;
+       }
+
+       for ( i = 0; i < nnew; i++ ) {
+               (*list)[i + oldnlist] = strdup( new[i] );
+       }
+       (*list)[*nlist] = NULL;
+
+       return;
+}
+
+static
+isgroup( e )
+    LDAPMessage        *e;
+{
+       int     i;
+       char    **oclist;
+
+       oclist = ldap_get_values( ld, e, "objectClass" );
+
+       for ( i = 0; oclist[i] != NULL; i++ ) {
+               if ( strcasecmp( oclist[i], "rfc822MailGroup" ) == 0 ) {
+                       ldap_value_free( oclist );
+                       return( 1 );
+               }
+       }
+       ldap_value_free( oclist );
+
+       return( 0 );
+}
+
+static
+add_error( err, nerr, code, addr, msg )
+    Error      **err;
+    int                *nerr;
+    int                code;
+    char       *addr;
+    LDAPMessage        *msg;
+{
+       if ( *nerr == 0 ) {
+               *err = (Error *) malloc( sizeof(Error) );
+       } else {
+               *err = (Error *) realloc( *err, (*nerr + 1) * sizeof(Error) );
+       }
+
+       (*err)[*nerr].e_code = code;
+       (*err)[*nerr].e_addr = strdup( addr );
+       (*err)[*nerr].e_msg = msg;
+       (*nerr)++;
+
+       return;
+}
+
+static
+add_group( dn, list, nlist )
+    char       *dn;
+    Group      **list;
+    int                *nlist;
+{
+       int     i, namelen;
+       char    **ufn;
+
+       for ( i = 0; i < *nlist; i++ ) {
+               if ( strcmp( dn, (*list)[i].g_dn ) == 0 ) {
+                       syslog( LOG_ALERT, "group loop 2 detected (%s)", dn );
+                       return;
+               }
+       }
+
+       ufn = ldap_explode_dn( dn, 1 );
+       namelen = strlen( ufn[0] );
+
+       if ( *nlist == 0 ) {
+               *list = (Group *) malloc( sizeof(Group) );
+       } else {
+               *list = (Group *) realloc( *list, (*nlist + 1) *
+                   sizeof(Group) );
+       }
+
+       /* send errors to groupname-errors@host */
+       (*list)[*nlist].g_errorsto = (char *) malloc( namelen + sizeof(ERRORS)
+           + hostlen + 2 );
+       sprintf( (*list)[*nlist].g_errorsto, "%s-%s@%s", ufn[0], ERRORS, host );
+       (void) canonical( (*list)[*nlist].g_errorsto );
+
+       /* send to groupname-members@host - make it a list for send_group */
+       (*list)[*nlist].g_members = (char **) malloc( 2 * sizeof(char *) );
+       (*list)[*nlist].g_members[0] = (char *) malloc( namelen +
+           sizeof(MEMBERS) + hostlen + 2 );
+       sprintf( (*list)[*nlist].g_members[0], "%s-%s@%s", ufn[0], MEMBERS,
+           host );
+       (void) canonical( (*list)[*nlist].g_members[0] );
+       (*list)[*nlist].g_members[1] = NULL;
+
+       /* save the group's dn so we can check for loops above */
+       (*list)[*nlist].g_dn = strdup( dn );
+
+       (*nlist)++;
+
+       ldap_value_free( ufn );
+
+       return;
+}
+
+static
+unbind_and_exit( rc )
+    int        rc;
+{
+       int     i;
+
+       if ( (i = ldap_unbind( ld )) != LDAP_SUCCESS )
+               syslog( LOG_ALERT, "ldap_unbind failed %d\n", i );
+
+       exit( rc );
+}
+
+static char *
+canonical( s )
+    char       *s;
+{
+       char    *saves = s;
+
+       for ( ; *s != '\0'; s++ ) {
+               if ( *s == ' ' )
+                       *s = '.';
+       }
+
+       return( saves );
+}
+
+static
+group_loop( dn )
+    char       *dn;
+{
+       int             i;
+       static char     **groups;
+       static int      ngroups;
+
+       for ( i = 0; i < ngroups; i++ ) {
+               if ( strcmp( dn, groups[i] ) == 0 )
+                       return( 1 );
+       }
+
+       if ( ngroups == 0 )
+               groups = (char **) malloc( sizeof(char *) );
+       else
+               groups = (char **) realloc( groups,
+                   (ngroups + 1) * sizeof(char *) );
+
+       groups[ngroups++] = strdup( dn );
+
+       return( 0 );
+}
+
+static
+has_attributes( e, attr1, attr2 )
+    LDAPMessage        *e;
+    char       *attr1;
+    char       *attr2;
+{
+       char    **attr;
+
+       if ( (attr = ldap_get_values( ld, e, attr1 )) != NULL ) {
+               ldap_value_free( attr );
+               return( 1 );
+       }
+
+       if ( (attr = ldap_get_values( ld, e, attr2 )) != NULL ) {
+               ldap_value_free( attr );
+               return( 1 );
+       }
+
+       return( 0 );
+}
+
+static char **
+get_attributes_mail_dn( e, attr1, attr2 )
+    LDAPMessage        *e;
+    char       *attr1;
+    char       *attr2;         /* this one is dn-valued */
+{
+       LDAPMessage     *ee, *res;
+       char            **vals, **dnlist, **mail;
+       int             nto, i, rc;
+       struct timeval  timeout;
+
+       vals = ldap_get_values( ld, e, attr1 );
+       for ( nto = 0; vals != NULL && vals[nto] != NULL; nto++ )
+               ;       /* NULL */
+
+       if ( (dnlist = ldap_get_values( ld, e, attr2 )) != NULL ) {
+               timeout.tv_sec = FAX_TIMEOUT;
+               timeout.tv_usec = 0;
+
+               for ( i = 0; dnlist[i] != NULL; i++ ) {
+                       if ( (rc = ldap_search_st( ld, dnlist[i],
+                           LDAP_SCOPE_BASE, "(objectclass=*)", attrs, 0,
+                           &timeout, &res )) != LDAP_SUCCESS ) {
+                               if ( rc != LDAP_NO_SUCH_OBJECT ) {
+                                       unbind_and_exit( EX_TEMPFAIL );
+                               }
+
+                               syslog( LOG_ALERT, "bad (%s) dn (%s)", attr2,
+                                   dnlist[i] );
+
+                               continue;
+                       }
+
+                       if ( (ee = ldap_first_entry( ld, res )) == NULL ) {
+                               syslog( LOG_ALERT, "error parsing x500 entry" );
+                               continue;
+                       }
+
+                       if ( (mail = ldap_get_values( ld, ee, "mail" ))
+                           != NULL ) {
+                               add_to( &vals, &nto, mail );
+
+                               ldap_value_free( mail );
+                       }
+
+                       ldap_msgfree( res );
+               }
+       }
+
+       return( vals );
+}
diff --git a/clients/fax500/rp500.c b/clients/fax500/rp500.c
new file mode 100644 (file)
index 0000000..25eece6
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <syslog.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <ldapconfig.h>
+#include "lber.h"
+#include "ldap.h"
+
+#define DEFAULT_PORT           79
+#define DEFAULT_SIZELIMIT      50
+
+int            debug;
+char           *ldaphost = LDAPHOST;
+char           *base = DEFAULT_BASE;
+int            deref;
+int            sizelimit;
+LDAPFiltDesc   *filtd;
+
+static print_entry();
+
+static
+usage( name )
+    char       *name;
+{
+       fprintf( stderr, "usage: %s [-d debuglevel] [-x ldaphost] [-b searchbase] [-a] [-z sizelimit] [-f filterfile] searchstring\r\n", name );
+       exit( -1 );
+}
+
+main (argc, argv)
+    int                argc;
+    char       **argv;
+{
+       int             i, rc, matches;
+       char            *filterfile = FILTERFILE;
+       struct timeval  timeout;
+       char            buf[10];
+       char            *key;
+       LDAP            *ld;
+       LDAPMessage     *result, *e;
+       LDAPFiltDesc    *filtd;
+       LDAPFiltInfo    *fi;
+       static char     *attrs[] = { "title", "o", "ou", "postalAddress",
+                                       "telephoneNumber", "mail",
+                                       "facsimileTelephoneNumber", NULL };
+       extern char     *optarg;
+       extern int      optind;
+
+       deref = LDAP_DEREF_ALWAYS;
+       while ( (i = getopt( argc, argv, "ab:d:f:x:z:" )) != EOF ) {
+               switch( i ) {
+               case 'a':       /* do not deref aliases when searching */
+                       deref = LDAP_DEREF_FINDING;
+                       break;
+
+               case 'b':       /* search base */
+                       base = strdup( optarg );
+                       break;
+
+               case 'd':       /* turn on debugging */
+                       debug = atoi( optarg );
+                       break;
+
+               case 'f':       /* ldap filter file */
+                       filterfile = strdup( optarg );
+                       break;
+
+               case 'x':       /* specify ldap host */
+                       ldaphost = strdup( optarg );
+                       break;
+
+               case 'z':       /* size limit */
+                       sizelimit = atoi( optarg );
+                       break;
+
+               default:
+                       usage( argv[0] );
+               }
+       }
+
+       if ( optind == argc ) {
+               usage( argv[0] );
+       }
+       key = argv[optind];
+
+       if ( (filtd = ldap_init_getfilter( filterfile )) == NULL ) {
+               fprintf( stderr, "Cannot open filter file (%s)\n", filterfile );
+               exit( -1 );
+       }
+
+       if ( (ld = ldap_open( ldaphost, LDAP_PORT )) == NULL ) {
+               perror( "ldap_open" );
+               exit( -1 );
+       }
+       ld->ld_sizelimit = sizelimit ? sizelimit : DEFAULT_SIZELIMIT;
+       ld->ld_deref = deref;
+
+       if ( ldap_simple_bind_s( ld, RP_BINDDN, NULL ) != LDAP_SUCCESS ) {
+               fprintf( stderr, "X.500 is temporarily unavailable.\n" );
+               ldap_perror( ld, "ldap_simple_bind_s" );
+               exit( -1 );
+       }
+
+       result = NULL;
+       if ( strchr( key, ',' ) != NULL ) {
+               ld->ld_deref = LDAP_DEREF_FINDING;
+               if ( (rc = ldap_ufn_search_s( ld, key, attrs, 0, &result ))
+                   != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED &&
+                   rc != LDAP_TIMELIMIT_EXCEEDED )
+               {
+                       ldap_perror( ld, "ldap_ufn_search_s" );
+                       exit( -1 );
+               }
+               matches = ldap_count_entries( ld, result );
+       } else {
+               for ( fi = ldap_getfirstfilter( filtd, "rp500", key );
+                   fi != NULL; fi = ldap_getnextfilter( filtd ) ) {
+                       if ( (rc = ldap_search_s( ld, base, LDAP_SCOPE_SUBTREE,
+                           fi->lfi_filter, attrs, 0, &result ))
+                           != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED
+                           && rc != LDAP_TIMELIMIT_EXCEEDED )
+                       {
+                               ldap_perror( ld, "ldap_search" );
+                               exit( -1 );
+                       }
+
+                       if ( (matches = ldap_count_entries( ld, result )) != 0
+                           || rc != LDAP_SUCCESS ) {
+                               break;
+                       }
+               }
+       }
+
+       if ( matches == 1 ) {
+               e = ldap_first_entry( ld, result );
+
+               print_entry( ld, e );
+       } else if ( matches > 1 ) {
+               fprintf( stderr, "%d %s matches for \"%s\":\r\n", matches,
+                   fi->lfi_desc, key );
+
+               for ( i = 1, e = ldap_first_entry( ld, result ); e != NULL;
+                   i++, e = ldap_next_entry( ld, e ) ) {
+                       int     j;
+                       char    *p, *dn, *rdn;
+                       char    **title;
+
+                       dn = ldap_get_dn( ld, e );
+                       rdn = dn;
+                       if ( (p = strchr( dn, ',' )) != NULL )
+                               *p = '\0';
+                       while ( *rdn && *rdn != '=' )
+                               rdn++;
+                       if ( *rdn )
+                               rdn++;
+                       if ( strcasecmp( rdn, buf ) == 0 ) {
+                               char    **cn;
+                               char    *s;
+                               int     i, last;
+
+                               cn = ldap_get_values( ld, e, "cn" );
+                               for ( i = 0; cn[i] != NULL; i++ ) {
+                                       last = strlen( cn[i] ) - 1;
+                                       if ( isdigit( cn[i][last] ) ) {
+                                               rdn = strdup( cn[i] );
+                                               break;
+                                       }
+                               }
+                       }
+                                       
+                       title = ldap_get_values( ld, e, "title" );
+
+                       fprintf( stderr, "  %d: %-20s    %s\r\n", i, rdn,
+                           title ? title[0] : "" );
+                       if ( title != NULL ) {
+                               for ( j = 1; title[j] != NULL; j++ )
+                                       fprintf( stderr, "  %-20s    %s\r\n",
+                                           "", title[j] );
+                       }
+                       if ( title != NULL )
+                               ldap_value_free( title );
+
+                       free( dn );
+               }
+               if ( rc == LDAP_SIZELIMIT_EXCEEDED
+                   || rc == LDAP_TIMELIMIT_EXCEEDED ) {
+                       fprintf( stderr, "(Size or time limit exceeded)\n" );
+               }
+
+               fprintf( stderr, "Enter the number of the person you want: ");
+
+               if ( fgets( buf, sizeof(buf), stdin ) == NULL
+                   || buf[0] == '\n' ) {
+                       exit( 1 );
+               }
+               i = atoi( buf ) - 1;
+               e = ldap_first_entry( ld, result );
+               for ( ; i > 0 && e != NULL; i-- ) {
+                       e = ldap_next_entry( ld, e );
+               }
+               if ( e == NULL ) {
+                       fprintf( stderr, "Invalid choice!\n" );
+                       exit( 1 );
+               }
+
+               print_entry( ld, e );
+       } else if ( matches == 0 ) {
+               fprintf( stderr, "No matches found for \"%s\"\n", key );
+               exit( 1 );
+       } else {
+               fprintf( stderr, "Error return from ldap_count_entries\n" );
+               exit( -1 );
+       }
+
+       ldap_unbind( ld );
+       return( 0 );
+}
+
+static
+print_entry( ld, e )
+    LDAP       *ld;
+    LDAPMessage        *e;
+{
+       int     i;
+       char    *dn, *rdn;
+       char    **ufn;
+       char    **title, **dept, **addr, **phone, **fax, **mail;
+       char    *faxmail, *org, *faxtotpc();
+
+       dn = ldap_get_dn( ld, e );
+       ufn = ldap_explode_dn( dn, 0 );
+       rdn = strchr( ufn[0], '=' ) + 1;
+
+       if ( (fax = ldap_get_values( ld, e, "facsimileTelephoneNumber" ))
+           == NULL ) {
+               fprintf( stderr, "Entry \"%s\" has no fax number.\n", dn );
+               exit( 1 );
+       }
+       faxmail = faxtotpc( fax[0] );
+       title = ldap_get_values( ld, e, "title" );
+       phone = ldap_get_values( ld, e, "telephoneNumber" );
+       mail = ldap_get_values( ld, e, "mail" );
+       dept = ldap_get_values( ld, e, "ou" );
+       addr = ldap_get_values( ld, e, "postalAddress" );
+       org = "";
+       for ( i = 0; ufn[i] != NULL; i++ ) {
+               if ( strncmp( "o=", ufn[i], 2 ) == 0 ) {
+                       org = strdup( strchr( ufn[i], '=' ) + 1 );
+                       break;
+               }
+       }
+
+       printf( "To: %s\n", faxmail );
+       printf( "Subject:\n" );
+       printf( "--------\n" );
+       printf( "#<application/remote-printing\n" );
+       printf( "Recipient:      %s\r\n", rdn );
+       printf( "Title:          %s\r\n", title ? title[0] : "" );
+       printf( "Organization:   %s\r\n", org );
+       printf( "Department:     %s\r\n", dept ? dept[0] : "" );
+       printf( "Telephone:      %s\r\n", phone ? phone[0] : "" );
+       printf( "Facsimile:      %s\r\n", fax ? fax[0] : "" );
+       printf( "Email:          %s\r\n", mail ? mail[0] : "" );
+}
diff --git a/clients/fax500/xrpcomp b/clients/fax500/xrpcomp
new file mode 100644 (file)
index 0000000..3a914ea
--- /dev/null
@@ -0,0 +1,85 @@
+: run this script through /bin/sh
+
+RP500=ETCDIR/rp500
+
+NAME="$1"
+if [ -z "$NAME" ]; then
+    echo "usage: xrpcomp name [arguments for comp]" 2>&1
+    exit 1
+fi
+
+DB=".rpdb"
+if [ ! -s "$DB" ]; then
+    DB="$HOME/.rpdb"
+fi
+if [ ! -s "$DB" ]; then
+    echo "unable to read $DB" 2>&1
+    exit 1
+fi
+
+C=/tmp/rp$$.comp       S=/tmp/rp$$.sh  O=/tmp/rp$$.orig
+trap "rm -f $C $S $O" 0 1 2 3 13 15
+
+cp /dev/null $S
+gawk -v NAME="$NAME" -v S="$S" -v O="$O" '
+function rev(f) {
+    s = ""
+    for (l = length(f); l > 0; l--)
+       s = s "." substr(f, l, 1)
+    return substr(s, 2, length(s) - 1)
+}
+
+BEGIN  {
+           RS= ""; FS = "\n"
+       }
+       {
+           if (NR == 1) {
+               from = $2
+               gsub("Recipient[        ]*:", "Originator:", from);
+               orig = "\r\n" from
+               for (i = 3; i <= NF; i++)
+                   orig = orig "\r\n" $i;
+               printf orig "\r\n" > O
+           }
+
+           if ($1 != NAME)
+               next
+           for (i = 2; i <= NF; i++) {
+               if (match($i, "Facsimile[       ]*:") > 0) {
+                   fax = substr($i, RSTART+RLENGTH)
+                   gsub("[     +-]", "", fax)
+
+                   printf "ADDR=\"remote-printer@%s.tpc.int\"\n", rev(fax) > S
+                   printf "To: remote-printer@%s.tpc.int\n", rev(fax)
+                   printf "Subject:\n"
+                   printf "--------\n"
+                   printf "#<application/remote-printing\n"
+
+                   recip = $2
+                   for (i = 3; i <= NF; i++)
+                       recip = recip "\r\n" $i;
+                   printf "%s\r\n%s\r\n", recip, orig
+
+                   printf "#\n"
+                   exit(0)
+               }
+           }
+       }' < $DB > $C
+. $S
+if [ -z "$ADDR" ]; then
+    echo "recipient \"$NAME\" not in $DB, checking X.500..." 2>&1
+    $RP500 "$NAME" > $C
+    RC=$?
+    if [ $RC = 1 ]; then
+       exit 1
+    elif [ $RC = 0 ]; then
+       cat $O >> $C
+       echo "#" >> $C
+    else
+       echo "error searching X.500" 2>&1
+       exit 1
+    fi
+fi
+
+shift
+comp -form $C $* -editor rpprompter
diff --git a/clients/finger/Make-template b/clients/finger/Make-template
new file mode 100644 (file)
index 0000000..d55329f
--- /dev/null
@@ -0,0 +1,70 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1994 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       X.500 ldap finger daemon makefile
+#
+#-----------------------------------------------------------------------------
+
+LDAPSRC        = ../..
+HDIR   = $(LDAPSRC)/include
+LDIR   = $(LDAPSRC)/libraries
+VERSIONFILE = $(LDAPSRC)/build/version
+
+SRCS   = main.c
+OBJS   = main.o
+
+INCLUDES=-I$(HDIR)
+DEFINES        = $(DEFS)
+
+CFLAGS = $(INCLUDES) $(DEFINES) $(ACFLAGS)
+LIBS   = -lldap -llber $(KRBLIBFLAG) $(KRBLIBS) $(ALIBS)
+
+all:   in.xfingerd
+
+in.xfingerd:   version.o
+       $(CC) $(ALDFLAGS) -o $@ $(OBJS) version.o \
+               -L$(LDIR) $(LIBS)
+
+version.c:     $(OBJS) $(LDIR)/libldap.a
+       $(RM) $@
+       (u=$${USER-root} v=`$(CAT) $(VERSIONFILE)` d=`$(PWD)` h=`$(HOSTNAME)` \
+        t=`$(DATE)`; $(SED) -e "s|%WHEN%|$${t}|" \
+       -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+       -e "s|%VERSION%|$${v}|" \
+       < Version.c > $@)
+
+install:       in.xfingerd FORCE
+       -$(MKDIR) -p $(ETCDIR)
+       $(INSTALL) $(INSTALLFLAGS) -m 755 in.xfingerd $(ETCDIR)
+
+lint:  FORCE
+       $(LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+5lint: FORCE
+       $(5LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+clean: FORCE
+       $(RM) *.o core a.out version.c in.xfingerd
+
+depend:        FORCE
+       $(MKDEP) $(INCLUDES) $(DEFINES) $(SRCS)
+
+links:
+       @$(LN) .src/README .src/*.[ch] .
+
+# DO NOT DELETE THIS LINE -- mkdep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+main.o: main.c ../../include/lber.h ../../include/ldap.h
+main.o: ../../include/disptmpl.h ../../include/portable.h
+main.o: ../../include/ldapconfig.h
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/clients/finger/Version.c b/clients/finger/Version.c
new file mode 100644 (file)
index 0000000..90456ee
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 1991 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+char Version[] = "  in.xfingerd v%VERSION% (%WHEN%)\n\t%WHOANDWHERE%\n";
diff --git a/clients/finger/main.c b/clients/finger/main.c
new file mode 100644 (file)
index 0000000..38c8dfc
--- /dev/null
@@ -0,0 +1,429 @@
+/*
+ * Copyright (c) 1990,1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include "lber.h"
+#include "ldap.h"
+#include "disptmpl.h"
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <syslog.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#ifdef aix
+#include <sys/select.h>
+#endif /* aix */
+#include <signal.h>
+#include "portable.h"
+#include "ldapconfig.h"
+
+#ifdef USE_SYSCONF
+#include <unistd.h>
+#endif /* USE_SYSCONF */
+
+int    dosyslog = 1;
+char   *ldaphost = LDAPHOST;
+int    ldapport = LDAP_PORT;
+char   *base = FINGER_BASE;
+int    deref;
+char   *filterfile = FILTERFILE;
+char   *templatefile = TEMPLATEFILE;
+int    rdncount = FINGER_RDNCOUNT;
+
+static do_query();
+static do_search();
+static do_read();
+static print_attr();
+
+static usage( name )
+char   *name;
+{
+       fprintf( stderr, "usage: %s [-l] [-x ldaphost] [-p ldapport] [-f filterfile] [-t templatefile] [-c rdncount]\r\n", name );
+       exit( 1 );
+}
+
+main (argc, argv)
+int    argc;
+char   **argv;
+{
+       int                     i;
+       char                    *myname;
+       unsigned long           mypeer = -1;
+       struct hostent          *hp;
+       struct sockaddr_in      peername;
+       int                     peernamelen;
+       int                     interactive = 0;
+       extern char             *optarg;
+
+       deref = FINGER_DEREF;
+       while ( (i = getopt( argc, argv, "f:ilp:t:x:p:c:" )) != EOF ) {
+               switch( i ) {
+               case 'f':       /* ldap filter file */
+                       filterfile = strdup( optarg );
+                       break;
+
+               case 'i':       /* interactive */
+                       interactive = 1;
+                       break;
+
+               case 'l':       /* don't do syslogging */
+                       dosyslog = 0;
+                       break;
+
+               case 't':       /* ldap template file */
+                       templatefile = strdup( optarg );
+                       break;
+
+               case 'x':       /* specify ldap host */
+                       ldaphost = strdup( optarg );
+                       break;
+
+               case 'p':       /* specify ldap port */
+                       ldapport = atoi( optarg );
+                       break;
+
+               case 'c':       /* specify number of DN components to show */
+                       rdncount = atoi( optarg );
+                       break;
+
+               default:
+                       usage( argv[0] );
+               }
+       }
+
+       if ( !interactive ) {
+               peernamelen = sizeof(peername);
+               if ( getpeername( 0, (struct sockaddr *)&peername,
+                   &peernamelen ) != 0 ) {
+                       perror( "getpeername" );
+                       exit( 1 );
+               }
+               mypeer = (unsigned long) peername.sin_addr.s_addr;
+       }
+
+#ifdef FINGER_BANNER
+       if ( FINGER_BANNER != NULL && strcmp( FINGER_BANNER, "" ) != 0 ) {
+               printf( FINGER_BANNER );
+               fflush( stdout );
+       }
+#endif
+
+       if ( (myname = strrchr( argv[0], '/' )) == NULL )
+               myname = strdup( argv[0] );
+       else
+               myname = strdup( myname + 1 );
+
+       if ( dosyslog ) {
+#ifdef LOG_LOCAL4
+               openlog( myname, OPENLOG_OPTIONS, LOG_LOCAL4 );
+#else
+               openlog( myname, OPENLOG_OPTIONS );
+#endif
+       }
+
+       if ( dosyslog && mypeer != -1 ) {
+               struct in_addr  addr;
+
+               hp = gethostbyaddr( (char *) &mypeer, sizeof(mypeer), AF_INET );
+               addr.s_addr = mypeer;
+               syslog( LOG_INFO, "connection from %s (%s)", (hp == NULL) ?
+                   "unknown" : hp->h_name, inet_ntoa( addr ) );
+       }
+
+       do_query();
+
+       return( 0 );
+}
+
+static do_query()
+{
+       char            buf[256];
+       int             len, rc, tblsize;
+       struct timeval  timeout;
+       fd_set          readfds;
+       LDAP            *ld;
+
+       if ( (ld = ldap_open( ldaphost, ldapport )) == NULL ) {
+               fprintf( stderr, FINGER_UNAVAILABLE );
+               perror( "ldap_open" );
+               exit( 1 );
+       }
+       ld->ld_sizelimit = FINGER_SIZELIMIT;
+       ld->ld_deref = deref;
+
+       if ( ldap_simple_bind_s( ld, FINGER_BINDDN, NULL ) != LDAP_SUCCESS ) {
+               fprintf( stderr, FINGER_UNAVAILABLE );
+               ldap_perror( ld, "ldap_simple_bind_s" );
+               exit( 1 );
+       }
+
+#ifdef USE_SYSCONF
+       tblsize = sysconf( _SC_OPEN_MAX );
+#else /* USE_SYSCONF */
+       tblsize = getdtablesize();
+#endif /* USE_SYSCONF */
+
+       timeout.tv_sec = FINGER_TIMEOUT;
+       timeout.tv_usec = 0;
+       FD_ZERO( &readfds );
+       FD_SET( fileno( stdin ), &readfds );
+
+       if ( (rc = select( tblsize, &readfds, 0, 0, &timeout )) <= 0 ) {
+               if ( rc < 0 )
+                       perror( "select" );
+               else
+                       fprintf( stderr, "connection timed out on input\r\n" );
+               exit( 1 );
+       }
+
+       if ( fgets( buf, sizeof(buf), stdin ) == NULL )
+               exit( 1 );
+
+       len = strlen( buf );
+
+       /* strip off \r \n */
+       if ( buf[len - 1] == '\n' ) {
+               buf[len - 1] = '\0';
+               len--;
+       }
+       if ( buf[len - 1] == '\r' ) {
+               buf[len - 1] = '\0';
+               len--;
+       }
+
+       if ( len == 0 ) {
+               printf( "No campus-wide login information available.  Info for this machine only:\r\n" );
+               fflush( stdout );
+               execl( FINGER_CMD, FINGER_CMD, NULL );
+       } else {
+               char    *p;
+
+               /* skip and ignore stinking /w */
+               if ( strncmp( buf, "/W ", 2 ) == 0 ) {
+                       p = buf + 2;
+               } else {
+                       p = buf;
+               }
+
+               for ( ; *p && isspace( *p ); p++ )
+                       ;       /* NULL */
+
+               do_search( ld, p );
+       }
+}
+
+static void
+spaces2dots( s )
+    char       *s;
+{
+       for ( ; *s; s++ ) {
+               if ( *s == ' ' ) {
+                       *s = '.';
+               }
+       }
+}
+
+static do_search( ld, buf )
+LDAP   *ld;
+char   *buf;
+{
+       char            *dn, *rdn;
+       char            **title;
+       int             rc, matches, i, ufn;
+       struct timeval  tv;
+       LDAPFiltInfo    *fi;
+       LDAPMessage     *result, *e;
+       static char     *attrs[] = { "cn", "title", "objectClass", "joinable",
+#ifdef FINGER_SORT_ATTR
+                                       FINGER_SORT_ATTR,
+#endif
+                                       0 };
+       extern int      strcasecmp();
+
+       ufn = 0;
+#ifdef FINGER_UFN
+       if ( strchr( buf, ',' ) != NULL ) {
+               ldap_ufn_setprefix( ld, base );
+               tv.tv_sec = FINGER_TIMEOUT;
+               tv.tv_usec = 0;
+               ldap_ufn_timeout( (void *) &tv );
+
+               if ( (rc = ldap_ufn_search_s( ld, buf, attrs, 0, &result ))
+                   != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED ) {
+                       fprintf( stderr, FINGER_UNAVAILABLE );
+                       ldap_perror( ld, "ldap_search_st" );
+                       exit( 1 );
+               }
+
+               matches = ldap_count_entries( ld, result );
+               ufn = 1;
+       } else {
+#endif
+               if ( (ld->ld_filtd = ldap_init_getfilter( filterfile ))
+                   == NULL ) {
+                       fprintf( stderr, "Cannot open filter file (%s)\n",
+                           filterfile );
+                       exit( 1 );
+               }
+
+               for ( fi = ldap_getfirstfilter( ld->ld_filtd, "finger", buf );
+                   fi != NULL;
+                   fi = ldap_getnextfilter( ld->ld_filtd ) )
+               {
+                       tv.tv_sec = FINGER_TIMEOUT;
+                       tv.tv_usec = 0;
+                       if ( (rc = ldap_search_st( ld, base, LDAP_SCOPE_SUBTREE,
+                           fi->lfi_filter, attrs, 0, &tv, &result ))
+                           != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED
+                           && rc != LDAP_TIMELIMIT_EXCEEDED )
+                       {
+                               fprintf( stderr, FINGER_UNAVAILABLE );
+                               ldap_perror( ld, "ldap_search_st" );
+                               exit( 1 );
+                       }
+
+                       if ( (matches = ldap_count_entries( ld, result )) != 0 )
+                               break;
+
+                       ldap_msgfree( result );
+                       result = NULL;
+               }
+#ifdef FINGER_UFN
+       }
+#endif
+
+       if ( rc == LDAP_SIZELIMIT_EXCEEDED ) {
+               printf( "(Partial results - a size limit was exceeded)\r\n" );
+       } else if ( rc == LDAP_TIMELIMIT_EXCEEDED ) {
+               printf( "(Partial results - a time limit was exceeded)\r\n" );
+       }
+
+       if ( matches == 0 ) {
+               printf( FINGER_NOMATCH );
+               fflush( stdout );
+       } else if ( matches < 0 ) {
+               fprintf( stderr, "error return from ldap_count_entries\r\n" );
+               exit( 1 );
+       } else if ( matches <= FINGER_LISTLIMIT ) {
+               printf( "%d %s match%s found for \"%s\":\r\n", matches,
+                   ufn ? "UFN" : fi->lfi_desc, matches > 1 ? "es" : "", buf );
+               fflush( stdout );
+
+               for ( e = ldap_first_entry( ld, result ); e != NULL; ) {
+                       do_read( ld, e );
+                       e = ldap_next_entry( ld, e );
+                       if ( e != NULL ) {
+                               printf( "--------------------\r\n" );
+                       }
+               }
+       } else {
+               printf( "%d %s matches for \"%s\":\r\n", matches,
+                   ufn ? "UFN" : fi->lfi_desc, buf );
+               fflush( stdout );
+
+#ifdef FINGER_SORT_ATTR
+               ldap_sort_entries( ld, &result, FINGER_SORT_ATTR, strcasecmp );
+#endif
+
+               for ( e = ldap_first_entry( ld, result ); e != NULL;
+                   e = ldap_next_entry( ld, e ) ) {
+                       char    *p;
+
+                       dn = ldap_get_dn( ld, e );
+                       rdn = dn;
+                       if ( (p = strchr( dn, ',' )) != NULL )
+                               *p = '\0';
+                       while ( *rdn && *rdn != '=' )
+                               rdn++;
+                       if ( *rdn )
+                               rdn++;
+
+                       /* hack attack */
+                       for ( i = 0; buf[i] != '\0'; i++ ) {
+                               if ( buf[i] == '.' || buf[i] == '_' )
+                                       buf[i] = ' ';
+                       }
+                       if ( strcasecmp( rdn, buf ) == 0 ) {
+                               char    **cn;
+                               int     i, last;
+
+                               cn = ldap_get_values( ld, e, "cn" );
+                               for ( i = 0; cn[i] != NULL; i++ ) {
+                                       last = strlen( cn[i] ) - 1;
+                                       if ( isdigit( cn[i][last] ) ) {
+                                               rdn = strdup( cn[i] );
+                                               break;
+                                       }
+                               }
+                       }
+                                       
+                       title = ldap_get_values( ld, e, "title" );
+
+                       spaces2dots( rdn );
+                       printf( "  %-20s    %s\r\n", rdn,
+                           title ? title[0] : "" );
+                       if ( title != NULL ) {
+                               for ( i = 1; title[i] != NULL; i++ )
+                                       printf( "  %-20s    %s\r\n", "",
+                                           title[i] );
+                       }
+                       fflush( stdout );
+
+                       if ( title != NULL )
+                               ldap_value_free( title );
+
+                       free( dn );
+               }
+       }
+
+       if ( result != NULL ) {
+               ldap_msgfree( result );
+       }
+       ldap_unbind( ld );
+}
+
+
+static int
+entry2textwrite( void *fp, char *buf, int len )
+{
+       return( fwrite( buf, len, 1, (FILE *)fp ) == 0 ? -1 : len );
+}
+
+
+static do_read( ld, e )
+LDAP           *ld;
+LDAPMessage    *e;
+{
+       static struct ldap_disptmpl *tmpllist;
+       static char     *defattrs[] = { "mail", NULL };
+       static char     *mailvals[] = FINGER_NOEMAIL;
+       static char     **defvals[] = { mailvals, NULL };
+
+       ldap_init_templates( templatefile, &tmpllist );
+
+       if ( ldap_entry2text_search( ld, NULL, base, e, tmpllist, defattrs,
+           defvals, entry2textwrite, (void *)stdout, "\r\n", rdncount,
+           LDAP_DISP_OPT_DOSEARCHACTIONS ) != LDAP_SUCCESS ) {
+               ldap_perror( ld, "ldap_entry2text_search" );
+               exit( 1 );
+       }
+
+       if ( tmpllist != NULL ) {
+           ldap_free_templates( tmpllist );
+       }
+}
diff --git a/clients/gopher/Make-template b/clients/gopher/Make-template
new file mode 100644 (file)
index 0000000..9c45559
--- /dev/null
@@ -0,0 +1,91 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1994 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       gopher to x.500 gateway makefile
+#
+#-----------------------------------------------------------------------------
+
+LDAPSRC        = ../..
+HDIR   = $(LDAPSRC)/include
+LDIR   = $(LDAPSRC)/libraries
+VERSIONFILE = $(LDAPSRC)/build/version
+
+SRCS   = go500.c go500gw.c detach.c setproctitle.c
+OBJS   = go500.o go500gw.o detach.o setproctitle.o
+GOOBJS = go500.o detach.o goversion.o setproctitle.o
+GWOBJS = go500gw.o detach.o gwversion.o setproctitle.o
+
+INCLUDES= -I$(HDIR)
+DEFINES        = $(DEFS)
+
+CFLAGS = $(INCLUDES) $(DEFS) $(ACFLAGS)
+LIBS   = -lldap -llber $(KRBLIBFLAG) $(KRBLIBS) $(ALIBS)
+
+DLIBS  = $(LDIR)/libldap.a $(LDIR)/liblber.a
+
+all:   go500gw go500
+
+go500gw:       gwversion.o
+       $(CC) $(ALDFLAGS) -o $@ $(GWOBJS) -L$(LDIR) $(LIBS)
+
+go500: goversion.o
+       $(CC) $(ALDFLAGS) -o $@ $(GOOBJS) -L$(LDIR) $(LIBS)
+
+goversion.c: go500.o detach.o setproctitle.o $(DLIBS)
+       $(RM) $@
+       (u=$${USER-root} v=`$(CAT) $(VERSIONFILE)` d=`$(PWD)` h=`$(HOSTNAME)` \
+       t=`$(DATE)`; $(SED) -e "s|%WHEN%|$${t}|" \
+       -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+       -e "s|%VERSION%|$${v}|" \
+       < Version.c > $@)
+
+gwversion.c: go500gw.o detach.o setproctitle.o $(DLIBS)
+       $(RM) $@
+       (u=$${USER-root} v=`$(CAT) $(VERSIONFILE)` d=`$(PWD)` h=`$(HOSTNAME)` \
+       t=`$(DATE)`; $(SED) -e "s|%WHEN%|$${t}|" \
+       -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+       -e "s|%VERSION%|$${v}|" \
+       < Versiongw.c > $@)
+
+install:       go500 go500gw go500gw.help FORCE
+       -$(MKDIR) -p $(ETCDIR)
+       $(INSTALL) $(INSTALLFLAGS) -m 755 go500 $(ETCDIR)
+       $(INSTALL) $(INSTALLFLAGS) -m 755 go500gw $(ETCDIR)
+       -$(MV) $(ETCDIR)/go500gw.help $(ETCDIR)/go500gw.help-
+       $(INSTALL) $(INSTALLFLAGS) -m 644 go500gw.help $(ETCDIR)
+
+lint:  FORCE
+       $(LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+5lint: FORCE
+       $(5LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+clean: FORCE
+       $(RM) *.o core a.out gwversion.c goversion.c go500gw go500
+
+depend:        FORCE
+       $(MKDEP) $(INCLUDES) $(DEFINES) $(SRCS)
+
+links:
+       @$(LN) .src/README .src/*.help .src/*.[ch] .
+
+# DO NOT DELETE THIS LINE -- mkdep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+go500.o: go500.c ../../include/portable.h ../../include/ldapconfig.h
+go500.o: ../../include/lber.h ../../include/ldap.h ../../include/disptmpl.h
+go500gw.o: go500gw.c ../../include/lber.h ../../include/ldap.h
+go500gw.o: ../../include/disptmpl.h ../../include/portable.h
+go500gw.o: ../../include/ldapconfig.h
+detach.o: detach.c ../../include/portable.h
+setproctitle.o: setproctitle.c
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/clients/gopher/README b/clients/gopher/README
new file mode 100644 (file)
index 0000000..1289269
--- /dev/null
@@ -0,0 +1,188 @@
+This directory contains source for two programs:
+
+       go500           A gopher index search server to X.500 gateway
+
+       go500gw         A more general gopher to X.500 gateway
+
+Both programs use the LDAP protocol to talk to X.500.  If you did not
+get this software with the U-M LDAP software distribution, you will
+need to have the LDAP libraries on hand to be able to make this software.
+The LDAP distribution is available for anonymous ftp from the host
+terminator.rs.itd.umich.edu in the x500/ directory.
+
+What you are trying to set up looks like this:
+
+ --------             -----------------            --------           --------
+| gopher |           | gopher to| LDAP |          | LDAP   |         | X.500  |
+| client |<- gophr ->| LDAP g/w | API  |<- LDAP ->| server |<- DAP ->| server |
+|________|           |__________|______|          |________|         |________|
+                       go500gw                      ldapd
+                         or
+                        go500
+
+Both go500 and go500gw can be run either from inetd or as stand-alone
+servers.
+
+go500 is useful when you always want to search a fixed portion of the X.500
+tree.  It does not let you browse around or change where you search.
+
+go500gw is useful when you want to provide a more general and flexible
+gateway from gopher to X.500.  It allows users to browse around anywhere
+in the X.500 tree, doing searches at any point.
+
+**************************************************************************
+*                            RUNNING go500                                *
+**************************************************************************
+
+1) Make and install the ldap distribution if you have not already done so:
+
+       (cd ../; make lib-only; make inst-lib)
+
+   or
+
+       (cd ../; make all; make install)
+
+   Use the second form if you don't already have an ldapd running
+   somewhere you can connect to.  Note that to make an ldap server,
+   you will need the ISODE libraries and include files.
+
+2) Tailor go500 to your site before compiling:
+
+       vi go500.c
+
+   There are a couple of things to change in go500.c:
+
+       DAPUSER - This is the DN go500 will bind to the directory as.
+               You can specify NULL if you want.
+
+       DEFAULT_BASE - This is the DN of the object below which go500
+               will conduct its search.  You typically want this to
+               be the DN or your organization.
+
+       DEFAULT_LDAPHOST - This is the host that is running the ldap
+               server.  If it's not on the localhost, you'll need to
+               change this.
+
+3) Make go500:
+
+       make
+
+4) Start the ldap daemon:
+
+       ldapd [-c dsaname]
+
+   You only need to do this if you're not already running one.
+
+5) Start go500 as a stand-alone server:
+
+       go500
+
+   or arrange to have it start from inetd:
+
+       # vi /etc/services      /* add the following line */
+       go500           5555/tcp        go500           # go500 server
+
+       # vi /etc/inetd.conf    /* add the following line */
+       go500   stream  tcp     nowait  nobody  $(ETCDIR)/go500    go500 -I
+
+       # kill -HUP <inetdpid>  /* make inetd notice the change */
+
+   where $(ETCDIR) is replaced by the ETCDIR from the top level Makefile
+   and <inetdpid> is replaced by the pid of the inetd process.
+
+6) Configure your local gopher server to have an entry for go500.
+   A sample .link file is given below, with the things you should
+   change given in <>'s:
+
+       Name=<Label of your choice>
+       Type=7
+       Port=5555
+       Path=
+       Host=<host.running.go500.here>
+
+   You may also have to restart your gopher daemon, or remove
+   the .cache file.
+
+7) Run a gopher client and try it out.
+
+**************************************************************************
+*                           RUNNING go500gw                              *
+**************************************************************************
+
+1) Make the ldap distribution if you have not already done so:
+
+       (cd ../; make lib-only)
+
+   or
+
+       (cd ../; make lib-only ldap-server)
+
+   Use the second form if you don't already have an ldapd running
+   somewhere you can connect to.  Note that to make an ldap server,
+   you will need the ISODE libraries and include files.
+
+2) Tailor go500gw to your site before compiling:
+
+       vi go500gw.c
+
+   There are a couple of things to change in go500gw.c:
+
+       GO500DN - This is the DN go500gw will bind to the directory as.
+               You can specify NULL if you want.
+
+       HELPFILE - This is the pathname of the helpfile (actually, the
+               file that's displayed when a user chooses "About the
+               Gopher to X.500 Gateway").
+
+       LDAPHOST - This is the host that is running the ldap server.
+               If it's not on the localhost, you'll need to change this.
+
+3) Make go500gw:
+
+       make
+
+4) Start the ldap daemon:
+
+       ldapd [-c dsaname]
+
+   You only need to do this if you're not already running one.
+
+5) Start go500gw either as a stand-alone server:
+
+       go500gw
+
+   or arrange to have it start from inetd:
+
+       # vi /etc/services      /* add the following line */
+       go500gw           5555/tcp        go500gw           # go500gw server
+
+       # vi /etc/inetd.conf    /* add the following line */
+       go500gw stream  tcp     nowait  nobody  $(ETCDIR)/go500gw  go500gw -I
+
+       # kill -HUP <inetdpid>  /* make inetd notice the change */
+
+   where $(ETCDIR) is replaced by the ETCDIR from the top level Makefile
+   and <inetdpid> is replaced by the pid of the inetd process.
+
+6) Configure your local gopher server to have an entry for go500gw.
+   A sample .link file is given below, with the things you should
+   change given in <>'s:
+
+       Name=<Label of your choice>
+       Type=1
+       Port=7777
+       Path=M
+       Host=<host.running.go500gw.here>
+
+   You may also have to restart your gopher daemon, or remove
+   the .cache file.
+
+   If you want to start go500gw at some point in the X.500 tree
+   other than the root, you can change the Path parameter above
+   to something like this, for example:
+
+       Path=Mo=University of Michigan,c=US
+
+   Of course, you would substitute your own organization's DN.
+
+7) Run a gopher client and try it out.
diff --git a/clients/gopher/Version.c b/clients/gopher/Version.c
new file mode 100644 (file)
index 0000000..a973d7d
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 1991 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+char Version[] = "  go500 v%VERSION% (%WHEN%)\n\t%WHOANDWHERE%\n";
diff --git a/clients/gopher/Versiongw.c b/clients/gopher/Versiongw.c
new file mode 100644 (file)
index 0000000..a3f8142
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 1991 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+char Version[] = "  go500gw 1.0 (%WHEN%)\n\t%WHOANDWHERE%\n";
diff --git a/clients/gopher/detach.c b/clients/gopher/detach.c
new file mode 100644 (file)
index 0000000..f543cc3
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 1990, 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <signal.h>
+#include "portable.h"
+
+#ifdef USE_SYSCONF
+#include <unistd.h>
+#endif /* USE_SYSCONF */
+
+detach( debug )
+int    debug;
+{
+       int     i, sd, nbits;
+
+#ifdef USE_SYSCONF
+       nbits = sysconf( _SC_OPEN_MAX );
+#else /* USE_SYSCONF */
+       nbits = getdtablesize();
+#endif /* USE_SYSCONF */
+
+       if ( debug == 0 || !(isatty( 1 )) ) {
+               for ( i = 0; i < 5; i++ ) {
+                       switch ( fork() ) {
+                       case -1:
+                               sleep( 5 );
+                               continue;
+
+                       case 0:
+                               break;
+
+                       default:
+                               _exit( 0 );
+                       }
+                       break;
+               }
+
+               for ( i = 3; i < nbits; i++ )
+                       close( i );
+
+               (void) chdir( "/" );
+
+               if ( (sd = open( "/dev/null", O_RDWR )) == -1 ) {
+                       if ( debug ) perror( "/dev/null" );
+                       exit( 1 );
+               }
+               if ( isatty( 0 ) )
+                       (void) dup2( sd, 0 );
+               if ( isatty( 1 ) )
+                       (void) dup2( sd, 1 );
+               if ( isatty(2) )
+                       (void) dup2( sd, 2 );
+               close( sd );
+
+#ifdef USE_SETSID
+               (void) setsid();
+#else /* USE_SETSID */
+               if ( (sd = open( "/dev/tty", O_RDWR )) != -1 ) {
+                       (void) ioctl( sd, TIOCNOTTY, NULL );
+                       (void) close( sd );
+               }
+#endif /* USE_SETSID */
+       } 
+
+       (void) signal( SIGPIPE, SIG_IGN );
+}
diff --git a/clients/gopher/go500.c b/clients/gopher/go500.c
new file mode 100644 (file)
index 0000000..3337876
--- /dev/null
@@ -0,0 +1,568 @@
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <syslog.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#ifdef aix
+#include <sys/select.h>
+#endif /* aix */
+#include <signal.h>
+#include "portable.h"
+#include "ldapconfig.h"
+#include "lber.h"
+#include "ldap.h"
+#include "disptmpl.h"
+
+#ifdef USE_SYSCONF
+#include <unistd.h>
+#endif /* USE_SYSCONF */
+
+int    debug;
+int    dosyslog;
+int    inetd;
+int    dtblsize;
+
+char   *ldaphost = LDAPHOST;
+char   *base = GO500_BASE;
+int    rdncount = GO500_RDNCOUNT;
+char   *filterfile = FILTERFILE;
+char   *templatefile = TEMPLATEFILE;
+
+char   myhost[MAXHOSTNAMELEN];
+int    myport;
+
+static set_socket();
+static SIG_FN wait4child();
+static do_queries();
+static do_error();
+static do_search();
+static do_read();
+extern int strcasecmp();
+
+static usage( name )
+char   *name;
+{
+       fprintf( stderr, "usage: %s [-d debuglevel] [-f filterfile] [-t templatefile]\r\n\t[-a] [-l] [-p port] [-x ldaphost] [-b searchbase] [-c rdncount]\r\n", name );
+       exit( 1 );
+}
+
+main (argc, argv)
+int    argc;
+char   **argv;
+{
+       int                     s, ns, rc;
+       int                     port = -1;
+       int                     i, pid;
+       char                    *myname;
+       fd_set                  readfds;
+       struct hostent          *hp;
+       struct sockaddr_in      from;
+       int                     fromlen;
+       SIG_FN                  wait4child();
+       extern char             *optarg;
+       extern char             **Argv;
+       extern int              Argc;
+
+       /* for setproctitle */
+        Argv = argv;
+        Argc = argc;
+
+       while ( (i = getopt( argc, argv, "b:d:f:lp:c:t:x:I" )) != EOF ) {
+               switch( i ) {
+               case 'b':       /* searchbase */
+                       base = strdup( optarg );
+                       break;
+
+               case 'd':       /* debug level */
+                       debug = atoi( optarg );
+                       break;
+
+               case 'f':       /* ldap filter file */
+                       filterfile = strdup( optarg );
+                       break;
+
+               case 'l':       /* log via LOG_LOCAL3 */
+                       dosyslog = 1;
+                       break;
+
+               case 'p':       /* port to listen to */
+                       port = atoi( optarg );
+                       break;
+
+               case 'c':       /* number of DN components to show */
+                       rdncount = atoi( optarg );
+                       break;
+
+               case 't':       /* ldap template file */
+                       templatefile = strdup( optarg );
+                       break;
+
+               case 'x':       /* ldap server hostname */
+                       ldaphost = strdup( optarg );
+                       break;
+
+               case 'I':       /* run from inetd */
+                       inetd = 1;
+                       break;
+
+               default:
+                       usage( argv[0] );
+               }
+       }
+
+#ifdef GO500_HOSTNAME
+       strcpy( myhost, GO500_HOSTNAME );
+#else
+       if ( myhost[0] == '\0' && gethostname( myhost, sizeof(myhost) )
+           == -1 ) {
+               perror( "gethostname" );
+               exit( 1 );
+       }
+#endif
+
+#ifdef USE_SYSCONF
+       dtblsize = sysconf( _SC_OPEN_MAX );
+#else /* USE_SYSCONF */
+       dtblsize = getdtablesize();
+#endif /* USE_SYSCONF */
+
+       /* detach if stderr is redirected or no debugging */
+       if ( inetd == 0 )
+               (void) detach( debug );
+
+       if ( (myname = strrchr( argv[0], '/' )) == NULL )
+               myname = strdup( argv[0] );
+       else
+               myname = strdup( myname + 1 );
+
+       if ( dosyslog ) {
+#ifdef LOG_LOCAL3
+               openlog( myname, OPENLOG_OPTIONS, LOG_LOCAL3 );
+#else
+               openlog( myname, OPENLOG_OPTIONS );
+#endif
+       }
+       if ( dosyslog )
+               syslog( LOG_INFO, "initializing" );
+
+       /* set up the socket to listen on */
+       if ( inetd == 0 ) {
+               s = set_socket( port );
+
+               /* arrange to reap children */
+               (void) signal( SIGCHLD, (void *) wait4child );
+       } else {
+               myport = GO500_PORT;
+
+               fromlen = sizeof(from);
+               if ( getpeername( 0, (struct sockaddr *) &from, &fromlen )
+                   == 0 ) {
+                       hp = gethostbyaddr( (char *) &(from.sin_addr.s_addr),
+                           sizeof(from.sin_addr.s_addr), AF_INET );
+                       Debug( LDAP_DEBUG_ARGS, "connection from %s (%s)\n",
+                           (hp == NULL) ? "unknown" : hp->h_name,
+                           inet_ntoa( from.sin_addr ), 0 );
+
+                       if ( dosyslog ) {
+                               syslog( LOG_INFO, "connection from %s (%s)",
+                                   (hp == NULL) ? "unknown" : hp->h_name,
+                                   inet_ntoa( from.sin_addr ) );
+                       }
+
+                       setproctitle( hp == NULL ? inet_ntoa( from.sin_addr ) :
+                           hp->h_name );
+               }
+
+               do_queries( 0 );
+
+               exit( 0 );
+       }
+
+       for ( ;; ) {
+               FD_ZERO( &readfds );
+               FD_SET( s, &readfds );
+
+               if ( (rc = select( dtblsize, &readfds, 0, 0 ,0 )) == -1 ) {
+                       if ( debug ) perror( "select" );
+                       continue;
+               } else if ( rc == 0 ) {
+                       continue;
+               }
+
+               if ( ! FD_ISSET( s, &readfds ) )
+                       continue;
+
+               fromlen = sizeof(from);
+               if ( (ns = accept( s, (struct sockaddr *) &from, &fromlen ))
+                   == -1 ) {
+                       if ( debug ) perror( "accept" );
+                       exit( 1 );
+               }
+
+               hp = gethostbyaddr( (char *) &(from.sin_addr.s_addr),
+                   sizeof(from.sin_addr.s_addr), AF_INET );
+
+               if ( dosyslog ) {
+                       syslog( LOG_INFO, "TCP connection from %s (%s)",
+                           (hp == NULL) ? "unknown" : hp->h_name,
+                           inet_ntoa( from.sin_addr ) );
+               }
+
+               switch( pid = fork() ) {
+               case 0:         /* child */
+                       close( s );
+                       do_queries( ns );
+                       break;
+
+               case -1:        /* failed */
+                       perror( "fork" );
+                       break;
+
+               default:        /* parent */
+                       close( ns );
+                       if ( debug )
+                               fprintf( stderr, "forked child %d\n", pid );
+                       break;
+               }
+       }
+       /* NOT REACHED */
+}
+
+static
+set_socket( port )
+int    port;
+{
+       int                     s, one;
+       struct sockaddr_in      addr;
+
+       if ( port == -1 )
+               port = GO500_PORT;
+       myport = port;
+
+       if ( (s = socket( AF_INET, SOCK_STREAM, 0 )) == -1 ) {
+                perror( "socket" );
+                exit( 1 );
+        }
+
+        /* set option so clients can't keep us from coming back up */
+       one = 1;
+        if ( setsockopt( s, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
+           sizeof(one) ) < 0 ) {
+                perror( "setsockopt" );
+                exit( 1 );
+        }
+
+        /* bind to a name */
+        addr.sin_family = AF_INET;
+        addr.sin_addr.s_addr = INADDR_ANY;
+        addr.sin_port = htons( port );
+        if ( bind( s, (struct sockaddr *) &addr, sizeof(addr) ) ) {
+                perror( "bind" );
+                exit( 1 );
+        }
+
+       /* listen for connections */
+        if ( listen( s, 5 ) == -1 ) {
+                perror( "listen" );
+                exit( 1 );
+        }
+
+        if ( debug ) printf("tcp socket allocated, bound, and listening\n");
+
+       return( s );
+}
+
+static SIG_FN
+wait4child()
+{
+        WAITSTATUSTYPE     status;
+
+        if ( debug ) printf( "parent: catching child status\n" );
+#ifdef USE_WAITPID
+       while (waitpid ((pid_t) -1, 0, WAIT_FLAGS) > 0)
+#else /* USE_WAITPID */
+        while ( wait3( &status, WAIT_FLAGS, 0 ) > 0 )
+#endif /* USE_WAITPID */
+                ;       /* NULL */
+
+       (void) signal( SIGCHLD, (void *) wait4child );
+}
+
+static
+do_queries( s )
+int    s;
+{
+       char            buf[1024], *query;
+       int             len;
+       FILE            *fp;
+       int             rc;
+       struct timeval  timeout;
+       fd_set          readfds;
+       LDAP            *ld;
+
+       if ( (fp = fdopen( s, "a+")) == NULL ) {
+               exit( 1 );
+       }
+
+       timeout.tv_sec = GO500_TIMEOUT;
+       timeout.tv_usec = 0;
+       FD_ZERO( &readfds );
+       FD_SET( fileno( fp ), &readfds );
+
+       if ( (rc = select( dtblsize, &readfds, 0, 0, &timeout )) <= 0 )
+               exit( 1 );
+
+       if ( fgets( buf, sizeof(buf), fp ) == NULL )
+               exit( 1 );
+
+       len = strlen( buf );
+       if ( debug ) {
+               fprintf( stderr, "got %d bytes\n", len );
+#ifdef LDAP_DEBUG
+               lber_bprint( buf, len );
+#endif
+       }
+
+       /* strip of \r \n */
+       if ( buf[len - 1] == '\n' )
+               buf[len - 1] = '\0';
+       len--;
+       if ( buf[len - 1] == '\r' )
+               buf[len - 1] = '\0';
+       len--;
+
+       query = buf;
+
+       /* strip off leading white space */
+       while ( isspace( *query )) {
+               ++query;
+               --len;
+       }
+
+       rewind(fp);
+
+       if ( *query != '~' && *query != '@' ) {
+               if ( (ld = ldap_open( ldaphost, LDAP_PORT )) == NULL ) {
+                       fprintf(fp,
+                           "0An error occurred (explanation)\t@%d\t%s\t%d\r\n",
+                           LDAP_SERVER_DOWN, myhost, myport );
+                       fprintf( fp, ".\r\n" );
+                       rewind(fp);
+                       exit( 1 );
+               }
+
+               ld->ld_deref = GO500_DEREF;
+               if ( (rc = ldap_simple_bind_s( ld, GO500_BINDDN, NULL ))
+                   != LDAP_SUCCESS ) {
+                       fprintf(fp,
+                           "0An error occurred (explanation)\t@%d\t%s\t%d\r\n",
+                           rc, myhost, myport );
+                       fprintf( fp, ".\r\n" );
+                       rewind(fp);
+                       exit( 1 );
+               }
+       }
+
+       switch ( *query ) {
+       case '~':
+               fprintf( fp, "The query you specified was not specific enough, causing a size limit\r\n" );
+               fprintf( fp, "to be exceeded and the first several matches found to be returned.\r\n" );
+               fprintf( fp, "If you did not find the match you were looking for, try issuing a more\r\n" );
+               fprintf( fp, "specific query, for example one that contains both first and last name.\r\n" );
+               fprintf( fp, ".\r\n" );
+               break;
+
+       case '=':
+               do_read( ld, fp, ++query );
+               break;
+
+       case '@':
+               do_error( fp, ++query );
+               break;
+
+       default:
+               do_search( ld, fp, query );
+               break;
+       }
+
+       fprintf( fp, ".\r\n" );
+       rewind(fp);
+       ldap_unbind( ld );
+
+       exit( 1 );
+       /* NOT REACHED */
+}
+
+static
+do_error( fp, s )
+FILE   *fp;
+char   *s;
+{
+       int     code;
+
+       code = atoi( s );
+
+       fprintf( fp, "An error occurred searching X.500.  The error code was %d\r\n", code );
+       fprintf( fp, "The corresponding error is: %s\r\n", ldap_err2string( code ) );
+       fprintf( fp, "No additional information is available\r\n" );
+       fprintf( fp, ".\r\n" );
+}
+
+static
+do_search( ld, fp, buf )
+LDAP   *ld;
+FILE   *fp;
+char   *buf;
+{
+       char            *dn, *rdn;
+       char            **title;
+       int             rc, matches = 0;
+       struct timeval  tv;
+       LDAPFiltInfo    *fi;
+       LDAPFiltDesc    *filtd;
+       LDAPMessage     *e, *res;
+       static char     *attrs[] = { "title", 0 };
+
+#ifdef GO500_UFN
+       if ( strchr( buf, ',' ) != NULL ) {
+               ldap_ufn_setprefix( ld, base );
+               tv.tv_sec = GO500_TIMEOUT;
+               tv.tv_usec = 0;
+               ldap_ufn_timeout( (void *) &tv );
+
+               if ( (rc = ldap_ufn_search_s( ld, buf, attrs, 0, &res ))
+                   != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED ) {
+                       fprintf(fp,
+                           "0An error occurred (explanation)\t@%d\t%s\t%d\r\n",
+                           rc, myhost, myport );
+                       return;
+               }
+
+               matches = ldap_count_entries( ld, res );
+       } else {
+#endif
+               if ( (filtd = ldap_init_getfilter( filterfile )) == NULL ) {
+                       fprintf( stderr, "Cannot open filter file (%s)\n",
+                           filterfile );
+                       exit( 1 );
+               }
+
+               tv.tv_sec = GO500_TIMEOUT;
+               tv.tv_usec = 0;
+               for ( fi = ldap_getfirstfilter( filtd, "go500", buf );
+                   fi != NULL;
+                   fi = ldap_getnextfilter( filtd ) )
+               {
+                       if ( (rc = ldap_search_st( ld, base, LDAP_SCOPE_SUBTREE,
+                           fi->lfi_filter, attrs, 0, &tv, &res ))
+                           != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED ) {
+                               fprintf(fp, "0An error occurred (explanation)\t@%d\t%s\t%d\r\n",
+                                   rc, myhost, myport );
+                               ldap_getfilter_free( filtd );
+                               return;
+                       }
+
+                       if ( (matches = ldap_count_entries( ld, res )) != 0 )
+                               break;
+               }
+               ldap_getfilter_free( filtd );
+#ifdef GO500_UFN
+       }
+#endif
+
+       if ( matches <= 0 ) {
+               return;
+       }
+
+#ifdef GO500_SORT_ATTR
+       ldap_sort_entries( ld, &res, GO500_SORT_ATTR, strcasecmp );
+#endif
+
+       for ( e = ldap_first_entry( ld, res ); e != NULL;
+           e = ldap_next_entry( ld, e ) ) {
+               char    *s;
+
+               dn = ldap_get_dn( ld, e );
+               rdn = strdup( dn );
+               if ( (s = strchr( rdn, ',' )) != NULL )
+                       *s = '\0';
+
+               if ( (s = strchr( rdn, '=' )) == NULL )
+                       s = rdn;
+               else
+                       ++s;
+
+               title = ldap_get_values( ld, e, "title" );
+
+               if ( title != NULL ) {
+                       char    *p;
+
+                       for ( p = title[0]; *p; p++ ) {
+                               if ( *p == '/' )
+                                       *p = '\\';
+                       }
+               }
+
+               fprintf( fp, "0%-20s    %s\t=%s\t%s\t%d\r\n", s,
+                   title ? title[0] : "", dn, myhost, myport );
+
+               if ( title != NULL )
+                       ldap_value_free( title );
+
+               free( rdn );
+               free( dn );
+       }
+
+       if ( ldap_result2error( ld, res, 1 ) == LDAP_SIZELIMIT_EXCEEDED ) {
+               fprintf( fp, "0A size limit was exceeded (explanation)\t~\t%s\t%d\r\n",
+                   myhost, myport );
+       }
+}
+
+static int
+entry2textwrite( void *fp, char *buf, int len )
+{
+        return( fwrite( buf, len, 1, (FILE *)fp ) == 0 ? -1 : len );
+}
+
+static
+do_read( ld, fp, dn )
+LDAP   *ld;
+FILE   *fp;
+char   *dn;
+{
+       static struct ldap_disptmpl *tmpllist;
+
+       ldap_init_templates( templatefile, &tmpllist );
+
+       if ( ldap_entry2text_search( ld, dn, base, NULL, tmpllist, NULL, NULL,
+           entry2textwrite, (void *) fp, "\r\n", rdncount,
+           LDAP_DISP_OPT_DOSEARCHACTIONS ) != LDAP_SUCCESS ) {
+               ldap_perror( ld, "ldap_entry2text_search" );
+               exit( 1 );
+       }
+
+       if ( tmpllist != NULL ) {
+               ldap_free_templates( tmpllist );
+       }
+}
diff --git a/clients/gopher/go500gw.c b/clients/gopher/go500gw.c
new file mode 100644 (file)
index 0000000..7f74fbf
--- /dev/null
@@ -0,0 +1,891 @@
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include "lber.h"
+#include "ldap.h"
+#include "disptmpl.h"
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <syslog.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <signal.h>
+#ifdef aix
+#include <sys/select.h>
+#endif /* aix */
+#include "portable.h"
+#include "ldapconfig.h"
+
+#ifdef USE_SYSCONF
+#include <unistd.h>
+#endif /* USE_SYSCONF */
+
+int    debug;
+int    dosyslog;
+int    inetd;
+int    dtblsize;
+
+char           *ldaphost = LDAPHOST;
+int            ldapport = LDAP_PORT;
+int            searchaliases = 1;
+char           *helpfile = GO500GW_HELPFILE;
+char           *filterfile = FILTERFILE;
+char           *templatefile = TEMPLATEFILE;
+char           *friendlyfile = FRIENDLYFILE;
+int            rdncount = GO500GW_RDNCOUNT;
+
+static set_socket();
+static SIG_FN wait4child();
+static do_queries();
+static do_menu();
+static do_list();
+static do_search();
+static do_read();
+static do_help();
+static do_sizelimit();
+static do_error();
+extern int strcasecmp();
+
+char   myhost[MAXHOSTNAMELEN];
+int    myport = GO500GW_PORT;
+
+static usage( name )
+char   *name;
+{
+       fprintf( stderr, "usage: %s [-d debuglevel] [-I] [-p port] [-P ldapport] [-l]\r\n\t[-x ldaphost] [-a] [-h helpfile] [-f filterfile] [-t templatefile] [-c rdncount]\r\n", name );
+       exit( 1 );
+}
+
+main (argc, argv)
+int    argc;
+char   **argv;
+{
+       int                     s, ns, rc;
+       int                     port = -1;
+       int                     i, pid;
+       char                    *myname;
+       fd_set                  readfds;
+       struct hostent          *hp;
+       struct sockaddr_in      from;
+       int                     fromlen;
+       SIG_FN                  wait4child();
+       extern char             *optarg;
+       extern char             **Argv;
+       extern int              Argc;
+
+       /* for setproctitle */
+        Argv = argv;
+        Argc = argc;
+
+       while ( (i = getopt( argc, argv, "P:ad:f:h:lp:t:x:Ic:" )) != EOF ) {
+               switch( i ) {
+               case 'a':       /* search aliases */
+                       searchaliases = 0;
+                       break;
+
+               case 'd':       /* debugging level */
+                       debug = atoi( optarg );
+#ifdef LDAP_DEBUG
+                       ldap_debug = debug;
+#else
+                       fprintf( stderr, "warning: ldap debugging requires LDAP_DEBUG\n" );
+#endif
+                       break;
+
+               case 'f':       /* ldap filter file */
+                       filterfile = strdup( optarg );
+                       break;
+
+               case 'h':       /* gopher help file */
+                       helpfile = strdup( optarg );
+                       break;
+
+               case 'l':       /* log to LOG_LOCAL3 */
+                       dosyslog = 1;
+                       break;
+
+               case 'p':       /* port to listen on */
+                       port = atoi( optarg );
+                       break;
+
+               case 'P':       /* port to connect to ldap server */
+                       ldapport = atoi( optarg );
+                       break;
+
+               case 't':       /* ldap template file */
+                       templatefile = strdup( optarg );
+                       break;
+
+               case 'x':       /* ldap server hostname */
+                       ldaphost = strdup( optarg );
+                       break;
+
+               case 'I':       /* run from inetd */
+                       inetd = 1;
+                       break;
+
+               case 'c':       /* count of DN components to show */
+                       rdncount = atoi( optarg );
+                       break;
+
+               default:
+                       usage( argv[0] );
+               }
+       }
+
+#ifdef USE_SYSCONF
+       dtblsize = sysconf( _SC_OPEN_MAX );
+#else /* USE_SYSCONF */
+       dtblsize = getdtablesize();
+#endif /* USE_SYSCONF */
+
+#ifdef GO500GW_HOSTNAME
+       strcpy( myhost, GO500GW_HOSTNAME );
+#else
+       if ( myhost[0] == '\0' && gethostname( myhost, sizeof(myhost) )
+           == -1 ) {
+               perror( "gethostname" );
+               exit( 1 );
+       }
+#endif
+
+       /* detach if stderr is redirected or no debugging */
+       if ( inetd == 0 )
+               (void) detach( debug );
+
+       if ( (myname = strrchr( argv[0], '/' )) == NULL )
+               myname = strdup( argv[0] );
+       else
+               myname = strdup( myname + 1 );
+
+       if ( dosyslog ) {
+#ifdef LOG_LOCAL3
+               openlog( myname, OPENLOG_OPTIONS, LOG_LOCAL3 );
+#else
+               openlog( myname, OPENLOG_OPTIONS );
+#endif
+       }
+       if ( dosyslog )
+               syslog( LOG_INFO, "initializing" );
+
+       /* set up the socket to listen on */
+       if ( inetd == 0 ) {
+               s = set_socket( port );
+
+               /* arrange to reap children */
+               (void) signal( SIGCHLD, (void *) wait4child );
+       }
+
+       if ( inetd ) {
+               fromlen = sizeof(from);
+               if ( getpeername( 0, (struct sockaddr *) &from, &fromlen )
+                   == 0 ) {
+                       hp = gethostbyaddr( (char *) &(from.sin_addr.s_addr),
+                           sizeof(from.sin_addr.s_addr), AF_INET );
+                       Debug( LDAP_DEBUG_ARGS, "connection from %s (%s)\n",
+                           (hp == NULL) ? "unknown" : hp->h_name,
+                           inet_ntoa( from.sin_addr ), 0 );
+
+                       if ( dosyslog ) {
+                               syslog( LOG_INFO, "connection from %s (%s)",
+                                   (hp == NULL) ? "unknown" : hp->h_name,
+                                   inet_ntoa( from.sin_addr ) );
+                       }
+
+                       setproctitle( hp == NULL ? inet_ntoa( from.sin_addr ) :
+                           hp->h_name );
+               }
+
+               do_queries( 0 );
+
+               close( 0 );
+
+               exit( 0 );
+       }
+
+       for ( ;; ) {
+               FD_ZERO( &readfds );
+               FD_SET( s, &readfds );
+
+               if ( (rc = select( dtblsize, &readfds, 0, 0 ,0 )) == -1 ) {
+                       if ( debug ) perror( "select" );
+                       continue;
+               } else if ( rc == 0 ) {
+                       continue;
+               }
+
+               if ( ! FD_ISSET( s, &readfds ) )
+                       continue;
+
+               fromlen = sizeof(from);
+               if ( (ns = accept( s, (struct sockaddr *) &from, &fromlen ))
+                   == -1 ) {
+                       if ( debug ) perror( "accept" );
+                       exit( 1 );
+               }
+
+               hp = gethostbyaddr( (char *) &(from.sin_addr.s_addr),
+                   sizeof(from.sin_addr.s_addr), AF_INET );
+
+               if ( dosyslog ) {
+                       syslog( LOG_INFO, "TCP connection from %s (%s)",
+                           (hp == NULL) ? "unknown" : hp->h_name,
+                           inet_ntoa( from.sin_addr ) );
+               }
+
+               switch( pid = fork() ) {
+               case 0:         /* child */
+                       close( s );
+                       do_queries( ns );
+                       break;
+
+               case -1:        /* failed */
+                       perror( "fork" );
+                       break;
+
+               default:        /* parent */
+                       close( ns );
+                       if ( debug )
+                               fprintf( stderr, "forked child %d\n", pid );
+                       break;
+               }
+       }
+       /* NOT REACHED */
+}
+
+static set_socket( port )
+int    port;
+{
+       int                     s, one;
+       struct sockaddr_in      addr;
+
+       if ( port == -1 )
+               port = GO500GW_PORT;
+       myport = port;
+
+       if ( (s = socket( AF_INET, SOCK_STREAM, 0 )) == -1 ) {
+                perror( "socket" );
+                exit( 1 );
+        }
+
+        /* set option so clients can't keep us from coming back up */
+       one = 1;
+        if ( setsockopt( s, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
+           sizeof(one) ) < 0 ) {
+                perror( "setsockopt" );
+                exit( 1 );
+        }
+
+        /* bind to a name */
+        addr.sin_family = AF_INET;
+        addr.sin_addr.s_addr = INADDR_ANY;
+        addr.sin_port = htons( port );
+        if ( bind( s, (struct sockaddr *) &addr, sizeof(addr) ) ) {
+                perror( "bind" );
+                exit( 1 );
+        }
+
+       /* listen for connections */
+        if ( listen( s, 5 ) == -1 ) {
+                perror( "listen" );
+                exit( 1 );
+        }
+
+        if ( debug )
+               printf( "go500gw listening on port %d\n", port );
+
+       return( s );
+}
+
+static SIG_FN
+wait4child()
+{
+        WAITSTATUSTYPE     status;
+
+        if ( debug ) printf( "parent: catching child status\n" );
+#ifdef USE_WAITPID
+       while (waitpid ((pid_t) -1, 0, WAIT_FLAGS) > 0)
+#else /* USE_WAITPID */
+        while ( wait3( &status, WAIT_FLAGS, 0 ) > 0 )
+#endif /* USE_WAITPID */
+                ;       /* NULL */
+
+       (void) signal( SIGCHLD, (void *) wait4child );
+}
+
+static do_queries( s )
+int    s;
+{
+       char            buf[1024], *query;
+       int             len;
+       FILE            *fp;
+       int             rc;
+       struct timeval  timeout;
+       fd_set          readfds;
+       LDAP            *ld;
+
+       if ( (fp = fdopen( s, "a+")) == NULL ) {
+               perror( "fdopen" );
+               exit( 1 );
+       }
+
+       timeout.tv_sec = GO500GW_TIMEOUT;
+       timeout.tv_usec = 0;
+       FD_ZERO( &readfds );
+       FD_SET( fileno( fp ), &readfds );
+
+       if ( (rc = select( dtblsize, &readfds, 0, 0, &timeout )) <= 0 )
+               exit( 1 );
+
+       if ( fgets( buf, sizeof(buf), fp ) == NULL )
+               exit( 1 );
+
+       len = strlen( buf );
+       if ( debug ) {
+               fprintf( stderr, "got %d bytes\n", len );
+#ifdef LDAP_DEBUG
+               lber_bprint( buf, len );
+#endif
+       }
+
+       /* strip of \r \n */
+       if ( buf[len - 1] == '\n' )
+               buf[len - 1] = '\0';
+       len--;
+       if ( buf[len - 1] == '\r' )
+               buf[len - 1] = '\0';
+       len--;
+
+       query = buf;
+
+       /* strip off leading white space */
+       while ( isspace( *query )) {
+               ++query;
+               --len;
+       }
+
+       rewind(fp);
+
+       if ( *query == 'H' || *query == 'L' || *query == 'E' ) {
+               switch ( *query++ ) {
+               case 'H':       /* help file */
+                       do_help( fp );
+                       break;
+
+               case 'L':       /* size limit explanation */
+                       do_sizelimit( fp, *query );
+                       break;
+
+               case 'E':       /* error explanation */
+                       do_error( fp, query );
+                       break;
+               }
+
+               fprintf( fp, ".\r\n" );
+               rewind(fp);
+
+               exit( 0 );
+               /* NOT REACHED */
+       }
+
+       if ( (ld = ldap_open( ldaphost, ldapport )) == NULL ) {
+               if ( debug ) perror( "ldap_open" );
+               fprintf(fp, "0An error occurred (explanation)\tE%d\t%s\t%d\r\n",
+                   LDAP_SERVER_DOWN, myhost, myport );
+               fprintf( fp, ".\r\n" );
+               rewind(fp);
+               exit( 1 );
+       }
+
+       ld->ld_deref = LDAP_DEREF_ALWAYS;
+       if ( !searchaliases )
+               ld->ld_deref = LDAP_DEREF_FINDING;
+
+       if ( (rc = ldap_simple_bind_s( ld, GO500GW_BINDDN, NULL ))
+           != LDAP_SUCCESS ) {
+               if ( debug ) ldap_perror( ld, "ldap_simple_bind_s" );
+               fprintf(fp, "0An error occurred (explanation)\tE%d\t%s\t%d\r\n",
+                   rc, myhost, myport );
+               fprintf( fp, ".\r\n" );
+               rewind(fp);
+               exit( 1 );
+       }
+
+       switch ( *query++ ) {
+       case 'R':       /* read an entry */
+               do_read( ld, fp, query );
+               break;
+
+       case 'S':       /* search */
+               do_search( ld, fp, query, 1 );
+               break;
+
+       case 'M':       /* X.500 menu */
+               do_menu( ld, fp, query );
+               break;
+
+       default:
+               do_menu( ld, fp, "" );
+               break;
+       }
+
+       fprintf( fp, ".\r\n" );
+       rewind(fp);
+
+       exit( 0 );
+       /* NOT REACHED */
+}
+
+static char *pick_oc( oclist )
+char   **oclist;
+{
+       int     i;
+
+       if ( oclist == NULL )
+               return( "unknown" );
+
+       for ( i = 0; oclist[i] != NULL; i++ ) {
+               if ( strcasecmp( oclist[i], "top" ) != 0 &&
+                   strcasecmp( oclist[i], "quipuObject" ) != 0 &&
+                   strcasecmp( oclist[i], "quipuNonLeafObject" ) != 0 )
+                       return( oclist[i] );
+       }
+
+       return( "unknown" );
+}
+
+static isnonleaf( ld, oclist, dn )
+LDAP   *ld;
+char   **oclist;
+char   *dn;
+{
+       int     i, quipuobject = 0;
+
+       if ( oclist == NULL )
+               return( 0 );
+
+       for ( i = 0; oclist[i] != NULL; i++ ) {
+               if ( strcasecmp( oclist[i], "quipuObject" ) == 0 )
+                       quipuobject = 1;
+               if ( strcasecmp( oclist[i], "quipuNonLeafObject" ) == 0 ||
+                   strcasecmp( oclist[i], "externalNonLeafObject" ) == 0 )
+                       return( 1 );
+       }
+
+       /*
+        * not a quipu thang - no easy way to tell leaves from nonleaves
+        * except by trying to search or list.  ldap only lets us search.
+        */
+
+       /* expensive - just guess for now */
+       return( quipuobject ? 0 : 1 );
+
+#ifdef notdef
+       if ( !quipuobject ) {
+               int             rc, numentries;
+               struct timeval  timeout;
+               LDAPMessage     *res = NULL;
+               static char     *attrs[] = { "objectClass", 0 };
+
+               timeout.tv_sec = GO500GW_TIMEOUT;
+               timeout.tv_usec = 0;
+               ld->ld_sizelimit = 1;
+               if ( (rc = ldap_search_st( ld, dn, LDAP_SCOPE_ONELEVEL,
+                   "(objectClass=*)", attrs, 0, &timeout, &res ))
+                   == LDAP_SUCCESS || rc == LDAP_SIZELIMIT_EXCEEDED ) {
+                       ld->ld_sizelimit = LDAP_NO_LIMIT;
+
+                       numentries = ldap_count_entries( ld, res );
+                       if ( res != NULL )
+                               ldap_msgfree( res );
+                       return( numentries == 1 ? 1 : 0 );
+               }
+       }
+
+       return( 0 );
+#endif
+}
+
+static do_menu( ld, fp, dn )
+LDAP   *ld;
+FILE   *fp;
+char   *dn;
+{
+       char            **s;
+       char            *rdn = NULL;
+       FriendlyMap     *fm = NULL;
+
+       if ( strcmp( dn, "" ) != 0 ) {
+               s = ldap_explode_dn( dn, 1 );
+
+               if ( s[1] == NULL )
+                       rdn = ldap_friendly_name( friendlyfile, s[0], &fm );
+               else
+                       rdn = s[0];
+               fprintf( fp, "0Read %s entry\tR%s\t%s\t%d\r\n", rdn ? rdn: s[0],
+                   dn, myhost, myport );
+
+               ldap_value_free( s );
+       } else {
+               fprintf( fp, "0About the Gopher to X.500 Gateway\tH\t%s\t%d\r\n",
+                   myhost, myport );
+       }
+
+       fprintf( fp, "7Search %s\tS%s\t%s\t%d\r\n", rdn ? rdn : "root", dn,
+           myhost, myport );
+
+       do_list( ld, fp, dn );
+
+       ldap_free_friendlymap( &fm );
+}
+
+static do_list( ld, fp, dn )
+LDAP   *ld;
+FILE   *fp;
+char   *dn;
+{
+       int             rc;
+       LDAPMessage     *e, *res;
+       struct timeval  timeout;
+       FriendlyMap     *fm = NULL;
+       static char     *attrs[] = { "objectClass", 0 };
+
+       timeout.tv_sec = GO500GW_TIMEOUT;
+       timeout.tv_usec = 0;
+       ld->ld_deref = LDAP_DEREF_FINDING;
+       if ( (rc = ldap_search_st( ld, dn, LDAP_SCOPE_ONELEVEL,
+           "(!(objectClass=dSA))", attrs, 0, &timeout, &res )) != LDAP_SUCCESS
+           && rc != LDAP_SIZELIMIT_EXCEEDED ) {
+               fprintf(fp, "0An error occurred (explanation)\tE%d\t%s\t%d\r\n",
+                   rc, myhost, myport );
+               return;
+       }
+       ld->ld_deref = LDAP_DEREF_ALWAYS;
+
+       if ( ldap_count_entries( ld, res ) < 1 ) {
+               return;
+       }
+
+#ifdef GO500GW_SORT_ATTR
+       ldap_sort_entries( ld, &res, GO500GW_SORT_ATTR, strcasecmp );
+#endif
+
+       fm = NULL;
+       for ( e = ldap_first_entry( ld, res ); e != NULL;
+           e = ldap_next_entry( ld, e ) ) {
+               char    **s, **oc;
+               char    *rdn, *doc;
+
+               dn = ldap_get_dn( ld, e );
+               s = ldap_explode_dn( dn, 1 );
+               oc = ldap_get_values( ld, e, "objectClass" );
+
+               doc = pick_oc( oc );
+               if ( strcasecmp( doc, "country" ) == 0 ) {
+                       rdn = ldap_friendly_name( friendlyfile, s[0], &fm );
+               } else {
+                       rdn = s[0];
+               }
+               if ( rdn == NULL ) {
+                       rdn = s[0];
+               }
+
+               if ( strncasecmp( rdn, "{ASN}", 5 ) != 0 ) {
+                       if ( isnonleaf( ld, oc, dn ) ) {
+                               fprintf( fp, "1%s (%s)\tM%s\t%s\t%d\r\n", rdn,
+                                   doc, dn, myhost, myport );
+                       } else {
+                               fprintf( fp, "0%s (%s)\tR%s\t%s\t%d\r\n", rdn,
+                                   doc, dn, myhost, myport );
+                       }
+               }
+
+               free( dn );
+               ldap_value_free( s );
+               ldap_value_free( oc );
+       }
+       ldap_free_friendlymap( &fm );
+
+       if ( ldap_result2error( ld, res, 1 ) == LDAP_SIZELIMIT_EXCEEDED ) {
+               fprintf( fp, "0A size limit was exceeded (explanation)\tLL\t%s\t%d\r\n",
+                   myhost, myport );
+       }
+}
+
+static isoc( ocl, oc )
+char   **ocl;
+char   *oc;
+{
+       int     i;
+
+       for ( i = 0; ocl[i] != NULL; i++ ) {
+               if ( strcasecmp( ocl[i], oc ) == 0 )
+                       return( 1 );
+       }
+
+       return( 0 );
+}
+
+static int make_scope( ld, dn )
+LDAP   *ld;
+char   *dn;
+{
+       int             scope;
+       char            **oc;
+       LDAPMessage     *res;
+       struct timeval  timeout;
+       static char     *attrs[] = { "objectClass", 0 };
+
+       if ( strcmp( dn, "" ) == 0 )
+               return( LDAP_SCOPE_ONELEVEL );
+
+       timeout.tv_sec = GO500GW_TIMEOUT;
+       timeout.tv_usec = 0;
+       if ( ldap_search_st( ld, dn, LDAP_SCOPE_BASE, "objectClass=*",
+           attrs, 0, &timeout, &res ) != LDAP_SUCCESS ) {
+               return( -1 );
+       }
+
+       oc = ldap_get_values( ld, ldap_first_entry( ld, res ), "objectClass" );
+
+       if ( isoc( oc, "organization" ) || isoc( oc, "organizationalUnit" ) )
+               scope = LDAP_SCOPE_SUBTREE;
+       else
+               scope = LDAP_SCOPE_ONELEVEL;
+
+       ldap_value_free( oc );
+       ldap_msgfree( res );
+
+       return( scope );
+}
+
+static do_search( ld, fp, query )
+LDAP   *ld;
+FILE   *fp;
+char   *query;
+{
+       int             scope;
+       char            *base, *filter;
+       char            *filtertype;
+       int             count, rc;
+       struct timeval  timeout;
+       LDAPFiltInfo    *fi;
+       LDAPMessage     *e, *res;
+       LDAPFiltDesc    *filtd;
+       static char     *attrs[] = { "objectClass", 0 };
+
+       if ( (filter = strchr( query, '\t' )) == NULL ) {
+               fprintf( fp, "3Missing filter!\r\n" );
+               exit( 1 );
+       }
+       *filter++ = '\0';
+       base = query;
+
+#ifdef GO500GW_UFN
+       if ( strchr( filter, ',' ) != NULL ) {
+               ldap_ufn_setprefix( ld, base );
+               timeout.tv_sec = GO500GW_TIMEOUT;
+               timeout.tv_usec = 0;
+               ldap_ufn_timeout( (void *) &timeout );
+               ld->ld_deref = LDAP_DEREF_FINDING;
+
+               if ( (rc = ldap_ufn_search_s( ld, filter, attrs, 0, &res ))
+                   != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED ) {
+                       fprintf(fp,
+                           "0An error occurred (explanation)\t@%d\t%s\t%d\r\n",
+                           rc, myhost, myport );
+                       return;
+               }
+
+               count = ldap_count_entries( ld, res );
+       } else {
+#endif
+               if ( (scope = make_scope( ld, base )) == -1 ) {
+                       fprintf( fp, "3Bad scope\r\n" );
+                       exit( 1 );
+               }
+
+               filtertype = (scope == LDAP_SCOPE_ONELEVEL ?
+                   "go500gw onelevel" : "go500gw subtree");
+               ld->ld_deref = (scope == LDAP_SCOPE_ONELEVEL ?
+                   LDAP_DEREF_FINDING : LDAP_DEREF_ALWAYS);
+               timeout.tv_sec = GO500GW_TIMEOUT;
+               timeout.tv_usec = 0;
+
+               if ( (filtd = ldap_init_getfilter( filterfile )) == NULL ) {
+                       fprintf( stderr, "Cannot open filter file (%s)\n",
+                           filterfile );
+                       exit( 1 );
+               }
+
+               count = 0;
+               res = NULL;
+               for ( fi = ldap_getfirstfilter( filtd, filtertype, filter );
+                   fi != NULL; fi = ldap_getnextfilter( filtd ) )
+               {
+                       if ( (rc = ldap_search_st( ld, base, scope,
+                           fi->lfi_filter, attrs, 0, &timeout, &res ))
+                           != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED ) {
+                               fprintf(fp, "0An error occurred (explanation)\tE%d\t%s\t%d\r\n",
+                                   rc, myhost, myport );
+                               return( 1 );
+                       }
+                       if ( (count = ldap_count_entries( ld, res )) != 0 )
+                               break;
+               }
+               ld->ld_deref = LDAP_DEREF_ALWAYS;
+               ldap_getfilter_free( filtd );
+#ifdef GO500GW_UFN
+       }
+#endif
+
+       if ( count == 0 ) {
+               return( 0 );
+       }
+
+       if ( count == 1 ) {
+               char    *dn, **s, **oc;
+               int     rc;
+
+               e = ldap_first_entry( ld, res );
+               oc = ldap_get_values( ld, e, "objectClass" );
+               if ( isnonleaf( ld, oc, dn ) ) {
+                       dn = ldap_get_dn( ld, e );
+
+                       rc = do_menu( ld, fp, dn );
+
+                       free( dn );
+                       return( rc );
+               }
+
+               ldap_value_free( oc );
+       }
+
+#ifdef GO500GW_SORT_ATTR
+       ldap_sort_entries( ld, &res, GO500GW_SORT_ATTR, strcasecmp );
+#endif
+
+       for ( e = ldap_first_entry( ld, res ); e != NULL;
+           e = ldap_next_entry( ld, e ) ) {
+               char    **s, **oc;
+               char    *dn;
+
+               dn = ldap_get_dn( ld, e );
+               s = ldap_explode_dn( dn, 1 );
+               oc = ldap_get_values( ld, e, "objectClass" );
+
+               if ( isnonleaf( ld, oc, dn ) )
+                       fprintf( fp, "1%s (%s)\tM%s\t%s\t%d\r\n", s[0],
+                           pick_oc( oc ), dn, myhost, myport );
+               else
+                       fprintf( fp, "0%s (%s)\tR%s\t%s\t%d\r\n", s[0],
+                           pick_oc( oc ), dn, myhost, myport );
+
+               free( dn );
+               ldap_value_free( s );
+               ldap_value_free( oc );
+       }
+
+       if ( ldap_result2error( ld, res, 1 ) == LDAP_SIZELIMIT_EXCEEDED ) {
+               fprintf( fp, "0A size limit was exceeded (explanation)\tLS\t%s\t%d\r\n",
+                   myhost, myport );
+       }
+}
+
+
+static int
+entry2textwrite( void *fp, char *buf, int len )
+{
+        return( fwrite( buf, len, 1, (FILE *)fp ) == 0 ? -1 : len );
+}
+
+static do_read( ld, fp, dn )
+LDAP   *ld;
+FILE   *fp;
+char   *dn;
+{
+       static struct ldap_disptmpl *tmpllist;
+
+       ldap_init_templates( templatefile, &tmpllist );
+
+       if ( ldap_entry2text_search( ld, dn, NULL, NULL, tmpllist, NULL, NULL,
+           entry2textwrite,(void *) fp, "\r\n", rdncount, 0 )
+           != LDAP_SUCCESS ) {
+               fprintf(fp,
+                   "0An error occurred (explanation)\t@%d\t%s\t%d\r\n",
+                   ld->ld_errno, myhost, myport );
+       }
+
+       if ( tmpllist != NULL ) {
+               ldap_free_templates( tmpllist );
+       }
+}
+
+static do_help( op )
+FILE   *op;
+{
+       FILE    *fp;
+       char    line[BUFSIZ];
+
+       if ( (fp = fopen( helpfile, "r" )) == NULL ) {
+               fprintf( op, "Cannot access helpfile (%s)\r\n", helpfile );
+               return;
+       }
+
+       while ( fgets( line, sizeof(line), fp ) != NULL ) {
+               line[ strlen( line ) - 1 ] = '\0';
+
+               fprintf( op, "%s\r\n", line );
+       }
+
+       fclose( fp );
+}
+
+static do_sizelimit( fp, type )
+FILE   *fp;
+char   type;
+{
+       if ( type == 'S' ) {
+               fprintf( fp, "The query you specified was not specific enough, causing a size limit\r\n" );
+               fprintf( fp, "to be exceeded and the first several matches found to be returned.\r\n" );
+               fprintf( fp, "If you did not find the match you were looking for, try issuing a more\r\n" );
+               fprintf( fp, "specific query, for example one that contains both first and last name.\r\n" );
+       } else {
+               fprintf( fp, "Not all entries could be returned because a size limit was exceeded.\r\n" );
+               fprintf( fp, "There is no way to defeat this feature, but if you know who you are\r\n" );
+               fprintf( fp, "looking for, try choosing the \"Search\" option listed above and\r\n" );
+               fprintf( fp, "specifying the name of the person you want.\r\n" );
+       }
+       fprintf( fp, ".\r\n" );
+}
+
+static do_error( fp, s )
+FILE   *fp;
+char   *s;
+{
+       int     code;
+
+       code = atoi( s );
+
+       fprintf( fp, "An error occurred searching X.500.  The error code was %d\r\n", code );
+       fprintf( fp, "The corresponding error is: %s\r\n", ldap_err2string( code ) );
+       fprintf( fp, "No additional information is available\r\n" );
+       fprintf( fp, ".\r\n" );
+}
diff --git a/clients/gopher/go500gw.help b/clients/gopher/go500gw.help
new file mode 100644 (file)
index 0000000..dd6106e
--- /dev/null
@@ -0,0 +1,17 @@
+This is a second pass at a general Gopher to X.500 gateway.  It is
+somewhat tailored to white pages usage, but is pretty general.
+
+There are two modes of operation that the gateway supports: browsing
+and searching.  To browse, simply choose one of the countries,
+organizations, etc. that appear in gopher as menu items.  The next
+level of the X.500 DIT will then be displayed.  To search, choose the
+search item (second choice in all menus) and type the name of whatever
+it is you're looking for.  At the upper levels of the tree (i.e. root
+or country level) searches are assumed to be for organizations or
+localities and are one-level in scope.  At the lower levels of the tree
+(i.e. organization or organizationalunit level) searches are assumed to
+be for people and are subtree in scope.  What sort of search is done
+depends on what you type, but a variety of things are tried.
+
+If you have comments, suggestions or questions about this service,
+please send mail to x500@umich.edu.            -- Tim Howes 8/25/93
diff --git a/clients/gopher/setproctitle.c b/clients/gopher/setproctitle.c
new file mode 100644 (file)
index 0000000..26b42c0
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1990,1991 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+char   **Argv;         /* pointer to original (main's) argv */
+int    Argc;           /* original argc */
+
+/*
+ * takes a printf-style format string (fmt) and up to three parameters (a,b,c)
+ * this clobbers the original argv...
+ */
+
+/* VARARGS */
+setproctitle( fmt, a, b, c )
+char *fmt;
+{
+       static char *endargv = (char *)0;
+       char    *s;
+       int             i;
+       char    buf[ 1024 ];
+
+       if ( endargv == (char *)0 ) {
+               /* set pointer to end of original argv */
+               endargv = Argv[ Argc-1 ] + strlen( Argv[ Argc-1 ] );
+       }
+       sprintf( buf, fmt, a, b, c );
+       /* make ps print "([prog name])" */
+       s = Argv[0];
+       *s++ = '-';
+       i = strlen( buf );
+       if ( i > endargv - s - 2 ) {
+               i = endargv - s - 2;
+               buf[ i ] = '\0';
+       }
+       strcpy( s, buf );
+       s += i;
+       while ( s < endargv ) *s++ = ' ';
+}
diff --git a/clients/mail500/Make-template b/clients/mail500/Make-template
new file mode 100644 (file)
index 0000000..bdac2a2
--- /dev/null
@@ -0,0 +1,68 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1994 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       X.500 ldap mailer makefile
+#
+#-----------------------------------------------------------------------------
+LDAPSRC        = ../..
+HDIR   = $(LDAPSRC)/include
+LDIR   = $(LDAPSRC)/libraries
+VERSIONFILE = $(LDAPSRC)/build/version
+
+SRCS   = main.c
+OBJS   = main.o
+
+INCLUDES= -I$(HDIR)
+DEFINES        = $(DEFS)
+
+CFLAGS = $(INCLUDES) $(DEFINES) $(ACFLAGS)
+LDFLAGS        = -L$(LDIR)
+LIBS   = -lldap -llber $(KRBLIBFLAG) $(KRBLIBS) $(ALIBS)
+
+all:   mail500
+
+mail500:       version.o
+       $(CC) $(ALDFLAGS) -o $@ $(OBJS) version.o $(LDFLAGS) $(LIBS)
+
+version.c: $(OBJS) $(LDIR)/libldap/libldap.a
+       $(RM) $@
+       (u=$${USER-root} v=`$(CAT) $(VERSIONFILE)` d=`$(PWD)` h=`$(HOSTNAME)` \
+       t=`$(DATE)`; $(SED) -e "s|%WHEN%|$${t}|" \
+       -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+       -e "s|%VERSION%|$${v}|" \
+       < Version.c > $@)
+
+install:       mail500 FORCE
+       -$(MKDIR) -p $(ETCDIR)
+       $(INSTALL) $(INSTALLFLAGS) -m 755 mail500 $(ETCDIR)
+
+lint:  FORCE
+       $(LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+5lint: FORCE
+       $(5LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+clean: FORCE
+       $(RM) *.o core a.out version.c mail500
+
+depend:        FORCE
+       $(MKDEP) $(INCLUDES) $(DEFINES) $(SRCS)
+
+links:
+       @$(LN) .src/README .src/sendmail.cf .src/*.[ch] .
+
+# DO NOT DELETE THIS LINE -- mkdep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+main.o: main.c ../../include/portable.h ../../include/lber.h
+main.o: ../../include/ldap.h ../../include/ldapconfig.h
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/clients/mail500/README b/clients/mail500/README
new file mode 100644 (file)
index 0000000..57e7dd1
--- /dev/null
@@ -0,0 +1,186 @@
+This is the README file for mail500, a mailer that does X.500 lookups
+via LDAP.
+
+If you are planning to run mail500 at your site, there are several
+things you will have to tailor in main.c:
+
+       LDAPHOST - The host running an LDAP server
+
+       base[] - The array telling mail500 where/how to search for
+               things.  See the explanation below.
+
+*** WHAT mail500 DOES: ***
+
+mail500 is designed to be invoked as a mailer (e.g., from sendmail),
+similar to the way /bin/mail works.  It takes a few required arguments
+and then a list of addresses to deliver to.  It expects to find the
+message to deliver on its standard input.  It looks up the addresses in
+X.500 to figure out where to route the mail, and then execs sendmail to
+do the actual delivery.  It supports simple aliases, groups, and
+mailing lists, the details of which are given below.
+
+*** HOW IT WORKS (from the sendmail side): ***
+
+The idea is that you might have a rule like this in your sendmail.cf
+file somewhere in rule set 0:
+
+R$*<@umich.edu>$*      $#mail500$@umich.edu$:<$1>
+
+This rule says that any address that ends in @umich.edu will cause
+the mail500 mailer to be called to deliver the mail.  You probably
+also want to do something to prevent addresses like terminator!tim@umich.edu
+or tim%terminator.rs.itd.umich.edu@umich.edu from being passed to mail500.
+At U-M, we do this by adding rules like this to rule set 9 where we
+strip off our local names:
+
+R<@umich.edu>$*:$*                 $>10<@>$1:$2
+R$+%$+<@umich.edu>                 $>10$1%$2<@>
+R$+!$+<@umich.edu>                 $>10$1!$2<@>
+
+See the sample sendmail.cf in this directory for more details.
+
+The mail500 mailer should be defined similar to this in the
+sendmail.cf file:
+
+Mmail500, P=/usr/local/etc/mail500, F=DFMSmnXuh, A=mail500 -f $f -h $h -m $n@$w $u
+
+This defines how mail500 will be treated by sendmail and what
+arguments it will have when it's called.  The various flags specified
+by the F=... parameter are explained in your local sendmail book (with
+any luck).  The arguments to mail500 are as follows:
+
+       -f      Who the mail is from.  This will be used as the address
+               to which any errors should be sent (unless the address
+               specifies a mailing list - see below).  Normally, sendmail
+               defines the $f macro to be the sender.
+
+       -h      The domain for which the mail is destined.  This is passed
+               in to mail500 via the $h macro, which is set by the
+               $@ metasymbol in the rule added to rule set 0 above.
+               It's normally used when searching for groups.
+
+       -m      The mailer-daemon address.  If errors have to be sent,
+               this is the address they will come from.  $n is normally
+               set to mailer-daemon and $w is normally the local host
+               name.
+
+The final argument $u is used to stand for the addresses to which to
+deliver the mail.
+
+*** HOW IT WORKS (from the mail500 side): ***
+
+When mail500 gets invoked with one or more names to which to
+deliver mail, it searches for each name in X.500.  Where it searches,
+and what kind(s) of search(es) it does are compile-time configurable
+by changing the base array in main.c.  For example, the configuration
+we use at U-M is like this:
+
+       Base    base[] =
+               { "ou=People, o=University of Michigan, c=US", 0
+                       "uid=%s", "cn=%s", NULL,
+                 "ou=System Groups, ou=Groups, o=University of Michigan, c=US", 1
+                       "(&(cn=%s)(associatedDomain=%h))", NULL, NULL,
+                 "ou=User Groups, ou=Groups, o=University of Michigan, c=US", 1
+                       "(&(cn=%s)(associatedDomain=%h))", NULL, NULL,
+                 NULL
+               };
+
+which means that in delivering mail to "name" mail500 would do the
+the following searches, stopping if it found anything at any step:
+
+       Search (18) [2]: c=US@o=University of Michigan@ou=People
+       Search subtree (uid=name)
+       Search (18) [3]: c=US@o=University of Michigan@ou=People
+       Search subtree (cn=name)
+
+       Search (18) [4]: c=US@o=University of Michigan@ou=Groups@ou=System Groups
+       Search subtree & ((cn=name)(associatedDomain=umich.edu))
+
+       Search (18) [5]: c=US@o=University of Michigan@ou=Groups@ou=User Groups
+       Search subtree & ((cn=name)(associatedDomain=umich.edu))
+
+Notice that when specifying a filter %s is replaced by the name,
+or user portion of the address while %h is replaced by whatever is
+passed in to mail500 via the -h option (typically the host portion
+of the address).
+
+You can also specify whether you want search results that matched
+because the entry's RDN matched the search to be given preference
+or not.  At U-M, we only give such preference in the mail group
+portion of the searches.  Beware with this option:  the algorithm
+used to decide whether an entry's RDN matched the search is very
+simple-minded, and may not always be correct.
+
+There is currently no limit on the number of areas searched (the base
+array can be as large as you want), and an arbitrary limit of 2 filters
+for each base.  If you want more than that, simply changing the 3 in
+the typedef for Base should do the trick.
+
+*** HOW IT WORKS (from the X.500 side): ***
+
+In X.500, there are several new attribute types and one new object
+class defined that mail500 makes use of.  At its most basic, for normal
+entries mail500 will deliver to the value(s) listed in the
+rfc822Mailbox attribute of the entry.  For example, at U-M my entry has
+the attribute
+
+       mail= tim@terminator.rs.itd.umich.edu
+
+So mail sent to tim@umich.edu will be delivered via mail500 to that
+address.  If there were multiple values for the mail attribute, multiple
+copies of the mail would be sent.
+
+A new object class, rfc822MailGroup, and several new attributes have
+been defined to handle email groups/mailing lists.  To use this, you
+will need to add this to your local oidtable.oc:
+
+       # object class for representing rfc 822 mailgroups
+       rfc822MailGroup:        umichObjectClass.2 : \
+               top : \
+               cn : \
+               rfc822Mailbox, member, memberOfGroup, owner, \
+               errorsTo, rfc822ErrorsTo, requestsTo, rfc822RequestsTo,
+               joinable, associatedDomain, \
+               description, multiLineDescription, \
+               userPassword, krbName, \
+               telecommunicationAttributeSet, postalAttributeSet
+
+And you will need to add these to your local oidtable.at:
+
+       # attrs for rfc822mailgroups
+       multiLineDescription:   umichAttributeType.2    : CaseIgnoreList
+       rfc822ErrorsTo:         umichAttributeType.26   : CaseIgnoreIA5String
+       rfc822RequestsTo:       umichAttributeType.27   : CaseIgnoreIA5String
+       joinable:               umichAttributeType.28   : Boolean
+       memberOfGroup:          umichAttributeType.29   : DN
+       errorsTo:               umichAttributeType.30   : DN
+       requestsTo:             umichAttributeType.31   : DN
+
+The idea was to define a kind of hybrid mail group that could handle
+people who were in X.500 or not.  So, for example, members of a group
+can be specified via the member attribute (for X.500 members) or the
+rfc822MailBox attribute (for non-X.500 members).  Similarly for the
+errorsTo and rfc822ErrorsTo, and the requestsTo and rfc822RequestsTo
+attributes.
+
+To create a real mailing list, with a list maintainer, all you have to
+do is create an rfc822MailGroup and fill in the errorsTo or
+rfc822ErrorsTo attributes (or both).  That will cause any errors
+encountered when delivering mail to the group to go to the addresses
+listed (or X.500 entry via it's mail attribute).
+
+If you fill in the requestsTo or rfc822RequestsTo (or both) attributes,
+mail sent to groupname-request will be sent to the addresses listed
+there.  mail500 does this automatically, so you don't have to explicitly
+add the groupname-request alias to your group.
+
+To allow users to join a group, there is the joinable flag.  If TRUE,
+mail500 will search for entries that have a memberOfGroup attribute
+equal to the DN of the group, using the same algorithm it used to find
+the group in the first place (i.e. the DNs and filters listed in the
+base array).  This allows people to join (or subscribe to) a group
+without having to modify the group entry directly.  If joinable is
+FALSE, the search is not done.
+
+Finally, keep in mind that this is somewhat experimental at the moment.
+We are using it in production at U-M, but your mileage may vary...
diff --git a/clients/mail500/Version.c b/clients/mail500/Version.c
new file mode 100644 (file)
index 0000000..633c927
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 1991 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+char Version[] = "  mail500 v%VERSION% (%WHEN%)\n\t%WHOANDWHERE%\n";
diff --git a/clients/mail500/main.c b/clients/mail500/main.c
new file mode 100644 (file)
index 0000000..5fdea96
--- /dev/null
@@ -0,0 +1,1691 @@
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <memory.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <syslog.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <sysexits.h>
+#include "portable.h"
+
+#include "lber.h"
+#include "ldap.h"
+#include "ldapconfig.h"
+
+#define USER           0x01
+#define GROUP_ERRORS   0x02
+#define GROUP_REQUEST  0x04
+#define GROUP_MEMBERS  0x08
+#define GROUP_OWNER    0x10
+
+#define ERROR          "error"
+#define ERRORS         "errors"
+#define REQUEST                "request"
+#define REQUESTS       "requests"
+#define MEMBERS                "members"
+#define OWNER          "owner"
+#define OWNERS         "owners"
+
+LDAP   *ld;
+char   *vacationhost = NULL;
+char   *errorsfrom = NULL;
+char   *mailfrom = NULL;
+char   *host = NULL;
+char   *ldaphost = LDAPHOST;
+int    hostlen = 0;
+int    debug;
+
+typedef struct errs {
+       int             e_code;
+#define E_USERUNKNOWN          1
+#define E_AMBIGUOUS            2
+#define E_NOEMAIL              3
+#define E_NOREQUEST            4
+#define E_NOERRORS             5
+#define E_BADMEMBER            6
+#define E_JOINMEMBERNOEMAIL    7
+#define E_MEMBERNOEMAIL                8
+#define E_LOOP                 9
+#define E_NOMEMBERS            10
+#define        E_NOOWNER               11
+#define E_GROUPUNKNOWN         12
+       char            *e_addr;
+       union {
+               char            *e_u_loop;
+               LDAPMessage     *e_u_msg;
+       } e_union;
+#define e_msg  e_union.e_u_msg
+#define e_loop e_union.e_u_loop
+} Error;
+
+typedef struct groupto {
+       char    *g_dn;
+       char    *g_errorsto;
+       char    **g_members;
+} Group;
+
+typedef struct baseinfo {
+       char    *b_dn;          /* dn to start searching at */
+       char    b_rdnpref;      /* give rdn's preference when searching? */
+       int     b_search;       /* ORed with the type of thing the address */
+                               /*  looks like (USER, GROUP_ERRORS, etc.)  */
+                               /*  to see if this should be searched      */
+       char    *b_filter[3];   /* filter to apply - name substituted for %s */
+                               /* (up to three of them) */
+} Base;
+
+Base   base[] = 
+       { "ou=People, o=University of Michigan, c=US",
+               0, USER,
+               "uid=%s", "cn=%s", NULL,
+         "ou=System Groups, ou=Groups, o=University of Michigan, c=US",
+               1, 0xff,
+               "(&(cn=%s)(associatedDomain=%h))", NULL, NULL,
+         "ou=User Groups, ou=Groups, o=University of Michigan, c=US",
+               1, 0xff,
+               "(&(cn=%s)(associatedDomain=%h))", NULL, NULL,
+         NULL
+       };
+
+char   *sendmailargs[] = { MAIL500_SENDMAIL, "-oMrX.500", "-odi", "-oi", "-f", NULL, NULL };
+
+static char    *attrs[] = { "objectClass", "title", "postaladdress",
+                       "telephoneNumber", "mail", "description", "owner",
+                       "errorsTo", "rfc822ErrorsTo", "requestsTo",
+                       "rfc822RequestsTo", "joinable", "cn", "member",
+                       "moderator", "onVacation", "uid",
+                       "suppressNoEmailError", NULL };
+
+static do_address();
+static do_group();
+static do_group_members();
+static send_message();
+static send_errors();
+static do_noemail();
+static do_ambiguous();
+static add_to();
+static isgroup();
+static add_error();
+static add_group();
+static unbind_and_exit();
+static group_loop();
+static send_group();
+static has_attributes();
+static char **get_attributes_mail_dn();
+static char *canonical();
+
+main (argc, argv)
+int    argc;
+char   **argv;
+{
+       char            *myname;
+       char            **tolist;
+       Error           *errlist;
+       Group           *togroups;
+       int             numto, ngroups, numerr, nargs;
+       int             i, j;
+       FILE            *fp;
+       extern int      optind, errno;
+       extern char     *optarg;
+
+       if ( (myname = strrchr( argv[0], '/' )) == NULL )
+               myname = strdup( argv[0] );
+       else
+               myname = strdup( myname + 1 );
+
+#ifdef LOG_MAIL
+       openlog( myname, OPENLOG_OPTIONS, LOG_MAIL );
+#else
+       openlog( myname, OPENLOG_OPTIONS );
+#endif
+
+       while ( (i = getopt( argc, argv, "d:f:h:l:m:v:" )) != EOF ) {
+               switch( i ) {
+               case 'd':       /* turn on debugging */
+                       debug = atoi( optarg );
+                       break;
+
+               case 'f':       /* who it's from & where errors should go */
+                       mailfrom = strdup( optarg );
+                       for ( j = 0; sendmailargs[j] != NULL; j++ ) {
+                               if ( strcmp( sendmailargs[j], "-f" ) == 0 ) {
+                                       sendmailargs[j+1] = mailfrom;
+                                       break;
+                               }
+                       }
+                       break;
+
+               case 'h':       /* hostname */
+                       host = strdup( optarg );
+                       hostlen = strlen(host);
+                       break;
+
+               case 'l':       /* ldap host */
+                       ldaphost = strdup( optarg );
+                       break;
+
+                               /* mailer-daemon address - who we should */
+               case 'm':       /* say errors come from */
+                       errorsfrom = strdup( optarg );
+                       break;
+
+               case 'v':       /* vacation host */
+                       vacationhost = strdup( optarg );
+                       break;
+
+               default:
+                       syslog( LOG_ALERT, "unknown option" );
+                       break;
+               }
+       }
+
+       if ( mailfrom == NULL ) {
+               syslog( LOG_ALERT, "required argument -f not present" );
+               exit( EX_TEMPFAIL );
+       }
+       if ( errorsfrom == NULL ) {
+               syslog( LOG_ALERT, "required argument -m not present" );
+               exit( EX_TEMPFAIL );
+       }
+       if ( host == NULL ) {
+               syslog( LOG_ALERT, "required argument -h not present" );
+               exit( EX_TEMPFAIL );
+       }
+
+       if ( connect_to_x500() != 0 )
+               exit( EX_TEMPFAIL );
+
+       setuid( geteuid() );
+
+       if ( debug ) {
+               char    buf[1024];
+               int     i;
+
+               syslog( LOG_ALERT, "running as %d", geteuid() );
+               strcpy( buf, argv[0] );
+               for ( i = 1; i < argc; i++ ) {
+                       strcat( buf, " " );
+                       strcat( buf, argv[i] );
+               }
+
+               syslog( LOG_ALERT, "args: (%s)", buf );
+       }
+
+       tolist = NULL;
+       numto = 0;
+       add_to( &tolist, &numto, sendmailargs );
+       nargs = numto;
+       ngroups = numerr = 0;
+       togroups = NULL;
+       errlist = NULL;
+       for ( i = optind; i < argc; i++ ) {
+               char    *s;
+               int     type;
+
+               for ( j = 0; argv[i][j] != '\0'; j++ ) {
+                       if ( argv[i][j] == '.' || argv[i][j] == '_' )
+                               argv[i][j] = ' ';
+               }
+
+               type = USER;
+               if ( (s = strrchr( argv[i], '-' )) != NULL ) {
+                       s++;
+
+                       if ((strcasecmp(s, ERROR) == 0) ||
+                               (strcasecmp(s, ERRORS) == 0)) {
+                               type = GROUP_ERRORS;
+                               *(--s) = '\0';
+                       } else if ((strcasecmp(s, REQUEST) == 0) ||
+                               (strcasecmp(s, REQUESTS) == 0)) {
+                               type = GROUP_REQUEST;
+                               *(--s) = '\0';
+                       } else if ( strcasecmp( s, MEMBERS ) == 0 ) {
+                               type = GROUP_MEMBERS;
+                               *(--s) = '\0';
+                       } else if ((strcasecmp(s, OWNER) == 0) ||
+                               (strcasecmp(s, OWNERS) == 0)) {
+                               type = GROUP_OWNER;
+                               *(--s) = '\0';
+                       }
+               }
+
+               do_address( argv[i], &tolist, &numto, &togroups, &ngroups,
+                   &errlist, &numerr, type );
+       }
+
+       /*
+        * If we have both errors and successful deliveries to make or if
+        * if there are any groups to deliver to, we basically need to read
+        * the message twice.  So, we have to put it in a tmp file.
+        */
+
+       if ( numerr > 0 && numto > nargs || ngroups > 0 ) {
+               int     fd;
+               char    buf[BUFSIZ];
+
+               umask( 077 );
+               if ( (fp = tmpfile()) == NULL ) {
+                       syslog( LOG_ALERT, "could not open tmp file" );
+                       unbind_and_exit( EX_TEMPFAIL );
+               }
+
+               /* copy the message to a temp file */
+               while ( fgets( buf, sizeof(buf), stdin ) != NULL ) {
+                       if ( fputs( buf, fp ) == EOF ) {
+                               syslog( LOG_ALERT, "error writing tmpfile" );
+                               unbind_and_exit( EX_TEMPFAIL );
+                       }
+               }
+
+               if ( dup2( fileno( fp ), 0 ) == -1 ) {
+                       syslog( LOG_ALERT, "could not dup2 tmpfile" );
+                       unbind_and_exit( EX_TEMPFAIL );
+               }
+
+               fclose( fp );
+       }
+
+       /* deal with errors */
+       if ( numerr > 0 ) {
+               if ( debug ) {
+                       syslog( LOG_ALERT, "sending errors" );
+               }
+               (void) rewind( stdin );
+               send_errors( errlist, numerr );
+       }
+
+       (void) ldap_unbind( ld );
+
+       /* send to groups with errorsTo */
+       if ( ngroups > 0 ) {
+               if ( debug ) {
+                       syslog( LOG_ALERT, "sending to groups with errorsto" );
+               }
+               (void) rewind( stdin );
+               send_group( togroups, ngroups );
+       }
+
+       /* send to expanded aliases and groups w/o errorsTo */
+       if ( numto > nargs ) {
+               if ( debug ) {
+                       syslog( LOG_ALERT, "sending to aliases and groups" );
+               }
+               (void) rewind( stdin );
+               send_message( tolist );
+       }
+
+       return( EX_OK );
+}
+
+connect_to_x500()
+{
+       if ( (ld = ldap_open( ldaphost, LDAP_PORT )) == NULL ) {
+               syslog( LOG_ALERT, "ldap_open failed" );
+               return( -1 );
+       }
+       ld->ld_sizelimit = MAIL500_MAXAMBIGUOUS;
+       ld->ld_deref = LDAP_DEREF_ALWAYS;
+
+       if ( ldap_simple_bind_s( ld, MAIL500_BINDDN, NULL ) != LDAP_SUCCESS ) {
+               syslog( LOG_ALERT, "ldap_simple_bind_s failed" );
+               return( -1 );
+       }
+
+       return( 0 );
+}
+
+static
+mailcmp( a, b )
+    char       *a;
+    char       *b;
+{
+       int     i;
+
+       for ( i = 0; a[i] != '\0'; i++ ) {
+               if ( a[i] != b[i] ) {
+                       switch ( a[i] ) {
+                       case ' ':
+                       case '.':
+                       case '_':
+                               if ( b[i] == ' ' || b[i] == '.' || b[i] == '_' )
+                                       break;
+                               return( 1 );
+
+                       default:
+                               return( 1 );
+                       }
+               }
+       }
+
+       return( 0 );
+}
+
+static
+do_address( name, to, nto, togroups, ngroups, err, nerr, type )
+    char       *name;
+    char       ***to;
+    int                *nto;
+    Group      **togroups;
+    int                *ngroups;
+    Error      **err;
+    int                *nerr;
+    int                type;
+{
+       int             rc, b, f, match;
+       LDAPMessage     *e, *res;
+       struct timeval  timeout;
+       char            *dn;
+       char            filter[1024];
+       char            realfilter[1024];
+       char            **mail, **onvacation = NULL, **uid = NULL;
+
+       /*
+        * Look up the name in X.500, add the appropriate addresses found
+        * to the to list, or to the err list in case of error.  Groups are
+        * handled by the do_group routine, individuals are handled here.
+        * When looking up name, we follow the bases hierarchy, looking
+        * in base[0] first, then base[1], etc.  For each base, there is
+        * a set of search filters to try, in order.  If something goes
+        * wrong here trying to contact X.500, we exit with EX_TEMPFAIL.
+        * If the b_rdnpref flag is set, then we give preference to entries
+        * that matched name because it's their rdn, otherwise not.
+        */
+
+       timeout.tv_sec = MAIL500_TIMEOUT;
+       timeout.tv_usec = 0;
+       for ( b = 0, match = 0; !match && base[b].b_dn != NULL; b++ ) {
+               if ( ! (base[b].b_search & type) ) {
+                       continue;
+               }
+               for ( f = 0; base[b].b_filter[f] != NULL; f++ ) {
+                       char    *format, *p, *s, *d;
+                       char    *argv[3];
+                       int     argc;
+
+                       for ( argc = 0; argc < 3; argc++ ) {
+                               argv[argc] = NULL;
+                       }
+
+                       format = strdup( base[b].b_filter[f] );
+                       for ( argc = 0, p = format; *p; p++ ) {
+                               if ( *p == '%' ) {
+                                       switch ( *++p ) {
+                                       case 's':       /* %s is the name */
+                                               argv[argc] = name;
+                                               break;
+
+                                       case 'h':       /* %h is the host */
+                                               *p = 's';
+                                               argv[argc] = host;
+                                               break;
+
+                                       default:
+                                               syslog( LOG_ALERT,
+                                                   "unknown format %c", *p );
+                                               break;
+                                       }
+
+                                       argc++;
+                               }
+                       }
+
+                       /* three names ought to do... */
+                       sprintf( filter, format, argv[0], argv[1], argv[2] );
+                       free( format );
+                       for ( s = filter, d = realfilter; *s; s++, d++ ) {
+                               if ( *s == '*' ) {
+                                       *d++ = '\\';
+                               }
+                               *d = *s;
+                       }
+                       *d = '\0';
+
+                       res = NULL;
+                       rc = ldap_search_st( ld, base[b].b_dn,
+                           LDAP_SCOPE_SUBTREE, realfilter, attrs, 0, &timeout,
+                           &res );
+
+                       /* some other trouble - try again later */
+                       if ( rc != LDAP_SUCCESS &&
+                           rc != LDAP_SIZELIMIT_EXCEEDED ) {
+                               syslog( LOG_ALERT, "return 0x%x from X.500",
+                                   rc );
+                               unbind_and_exit( EX_TEMPFAIL );
+                       }
+
+                       if ( (match = ldap_count_entries( ld, res )) != 0 )
+                               break;
+
+                       ldap_msgfree( res );
+               }
+
+               if ( match )
+                       break;
+       }
+
+       /* trouble - try again later */
+       if ( match == -1 ) {
+               syslog( LOG_ALERT, "error parsing result from X.500" );
+               unbind_and_exit( EX_TEMPFAIL );
+       }
+
+       /* no matches - bounce with user unknown */
+       if ( match == 0 ) {
+               if ( type == USER ) {
+                       add_error( err, nerr, E_USERUNKNOWN, name, NULLMSG );
+               } else {
+                       add_error( err, nerr, E_GROUPUNKNOWN, name, NULLMSG );
+               }
+               return;
+       }
+
+       /* more than one match - bounce with ambiguous user? */
+       if ( match > 1 ) {
+               LDAPMessage     *next, *tmpres = NULL;
+               char            *dn;
+               char            **xdn;
+
+               /* not giving rdn preference - bounce with ambiguous user */
+               if ( base[b].b_rdnpref == 0 ) {
+                       add_error( err, nerr, E_AMBIGUOUS, name, res );
+                       return;
+               }
+
+               /*
+                * giving rdn preference - see if any entries were matched
+                * because of their rdn.  If so, collect them to deal with
+                * later (== 1 we deliver, > 1 we bounce).
+                */
+
+               for ( e = ldap_first_entry( ld, res ); e != NULL; e = next ) {
+                       next = ldap_next_entry( ld, e );
+                       dn = ldap_get_dn( ld, e );
+                       xdn = ldap_explode_dn( dn, 1 );
+
+                       /* XXX bad, but how else can we do it? XXX */
+                       if ( strcasecmp( xdn[0], name ) == 0 ) {
+                               ldap_delete_result_entry( &res, e );
+                               ldap_add_result_entry( &tmpres, e );
+                       }
+
+                       ldap_value_free( xdn );
+                       free( dn );
+               }
+
+               /* nothing matched by rdn - go ahead and bounce */
+               if ( tmpres == NULL ) {
+                       add_error( err, nerr, E_AMBIGUOUS, name, res );
+                       return;
+
+               /* more than one matched by rdn - bounce with rdn matches */
+               } else if ( (match = ldap_count_entries( ld, tmpres )) > 1 ) {
+                       add_error( err, nerr, E_AMBIGUOUS, name, tmpres );
+                       return;
+
+               /* trouble... */
+               } else if ( match < 0 ) {
+                       syslog( LOG_ALERT, "error parsing result from X.500" );
+                       unbind_and_exit( EX_TEMPFAIL );
+               }
+
+               /* otherwise one matched by rdn - send to it */
+               ldap_msgfree( res );
+               res = tmpres;
+       }
+
+       /*
+        * if we get this far, it means that we found a single match for
+        * name.  for a user, we deliver to the mail attribute or bounce
+        * with address and phone if no mail attr.  for a group, we
+        * deliver to all members or bounce to rfc822ErrorsTo if no members.
+        */
+
+       /* trouble */
+       if ( (e = ldap_first_entry( ld, res )) == NULL ) {
+               syslog( LOG_ALERT, "error parsing entry from X.500" );
+               unbind_and_exit( EX_TEMPFAIL );
+       }
+
+       dn = ldap_get_dn( ld, e );
+
+       if ( type == GROUP_ERRORS ) {
+               /* sent to group-errors - resend to [rfc822]ErrorsTo attr */
+               do_group_errors( e, dn, to, nto, err, nerr );
+
+       } else if ( type == GROUP_REQUEST ) {
+               /* sent to group-request - resend to [rfc822]RequestsTo attr */
+               do_group_request( e, dn, to, nto, err, nerr );
+
+       } else if ( type == GROUP_MEMBERS ) {
+               /* sent to group-members - expand */
+               do_group_members( e, dn, to, nto, togroups, ngroups, err,
+                   nerr );
+
+       } else if ( type == GROUP_OWNER ) {
+               /* sent to group-owner - resend to owner attr */
+               do_group_owner( e, dn, to, nto, err, nerr );
+
+       } else if ( isgroup( e ) ) {
+               /* 
+                * sent to group - resend from [rfc822]ErrorsTo if it's there,
+                * otherwise, expand the group
+                */
+
+               do_group( e, dn, to, nto, togroups, ngroups, err, nerr );
+
+               ldap_msgfree( res );
+
+       } else {
+               /*
+                * sent to user - mail attribute => add it to the to list,
+                * otherwise bounce
+                */
+               if ( (mail = ldap_get_values( ld, e, "mail" )) != NULL ) {
+                       char    buf[1024];
+                       char    *h;
+                       int     i, j;
+
+                       /* try to detect simple mail loops */
+                       sprintf( buf, "%s@%s", name, host );
+                       for ( i = 0; mail[i] != NULL; i++ ) {
+                               /*
+                                * address is the same as the one we're
+                                * sending to - mail loop.  syslog the
+                                * problem, bounce a message back to the
+                                * sender (who else?), and delete the bogus
+                                * addr from the list.
+                                */
+
+                               if ( (h = strchr( mail[i], '@' )) != NULL ) {
+                                       h++;
+                                       if ( strcasecmp( h, host ) == 0 ) {
+                                               syslog( LOG_ALERT,
+                                           "potential loop detected (%s)",
+                                                   mail[i] );
+                                       }
+                               }
+
+                               if ( mailcmp( buf, mail[i] ) == 0 ) {
+                                       syslog( LOG_ALERT,
+                                           "loop detected (%s)", mail[i] );
+
+                                       /* remove the bogus address */
+                                       for ( j = i; mail[j] != NULL; j++ ) {
+                                               mail[j] = mail[j+1];
+                                       }
+                               }
+                       }
+                       if ( mail[0] != NULL ) {
+                               add_to( to, nto, mail );
+                       } else {
+                               add_error( err, nerr, E_NOEMAIL, name, res );
+                       }
+
+                       ldap_value_free( mail );
+               } else {
+                       add_error( err, nerr, E_NOEMAIL, name, res );
+               }
+
+               /*
+                * If the user is on vacation, send a copy of the mail to
+                * the vacation server.  The address is constructed from
+                * the vacationhost (set in a command line argument) and
+                * the uid (XXX this should be more general XXX).
+                */
+
+               if ( vacationhost != NULL && (onvacation = ldap_get_values( ld,
+                   e, "onVacation" )) != NULL && strcasecmp( onvacation[0],
+                   "TRUE" ) == 0 ) {
+                       char    buf[1024];
+                       char    *vaddr[2];
+
+                       if ( (uid = ldap_get_values( ld, e, "uid" )) != NULL ) {
+                               sprintf( buf, "%s@%s", uid[0], vacationhost );
+
+                               vaddr[0] = buf;
+                               vaddr[1] = NULL;
+
+                               add_to( to, nto, vaddr );
+                       } else {
+                               syslog( LOG_ALERT,
+                                   "user without a uid on vacation (%s)",
+                                   name );
+                       }
+               }
+       }
+
+       if ( onvacation != NULL ) {
+               ldap_value_free( onvacation );
+       }
+       if ( uid != NULL ) {
+               ldap_value_free( uid );
+       }
+       free( dn );
+
+       return;
+}
+
+static
+do_group( e, dn, to, nto, togroups, ngroups, err, nerr )
+    LDAPMessage        *e;
+    char       *dn;
+    char       ***to;
+    int                *nto;
+    Group      **togroups;
+    int                *ngroups;
+    Error      **err;
+    int                *nerr;
+{
+       int     i;
+       char    **moderator;
+
+       /*
+        * If this group has an rfc822ErrorsTo attribute, we need to
+        * arrange for errors involving this group to go there, not
+        * to the sender.  Since sendmail only has the concept of a
+        * single sender, we arrange for errors to go to groupname-errors,
+        * which we then handle specially when (if) it comes back to us
+        * by expanding to all the rfc822ErrorsTo addresses.  If it has no
+        * rfc822ErrorsTo attribute, we call do_group_members() to expand
+        * the group.
+        */
+
+       if ( group_loop( dn ) ) {
+               return( -1 );
+       }
+
+       /*
+        * check for moderated groups - if the group has a moderator
+        * attribute, we check to see if the from address is one of
+        * the moderator values.  if so, continue on.  if not, arrange
+        * to send the mail to the moderator(s).  need to do this before
+        * we change the from below.
+        */
+
+       if ( (moderator = ldap_get_values( ld, e, "moderator" )) != NULL ) {
+               /* check if it came from any of the group's moderators */
+               for ( i = 0; moderator[i] != NULL; i++ ) {
+                       if ( strcasecmp( moderator[i], mailfrom ) == 0 )
+                               break;
+               }
+
+               /* not from the moderator? */
+               if ( moderator[i] == NULL ) {
+                       add_to( to, nto, moderator );
+                       ldap_value_free( moderator );
+
+                       return( 0 );
+               }
+               /* else from the moderator - fall through and deliver it */
+       }
+
+       if ( has_attributes( e, "rfc822ErrorsTo", "errorsTo" ) ) {
+               add_group( dn, togroups, ngroups );
+
+               return( 0 );
+       }
+
+       do_group_members( e, dn, to, nto, togroups, ngroups, err, nerr );
+
+       return( 0 );
+}
+
+/* ARGSUSED */
+static
+do_group_members( e, dn, to, nto, togroups, ngroups, err, nerr )
+    LDAPMessage        *e;
+    char       *dn;
+    char       ***to;
+    int                *nto;
+    Group      **togroups;
+    int                *ngroups;
+    Error      **err;
+    int                *nerr;
+{
+       int             i, rc, anymembers;
+       char            *ndn;
+       char            **mail, **member, **joinable, **suppress;
+       char            filter[1024];
+       LDAPMessage     *ee, *res;
+       struct timeval  timeout;
+
+       /*
+        * if all has gone according to plan, we've already arranged for
+        * errors to go to the [rfc822]ErrorsTo attributes (if they exist),
+        * so all we have to do here is arrange to send to the
+        * rfc822Mailbox attribute, the member attribute, and anyone who
+        * has joined the group by setting memberOfGroup equal to the
+        * group dn.
+        */
+
+       /* add members in the group itself - mail attribute */
+       anymembers = 0;
+       if ( (mail = ldap_get_values( ld, e, "mail" )) != NULL ) {
+               anymembers = 1;
+               add_to( to, nto, mail );
+
+               ldap_value_free( mail );
+       }
+
+       /* add members in the group itself - member attribute */
+       if ( (member = ldap_get_values( ld, e, "member" )) != NULL ) {
+               suppress = ldap_get_values( ld, e, "suppressNoEmailError" );
+               anymembers = 1;
+               for ( i = 0; member[i] != NULL; i++ ) {
+                       if ( strcasecmp( dn, member[i] ) == 0 ) {
+                               syslog( LOG_ALERT, "group (%s) contains itself",
+                                   dn );
+                               continue;
+                       }
+                       add_member( dn, member[i], to, nto, togroups,
+                           ngroups, err, nerr, suppress );
+               }
+
+               if ( suppress ) {
+                       ldap_value_free( suppress );
+               }
+               ldap_value_free( member );
+       }
+
+       /* add members who have joined by setting memberOfGroup */
+       if ( (joinable = ldap_get_values( ld, e, "joinable" )) != NULL ) {
+               if ( strcasecmp( joinable[0], "FALSE" ) == 0 ) {
+                       if ( ! anymembers ) {
+                               add_error( err, nerr, E_NOMEMBERS, dn,
+                                   NULLMSG );
+                       }
+
+                       ldap_value_free( joinable );
+                       return;
+               }
+               ldap_value_free( joinable );
+
+               sprintf( filter, "(memberOfGroup=%s)", dn );
+
+               timeout.tv_sec = MAIL500_TIMEOUT;
+               timeout.tv_usec = 0;
+
+               /* for each subtree to look in... */
+               ld->ld_sizelimit = MAIL500_MAXGROUPMEMBERS;
+               for ( i = 0; base[i].b_dn != NULL; i++ ) {
+                       /* find entries that have joined this group... */
+                       rc = ldap_search_st( ld, base[i].b_dn,
+                           LDAP_SCOPE_SUBTREE, filter, attrs, 0, &timeout,
+                           &res );
+
+                       if ( rc == LDAP_SIZELIMIT_EXCEEDED ||
+                           rc == LDAP_TIMELIMIT_EXCEEDED ) {
+                               syslog( LOG_ALERT,
+                                   "group search limit exceeded %d", rc );
+                               unbind_and_exit( EX_TEMPFAIL );
+                       }
+
+                       if ( rc != LDAP_SUCCESS ) {
+                               syslog( LOG_ALERT, "group search return 0x%x",
+                                   rc );
+                               unbind_and_exit( EX_TEMPFAIL );
+                       }
+
+                       /* for each entry that has joined... */
+                       for ( ee = ldap_first_entry( ld, res ); ee != NULL;
+                           ee = ldap_next_entry( ld, ee ) ) {
+                               anymembers = 1;
+                               if ( isgroup( ee ) ) {
+                                       ndn = ldap_get_dn( ld, ee );
+
+                                       if ( do_group( e, ndn, to, nto,
+                                           togroups, ngroups, err, nerr )
+                                           == -1 ) {
+                                               syslog( LOG_ALERT,
+                                                   "group loop (%s) (%s)",
+                                                   dn, ndn );
+                                       }
+
+                                       free( ndn );
+
+                                       continue;
+                               }
+
+                               /* add them to the to list */
+                               if ( (mail = ldap_get_values( ld, ee, "mail" ))
+                                   != NULL ) {
+                                       add_to( to, nto, mail );
+
+                                       ldap_value_free( mail );
+
+                               /* else generate a bounce */
+                               } else {
+                                       ndn = ldap_get_dn( ld, ee );
+
+                                       add_error( err, nerr,
+                                           E_JOINMEMBERNOEMAIL, ndn, NULLMSG );
+
+                                       free( ndn );
+                               }
+                       }
+
+                       ldap_msgfree( res );
+               }
+               ld->ld_sizelimit = MAIL500_MAXAMBIGUOUS;
+       }
+
+       if ( ! anymembers ) {
+               add_error( err, nerr, E_NOMEMBERS, dn, NULLMSG );
+       }
+
+       return;
+}
+
+add_member( gdn, dn, to, nto, togroups, ngroups, err, nerr, suppress )
+    char       *gdn;
+    char       *dn;
+    char       ***to;
+    int                *nto;
+    Group      **togroups;
+    int                *ngroups;
+    Error      **err;
+    int                *nerr;
+    char       **suppress;
+{
+       char            *ndn;
+       char            **mail;
+       int             i, rc;
+       LDAPMessage     *res, *e;
+       struct timeval  timeout;
+
+       timeout.tv_sec = MAIL500_TIMEOUT;
+       timeout.tv_usec = 0;
+       if ( (rc = ldap_search_st( ld, dn, LDAP_SCOPE_BASE, "(objectclass=*)",
+           attrs, 0, &timeout, &res )) != LDAP_SUCCESS ) {
+               if ( rc == LDAP_NO_SUCH_OBJECT ) {
+                       add_error( err, nerr, E_BADMEMBER, dn, NULLMSG );
+
+                       return;
+               } else {
+                       syslog( LOG_ALERT, "member search return 0x%x", rc );
+
+                       unbind_and_exit( EX_TEMPFAIL );
+               }
+       }
+
+       if ( (e = ldap_first_entry( ld, res )) == NULL ) {
+               syslog( LOG_ALERT, "member search error parsing entry" );
+
+               unbind_and_exit( EX_TEMPFAIL );
+       }
+       ndn = ldap_get_dn( ld, e );
+
+       /* allow groups within groups */
+       if ( isgroup( e ) ) {
+               if ( do_group( e, ndn, to, nto, togroups, ngroups, err, nerr )
+                   == -1 ) {
+                       syslog( LOG_ALERT, "group loop (%s) (%s)", gdn, ndn );
+               }
+
+               free( ndn );
+
+               return;
+       }
+
+       /* send to the member's mail attribute */
+       if ( (mail = ldap_get_values( ld, e, "mail" )) != NULL ) {
+               add_to( to, nto, mail );
+
+               ldap_value_free( mail );
+
+       /* else generate a bounce */
+       } else {
+               if ( suppress == NULL || strcasecmp( suppress[0], "FALSE" )
+                   == 0 ) {
+                       add_error( err, nerr, E_MEMBERNOEMAIL, ndn, NULLMSG );
+               }
+       }
+
+       free( ndn );
+
+       return;
+}
+
+do_group_request( e, dn, to, nto, err, nerr )
+    LDAPMessage        *e;
+    char       *dn;
+    char       ***to;
+    int                *nto;
+    Error      **err;
+    int                *nerr;
+{
+       char            **requeststo;
+
+       if ( (requeststo = get_attributes_mail_dn( e, "rfc822RequestsTo",
+           "requestsTo" )) != NULL ) {
+               add_to( to, nto, requeststo );
+
+               ldap_value_free( requeststo );
+       } else {
+               add_error( err, nerr, E_NOREQUEST, dn, NULLMSG );
+       }
+
+       return;
+}
+
+do_group_errors( e, dn, to, nto, err, nerr )
+    LDAPMessage        *e;
+    char       *dn;
+    char       ***to;
+    int                *nto;
+    Error      **err;
+    int                *nerr;
+{
+       char            **errorsto;
+
+       if ( (errorsto = get_attributes_mail_dn( e, "rfc822ErrorsTo",
+           "errorsTo" )) != NULL ) {
+               add_to( to, nto, errorsto );
+
+               ldap_value_free( errorsto );
+       } else {
+               add_error( err, nerr, E_NOERRORS, dn, NULLMSG );
+       }
+
+       return;
+}
+
+do_group_owner( e, dn, to, nto, err, nerr )
+    LDAPMessage        *e;
+    char       *dn;
+    char       ***to;
+    int                *nto;
+    Error      **err;
+    int                *nerr;
+{
+       char            **owner;
+
+       if ( (owner = get_attributes_mail_dn( e, "", "owner" )) != NULL ) {
+               add_to( to, nto, owner );
+               ldap_value_free( owner );
+       } else {
+               add_error( err, nerr, E_NOOWNER, dn, NULLMSG );
+       }
+       return;
+}
+
+static
+send_message( to )
+    char       **to;
+{
+       int     pid;
+#ifndef USE_WAITPID
+       WAITSTATUSTYPE  status;
+#endif
+
+       if ( debug ) {
+               char    buf[1024];
+               int     i;
+
+               strcpy( buf, to[0] );
+               for ( i = 1; to[i] != NULL; i++ ) {
+                       strcat( buf, " " );
+                       strcat( buf, to[i] );
+               }
+
+               syslog( LOG_ALERT, "send_message execing sendmail: (%s)", buf );
+       }
+
+       /* parent */
+       if ( pid = fork() ) {
+#ifdef USE_WAITPID
+               waitpid( pid, (int *) NULL, 0 );
+#else
+               wait4( pid, &status, WAIT_FLAGS, 0 );
+#endif
+       /* child */
+       } else {
+               /* to includes sendmailargs */
+               execv( MAIL500_SENDMAIL, to );
+
+               syslog( LOG_ALERT, "execv failed" );
+
+               exit( EX_TEMPFAIL );
+       }
+}
+
+static
+send_group( group, ngroup )
+    Group      *group;
+    int                ngroup;
+{
+       int     i, pid;
+       char    **argv;
+       int     argc;
+       char    *iargv[7];
+#ifndef USE_WAITPID
+       WAITSTATUSTYPE  status;
+#endif
+
+       for ( i = 0; i < ngroup; i++ ) {
+               (void) rewind( stdin );
+
+               iargv[0] = MAIL500_SENDMAIL;
+               iargv[1] = "-f";
+               iargv[2] = group[i].g_errorsto;
+               iargv[3] = "-oMrX.500";
+               iargv[4] = "-odi";
+               iargv[5] = "-oi";
+               iargv[6] = NULL;
+
+               argv = NULL;
+               argc = 0;
+               add_to( &argv, &argc, iargv );
+               add_to( &argv, &argc, group[i].g_members );
+
+               if ( debug ) {
+                       char    buf[1024];
+                       int     i;
+
+                       strcpy( buf, argv[0] );
+                       for ( i = 1; i < argc; i++ ) {
+                               strcat( buf, " " );
+                               strcat( buf, argv[i] );
+                       }
+
+                       syslog( LOG_ALERT, "execing sendmail: (%s)", buf );
+               }
+
+               /* parent */
+               if ( pid = fork() ) {
+#ifdef USE_WAITPID
+                       waitpid( pid, (int *) NULL, 0 );
+#else
+                       wait4( pid, &status, WAIT_FLAGS, 0 );
+#endif
+               /* child */
+               } else {
+                       execv( MAIL500_SENDMAIL, argv );
+
+                       syslog( LOG_ALERT, "execv failed" );
+
+                       exit( EX_TEMPFAIL );
+               }
+       }
+
+       return;
+}
+
+static
+send_errors( err, nerr )
+    Error      *err;
+    int                nerr;
+{
+       int     pid, i, namelen;
+       FILE    *fp;
+       int     fd[2];
+       char    *argv[8];
+       char    buf[1024];
+#ifndef USE_WAITPID
+       WAITSTATUSTYPE  status;
+#endif
+
+       argv[0] = MAIL500_SENDMAIL;
+       argv[1] = "-oMrX.500";
+       argv[2] = "-odi";
+       argv[3] = "-oi";
+       argv[4] = "-f";
+       argv[5] = errorsfrom;
+       argv[6] = mailfrom;
+       argv[7] = NULL;
+
+       if ( debug ) {
+               int     i;
+
+               strcpy( buf, argv[0] );
+               for ( i = 1; argv[i] != NULL; i++ ) {
+                       strcat( buf, " " );
+                       strcat( buf, argv[i] );
+               }
+
+               syslog( LOG_ALERT, "execing sendmail: (%s)", buf );
+       }
+
+       if ( pipe( fd ) == -1 ) {
+               syslog( LOG_ALERT, "cannot create pipe" );
+               exit( EX_TEMPFAIL );
+       }
+
+       if ( pid = fork() ) {
+               if ( (fp = fdopen( fd[1], "w" )) == NULL ) {
+                       syslog( LOG_ALERT, "cannot fdopen pipe" );
+                       exit( EX_TEMPFAIL );
+               }
+
+               fprintf( fp, "To: %s\n", mailfrom );
+               fprintf( fp, "From: %s\n", errorsfrom );
+               fprintf( fp, "Subject: undeliverable mail\n" );
+               fprintf( fp, "\n" );
+               fprintf( fp, "The following errors occurred when trying to deliver the attached mail:\n" );
+               for ( i = 0; i < nerr; i++ ) {
+                       namelen = strlen( err[i].e_addr );
+                       fprintf( fp, "\n" );
+
+                       switch ( err[i].e_code ) {
+                       case E_USERUNKNOWN:
+                               fprintf( fp, "%s: User unknown\n", err[i].e_addr );
+                               break;
+
+                       case E_GROUPUNKNOWN:
+                               fprintf( fp, "%s: Group unknown\n", err[i].e_addr );
+                               break;
+
+                       case E_BADMEMBER:
+                               fprintf( fp, "%s: Group member does not exist\n",
+                                   err[i].e_addr );
+                               fprintf( fp, "This could be because the distinguished name of the person has changed\n" );
+                               fprintf( fp, "If this is the case, the problem can be solved by removing and\n" );
+                               fprintf( fp, "then re-adding the person to the group.\n" );
+                               break;
+
+                       case E_NOREQUEST:
+                               fprintf( fp, "%s: Group exists but has no request address\n",
+                                   err[i].e_addr );
+                               break;
+
+                       case E_NOERRORS:
+                               fprintf( fp, "%s: Group exists but has no errors-to address\n",
+                                   err[i].e_addr );
+                               break;
+
+                       case E_NOOWNER:
+                               fprintf( fp, "%s: Group exists but has no owner\n",
+                                   err[i].e_addr );
+                               break;
+
+                       case E_AMBIGUOUS:
+                               do_ambiguous( fp, &err[i], namelen );
+                               break;
+
+                       case E_NOEMAIL:
+                               do_noemail( fp, &err[i], namelen );
+                               break;
+
+                       case E_MEMBERNOEMAIL:
+                               fprintf( fp, "%s: Group member exists but does not have an email address\n",
+                                   err[i].e_addr );
+                               break;
+
+                       case E_JOINMEMBERNOEMAIL:
+                               fprintf( fp, "%s: User has joined group but does not have an email address\n",
+                                   err[i].e_addr );
+                               break;
+
+                       case E_LOOP:
+                               fprintf( fp, "%s: User has created a mail loop by adding address %s to their X.500 entry\n",
+                                   err[i].e_addr, err[i].e_loop );
+                               break;
+
+                       case E_NOMEMBERS:
+                               fprintf( fp, "%s: Group has no members\n",
+                                   err[i].e_addr );
+                               break;
+
+                       default:
+                               syslog( LOG_ALERT, "unknown error %d", err[i].e_code );
+                               unbind_and_exit( EX_TEMPFAIL );
+                               break;
+                       }
+               }
+
+               fprintf( fp, "\n------- The original message sent:\n\n" );
+
+               while ( fgets( buf, sizeof(buf), stdin ) != NULL ) {
+                       fputs( buf, fp );
+               }
+               fclose( fp );
+
+#ifdef USE_WAITPID
+               waitpid( pid, (int *) NULL, 0 );
+#else
+               wait4( pid, &status, WAIT_FLAGS, 0 );
+#endif
+       } else {
+               dup2( fd[0], 0 );
+
+               execv( MAIL500_SENDMAIL, argv );
+
+               syslog( LOG_ALERT, "execv failed" );
+
+               exit( EX_TEMPFAIL );
+       }
+
+       return;
+}
+
+static
+do_noemail( fp, err, namelen )
+    FILE       *fp;
+    Error      *err;
+    int                namelen;
+{
+       int             i, last;
+       char            *dn, *rdn;
+       char            **ufn, **vals;
+
+       fprintf(fp, "%s: User has no email address registered.\n",
+           err->e_addr );
+       fprintf( fp, "%*s  Name, title, postal address and phone for '%s':\n\n",
+           namelen, " ", err->e_addr );
+
+       /* name */
+       dn = ldap_get_dn( ld, err->e_msg );
+       ufn = ldap_explode_dn( dn, 1 );
+       rdn = strdup( ufn[0] );
+       if ( strcasecmp( rdn, err->e_addr ) == 0 ) {
+               if ( (vals = ldap_get_values( ld, err->e_msg, "cn" ))
+                   != NULL ) {
+                       for ( i = 0; vals[i]; i++ ) {
+                               last = strlen( vals[i] ) - 1;
+                               if ( isdigit( vals[i][last] ) ) {
+                                       rdn = strdup( vals[i] );
+                                       break;
+                               }
+                       }
+
+                       ldap_value_free( vals );
+               }
+       }
+       fprintf( fp, "%*s  %s\n", namelen, " ", rdn );
+       free( dn );
+       free( rdn );
+       ldap_value_free( ufn );
+
+       /* titles or descriptions */
+       if ( (vals = ldap_get_values( ld, err->e_msg, "title" )) == NULL &&
+           (vals = ldap_get_values( ld, err->e_msg, "description" ))
+           == NULL ) {
+               fprintf( fp, "%*s  No title or description registered\n",
+                   namelen, " " );
+       } else {
+               for ( i = 0; vals[i] != NULL; i++ ) {
+                       fprintf( fp, "%*s  %s\n", namelen, " ", vals[i] );
+               }
+
+               ldap_value_free( vals );
+       }
+
+       /* postal address */
+       if ( (vals = ldap_get_values( ld, err->e_msg, "postalAddress" ))
+           == NULL ) {
+               fprintf( fp, "%*s  No postal address registered\n", namelen,
+                   " " );
+       } else {
+               fprintf( fp, "%*s  ", namelen, " " );
+               for ( i = 0; vals[0][i] != '\0'; i++ ) {
+                       if ( vals[0][i] == '$' ) {
+                               fprintf( fp, "\n%*s  ", namelen, " " );
+                               while ( isspace( vals[0][i+1] ) )
+                                       i++;
+                       } else {
+                               fprintf( fp, "%c", vals[0][i] );
+                       }
+               }
+               fprintf( fp, "\n" );
+
+               ldap_value_free( vals );
+       }
+
+       /* telephone number */
+       if ( (vals = ldap_get_values( ld, err->e_msg, "telephoneNumber" ))
+           == NULL ) {
+               fprintf( fp, "%*s  No phone number registered\n", namelen,
+                   " " );
+       } else {
+               for ( i = 0; vals[i] != NULL; i++ ) {
+                       fprintf( fp, "%*s  %s\n", namelen, " ", vals[i] );
+               }
+
+               ldap_value_free( vals );
+       }
+}
+
+/* ARGSUSED */
+static
+do_ambiguous( fp, err, namelen )
+    FILE       *fp;
+    Error      *err;
+    int                namelen;
+{
+       int             i, last;
+       char            *dn, *rdn;
+       char            **ufn, **vals;
+       LDAPMessage     *e;
+
+       i = ldap_result2error( ld, err->e_msg, 0 );
+
+       fprintf( fp, "%s: Ambiguous user.  %s%d matches found:\n\n",
+           err->e_addr, i == LDAP_SIZELIMIT_EXCEEDED ? "First " : "",
+           ldap_count_entries( ld, err->e_msg ) );
+
+       for ( e = ldap_first_entry( ld, err->e_msg ); e != NULL;
+           e = ldap_next_entry( ld, e ) ) {
+               dn = ldap_get_dn( ld, e );
+               ufn = ldap_explode_dn( dn, 1 );
+               rdn = strdup( ufn[0] );
+               if ( strcasecmp( rdn, err->e_addr ) == 0 ) {
+                       if ( (vals = ldap_get_values( ld, e, "cn" )) != NULL ) {
+                               for ( i = 0; vals[i]; i++ ) {
+                                       last = strlen( vals[i] ) - 1;
+                                       if ( isdigit( vals[i][last] ) ) {
+                                               rdn = strdup( vals[i] );
+                                               break;
+                                       }
+                               }
+
+                               ldap_value_free( vals );
+                       }
+               }
+
+               if ( isgroup( e ) ) {
+                       vals = ldap_get_values( ld, e, "description" );
+               } else {
+                       vals = ldap_get_values( ld, e, "title" );
+               }
+
+               fprintf( fp, "    %-20s %s\n", rdn, vals ? vals[0] : "" );
+               for ( i = 1; vals && vals[i] != NULL; i++ ) {
+                       fprintf( fp, "                         %s\n", vals[i] );
+               }
+
+               free( dn );
+               free( rdn );
+               ldap_value_free( ufn );
+               if ( vals != NULL )
+                       ldap_value_free( vals );
+       }
+}
+
+static
+count_values( list )
+    char       **list;
+{
+       int     i;
+
+       for ( i = 0; list && list[i] != NULL; i++ )
+               ;       /* NULL */
+
+       return( i );
+}
+
+static
+add_to( list, nlist, new )
+    char       ***list;
+    int                *nlist;
+    char       **new;
+{
+       int     i, nnew, oldnlist;
+
+       nnew = count_values( new );
+
+       oldnlist = *nlist;
+       if ( *list == NULL || *nlist == 0 ) {
+               *list = (char **) malloc( (nnew + 1) * sizeof(char *) );
+               *nlist = nnew;
+       } else {
+               *list = (char **) realloc( *list, *nlist * sizeof(char *) +
+                   nnew * sizeof(char *) + sizeof(char *) );
+               *nlist += nnew;
+       }
+
+       for ( i = 0; i < nnew; i++ )
+               (*list)[i + oldnlist] = strdup( new[i] );
+       (*list)[*nlist] = NULL;
+
+       return;
+}
+
+static
+isgroup( e )
+    LDAPMessage        *e;
+{
+       int     i;
+       char    **oclist;
+
+       oclist = ldap_get_values( ld, e, "objectClass" );
+
+       for ( i = 0; oclist[i] != NULL; i++ ) {
+               if ( strcasecmp( oclist[i], "rfc822MailGroup" ) == 0 ) {
+                       ldap_value_free( oclist );
+                       return( 1 );
+               }
+       }
+       ldap_value_free( oclist );
+
+       return( 0 );
+}
+
+static
+add_error( err, nerr, code, addr, msg )
+    Error      **err;
+    int                *nerr;
+    int                code;
+    char       *addr;
+    LDAPMessage        *msg;
+{
+       if ( *nerr == 0 ) {
+               *err = (Error *) malloc( sizeof(Error) );
+       } else {
+               *err = (Error *) realloc( *err, (*nerr + 1) * sizeof(Error) );
+       }
+
+       (*err)[*nerr].e_code = code;
+       (*err)[*nerr].e_addr = strdup( addr );
+       (*err)[*nerr].e_msg = msg;
+       (*nerr)++;
+
+       return;
+}
+
+static
+add_group( dn, list, nlist )
+    char       *dn;
+    Group      **list;
+    int                *nlist;
+{
+       int     i, namelen;
+       char    **ufn;
+
+       for ( i = 0; i < *nlist; i++ ) {
+               if ( strcmp( dn, (*list)[i].g_dn ) == 0 ) {
+                       syslog( LOG_ALERT, "group loop 2 detected (%s)", dn );
+                       return;
+               }
+       }
+
+       ufn = ldap_explode_dn( dn, 1 );
+       namelen = strlen( ufn[0] );
+
+       if ( *nlist == 0 ) {
+               *list = (Group *) malloc( sizeof(Group) );
+       } else {
+               *list = (Group *) realloc( *list, (*nlist + 1) *
+                   sizeof(Group) );
+       }
+
+       /* send errors to groupname-errors@host */
+       (*list)[*nlist].g_errorsto = (char *) malloc( namelen + sizeof(ERRORS)
+           + hostlen + 2 );
+       sprintf( (*list)[*nlist].g_errorsto, "%s-%s@%s", ufn[0], ERRORS, host );
+       (void) canonical( (*list)[*nlist].g_errorsto );
+
+       /* send to groupname-members@host - make it a list for send_group */
+       (*list)[*nlist].g_members = (char **) malloc( 2 * sizeof(char *) );
+       (*list)[*nlist].g_members[0] = (char *) malloc( namelen +
+           sizeof(MEMBERS) + hostlen + 2 );
+       sprintf( (*list)[*nlist].g_members[0], "%s-%s@%s", ufn[0], MEMBERS,
+           host );
+       (void) canonical( (*list)[*nlist].g_members[0] );
+       (*list)[*nlist].g_members[1] = NULL;
+
+       /* save the group's dn so we can check for loops above */
+       (*list)[*nlist].g_dn = strdup( dn );
+
+       (*nlist)++;
+
+       ldap_value_free( ufn );
+
+       return;
+}
+
+static
+unbind_and_exit( rc )
+    int        rc;
+{
+       int     i;
+
+       if ( (i = ldap_unbind( ld )) != LDAP_SUCCESS )
+               syslog( LOG_ALERT, "ldap_unbind failed %d\n", i );
+
+       exit( rc );
+}
+
+static char *
+canonical( s )
+    char       *s;
+{
+       char    *saves = s;
+
+       for ( ; *s != '\0'; s++ ) {
+               if ( *s == ' ' )
+                       *s = '.';
+       }
+
+       return( saves );
+}
+
+static
+group_loop( dn )
+    char       *dn;
+{
+       int             i;
+       static char     **groups;
+       static int      ngroups;
+
+       for ( i = 0; i < ngroups; i++ ) {
+               if ( strcmp( dn, groups[i] ) == 0 )
+                       return( 1 );
+       }
+
+       if ( ngroups == 0 )
+               groups = (char **) malloc( sizeof(char *) );
+       else
+               groups = (char **) realloc( groups,
+                   (ngroups + 1) * sizeof(char *) );
+
+       groups[ngroups++] = strdup( dn );
+
+       return( 0 );
+}
+
+static
+has_attributes( e, attr1, attr2 )
+    LDAPMessage        *e;
+    char       *attr1;
+    char       *attr2;
+{
+       char    **attr;
+
+       if ( (attr = ldap_get_values( ld, e, attr1 )) != NULL ) {
+               ldap_value_free( attr );
+               return( 1 );
+       }
+
+       if ( (attr = ldap_get_values( ld, e, attr2 )) != NULL ) {
+               ldap_value_free( attr );
+               return( 1 );
+       }
+
+       return( 0 );
+}
+
+static char **
+get_attributes_mail_dn( e, attr1, attr2 )
+    LDAPMessage        *e;
+    char       *attr1;
+    char       *attr2;         /* this one is dn-valued */
+{
+       LDAPMessage     *ee, *res;
+       char            **vals, **dnlist, **mail, **grname, **graddr;
+        char            *dn;
+       int             nto = 0, i, rc;
+       struct timeval  timeout;
+
+       dn = ldap_get_dn( ld, e );
+
+       vals = ldap_get_values( ld, e, attr1 );
+       for ( nto = 0; vals != NULL && vals[nto] != NULL; nto++ )
+               ;       /* NULL */
+
+       if ( (dnlist = ldap_get_values( ld, e, attr2 )) != NULL ) {
+               timeout.tv_sec = MAIL500_TIMEOUT;
+               timeout.tv_usec = 0;
+
+               for ( i = 0; dnlist[i] != NULL; i++ ) {
+                       if ( (rc = ldap_search_st( ld, dnlist[i],
+                           LDAP_SCOPE_BASE, "(objectclass=*)", attrs, 0,
+                           &timeout, &res )) != LDAP_SUCCESS ) {
+                               if ( rc != LDAP_NO_SUCH_OBJECT ) {
+                                       unbind_and_exit( EX_TEMPFAIL );
+                               }
+
+                               syslog( LOG_ALERT, "bad (%s) dn (%s)", attr2,
+                                   dnlist[i] );
+
+                               continue;
+                       }
+
+                       if ( (ee = ldap_first_entry( ld, res )) == NULL ) {
+                               syslog( LOG_ALERT, "error parsing x500 entry" );
+                               continue;
+                       }
+
+                       if ( isgroup(ee) ) {
+                               char    *graddr[2];
+
+                               grname = ldap_explode_dn( dnlist[i], 1 );
+
+                               /* groupname + host + @ + null */
+                               graddr[0] = (char *) malloc( strlen( grname[0] )
+                                   + strlen( host ) + 2 );
+                               graddr[1] = NULL;
+                               sprintf( graddr[0], "%s@%s", grname[0], host);
+                               (void) canonical( graddr[0] );
+
+                               add_to( &vals, &nto, graddr );
+
+                               free( graddr[0] );
+                               ldap_value_free( grname );
+                       } else if ( (mail = ldap_get_values( ld, ee, "mail" ))
+                           != NULL ) {
+                               add_to( &vals, &nto, mail );
+
+                               ldap_value_free( mail );
+                       }
+
+                       ldap_msgfree( res );
+               }
+       }
+
+       return( vals );
+}
diff --git a/clients/mail500/sendmail.cf b/clients/mail500/sendmail.cf
new file mode 100644 (file)
index 0000000..b7ec14d
--- /dev/null
@@ -0,0 +1,203 @@
+# Mostly rfc1123 compliant sendmail.cf
+#
+# Mail sendmail-admins-request@itd.umich.edu to join
+# sendmail-admins@itd.umich.edu. sendmail-admins carries information
+# regarding this sendmail.cf, including announcements of changes
+# and discussions of interest to admins.
+#
+DWtotalrecall
+Dw$W.rs.itd.umich.edu
+
+DBcunyvm.cuny.edu
+DUdestroyer.rs.itd.umich.edu
+
+DV2.2
+De$j sendmail ($v/$V) ready at $b
+Dj$w
+DlFrom $g $d
+Dnmailer-daemon
+Do.:%@!^=/[]
+Dq$?x\"$x\" <$g>$|$g$.
+
+OA/etc/aliases
+OQ/var/spool/mqueue
+OH/usr/lib/sendmail.hf
+OS/usr/lib/sendmail.st
+OP
+OD
+OX10
+Ox5
+Ou1
+Og1
+Odb
+OF0600
+OL9
+Oo
+Or15m
+Os
+OT3d
+
+H?P?Return-Path: <$g>
+HReceived: $?sfrom $s $.by $j ($v/$V)
+       $?rwith $r $.id $i; $b
+H?D?Resent-Date: $a
+H?F?Resent-From: $q
+H?M?Resent-Message-Id: <$t.$i@$j>
+H?M?Message-Id: <$t.$i@$j>
+H?D?Date: $a
+H?x?Full-Name: $x
+H?F?From: $q
+
+Troot uucp daemon
+
+Pspecial-delivery=100
+Pfirst-class=0
+Pjunk=-100
+
+# Organization:
+#
+#      ruleset 3 and friends
+#              focus addresses, don't screw with them
+#      ruleset 0 and friends
+#              beat the hell out of addresses, convert them to
+#              their deliverable form
+#      mailers and associated rulesets
+#              * focused addresses are body addresses, and should be
+#                left as they are
+#              * unfocused addresses are envelope addresses, and should
+#                be converted to the mailers format
+#      ruleset 4
+#              remove focus on all addresses
+
+# All addresses are passed through this rule. It functions by finding
+# the host to delivery to, and marking it with <>
+S3
+R$*<$+>$*                         $2                   remove comments
+R$+:$*;                                $@ $1:$2;               done if list
+R$*@$+                         $: $>5$1@$2             focus rfc822 addresses
+R$+!$+                         $: $>6$1!$2             focus uucp
+R$*<@$+>$*                     $: $1<@$[$2$]>$3        canonicalize
+R$*<$+>$*                      $@ $1<$2>$3             done if focused
+R$+%$+                         $: $1@$2                a%b -> a@b
+R$+@$+%$+                         $1%$2@$3             a@b%c -> a%b@c
+R$+@$+                         $: $>3$1@$2             try again...
+
+# Find the "next hop" in normal rfc822 syntax. These rules
+# all return upon marking the next hop with <>
+S5
+R@$+,@$+:$+                    $@ <@$1>,@$2:$3         @a,@b:@c -> <@a>,@b:c
+R@$+:$+                                $@ <@$1>:$2             @a:b -> <@a>:b
+R$+@$+                         $@ $1<@$2>              a@b -> a<@b>
+
+# Focus bang style addresses. Won't change already focused addresses.
+# Strips .uucp in bang paths, and converts domain syntax to rfc822 adresses.
+S6
+R$*<$+>$*                      $@ $1<$2>$3             already focused
+R$+!$+                         $: <$1!>$2              a!b -> <a!>b
+R<$+.uucp!>$+                     <$1!>$2              <a.uucp!>b -> <a!>b
+
+# Find a mailer. This involves finding the "real" host to deliver to,
+# by removing our local name, and/or doing a "domain forward"
+S0
+R$+                            $: $>7$1                deliverable format
+R$*<$+>$*                      $: $>11$1<$2>$3         domain forward
+R<$+!>$+                       $: $>12<$1!>$2          route uucp
+R$*<@$+.bitnet>$*                 $#inet$@$B$:$1<@$2.bitnet>$3
+R$*<@umich.edu>$*                 $#mail500$@umich.edu$:<$1>
+R$*<@itd.umich.edu>$*             $#mail500$@itd.umich.edu$:<$1>
+#R<$+!>$+                         $#uux$@$U$:<$1!>$2
+R<$+!>$+                          $#unet$@$U$:<$1!>$2
+R$*<@$+>$*                        $#inet$@$2$:$1<@$2>$3
+R$+                               $#local$:$1
+
+# Find the delivery address. Convert to standard-internal form,
+# remove local name.
+S7
+R<$-.$+!>$+                       $3<@$1.$2>           <a.b!>c -> c<@a.b>
+R$*<@$-.uucp>$*                           $>8$1@$2.uucp$3      *.uucp to !
+R$*<$+>$*                      $: $>9$1<$2>$3          strip local name
+
+# Convert rfc822 syntax to a uucp "bang path". This works well
+# on normal a@b address and route-addrs. It will also do something
+# to list syntax address, but it's not clear how correct it is.
+S8
+R@$+,@$+:$+                       @$1!$2:$3            @a,@b:c -> @a!b:c
+R@$+:$+@$+                        $1!$3!$2             @a:b@c -> a!c!b
+R@$+:$+!$+                        $1!$2!$3             @a:b!c -> a!b!c
+R$+@$+                            $2!$1                a@b -> b!c
+R$+                            $: $>3$1                refocus
+
+# Remove local names. You won't see things like a.b!u or u@b.uucp.
+# Add new rules here to accept more than just the default locally.
+S9
+R$*<@$w>$*                        $>10$1<@>$2          remove local name
+R<$W!>$+                          $>10<!>$1
+R<@umich.edu>$*:$*                $>10<@>$1:$2
+R$+%$+<@umich.edu>                $>10$1%$2<@>
+R$+!$+<@umich.edu>                $>10$1!$2<@>
+
+# Called only from above. Refocus and loop.
+S10
+R<@>,$+                                   $>3$1
+R<@>:$+                                   $>3$1
+R$+<@>                            $>3$1
+R<!>$+                            $>3$1
+R$*<$+>$*                      $: $>7$1<$2>$3
+
+# Convert domain names to uucp names, and refocus
+S11
+#R$*<@inquiry.org>$*                   $: $>8$1@inquiry$2
+
+# Route uucp addresses, if we're not connected to them. We rely on the
+# domain-path operator to down case addresses.
+S12
+R<$+!>$+                       $: <${$1$}!>$2          pathalias route
+R<$+!$+!>$+                       <$1!>$2!$3           <a!b!>c -> <a!>b!c
+
+Muux, P=/usr/bin/uux, F=DFMhu, S=13, R=14,
+       A=uux - -gC -b -r -a$f $h!rmail ($u)
+Munet, P=[IPC], F=mDFMhuX, S=13, R=14, A=IPC $h, E=\r\n
+Minet, P=[IPC], F=mDFMuX, S=15, R=15, A=IPC $h, E=\r\n
+Mlocal, P=/bin/mail, F=rlsDFMmn, S=16, R=16, A=mail -d $u
+Mprog, P=/bin/sh, F=lsDFMe, S=16, R=16, A=sh -c $u
+Mmail500, P=/usr/local/etc/mail500, F=DFMSmnXuh,
+       A=mail500 -f $f -h $h -m $n@$w $u
+
+# UUCP mailers require that the sender be in ! format.
+# XXX Do we add our name to other people's paths?
+S13
+R$*<@$+>$*                     $: $>8$1@$2$3
+#R<$w!>$+                      $@ <$W!>$1
+R<$+!>$+                       $@ <$1!>$2
+R$+:$*;                                $@ $1:$2;
+R<>                            $@
+#R$+                           $@ <$W!>$1
+R$+                            $@ <$w!>$1
+
+# Only add our name to local mail. Anything that's focused, leave alone.
+S14
+R$*<$+>$*                      $@ $1<$2>$3
+R$+:$*;                                $@ $1:$2;
+#R$+                           $@ <$W!>$1
+R$+                            $@ <$w!>$1
+
+# SMTP mailers require that addresses be in rfc822 format. If there's no
+# @ in the address, add one.
+S15
+R<$W!>$+                          $1<@$w>
+R<$-.$+!>$+                       $3<@$1.$2>
+R$*<@$+>$*                     $@ $1<@$2>$3
+R<$+!>$+                       $@ $1!$2<@$w>
+R$+:$*;                                $@ $1:$2;
+R<>                            $@
+R$+                            $@ $1<@$w>
+
+# Local and prog mailer
+S16
+R$+                            $@ $1
+
+#
+# Called on all outgoing addresses. Used to remove the <> focus
+#
+S4
+R$*<$+>$*                      $@ $1$2$3               defocus
diff --git a/clients/rcpt500/Make-template b/clients/rcpt500/Make-template
new file mode 100644 (file)
index 0000000..2677021
--- /dev/null
@@ -0,0 +1,71 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1994 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       X.500 ldap rcpt500 mail query responder makefile
+#
+#-----------------------------------------------------------------------------
+LDAPSRC        = ../..
+HDIR   = $(LDAPSRC)/include
+LDIR   = $(LDAPSRC)/libraries
+VERSIONFILE = $(LDAPSRC)/build/version
+
+SRCS= main.c cmds.c help.c query.c
+OBJS= main.o cmds.o help.o query.o
+
+INCLUDES= -I$(HDIR)
+DEFINES        = $(DEFS)
+CFLAGS = $(INCLUDES) $(DEFINES) $(ACFLAGS)
+LIBS   = -lldap -llber $(KRBLIBFLAG) $(KRBLIBS) $(ALIBS)
+
+all:   rcpt500
+
+rcpt500:       version.o
+       $(CC) $(ALDFLAGS) -o $@ $(OBJS) version.o -L$(LDIR) $(LIBS)
+
+version.c: $(OBJS) $(LDIR)/libldap.a
+       $(RM) $@
+       (u=$${USER-root} v=`$(CAT) $(VERSIONFILE)` d=`$(PWD)` h=`$(HOSTNAME)` \
+       t=`$(DATE)`; $(SED) -e "s|%WHEN%|$${t}|" \
+       -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+       -e "s|%VERSION%|$${v}|" \
+       < Version.c > $@)
+
+install:       rcpt500 rcpt500.help FORCE
+       -$(MKDIR) -p $(ETCDIR)
+       $(INSTALL) $(INSTALLFLAGS) -m 755 rcpt500 $(ETCDIR)
+       $(INSTALL) $(INSTALLFLAGS) -m 644 rcpt500.help $(ETCDIR)
+
+lint:  FORCE
+       $(LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+5lint: FORCE
+       $(5LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+clean: FORCE
+       $(RM) *.o core a.out version.c rcpt500
+
+depend:        FORCE
+       $(MKDEP) $(INCLUDES) $(DEFINES) $(SRCS)
+
+links:
+       @$(LN) .src/README .src/*.[ch] .src/*.help .
+
+# DO NOT DELETE THIS LINE -- mkdep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+main.o: main.c ../../include/portable.h ../../include/ldapconfig.h rcpt500.h
+cmds.o: cmds.c rcpt500.h
+help.o: help.c ../../include/portable.h ../../include/ldapconfig.h rcpt500.h
+query.o: query.c ../../include/lber.h ../../include/ldap.h
+query.o: ../../include/portable.h ../../include/ldapconfig.h
+query.o: ../../include/disptmpl.h rcpt500.h
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/clients/rcpt500/README b/clients/rcpt500/README
new file mode 100644 (file)
index 0000000..a6614f5
--- /dev/null
@@ -0,0 +1,115 @@
+LDAP rcpt500 mail query server README
+
+OVERVIEW
+This is a mail-query server that answers X.500 white pages queries.
+It is designed to be run out of your mail systems alias file, or the
+equivalent.  It expects to be fed the entire contents (including
+headers) of an RFC822 message via standard input.  It parses the
+message, looking in the Subject: field or the body of the message
+for a command that it recognizes.
+
+The commands currently recognized are listed in the file cmd.c.  They
+all map into two actual operations the server performs: an X.500 query
+or a help command.  If no recognizable command is found in the
+Subject:  or body of the message, help is assumed.  An appropriate
+reply is sent to the sender of the message in response to the command.
+
+The help command returns the contents of the file rcpt500.help.  You
+can modify the contents as appropriate for your local site.
+
+The query command performs a series of X.500 searches to try to find
+a person that matches the object of the query.  If more than one
+X.500 entry matches, a list is returned.  If exactly one is matched,
+detailed information is returned. Here is an example message and rcpt500
+generated reply:
+
+Query message:
+       Mail x500-query@umich.edu
+       Subject: find tim howes
+       .
+
+Reply from rcpt500:
+    Received: from totalrecall.rs.itd.umich.edu by terminator.cc.umich.edu
+           id AA26151; Wed, 16 Sep 92 11:26:18 -0400
+    Received: by umich.edu (5.65/2.2)
+           id AA12041; Wed, 16 Sep 92 11:26:17 -0400
+    Message-Id: <9209161526.AA12041@umich.edu>
+    Date: Wed, 16 Sep 92 11:26:17 -0400
+    From: "X.500 Query Program" <X500-Query@umich.edu>
+    Subject: Re: find tim howes
+    In-Reply-To: Your message of "Wed, 16 Sep 92 11:26:12 -0400"
+                <9209161526.AA26144@terminator.cc.umich.edu>
+    To: "Mark Smith" <mcs@terminator.cc.umich.edu>
+
+    One exact match was found for 'tim howes':
+    "Timothy A Howes, Information Technology Division, Faculty and Staff"
+      Also known as:   
+                       Timothy Howes
+                       Timothy A Howes 1
+                       Timothy A Howes
+                       Tim Howes
+      E-mail address:  
+                       tim@terminator.cc.umich.edu
+      Fax number:      
+                       +1 313 764 5140 (argus building)
+      Business phone:  
+                       +1 313 747-4454
+      Business address:
+                       ITD Research Systems 
+                       535 W William St. 
+                       Ann Arbor, MI 48103-4943
+      Title:           
+                       Systems Research Programmer II, Research Systems
+      Uniqname:        
+                       tim
+
+If you want to try out rcpt500 yourself before installing it at your site,
+send a message to x500-query@umich.edu (we have a server running
+there that serves University of Michigan white pages information).
+
+
+CONFIGURING AND RUNNING rcpt500 AT YOUR LOCAL SITE
+You will probably need to make changes to the file ldapconfig.h.edit to
+configure rcpt500 for your local site.  There are comments in the file
+describing each variable you might need to change.  Then type make in
+the rcpt500 directory to make sure things are up to date.  You will
+need to install the rcpt500 binary and help files (make install).  This
+all assumes you have built the LDAP libraries already.  If in doubt,
+just do a make from the top of the LDAP distribution.
+
+You will then need to set up an alias that your users can send mail
+to that will feed the messages to rcpt500.  At our site, we run sendmail
+so the alias is in /usr/lib/aliases and looks like:
+
+       x500-query:     "|/usr/local/etc/rcpt500 -l"
+
+The available command line options for rcpt500 are:
+    -l                 enable logging of requests via the syslog
+                         LOG_DAEMON facility
+    -h ldaphost                specify LDAP server host to connect to
+    -b searchbase      specify starting point of X.500 searches
+    -a                 don't deference aliases during searches
+    -s stripcount      remove "stripcount" DN components from user
+                         friendly form names that are displayed
+    -z sizelimit       return at most "sizelimit" entries
+    -u dapuser         DN to bind to X.500 as when searching
+
+The search and display behavior is defined in the ldapfilter.conf and
+ldaptemplates.conf files.
+
+
+SUPPORT
+
+    The software is provided as is without any express or implied
+    warranty, but there is a bug reporting mail address which is
+    responded to on a best-effort basis:
+
+           ldap-support@terminator.cc.umich.edu
+
+
+BUG REPORTING
+
+    Bug reports should be sent to bug-ldap@terminator.cc.umich.edu.
+
+
+README Last updated 10 November 1994 Mark Smith
diff --git a/clients/rcpt500/Version.c b/clients/rcpt500/Version.c
new file mode 100644 (file)
index 0000000..62c9a6c
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 1992 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+char Version[] = "  rcpt500 v%VERSION% (%WHEN%)\n\t%WHOANDWHERE%\n";
diff --git a/clients/rcpt500/cmds.c b/clients/rcpt500/cmds.c
new file mode 100644 (file)
index 0000000..fe89309
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * cmds.c: command table for rcpt500 (X.500 email query responder)
+ *
+ * 18 June 1992 by Mark C Smith
+ * Copyright (c) 1992 The Regents of The University of Michigan
+ * All Rights Reserved
+ */
+
+#include <stdio.h>
+#include "rcpt500.h"
+
+struct command cmds[] = {
+       "help",         help_cmd,       /* help must be the first command */
+       "query for",    query_cmd,      /* must come before "query for" */
+       "query",        query_cmd,
+       "find",         query_cmd,
+       "read",         query_cmd,
+       "search for",   query_cmd,      /* must come before "search" */
+       "search",       query_cmd,
+       "lookup",       query_cmd,
+       "look up",      query_cmd,
+       "show",         query_cmd,
+       "finger",       query_cmd,
+       "whois",        query_cmd,
+       "who is",       query_cmd,
+       "locate",       query_cmd,
+       NULL,           NULL            /* end of command list */
+};
diff --git a/clients/rcpt500/help.c b/clients/rcpt500/help.c
new file mode 100644 (file)
index 0000000..0f541ab
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * help.c: for rcpt500 (X.500 email query responder)
+ *
+ * 16 June 1992 by Mark C Smith
+ * Copyright (c) 1992 The Regents of The University of Michigan
+ * All Rights Reserved
+ */
+
+#include <stdio.h>
+#include <syslog.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include "portable.h"
+#include "ldapconfig.h"
+#include "rcpt500.h"
+
+extern int dosyslog;
+
+
+int
+help_cmd( msgp, reply )
+    struct msginfo     *msgp;
+    char               *reply;
+{
+    int                fd, len;
+
+    if (( fd = open( RCPT500_HELPFILE, O_RDONLY )) == -1 ) {
+       if ( dosyslog ) {
+           syslog( LOG_ERR, "open help file: %m" );
+       }
+       strcat( reply, "Unable to access the help file.  Sorry!\n" );
+       return( 0 );
+    }
+
+    len = read( fd, reply + strlen( reply ), MAXSIZE );
+    close( fd );
+
+    if ( len == -1 ) {
+       if ( dosyslog ) {
+           syslog( LOG_ERR, "read help file: %m" );
+       }
+       strcat( reply, "Unable to read the help file.  Sorry!\n" );
+       return( 0 );
+    }
+
+    *(reply + len ) = '\0';
+    return( 0 );
+}
diff --git a/clients/rcpt500/main.c b/clients/rcpt500/main.c
new file mode 100644 (file)
index 0000000..3e65ac2
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+ * main.c: for rcpt500 (X.500 email query responder)
+ *
+ * 16 June 1992 by Mark C Smith
+ * Copyright (c) 1992 The Regents of The University of Michigan
+ * All Rights Reserved
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "portable.h"
+#include "ldapconfig.h"
+#include "rcpt500.h"
+
+#ifdef ultrix
+extern char *strdup();
+#endif
+
+int dosyslog = 0;
+#ifdef CLDAP
+int do_cldap = 0;
+#endif /* CLDAP */
+int derefaliases = 1;
+int sizelimit = RCPT500_SIZELIMIT;
+int rdncount = RCPT500_RDNCOUNT;
+int ldapport = 0;
+char *ldaphost = LDAPHOST;
+char *searchbase = RCPT500_BASE;
+char *dapuser = RCPT500_BINDDN;
+char *filterfile = FILTERFILE;
+char *templatefile = TEMPLATEFILE;
+char reply[ MAXSIZE * RCPT500_LISTLIMIT ];
+
+
+
+/*
+ * functions
+ */
+int    read_msg();
+char   *read_hdr();
+int    send_reply();
+
+/*
+ * main is invoked by sendmail via the alias file
+ * the entire incoming message gets piped to our standard input
+ */
+main( argc, argv )
+    int                argc;
+    char       **argv;
+{
+    char               *prog, *usage = "%s [-l] [-U] [-h ldaphost] [-p ldapport] [-b searchbase] [-a] [-z sizelimit] [-u dapuser] [-f filterfile] [-t templatefile] [-c rdncount]\n";
+    struct msginfo     msg;
+    int                        c, errflg;
+    char               *replytext;
+
+    extern int         optind;
+    extern char                *optarg;
+
+    *reply = '\0';
+
+    if (( prog = strrchr( argv[ 0 ], '/' )) == NULL ) {
+       prog = strdup( argv[ 0 ] );
+    } else {
+       prog = strdup( prog + 1 );
+    }
+
+    errflg = 0;
+    while (( c = getopt( argc, argv, "alUh:b:s:z:f:t:p:c:" )) != EOF ) {
+       switch( c ) {
+       case 'a':
+           derefaliases = 0;
+           break;
+       case 'l':
+           dosyslog = 1;
+           break;
+       case 'U':
+#ifdef CLDAP
+           do_cldap = 1;
+#else /* CLDAP */
+           fprintf( stderr, "Compile with -DCLDAP for -U support\n" );
+#endif /* CLDAP */
+           break;      
+       case 'b':
+           searchbase = optarg;
+           break;
+       case 'h':
+           ldaphost = optarg;
+           break;
+       case 'p':
+           ldapport = atoi( optarg );
+           break;
+       case 'z':
+           sizelimit = atoi( optarg );
+           break;
+       case 'u':
+           dapuser = optarg;
+           break;
+       case 'f':
+           filterfile = optarg;
+           break;
+       case 't':
+           templatefile = optarg;
+           break;
+       case 'c':
+           rdncount = atoi( optarg );
+           break;
+       default:
+           ++errflg;
+       }
+    }
+    if ( errflg || optind < argc ) {
+       fprintf( stderr, usage, prog );
+       exit( 1 );
+    }
+
+    if ( dosyslog ) {
+       /*
+        * if syslogging requested, initialize
+        */
+#ifdef LOG_DAEMON
+       openlog( prog, OPENLOG_OPTIONS, LOG_DAEMON );
+#else
+       openlog( prog, OPENLOG_OPTIONS );
+#endif
+    }
+
+    if ( read_msg( stdin, &msg ) < 0 ) {
+       if ( dosyslog ) {
+           syslog( LOG_INFO, "unparseable message ignored" );
+       }
+       exit( 0 );      /* so as not to give sendmail an error */
+    }
+
+    if ( dosyslog ) {
+       syslog( LOG_INFO, "processing command \"%s %s\" from %s",
+               ( msg.msg_command < 0 ) ? "Unknown" :
+               cmds[ msg.msg_command ].cmd_text,
+               ( msg.msg_arg == NULL ) ? "" : msg.msg_arg, msg.msg_replyto );
+    }
+
+    if ( msg.msg_command < 0 ) {
+       msg.msg_command = 0;    /* unknown command == help command */
+    }
+
+/*
+    sprintf( reply, "Your request was interpreted as: %s %s\n\n",
+           cmds[ msg.msg_command ].cmd_text, msg.msg_arg );
+*/
+
+    (*cmds[ msg.msg_command ].cmd_handler)( &msg, reply );
+
+    if ( send_reply( &msg, reply ) < 0 ) {
+       if ( dosyslog ) {
+           syslog( LOG_INFO, "reply failed: %m" );
+       }
+       exit( 0 );      /* so as not to give sendmail an error */
+    }
+
+    if ( dosyslog ) {
+       syslog( LOG_INFO, "reply OK" );
+    }
+
+    exit( 0 );
+}
+
+
+int
+read_msg( fp, msgp )
+    FILE               *fp;
+    struct msginfo     *msgp;
+{
+    char       buf[ MAXSIZE ], *line;
+    int                command = -1;
+
+    msgp->msg_replyto = msgp->msg_date = msgp->msg_subject = NULL;
+
+    line = NULL;
+    while( 1 ) {
+       if ( line == NULL ) {
+           if (( line = fgets( buf, MAXSIZE, fp )) == NULL ) {
+               break;
+           }
+           buf[ strlen( buf ) - 1 ] = '\0';    /* remove trailing newline */
+       }
+
+       if ( *buf == '\0' ) {   /* start of message body */
+           break;
+       }
+       if ( strncasecmp( buf, "Reply-To:", 9 ) == 0 ) {
+           if ( msgp->msg_replyto != NULL ) {
+               free( msgp->msg_replyto );
+           }
+            msgp->msg_replyto = read_hdr( fp, 9, buf, MAXSIZE, &line );
+       } else if ( strncasecmp( buf, "From:", 5 ) == 0 &&
+                   msgp->msg_replyto == NULL ) {
+            msgp->msg_replyto = read_hdr( fp, 5, buf, MAXSIZE, &line );
+       } else if ( strncasecmp( buf, "Date:", 5 ) == 0 ) {
+            msgp->msg_date = read_hdr( fp, 5, buf, MAXSIZE, &line );
+       } else if ( strncasecmp( buf, "Message-ID:", 5 ) == 0 ) {
+            msgp->msg_messageid = read_hdr( fp, 11, buf, MAXSIZE, &line );
+       } else if ( strncasecmp( buf, "Subject:", 8 ) == 0 ) {
+            if (( msgp->msg_subject =
+                   read_hdr( fp, 8, buf, MAXSIZE, &line )) != NULL ) {
+               command = find_command( msgp->msg_subject, &msgp->msg_arg );
+           }
+       } else {
+           line = NULL;        /* discard current line */
+       }
+    }
+
+    while ( command < 0 && line != NULL ) {
+       /*
+        * read the body of the message, looking for commands
+        */
+       if (( line = fgets( buf, MAXSIZE, fp )) != NULL ) {
+           buf[ strlen( buf ) - 1 ] = '\0';    /* remove trailing newline */
+           command = find_command( buf, &msgp->msg_arg );
+       }
+    }
+
+    if ( msgp->msg_replyto == NULL ) {
+       return( -1 );
+    }
+
+    msgp->msg_command = command;
+    return( 0 );
+}
+
+
+char *
+read_hdr( fp, offset, buf, MAXSIZEe, linep )
+    FILE       *fp;
+    int                offset;
+    char       *buf;
+    int                MAXSIZEe;
+    char       **linep;
+{
+    char       *hdr;
+
+    for ( hdr = buf + offset; isspace( *hdr ); ++hdr ) {
+       ;
+    }
+    if (( hdr = strdup( hdr )) == NULL ) {
+       if ( dosyslog ) {
+           syslog( LOG_ERR, "strdup: %m" );
+       }
+       exit( 1 );
+    }
+
+    while ( 1 ) {
+       *linep = fgets( buf, MAXSIZE, fp );
+       buf[ strlen( buf ) - 1 ] = '\0';        /* remove trailing newline */
+       if ( *linep == NULL || !isspace( **linep )) {
+           break;
+       }
+       if (( hdr = realloc( hdr, strlen( hdr ) +
+                   strlen( *linep ) + 3 )) == NULL) {
+           if ( dosyslog ) {
+               syslog( LOG_ERR, "realloc: %m" );
+           }
+           exit( 1 );
+       }
+       strcat( hdr, "\n" );
+       strcat( hdr, *linep );
+    }
+
+    return( hdr );
+}
+
+
+int
+send_reply( msgp, body )
+    struct msginfo     *msgp;
+    char               *body;
+{
+    char       buf[ MAXSIZE ];
+    FILE       *cmdpipe;
+    int                rc;
+    
+    if (( cmdpipe = popen( RCPT500_PIPEMAILCMD, "w" )) == NULL ) {
+       if ( dosyslog ) {
+           syslog( LOG_ERR, "popen pipemailcmd failed: %m" );
+       }
+       return( -1 );
+    }
+
+    /*
+     * send the headers
+     */
+
+    sprintf( buf, "From: %s\n", RCPT500_FROM );
+    rc = fwrite( buf, strlen( buf ), 1, cmdpipe );
+
+    if ( rc == 1 ) {
+       if ( msgp->msg_subject != NULL ) {
+           sprintf( buf, "Subject: Re: %s\n", msgp->msg_subject );
+       } else {
+           sprintf( buf, "Subject: query response\n" );
+       }
+       rc = fwrite( buf, strlen( buf ), 1, cmdpipe );
+    }
+
+    if ( rc == 1 && msgp->msg_date != NULL ) {
+       /*
+        * add "In-reply-to:" header
+        */
+       if ( msgp->msg_messageid == NULL ) {
+           sprintf( buf, "In-reply-to: Your message of \"%s\"\n",
+                   msgp->msg_date );
+       } else {
+           sprintf( buf,
+                   "In-reply-to: Your message of \"%s\"\n             %s\n",
+                   msgp->msg_date, msgp->msg_messageid );
+       }
+       rc = fwrite( buf, strlen( buf ), 1, cmdpipe );
+    }
+
+    if ( rc == 1 ) {
+       sprintf( buf, "To: %s\n", msgp->msg_replyto );
+       rc = fwrite( buf, strlen( buf ), 1, cmdpipe );
+    }
+
+    /*
+     * send the header/body separator (blank line)
+     */
+    if ( rc == 1 ) {
+       rc = fwrite( "\n", 1, 1, cmdpipe );
+    }
+
+    /*
+     * send the body
+     */
+    if ( rc == 1 ) {
+       rc = fwrite( body, strlen( body ), 1, cmdpipe );
+    }
+
+    if ( rc != 1 && dosyslog ) {
+       syslog( LOG_ERR, "write to binmail failed: %m" );
+    }
+
+    if ( pclose( cmdpipe ) < 0 ) {
+       if ( dosyslog ) {
+           syslog( LOG_ERR, "pclose binmail failed: %m" );
+       }
+       return( -1 );
+    }
+
+    return( rc == 1 ? 0 : -1 );
+}
+
+
+int
+find_command( text, argp )
+    char       *text;
+    char       **argp;
+{
+    int                i;
+    char       *s, *p;
+    static char argbuf[ MAXSIZE ];
+
+    p = text;
+    for ( s = argbuf; *p != '\0'; ++p ) {
+       *s++ = tolower( *p );
+    }
+    *s = '\0';
+
+    for ( i = 0; cmds[ i ].cmd_text != NULL; ++i ) {
+       if (( s = strstr( argbuf, cmds[ i ].cmd_text )) != NULL
+                   && isspace( *(s + strlen( cmds[ i ].cmd_text )))) {
+           strcpy( argbuf, text + (s - argbuf) + strlen( cmds[ i ].cmd_text ));
+           *argp = argbuf;
+           while ( isspace( **argp )) {
+               ++(*argp);
+           }
+           return( i );
+       }
+    }
+
+    return( -1 );
+}
diff --git a/clients/rcpt500/query.c b/clients/rcpt500/query.c
new file mode 100644 (file)
index 0000000..1ac78c1
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * query.c: for rcpt500 (X.500 email query responder)
+ *
+ * 18 June 1992 by Mark C Smith
+ * Copyright (c) 1992 The Regents of The University of Michigan
+ * All Rights Reserved
+ */
+
+#include <stdio.h>
+#include <syslog.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/time.h>
+
+#include "lber.h"
+#include "ldap.h"
+#include "portable.h"
+#include "ldapconfig.h"
+#include "disptmpl.h"
+#include "rcpt500.h"
+
+extern int dosyslog;
+extern int do_cldap;
+extern int rdncount;
+extern int derefaliases;
+extern int sizelimit;
+extern int ldapport;
+extern char *ldaphost;
+extern char *searchbase;
+extern char *dapuser;
+extern char *filterfile;
+extern char *templatefile;
+
+static char buf[ MAXSIZE ];
+static char *errpreface = "Your query failed: ";
+
+extern int      strcasecmp();
+
+void close_ldap();
+
+
+int
+query_cmd( msgp, reply )
+    struct msginfo     *msgp;
+    char               *reply;
+{
+    LDAP                       *ldp;
+    LDAPMessage                        *ldmsgp, *entry;
+    char                       *s, *dn;
+    int                                matches, rc, ufn;
+    LDAPFiltDesc               *lfdp;
+    LDAPFiltInfo               *lfi;
+    struct ldap_disptmpl       *tmpllist = NULL;
+    static char        *attrs[] = { "cn", "title",
+#ifdef RCPT500_SORT_ATTR
+                       RCPT500_SORT_ATTR,
+#endif
+                       NULL };
+
+    ufn = 0;
+
+    if ( msgp->msg_arg == NULL ) {
+       return( help_cmd( msgp, reply ));
+    }
+
+    remove_trailing_space( msgp->msg_arg );
+    if ( *msgp->msg_arg == '\0' ) {
+       return( help_cmd( msgp, reply ));
+    }
+
+    if (( lfdp = ldap_init_getfilter( filterfile )) == NULL ) {
+       strcat( reply, errpreface );
+       strcat( reply, "filter file configuration error.  Try again later." );
+       return( 0 );
+    }
+
+    /*
+     * open connection to LDAP server and bind as dapuser
+     */
+#ifdef CLDAP
+    if ( do_cldap )
+       ldp = cldap_open( ldaphost, ldapport );
+    else
+#endif /* CLDAP */
+       ldp = ldap_open( ldaphost, ldapport );
+
+    if ( ldp == NULL ) {
+       strcat( reply, errpreface );
+       strcat( reply, "X.500 service unavailable.  Try again later." );
+       ldap_getfilter_free( lfdp );
+       return( 0 );
+    }
+
+#ifdef CLDAP
+    if ( !do_cldap )
+#endif /* CLDAP */
+       if ( ldap_simple_bind_s( ldp, dapuser, NULL ) != LDAP_SUCCESS ) {
+           report_ldap_err( ldp, reply );
+           close_ldap( ldp );
+           ldap_getfilter_free( lfdp );
+           return( 0 );
+       }
+
+    /*
+     * set options for search and build filter
+     */
+    ldp->ld_deref = derefaliases;
+    ldp->ld_sizelimit = sizelimit;
+
+    matches = 0;
+
+#ifdef RCPT500_UFN
+#ifdef CLDAP
+    if ( !do_cldap && strchr( msgp->msg_arg, ',' ) != NULL ) {
+#else /* CLDAP */
+    if ( strchr( msgp->msg_arg, ',' ) != NULL ) {
+#endif /* CLDAP */
+       struct timeval  tv;
+
+       ldap_ufn_setprefix( ldp, searchbase );
+       if (( rc = ldap_ufn_search_s( ldp, msgp->msg_arg, attrs, 0, &ldmsgp ))
+               != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED
+               && rc != LDAP_TIMELIMIT_EXCEEDED ) {
+           report_ldap_err( ldp, reply );
+           close_ldap( ldp );
+           ldap_getfilter_free( lfdp );
+           return( 0 );
+       }
+       matches = ldap_count_entries( ldp, ldmsgp );
+       ufn = 1;
+    } else {
+#endif /* RCPT500_UFN */
+    
+       for ( lfi = ldap_getfirstfilter( lfdp, "rcpt500", msgp->msg_arg );
+               lfi != NULL; lfi = ldap_getnextfilter( lfdp )) {
+#ifdef CLDAP
+           if ( do_cldap )
+               rc = cldap_search_s( ldp, searchbase, LDAP_SCOPE_SUBTREE,
+                       lfi->lfi_filter, attrs, 0, &ldmsgp, dapuser );
+           else 
+#endif /* CLDAP */
+               rc = ldap_search_s( ldp, searchbase, LDAP_SCOPE_SUBTREE,
+                       lfi->lfi_filter, attrs, 0, &ldmsgp );
+
+           if ( rc != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED
+                   && rc != LDAP_TIMELIMIT_EXCEEDED ) {
+               report_ldap_err( ldp, reply );
+               close_ldap( ldp );
+               ldap_getfilter_free( lfdp );
+               return( 0 );
+           }
+
+           if (( matches = ldap_count_entries( ldp, ldmsgp )) != 0 ) {
+               break;
+           }
+
+           if ( ldmsgp != NULL ) {
+               ldap_msgfree( ldmsgp );
+           }
+       }
+#ifdef RCPT500_UFN
+    }
+#endif /* RCPT500_UFN */
+
+    if ( matches == 0 ) {
+       sprintf( buf, "No matches were found for '%s'\n", msgp->msg_arg );
+       strcat( reply, buf );
+       close_ldap( ldp );
+       ldap_getfilter_free( lfdp );
+       return( 0 );
+    }
+
+    if ( ldp->ld_errno == LDAP_TIMELIMIT_EXCEEDED
+           || ldp->ld_errno == LDAP_SIZELIMIT_EXCEEDED ) {
+       strcat( reply, "(Partial results only - a limit was exceeded)\n" );
+    }
+
+    if ( matches <= RCPT500_LISTLIMIT ) {
+       sprintf( buf, "%d %s match%s found for '%s':\n\n", matches,
+               ufn ? "UFN" : lfi->lfi_desc,
+               ( matches > 1 ) ? "es" : "", msgp->msg_arg );
+       strcat( reply, buf );
+
+       if (( rc = ldap_init_templates( templatefile, &tmpllist )) != 0 ) {
+           sprintf( buf, "%s ldap_init_templates( %s ) failed (error %d)\n",
+               errpreface, templatefile, rc );
+           strcat( reply, buf );
+       }
+
+       for ( entry = ldap_first_entry( ldp, ldmsgp ); entry != NULL; ) {
+           dn = ldap_get_dn( ldp, entry );
+           if ( do_read( ldp, dn, reply, tmpllist ) != LDAP_SUCCESS ) {
+               report_ldap_err( ldp, reply );
+           }
+           free( dn );
+           if (( entry = ldap_next_entry( ldp, entry )) != NULL ) {
+               strcat( reply, "\n-------\n\n" );
+           }
+       }
+
+       if ( tmpllist != NULL ) {
+           ldap_free_templates( tmpllist );
+       }
+       ldap_msgfree( ldmsgp );
+
+    } else {
+       sprintf( buf, "%d %s matches were found for '%s':\n",
+               matches, ufn ? "UFN" : lfi->lfi_desc, msgp->msg_arg );
+       strcat( reply, buf );
+       append_entry_list( reply, msgp->msg_arg, ldp, ldmsgp );
+       ldap_msgfree( ldmsgp );
+    }
+
+    close_ldap( ldp );
+    ldap_getfilter_free( lfdp );
+    return( 0 );
+}
+
+
+void
+close_ldap( LDAP *ld )
+{
+#ifdef CLDAP
+    if ( do_cldap )
+       cldap_close( ld );
+    else
+#endif /* CLDAP */
+       ldap_unbind( ld );
+}
+
+
+append_entry_list( reply, query, ldp, ldmsgp )
+    char       *reply;
+    char       *query;
+    LDAP       *ldp;
+    LDAPMessage        *ldmsgp;
+{
+    LDAPMessage        *e;
+    char       *dn, *rdn, *s, **title;
+    int                free_rdn = 0;
+
+#ifdef RCPT500_SORT_ATTR
+    ldap_sort_entries( ldp, &ldmsgp, RCPT500_SORT_ATTR, strcasecmp );
+#endif
+
+    for ( e = ldap_first_entry( ldp, ldmsgp ); e != NULL;
+               e = ldap_next_entry( ldp, e )) {
+       dn = ldap_get_dn( ldp, e );
+       if (( s = strchr( dn, ',' )) != NULL ) {
+           *s = '\0';
+       }
+       if (( s = strchr( dn, '=' )) == NULL ) {
+           rdn = dn;
+       } else {
+           rdn = s + 1;
+       }
+
+#ifdef UOFM
+       /*
+        * if this entry's rdn is an exact match for the thing looked up, we
+        * return the CN that has a digit after it, so that the user is
+        * returned something guaranteed to yield exactly one match if they
+        * pick it from the list and query it
+        */
+
+       if ( strcasecmp( rdn, query ) == 0 ) {
+           char        **cn;
+           int         i;
+
+           if (( cn = ldap_get_values( ldp, e, "cn" )) != NULL ) {
+               for ( i = 0; cn[i] != NULL; i++ ) {
+                   if ( isdigit( *( cn[i] + strlen( cn[i] ) - 1 ))) {
+                       rdn = strdup( cn[i] );
+                       free_rdn = 1;
+                       break;
+                   }
+               }
+               ldap_value_free( cn );
+           }
+       }
+#endif /* UOFM */
+
+       title = ldap_get_values( ldp, e, "title" );
+       sprintf( buf, "  %-20s    %s\n", rdn, title ? title[0] : "" );
+       strcat( reply, buf );
+       if ( title != NULL ) {
+           ldap_value_free( title );
+       }
+       free( dn );
+       if ( free_rdn ) {
+           free( rdn );
+       }
+    }
+}
+
+
+int
+append_text( reply, text, len )
+    char       *reply;
+    char       *text;
+    int                len;
+{
+    strcat( reply, text );
+    return( len );
+}
+    
+
+int
+do_read( ldp, dn, reply, tmpll )
+    LDAP                       *ldp;
+    char                       *dn;
+    char                       *reply;
+    struct ldap_disptmpl       *tmpll;
+{
+    int                                rc;
+    static char        *maildefvals[] = { "None registered in this service", NULL };
+    static char        *defattrs[] = { "mail", NULL };
+    static char        **defvals[] = { maildefvals, NULL };
+
+
+    rc = ldap_entry2text_search( ldp, dn, searchbase, NULLMSG, tmpll,
+           defattrs, defvals, (void *)append_text, (void *)reply, "\n",
+           rdncount, LDAP_DISP_OPT_DOSEARCHACTIONS );
+
+    return( rc );
+}
+
+
+report_ldap_err( ldp, reply )
+    LDAP       *ldp;
+    char       *reply;
+{
+    strcat( reply, errpreface );
+    strcat( reply, ldap_err2string( ldp->ld_errno ));
+    strcat( reply, "\n" );
+}
+
+
+remove_trailing_space( s )
+    char       *s;
+{
+    char       *p = s + strlen( s ) - 1;
+
+    while ( isspace( *p ) && p > s ) {
+       --p;
+    }
+    *(++p) = '\0';
+}
diff --git a/clients/rcpt500/rcpt500.h b/clients/rcpt500/rcpt500.h
new file mode 100644 (file)
index 0000000..537f92c
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * rcpt500.h: includes for rcpt500 (X.500 email query responder)
+ *
+ * 16 June 1992 by Mark C Smith
+ * Copyright (c) 1992 The Regents of The University of Michigan
+ * All Rights Reserved
+ */
+
+struct msginfo {
+    char       *msg_subject;
+    char       *msg_replyto;   /* actually could be from From: line */
+    char       *msg_date;
+    char       *msg_messageid;
+    int                msg_command;
+    char       *msg_arg;
+};
+
+struct command {
+    char        *cmd_text;              /* text for command, e.g. "HELP" */
+    int        (*cmd_handler)();        /* pointer to handler function */
+};
+
+
+#define MAXSIZE                8096
+
+
+/*
+ * functions
+ */
+int    help_cmd();
+int    query_cmd();
+
+/*
+ * externs
+ */
+extern struct command cmds[];
diff --git a/clients/rcpt500/rcpt500.help b/clients/rcpt500/rcpt500.help
new file mode 100644 (file)
index 0000000..eccfb1c
--- /dev/null
@@ -0,0 +1,44 @@
+How to use the University of Michigan X.500 Email Query Service
+
+By sending electronic mail to the address:
+
+        x500-query@umich.edu
+
+you can access the campus X.500 Directory.  The Directory contains
+information about all faculty, staff, and students of the University,
+including phone numbers, mailing addresses, job titles, email
+addresses, and more.
+
+To query the service, send a piece of email to this address with a
+command similar to:
+
+       find <name>
+
+       e.g. find robert jones
+
+somewhere in the Subject: field or anywhere in the body (text) of the
+message.  You will receive a reply that contains information about the
+target of your query (in the above example, you would get information
+on all "robert jones" who are at the University).  The <name> can be
+a person's full name, last name, or uniqname.  An search for exact
+matches is first tried; if there are no exact matches, an approximate
+search (using soundex rules) is done.
+
+If your query matches exactly one person, you will receive detailed
+information about that person.  If more than one is matched, a list will
+be returned that should hopefully provide you with enough information
+to be able to determine which individual you really want.  Another
+query can then be made to obtain the detailed information.
+
+This service understands a number of synonyms for the "find" command,
+including: "whois", "search", "look up", "show."  You can also send
+a message with the word "help" in it to get this text returned to you.
+
+Note that this service is entirely automated -- no humans will respond
+to requests or other email sent here.  If you have questions or
+comments on the X.500 Directory service in general, or about this
+service in particular, please send electronic mail to:
+
+        x500@umich.edu
+
+This is the end of the help text.
diff --git a/clients/tools/Make-template b/clients/tools/Make-template
new file mode 100644 (file)
index 0000000..af3b4d5
--- /dev/null
@@ -0,0 +1,118 @@
+#----------------------------------------------------------------------------
+# Copyright (c) 1994 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP tools makefile
+#
+#-----------------------------------------------------------------------------
+LDAPSRC        = ../..
+HDIR   = $(LDAPSRC)/include
+LDIR   = $(LDAPSRC)/libraries
+VERSIONFILE = $(LDAPSRC)/build/version
+
+SRCS   = ldapsearch.c ldapmodify.c ldapdelete.c ldapmodrdn.c
+OBJS   = ldapsearch.o ldapmodify.o ldapdelete.o ldapmodrdn.o
+
+INCLUDES= -I$(HDIR)
+DEFINES        = $(DEFS)
+
+CFLAGS = $(INCLUDES) $(DEFINES) $(ACFLAGS)
+LIBS   = -lldap -llber -lldif $(KRBLIBFLAG) $(KRBLIBS) $(ALIBS)
+
+all:   ldapsearch ldapmodify ldapdelete ldapmodrdn ldapadd
+
+ldapsearch:    ldsversion.o
+       $(CC) $(ALDFLAGS) -o $@ ldapsearch.o ldsversion.o \
+               -L$(LDIR) $(LIBS)
+
+ldapmodify:    ldmversion.o
+       $(CC) $(ALDFLAGS) -o $@ ldapmodify.o ldmversion.o \
+               -L$(LDIR) $(LIBS)
+
+ldapdelete:    lddversion.o
+       $(CC) $(ALDFLAGS) -o $@ ldapdelete.o lddversion.o -L$(LDIR) $(LIBS)
+
+ldapmodrdn:    ldrversion.o
+       $(CC) $(ALDFLAGS) -o $@ ldapmodrdn.o ldrversion.o -L$(LDIR) $(LIBS)
+
+ldapadd:       ldapmodify
+       $(RM) $@
+       $(HARDLN) ldapmodify ldapadd
+
+ldsversion.c: ldapsearch.o
+       $(RM) $@
+       (u=$${USER-root} v=`$(CAT) $(VERSIONFILE)` d=`$(PWD)` h=`$(HOSTNAME)` \
+       t=`$(DATE)`; $(SED) -e "s|%WHEN%|$${t}|" \
+       -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+       -e "s|%VERSION%|$${v}|" \
+       < Versionlds.c > $@)
+
+ldmversion.c: ldapmodify.o
+       $(RM) $@
+       (u=$${USER-root} v=`$(CAT) $(VERSIONFILE)` d=`$(PWD)` h=`$(HOSTNAME)` \
+       t=`$(DATE)`; $(SED) -e "s|%WHEN%|$${t}|" \
+       -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+       -e "s|%VERSION%|$${v}|" \
+       < Versionldm.c > $@)
+
+lddversion.c: ldapdelete.o
+       $(RM) $@
+       (u=$${USER-root} v=`$(CAT) $(VERSIONFILE)` d=`$(PWD)` h=`$(HOSTNAME)` \
+       t=`$(DATE)`; $(SED) -e "s|%WHEN%|$${t}|" \
+       -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+       -e "s|%VERSION%|$${v}|" \
+       < Versionldd.c > $@)
+
+ldrversion.c: ldapmodrdn.o
+       $(RM) $@
+       (u=$${USER-root} v=`$(CAT) $(VERSIONFILE)` d=`$(PWD)` h=`$(HOSTNAME)` \
+       t=`$(DATE)`; $(SED) -e "s|%WHEN%|$${t}|" \
+       -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+       -e "s|%VERSION%|$${v}|" \
+       < Versionldr.c > $@)
+
+install:       ldapsearch ldapmodify ldapdelete ldapmodrdn ldapadd FORCE
+       -$(MKDIR) -p $(BINDIR)
+       $(INSTALL) $(INSTALLFLAGS) -m 755 ldapsearch $(BINDIR)
+       $(INSTALL) $(INSTALLFLAGS) -m 755 ldapmodify $(BINDIR)
+       $(INSTALL) $(INSTALLFLAGS) -m 755 ldapdelete $(BINDIR)
+       $(INSTALL) $(INSTALLFLAGS) -m 755 ldapmodrdn $(BINDIR)
+       $(RM) $(BINDIR)/ldapadd
+       $(HARDLN) $(BINDIR)/ldapmodify $(BINDIR)/ldapadd
+
+lint:  FORCE
+       $(LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+5lint: FORCE
+       $(5LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+clean: FORCE
+       $(RM) *.o core a.out ld*version.c ldapsearch ldapmodify ldapdelete \
+               ldapmodrdn ldapadd
+
+depend:        FORCE
+       $(MKDEP) $(INCLUDES) $(DEFINES) $(SRCS)
+
+links:
+       @$(LN) .src/*.[ch] .
+
+# DO NOT DELETE THIS LINE -- mkdep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+ldapsearch.o: ldapsearch.c ../../include/lber.h ../../include/ldap.h
+ldapsearch.o: ../../include/ldif.h ../../include/ldapconfig.h
+ldapmodify.o: ldapmodify.c ../../include/lber.h ../../include/ldap.h
+ldapmodify.o: ../../include/ldif.h ../../include/ldapconfig.h
+ldapdelete.o: ldapdelete.c ../../include/lber.h ../../include/ldap.h
+ldapdelete.o: ../../include/ldapconfig.h
+ldapmodrdn.o: ldapmodrdn.c ../../include/lber.h ../../include/ldap.h
+ldapmodrdn.o: ../../include/ldapconfig.h
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/clients/tools/Versionldd.c b/clients/tools/Versionldd.c
new file mode 100644 (file)
index 0000000..dab7a09
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+char Version[] = "  ldapdelete v%VERSION% (%WHEN%)\n\t%WHOANDWHERE%\n";
diff --git a/clients/tools/Versionldm.c b/clients/tools/Versionldm.c
new file mode 100644 (file)
index 0000000..aaec274
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+char Version[] = "  ldapmodify v%VERSION% (%WHEN%)\n\t%WHOANDWHERE%\n";
diff --git a/clients/tools/Versionldr.c b/clients/tools/Versionldr.c
new file mode 100644 (file)
index 0000000..95730d4
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+char Version[] = "  ldapmodrdn v%VERSION% (%WHEN%)\n\t%WHOANDWHERE%\n";
diff --git a/clients/tools/Versionlds.c b/clients/tools/Versionlds.c
new file mode 100644 (file)
index 0000000..fd68714
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+char Version[] = "  ldapsearch v%VERSION% (%WHEN%)\n\t%WHOANDWHERE%\n";
diff --git a/clients/tools/ldapdelete.c b/clients/tools/ldapdelete.c
new file mode 100644 (file)
index 0000000..3054cfb
--- /dev/null
@@ -0,0 +1,156 @@
+/* ldapdelete.c - simple program to delete an entry using LDAP */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <lber.h>
+#include <ldap.h>
+
+#include "ldapconfig.h"
+
+static char    *binddn = LDAPDELETE_BINDDN;
+static char    *base = LDAPDELETE_BASE;
+static char    *passwd = NULL;
+static char    *ldaphost = LDAPHOST;
+static int     ldapport = LDAP_PORT;
+static int     not, verbose, contoper;
+static LDAP    *ld;
+
+#ifdef LDAP_DEBUG
+extern int ldap_debug, lber_debug;
+#endif /* LDAP_DEBUG */
+
+#define safe_realloc( ptr, size )      ( ptr == NULL ? malloc( size ) : \
+                                        realloc( ptr, size ))
+
+
+main( argc, argv )
+    int                argc;
+    char       **argv;
+{
+    char               *usage = "usage: %s [-n] [-v] [-k] [-d debug-level] [-f file] [-h ldaphost] [-p ldapport] [-D binddn] [-w passwd] [dn]...\n";
+    char               *p, buf[ 4096 ];
+    FILE               *fp;
+    int                        i, rc, kerberos, linenum, authmethod;
+
+    extern char        *optarg;
+    extern int optind;
+
+    kerberos = not = verbose = contoper = 0;
+    fp = NULL;
+
+    while (( i = getopt( argc, argv, "nvkKch:p:D:w:d:f:" )) != EOF ) {
+       switch( i ) {
+       case 'k':       /* kerberos bind */
+           kerberos = 2;
+           break;
+       case 'K':       /* kerberos bind, part one only */
+           kerberos = 1;
+           break;
+       case 'c':       /* continuous operation mode */
+           ++contoper;
+           break;
+       case 'h':       /* ldap host */
+           ldaphost = strdup( optarg );
+           break;
+       case 'D':       /* bind DN */
+           binddn = strdup( optarg );
+           break;
+       case 'w':       /* password */
+           passwd = strdup( optarg );
+           break;
+       case 'f':       /* read DNs from a file */
+           if (( fp = fopen( optarg, "r" )) == NULL ) {
+               perror( optarg );
+               exit( 1 );
+           }
+           break;
+       case 'd':
+#ifdef LDAP_DEBUG
+           ldap_debug = lber_debug = atoi( optarg );   /* */
+#else /* LDAP_DEBUG */
+           fprintf( stderr, "compile with -DLDAP_DEBUG for debugging\n" );
+#endif /* LDAP_DEBUG */
+           break;
+       case 'p':
+           ldapport = atoi( optarg );
+           break;
+       case 'n':       /* print deletes, don't actually do them */
+           ++not;
+           break;
+       case 'v':       /* verbose mode */
+           verbose++;
+           break;
+       default:
+           fprintf( stderr, usage, argv[0] );
+           exit( 1 );
+       }
+    }
+
+    if ( fp == NULL ) {
+       if ( optind >= argc ) {
+           fp = stdin;
+       }
+    }
+
+    if (( ld = ldap_open( ldaphost, ldapport )) == NULL ) {
+       perror( "ldap_open" );
+       exit( 1 );
+    }
+
+    ld->ld_deref = LDAP_DEREF_NEVER;   /* prudent, but probably unnecessary */
+
+    if ( !kerberos ) {
+       authmethod = LDAP_AUTH_SIMPLE;
+    } else if ( kerberos == 1 ) {
+       authmethod = LDAP_AUTH_KRBV41;
+    } else {
+       authmethod = LDAP_AUTH_KRBV4;
+    }
+    if ( ldap_bind_s( ld, binddn, passwd, authmethod ) != LDAP_SUCCESS ) {
+       ldap_perror( ld, "ldap_bind" );
+       exit( 1 );
+    }
+
+    if ( fp == NULL ) {
+       for ( ; optind < argc; ++optind ) {
+           rc = dodelete( ld, argv[ optind ] );
+       }
+    } else {
+       rc = 0;
+       while ((rc == 0 || contoper) && fgets(buf, sizeof(buf), fp) != NULL) {
+           buf[ strlen( buf ) - 1 ] = '\0';    /* remove trailing newline */
+           if ( *buf != '\0' ) {
+               rc = dodelete( ld, buf );
+           }
+       }
+    }
+
+    ldap_unbind( ld );
+
+    exit( rc );
+}
+
+
+dodelete( ld, dn )
+    LDAP       *ld;
+    char       *dn;
+{
+    int        rc;
+
+    if ( verbose ) {
+       printf( "%sdeleting entry %s\n", not ? "!" : "", dn );
+    }
+    if ( not ) {
+       rc = LDAP_SUCCESS;
+    } else {
+       if (( rc = ldap_delete_s( ld, dn )) != LDAP_SUCCESS ) {
+           ldap_perror( ld, "ldap_delete" );
+       } else if ( verbose ) {
+           printf( "entry removed\n" );
+       }
+    }
+
+    return( rc );
+}
diff --git a/clients/tools/ldapmodify.c b/clients/tools/ldapmodify.c
new file mode 100644 (file)
index 0000000..d09b9ad
--- /dev/null
@@ -0,0 +1,798 @@
+/* ldapmodify.c - generic program to modify or add entries using LDAP */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <fcntl.h>
+#ifndef VMS
+#include <unistd.h>
+#endif /* VMS */
+#include <lber.h>
+#include <ldap.h>
+#include <ldif.h>
+
+#include "ldapconfig.h"
+
+static char    *prog;
+static char    *binddn = LDAPMODIFY_BINDDN;
+static char    *passwd = NULL;
+static char    *ldaphost = LDAPHOST;
+static int     ldapport = LDAP_PORT;
+static int     new, replace, not, verbose, contoper, force, valsfromfiles;
+static LDAP    *ld;
+
+#ifdef LDAP_DEBUG
+extern int ldap_debug, lber_debug;
+#endif /* LDAP_DEBUG */
+
+#define safe_realloc( ptr, size )      ( ptr == NULL ? malloc( size ) : \
+                                        realloc( ptr, size ))
+
+#define LDAPMOD_MAXLINE                4096
+
+/* strings found in replog/LDIF entries (mostly lifted from slurpd/slurp.h) */
+#define T_REPLICA_STR          "replica"
+#define T_DN_STR               "dn"
+#define T_CHANGETYPESTR         "changetype"
+#define T_ADDCTSTR             "add"
+#define T_MODIFYCTSTR          "modify"
+#define T_DELETECTSTR          "delete"
+#define T_MODRDNCTSTR          "modrdn"
+#define T_MODOPADDSTR          "add"
+#define T_MODOPREPLACESTR      "replace"
+#define T_MODOPDELETESTR       "delete"
+#define T_MODSEPSTR            "-"
+#define T_NEWRDNSTR            "newrdn"
+#define T_DELETEOLDRDNSTR      "deleteoldrdn"
+
+
+#ifdef NEEDPROTOS
+static int process_ldapmod_rec( char *rbuf );
+static int process_ldif_rec( char *rbuf );
+static void addmodifyop( LDAPMod ***pmodsp, int modop, char *attr,
+       char *value, int vlen );
+static int domodify( char *dn, LDAPMod **pmods, int newentry );
+static int dodelete( char *dn );
+static int domodrdn( char *dn, char *newrdn, int deleteoldrdn );
+static void freepmods( LDAPMod **pmods );
+static int fromfile( char *path, struct berval *bv );
+static char *read_one_record( FILE *fp );
+#else /* NEEDPROTOS */
+static int process_ldapmod_rec();
+static int process_ldif_rec();
+static void addmodifyop();
+static int domodify();
+static int dodelete();
+static int domodrdn();
+static void freepmods();
+static int fromfile();
+static char *read_one_record();
+#endif /* NEEDPROTOS */
+
+
+main( argc, argv )
+    int                argc;
+    char       **argv;
+{
+    char               *infile, *rbuf, *start, *p, *q;
+    FILE               *fp;
+    int                        rc, i, kerberos, use_ldif, authmethod;
+    char               *usage = "usage: %s [-abcknrvF] [-d debug-level] [-h ldaphost] [-p ldapport] [-D binddn] [-w passwd] [ -f file | < entryfile ]\n";
+
+    extern char        *optarg;
+    extern int optind;
+
+    if (( prog = strrchr( argv[ 0 ], '/' )) == NULL ) {
+       prog = argv[ 0 ];
+    } else {
+       ++prog;
+    }
+    new = ( strcmp( prog, "ldapadd" ) == 0 );
+
+    infile = NULL;
+    kerberos = not = verbose = valsfromfiles = 0;
+
+    while (( i = getopt( argc, argv, "FabckKnrtvh:p:D:w:d:f:" )) != EOF ) {
+       switch( i ) {
+       case 'a':       /* add */
+           new = 1;
+           break;
+       case 'b':       /* read values from files (for binary attributes) */
+           valsfromfiles = 1;
+           break;
+       case 'c':       /* continuous operation */
+           contoper = 1;
+           break;
+       case 'r':       /* default is to replace rather than add values */
+           replace = 1;
+           break;
+       case 'k':       /* kerberos bind */
+           kerberos = 2;
+           break;
+       case 'K':       /* kerberos bind, part 1 only */
+           kerberos = 1;
+           break;
+       case 'F':       /* force all changes records to be used */
+           force = 1;
+           break;
+       case 'h':       /* ldap host */
+           ldaphost = strdup( optarg );
+           break;
+       case 'D':       /* bind DN */
+           binddn = strdup( optarg );
+           break;
+       case 'w':       /* password */
+           passwd = strdup( optarg );
+           break;
+       case 'd':
+#ifdef LDAP_DEBUG
+           ldap_debug = lber_debug = atoi( optarg );   /* */
+#else /* LDAP_DEBUG */
+           fprintf( stderr, "%s: compile with -DLDAP_DEBUG for debugging\n",
+                   prog );
+#endif /* LDAP_DEBUG */
+           break;
+       case 'f':       /* read from file */
+           infile = strdup( optarg );
+           break;
+       case 'p':
+           ldapport = atoi( optarg );
+           break;
+       case 'n':       /* print adds, don't actually do them */
+           ++not;
+           break;
+       case 'v':       /* verbose mode */
+           verbose++;
+           break;
+       default:
+           fprintf( stderr, usage, prog );
+           exit( 1 );
+       }
+    }
+
+    if ( argc - optind != 0 ) {
+       fprintf( stderr, usage, prog );
+       exit( 1 );
+    }
+
+    if ( infile != NULL ) {
+       if (( fp = fopen( infile, "r" )) == NULL ) {
+           perror( infile );
+           exit( 1 );
+       }
+    } else {
+       fp = stdin;
+    }
+
+
+    if ( !not ) {
+       if (( ld = ldap_open( ldaphost, ldapport )) == NULL ) {
+           perror( "ldap_open" );
+           exit( 1 );
+       }
+
+       ld->ld_deref = LDAP_DEREF_NEVER;        /* this seems prudent */
+
+       if ( !kerberos ) {
+           authmethod = LDAP_AUTH_SIMPLE;
+       } else if ( kerberos == 1 ) {
+           authmethod = LDAP_AUTH_KRBV41;
+       } else {
+           authmethod = LDAP_AUTH_KRBV4;
+       }
+       if ( ldap_bind_s( ld, binddn, passwd, authmethod ) != LDAP_SUCCESS ) {
+           ldap_perror( ld, "ldap_bind" );
+           exit( 1 );
+       }
+    }
+
+    rc = 0;
+
+    while (( rc == 0 || contoper ) &&
+               ( rbuf = read_one_record( fp )) != NULL ) {
+       /*
+        * we assume record is ldif/slapd.replog if the first line
+        * has a colon that appears to the left of any equal signs, OR
+        * if the first line consists entirely of digits (an entry id)
+        */
+       use_ldif = ( p = strchr( rbuf, ':' )) != NULL &&
+               ( q = strchr( rbuf, '\n' )) != NULL && p < q &&
+               (( q = strchr( rbuf, '=' )) == NULL || p < q );
+
+       start = rbuf;
+
+       if ( !use_ldif && ( q = strchr( rbuf, '\n' )) != NULL ) {
+           for ( p = rbuf; p < q; ++p ) {
+               if ( !isdigit( *p )) {
+                   break;
+               }
+           }
+           if ( p >= q ) {
+               use_ldif = 1;
+               start = q + 1;
+           }
+       }
+
+       if ( use_ldif ) {
+           rc = process_ldif_rec( start );
+       } else {
+           rc = process_ldapmod_rec( start );
+       }
+
+       free( rbuf );
+    }
+
+    if ( !not ) {
+       ldap_unbind( ld );
+    }
+
+    exit( rc );
+}
+
+
+static int
+process_ldif_rec( char *rbuf )
+{
+    char       *line, *dn, *type, *value, *newrdn, *p;
+    int                rc, linenum, vlen, modop, replicaport;
+    int                expect_modop, expect_sep, expect_ct, expect_newrdn;
+    int                expect_deleteoldrdn, deleteoldrdn;
+    int                saw_replica, use_record, new_entry, delete_entry, got_all;
+    LDAPMod    **pmods;
+
+    new_entry = new;
+
+    rc = got_all = saw_replica = delete_entry = expect_modop = 0;
+    expect_deleteoldrdn = expect_newrdn = expect_sep = expect_ct = 0;
+    linenum = 0;
+    deleteoldrdn = 1;
+    use_record = force;
+    pmods = NULL;
+    dn = newrdn = NULL;
+
+    while ( rc == 0 && ( line = str_getline( &rbuf )) != NULL ) {
+       ++linenum;
+       if ( expect_sep && strcasecmp( line, T_MODSEPSTR ) == 0 ) {
+           expect_sep = 0;
+           expect_ct = 1;
+           continue;
+       }
+       
+       if ( str_parse_line( line, &type, &value, &vlen ) < 0 ) {
+           fprintf( stderr, "%s: invalid format (line %d of entry: %s\n",
+                   prog, linenum, dn == NULL ? "" : dn );
+           rc = LDAP_PARAM_ERROR;
+           break;
+       }
+
+       if ( dn == NULL ) {
+           if ( !use_record && strcasecmp( type, T_REPLICA_STR ) == 0 ) {
+               ++saw_replica;
+               if (( p = strchr( value, ':' )) == NULL ) {
+                   replicaport = LDAP_PORT;
+               } else {
+                   *p++ = '\0';
+                   replicaport = atoi( p );
+               }
+               if ( strcasecmp( value, ldaphost ) == 0 &&
+                       replicaport == ldapport ) {
+                   use_record = 1;
+               }
+           } else if ( strcasecmp( type, T_DN_STR ) == 0 ) {
+               if (( dn = strdup( value )) == NULL ) {
+                   perror( "strdup" );
+                   exit( 1 );
+               }
+               expect_ct = 1;
+           }
+           continue;   /* skip all lines until we see "dn:" */
+       }
+
+       if ( expect_ct ) {
+           expect_ct = 0;
+           if ( !use_record && saw_replica ) {
+               printf( "%s: skipping change record for entry: %s\n\t(LDAP host/port does not match replica: lines)\n",
+                       prog, dn );
+               free( dn );
+               return( 0 );
+           }
+
+           if ( strcasecmp( type, T_CHANGETYPESTR ) == 0 ) {
+               if ( strcasecmp( value, T_MODIFYCTSTR ) == 0 ) {
+                       new_entry = 0;
+                       expect_modop = 1;
+               } else if ( strcasecmp( value, T_ADDCTSTR ) == 0 ) {
+                       new_entry = 1;
+               } else if ( strcasecmp( value, T_MODRDNCTSTR ) == 0 ) {
+                   expect_newrdn = 1;
+               } else if ( strcasecmp( value, T_DELETECTSTR ) == 0 ) {
+                   got_all = delete_entry = 1;
+               } else {
+                   fprintf( stderr,
+                           "%s:  unknown %s \"%s\" (line %d of entry: %s)\n",
+                           prog, T_CHANGETYPESTR, value, linenum, dn );
+                   rc = LDAP_PARAM_ERROR;
+               }
+               continue;
+           } else if ( new ) {         /*  missing changetype => add */
+               new_entry = 1;
+               modop = LDAP_MOD_ADD;
+           } else {
+               expect_modop = 1;       /* missing changetype => modify */
+           }
+       }
+
+       if ( expect_modop ) {
+           expect_modop = 0;
+           expect_sep = 1;
+           if ( strcasecmp( type, T_MODOPADDSTR ) == 0 ) {
+               modop = LDAP_MOD_ADD;
+               continue;
+           } else if ( strcasecmp( type, T_MODOPREPLACESTR ) == 0 ) {
+               modop = LDAP_MOD_REPLACE;
+               continue;
+           } else if ( strcasecmp( type, T_MODOPDELETESTR ) == 0 ) {
+               modop = LDAP_MOD_DELETE;
+               addmodifyop( &pmods, modop, value, NULL, 0 );
+               continue;
+           } else {    /* no modify op:  use default */
+               modop = replace ? LDAP_MOD_REPLACE : LDAP_MOD_ADD;
+           }
+       }
+
+       if ( expect_newrdn ) {
+           if ( strcasecmp( type, T_NEWRDNSTR ) == 0 ) {
+               if (( newrdn = strdup( value )) == NULL ) {
+                   perror( "strdup" );
+                   exit( 1 );
+               }
+               expect_deleteoldrdn = 1;
+               expect_newrdn = 0;
+           } else {
+               fprintf( stderr, "%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry %s)\n",
+                       prog, T_NEWRDNSTR, type, linenum, dn );
+               rc = LDAP_PARAM_ERROR;
+           }
+       } else if ( expect_deleteoldrdn ) {
+           if ( strcasecmp( type, T_DELETEOLDRDNSTR ) == 0 ) {
+               deleteoldrdn = ( *value == '0' ) ? 0 : 1;
+               got_all = 1;
+           } else {
+               fprintf( stderr, "%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry %s)\n",
+                       prog, T_DELETEOLDRDNSTR, type, linenum, dn );
+               rc = LDAP_PARAM_ERROR;
+           }
+       } else if ( got_all ) {
+           fprintf( stderr,
+                   "%s: extra lines at end (line %d of entry %s)\n",
+                   prog, linenum, dn );
+           rc = LDAP_PARAM_ERROR;
+       } else {
+           addmodifyop( &pmods, modop, type, value, vlen );
+       }
+    }
+
+    if ( rc == 0 ) {
+       if ( delete_entry ) {
+           rc = dodelete( dn );
+       } else if ( newrdn != NULL ) {
+           rc = domodrdn( dn, newrdn, deleteoldrdn );
+       } else {
+           rc = domodify( dn, pmods, new_entry );
+       }
+
+       if ( rc == LDAP_SUCCESS ) {
+           rc = 0;
+       }
+    }
+
+    if ( dn != NULL ) {
+       free( dn );
+    }
+    if ( newrdn != NULL ) {
+       free( newrdn );
+    }
+    if ( pmods != NULL ) {
+       freepmods( pmods );
+    }
+
+    return( rc );
+}
+
+
+static int
+process_ldapmod_rec( char *rbuf )
+{
+    char       *line, *dn, *p, *q, *attr, *value;
+    int                rc, linenum, modop;
+    LDAPMod    **pmods;
+
+    pmods = NULL;
+    dn = NULL;
+    linenum = 0;
+    line = rbuf;
+    rc = 0;
+
+    while ( rc == 0 && rbuf != NULL && *rbuf != '\0' ) {
+       ++linenum;
+       if (( p = strchr( rbuf, '\n' )) == NULL ) {
+           rbuf = NULL;
+       } else {
+           if ( *(p-1) == '\\' ) {     /* lines ending in '\' are continued */
+               strcpy( p - 1, p );
+               rbuf = p;
+               continue;
+           }
+           *p++ = '\0';
+           rbuf = p;
+       }
+
+       if ( dn == NULL ) {     /* first line contains DN */
+           if (( dn = strdup( line )) == NULL ) {
+               perror( "strdup" );
+               exit( 1 );
+           }
+       } else {
+           if (( p = strchr( line, '=' )) == NULL ) {
+               value = NULL;
+               p = line + strlen( line );
+           } else {
+               *p++ = '\0';
+               value = p;
+           }
+
+           for ( attr = line; *attr != '\0' && isspace( *attr ); ++attr ) {
+               ;       /* skip attribute leading white space */
+           }
+
+           for ( q = p - 1; q > attr && isspace( *q ); --q ) {
+               *q = '\0';      /* remove attribute trailing white space */
+           }
+
+           if ( value != NULL ) {
+               while ( isspace( *value )) {
+                   ++value;            /* skip value leading white space */
+               }
+               for ( q = value + strlen( value ) - 1; q > value &&
+                       isspace( *q ); --q ) {
+                   *q = '\0';  /* remove value trailing white space */
+               }
+               if ( *value == '\0' ) {
+                   value = NULL;
+               }
+
+           }
+
+           if ( value == NULL && new ) {
+               fprintf( stderr, "%s: missing value on line %d (attr is %s)\n",
+                       prog, linenum, attr );
+               rc = LDAP_PARAM_ERROR;
+           } else {
+                switch ( *attr ) {
+               case '-':
+                   modop = LDAP_MOD_DELETE;
+                   ++attr;
+                   break;
+               case '+':
+                   modop = LDAP_MOD_ADD;
+                   ++attr;
+                   break;
+               default:
+                   modop = replace ? LDAP_MOD_REPLACE : LDAP_MOD_ADD;
+               }
+
+               addmodifyop( &pmods, modop, attr, value,
+                       ( value == NULL ) ? 0 : strlen( value ));
+           }
+       }
+
+       line = rbuf;
+    }
+
+    if ( rc == 0 ) {
+       if ( dn == NULL ) {
+           rc = LDAP_PARAM_ERROR;
+       } else if (( rc = domodify( dn, pmods, new )) == LDAP_SUCCESS ) {
+           rc = 0;
+       }
+    }
+
+    if ( pmods != NULL ) {
+       freepmods( pmods );
+    }
+    if ( dn != NULL ) {
+       free( dn );
+    }
+
+    return( rc );
+}
+
+
+static void
+addmodifyop( LDAPMod ***pmodsp, int modop, char *attr, char *value, int vlen )
+{
+    LDAPMod            **pmods;
+    int                        i, j;
+    struct berval      *bvp;
+
+    pmods = *pmodsp;
+    modop |= LDAP_MOD_BVALUES;
+
+    i = 0;
+    if ( pmods != NULL ) {
+       for ( ; pmods[ i ] != NULL; ++i ) {
+           if ( strcasecmp( pmods[ i ]->mod_type, attr ) == 0 &&
+                   pmods[ i ]->mod_op == modop ) {
+               break;
+           }
+       }
+    }
+
+    if ( pmods == NULL || pmods[ i ] == NULL ) {
+       if (( pmods = (LDAPMod **)safe_realloc( pmods, (i + 2) *
+               sizeof( LDAPMod * ))) == NULL ) {
+           perror( "safe_realloc" );
+           exit( 1 );
+       }
+       *pmodsp = pmods;
+       pmods[ i + 1 ] = NULL;
+       if (( pmods[ i ] = (LDAPMod *)calloc( 1, sizeof( LDAPMod )))
+               == NULL ) {
+           perror( "calloc" );
+           exit( 1 );
+       }
+       pmods[ i ]->mod_op = modop;
+       if (( pmods[ i ]->mod_type = strdup( attr )) == NULL ) {
+           perror( "strdup" );
+           exit( 1 );
+       }
+    }
+
+    if ( value != NULL ) {
+       j = 0;
+       if ( pmods[ i ]->mod_bvalues != NULL ) {
+           for ( ; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) {
+               ;
+           }
+       }
+       if (( pmods[ i ]->mod_bvalues =
+               (struct berval **)safe_realloc( pmods[ i ]->mod_bvalues,
+               (j + 2) * sizeof( struct berval * ))) == NULL ) {
+           perror( "safe_realloc" );
+           exit( 1 );
+       }
+       pmods[ i ]->mod_bvalues[ j + 1 ] = NULL;
+       if (( bvp = (struct berval *)malloc( sizeof( struct berval )))
+               == NULL ) {
+           perror( "malloc" );
+           exit( 1 );
+       }
+       pmods[ i ]->mod_bvalues[ j ] = bvp;
+
+       if ( valsfromfiles && *value == '/' ) { /* get value from file */
+           if ( fromfile( value, bvp ) < 0 ) {
+               exit( 1 );
+           }
+       } else {
+           bvp->bv_len = vlen;
+           if (( bvp->bv_val = (char *)malloc( vlen + 1 )) == NULL ) {
+               perror( "malloc" );
+               exit( 1 );
+           }
+           SAFEMEMCPY( bvp->bv_val, value, vlen );
+           bvp->bv_val[ vlen ] = '\0';
+       }
+    }
+}
+
+
+static int
+domodify( char *dn, LDAPMod **pmods, int newentry )
+{
+    int                        i, j, k, notascii, op;
+    struct berval      *bvp;
+
+    if ( pmods == NULL ) {
+       fprintf( stderr, "%s: no attributes to change or add (entry %s)\n",
+               prog, dn );
+       return( LDAP_PARAM_ERROR );
+    }
+
+    if ( verbose ) {
+       for ( i = 0; pmods[ i ] != NULL; ++i ) {
+           op = pmods[ i ]->mod_op & ~LDAP_MOD_BVALUES;
+           printf( "%s %s:\n", op == LDAP_MOD_REPLACE ?
+                   "replace" : op == LDAP_MOD_ADD ?
+                   "add" : "delete", pmods[ i ]->mod_type );
+           if ( pmods[ i ]->mod_bvalues != NULL ) {
+               for ( j = 0; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) {
+                   bvp = pmods[ i ]->mod_bvalues[ j ];
+                   notascii = 0;
+                   for ( k = 0; k < bvp->bv_len; ++k ) {
+                       if ( !isascii( bvp->bv_val[ k ] )) {
+                           notascii = 1;
+                           break;
+                       }
+                   }
+                   if ( notascii ) {
+                       printf( "\tNOT ASCII (%ld bytes)\n", bvp->bv_len );
+                   } else {
+                       printf( "\t%s\n", bvp->bv_val );
+                   }
+               }
+           }
+       }
+    }
+
+    if ( newentry ) {
+       printf( "%sadding new entry %s\n", not ? "!" : "", dn );
+    } else {
+       printf( "%smodifying entry %s\n", not ? "!" : "", dn );
+    }
+
+    if ( !not ) {
+       if ( newentry ) {
+           i = ldap_add_s( ld, dn, pmods );
+       } else {
+           i = ldap_modify_s( ld, dn, pmods );
+       }
+       if ( i != LDAP_SUCCESS ) {
+           ldap_perror( ld, newentry ? "ldap_add" : "ldap_modify" );
+       } else if ( verbose ) {
+           printf( "modify complete\n" );
+       }
+    } else {
+       i = LDAP_SUCCESS;
+    }
+
+    putchar( '\n' );
+
+    return( i );
+}
+
+
+static int
+dodelete( char *dn )
+{
+    int        rc;
+
+    printf( "%sdeleting entry %s\n", not ? "!" : "", dn );
+    if ( !not ) {
+       if (( rc = ldap_delete_s( ld, dn )) != LDAP_SUCCESS ) {
+           ldap_perror( ld, "ldap_delete" );
+       } else if ( verbose ) {
+           printf( "delete complete" );
+       }
+    } else {
+       rc = LDAP_SUCCESS;
+    }
+
+    putchar( '\n' );
+
+    return( rc );
+}
+
+
+static int
+domodrdn( char *dn, char *newrdn, int deleteoldrdn )
+{
+    int        rc;
+
+    if ( verbose ) {
+       printf( "new RDN: %s (%skeep existing values)\n",
+               newrdn, deleteoldrdn ? "do not " : "" );
+    }
+
+    printf( "%smodifying rdn of entry %s\n", not ? "!" : "", dn );
+    if ( !not ) {
+       if (( rc = ldap_modrdn2_s( ld, dn, newrdn, deleteoldrdn ))
+               != LDAP_SUCCESS ) {
+           ldap_perror( ld, "ldap_modrdn" );
+       } else {
+           printf( "modrdn completed\n" );
+       }
+    } else {
+       rc = LDAP_SUCCESS;
+    }
+
+    putchar( '\n' );
+
+    return( rc );
+}
+
+
+
+static void
+freepmods( LDAPMod **pmods )
+{
+    int        i;
+
+    for ( i = 0; pmods[ i ] != NULL; ++i ) {
+       if ( pmods[ i ]->mod_bvalues != NULL ) {
+           ber_bvecfree( pmods[ i ]->mod_bvalues );
+       }
+       if ( pmods[ i ]->mod_type != NULL ) {
+           free( pmods[ i ]->mod_type );
+       }
+       free( pmods[ i ] );
+    }
+    free( pmods );
+}
+
+
+static int
+fromfile( char *path, struct berval *bv )
+{
+       FILE            *fp;
+       long            rlen;
+       int             eof;
+
+       if (( fp = fopen( path, "r" )) == NULL ) {
+               perror( path );
+               return( -1 );
+       }
+
+       if ( fseek( fp, 0L, SEEK_END ) != 0 ) {
+               perror( path );
+               fclose( fp );
+               return( -1 );
+       }
+
+       bv->bv_len = ftell( fp );
+
+       if (( bv->bv_val = (char *)malloc( bv->bv_len )) == NULL ) {
+               perror( "malloc" );
+               fclose( fp );
+               return( -1 );
+       }
+
+       if ( fseek( fp, 0L, SEEK_SET ) != 0 ) {
+               perror( path );
+               fclose( fp );
+               return( -1 );
+       }
+
+       rlen = fread( bv->bv_val, 1, bv->bv_len, fp );
+       eof = feof( fp );
+       fclose( fp );
+
+       if ( rlen != bv->bv_len ) {
+               perror( path );
+               free( bv->bv_val );
+               return( -1 );
+       }
+
+       return( bv->bv_len );
+}
+
+
+static char *
+read_one_record( FILE *fp )
+{
+    int         len;
+    char        *buf, line[ LDAPMOD_MAXLINE ];
+    int                lcur, lmax;
+
+    lcur = lmax = 0;
+    buf = NULL;
+
+    while (( fgets( line, sizeof(line), fp ) != NULL ) &&
+            (( len = strlen( line )) > 1 )) {
+        if ( lcur + len + 1 > lmax ) {
+            lmax = LDAPMOD_MAXLINE
+                   * (( lcur + len + 1 ) / LDAPMOD_MAXLINE + 1 );
+           if (( buf = (char *)safe_realloc( buf, lmax )) == NULL ) {
+               perror( "safe_realloc" );
+               exit( 1 );
+           }
+        }
+        strcpy( buf + lcur, line );
+        lcur += len;
+    }
+
+    return( buf );
+}
diff --git a/clients/tools/ldapmodrdn.c b/clients/tools/ldapmodrdn.c
new file mode 100644 (file)
index 0000000..69d99e7
--- /dev/null
@@ -0,0 +1,196 @@
+/* ldapmodrdn.c - generic program to modify an entry's RDN using LDAP */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <lber.h>
+#include <ldap.h>
+
+#include "ldapconfig.h"
+
+static char    *binddn = LDAPMODRDN_BINDDN;
+static char    *base = LDAPMODRDN_BASE;
+static char    *passwd = NULL;
+static char    *ldaphost = LDAPHOST;
+static int     ldapport = LDAP_PORT;
+static int     not, verbose, contoper;
+static LDAP    *ld;
+
+#ifdef LDAP_DEBUG
+extern int ldap_debug, lber_debug;
+#endif /* LDAP_DEBUG */
+
+#define safe_realloc( ptr, size )      ( ptr == NULL ? malloc( size ) : \
+                                        realloc( ptr, size ))
+
+
+main( argc, argv )
+    int                argc;
+    char       **argv;
+{
+    char               *usage = "usage: %s [-nvkc] [-d debug-level] [-h ldaphost] [-p ldapport] [-D binddn] [-w passwd] [ -f file | < entryfile | dn newrdn ]\n";
+    char               *myname,*infile, *p, *entrydn, *rdn, buf[ 4096 ];
+    FILE               *fp;
+    int                        rc, i, kerberos, remove, havedn, authmethod;
+    LDAPMod            **pmods;
+
+    extern char        *optarg;
+    extern int optind;
+
+    infile = NULL;
+    kerberos = not = contoper = verbose = remove = 0;
+
+    myname = (myname = strrchr(argv[0], '/')) == NULL ? argv[0] : ++myname;
+
+    while (( i = getopt( argc, argv, "kKcnvrh:p:D:w:d:f:" )) != EOF ) {
+       switch( i ) {
+       case 'k':       /* kerberos bind */
+           kerberos = 2;
+           break;
+       case 'K':       /* kerberos bind, part one only */
+           kerberos = 1;
+           break;
+       case 'c':       /* continuous operation mode */
+           ++contoper;
+           break;
+       case 'h':       /* ldap host */
+           ldaphost = strdup( optarg );
+           break;
+       case 'D':       /* bind DN */
+           binddn = strdup( optarg );
+           break;
+       case 'w':       /* password */
+           passwd = strdup( optarg );
+           break;
+       case 'd':
+#ifdef LDAP_DEBUG
+           ldap_debug = lber_debug = atoi( optarg );   /* */
+#else /* LDAP_DEBUG */
+           fprintf( stderr, "compile with -DLDAP_DEBUG for debugging\n" );
+#endif /* LDAP_DEBUG */
+           break;
+       case 'f':       /* read from file */
+           infile = strdup( optarg );
+           break;
+       case 'p':
+           ldapport = atoi( optarg );
+           break;
+       case 'n':       /* print adds, don't actually do them */
+           ++not;
+           break;
+       case 'v':       /* verbose mode */
+           verbose++;
+           break;
+       case 'r':       /* remove old RDN */
+           remove++;
+           break;
+       default:
+           fprintf( stderr, usage, argv[0] );
+           exit( 1 );
+       }
+    }
+
+    havedn = 0;
+    if (argc - optind == 2) {
+       if (( rdn = strdup( argv[argc - 1] )) == NULL ) {
+           perror( "strdup" );
+           exit( 1 );
+       }
+        if (( entrydn = strdup( argv[argc - 2] )) == NULL ) {
+           perror( "strdup" );
+           exit( 1 );
+        }
+       ++havedn;
+    } else if ( argc - optind != 0 ) {
+       fprintf( stderr, "%s: invalid number of arguments, only two allowed\n", myname);
+       fprintf( stderr, usage, argv[0] );
+       exit( 1 );
+    }
+
+    if ( infile != NULL ) {
+       if (( fp = fopen( infile, "r" )) == NULL ) {
+           perror( infile );
+           exit( 1 );
+       }
+    } else {
+       fp = stdin;
+    }
+
+    if (( ld = ldap_open( ldaphost, ldapport )) == NULL ) {
+       perror( "ldap_open" );
+       exit( 1 );
+    }
+
+    ld->ld_deref = LDAP_DEREF_NEVER;   /* this seems prudent */
+
+    if ( !kerberos ) {
+       authmethod = LDAP_AUTH_SIMPLE;
+    } else if ( kerberos == 1 ) {
+       authmethod = LDAP_AUTH_KRBV41;
+    } else {
+       authmethod = LDAP_AUTH_KRBV4;
+    }
+    if ( ldap_bind_s( ld, binddn, passwd, authmethod ) != LDAP_SUCCESS ) {
+       ldap_perror( ld, "ldap_bind" );
+       exit( 1 );
+    }
+
+    rc = 0;
+    if (havedn)
+       rc = domodrdn(ld, entrydn, rdn, remove);
+    else while ((rc == 0 || contoper) && fgets(buf, sizeof(buf), fp) != NULL) {
+       if ( *buf != '\0' ) {   /* blank lines optional, skip */
+           buf[ strlen( buf ) - 1 ] = '\0';    /* remove nl */
+
+           if ( havedn ) {     /* have DN, get RDN */
+               if (( rdn = strdup( buf )) == NULL ) {
+                    perror( "strdup" );
+                    exit( 1 );
+               }
+               rc = domodrdn(ld, entrydn, rdn, remove);
+               havedn = 0;
+           } else if ( !havedn ) {     /* don't have DN yet */
+               if (( entrydn = strdup( buf )) == NULL ) {
+                   perror( "strdup" );
+                   exit( 1 );
+               }
+               ++havedn;
+           }
+       }
+    }
+
+    ldap_unbind( ld );
+
+    exit( rc );
+}
+
+domodrdn( ld, dn, rdn, remove )
+    LDAP       *ld;
+    char       *dn;
+    char       *rdn;
+    int                remove; /* flag: remove old RDN */
+{
+    int        i;
+
+    if ( verbose ) {
+       printf( "modrdn %s:\n\t%s\n", dn, rdn );
+       if (remove)
+           printf("removing old RDN\n");
+       else
+           printf("keeping old RDN\n");
+    }
+
+    if ( !not ) {
+       i = ldap_modrdn2_s( ld, dn, rdn, remove );
+       if ( i != LDAP_SUCCESS ) {
+           ldap_perror( ld, "ldap_modrdn2_s" );
+       } else if ( verbose ) {
+           printf( "modrdn complete\n" );
+       }
+    } else {
+       i = LDAP_SUCCESS;
+    }
+
+    return( i );
+}
diff --git a/clients/tools/ldapsearch.c b/clients/tools/ldapsearch.c
new file mode 100644 (file)
index 0000000..d96aff1
--- /dev/null
@@ -0,0 +1,475 @@
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <lber.h>
+#include <ldap.h>
+#include <ldif.h>
+
+#include "ldapconfig.h"
+
+#define DEFSEP         "="
+
+#ifdef LDAP_DEBUG
+extern int ldap_debug, lber_debug;
+#endif /* LDAP_DEBUG */
+
+
+usage( s )
+char   *s;
+{
+    fprintf( stderr, "usage: %s [options] filter [attributes...]\nwhere:\n", s );
+    fprintf( stderr, "    filter\tRFC-1558 compliant LDAP search filter\n" );
+    fprintf( stderr, "    attributes\twhitespace-separated list of attributes to retrieve\n" );
+    fprintf( stderr, "\t\t(if no attribute list is given, all are retrieved)\n" );
+    fprintf( stderr, "options:\n" );
+    fprintf( stderr, "    -n\t\tshow what would be done but don't actually search\n" );
+    fprintf( stderr, "    -v\t\trun in verbose mode (diagnostics to standard output)\n" );
+    fprintf( stderr, "    -t\t\twrite values to files in /tmp\n" );
+    fprintf( stderr, "    -u\t\tinclude User Friendly entry names in the output\n" );
+    fprintf( stderr, "    -A\t\tretrieve attribute names only (no values)\n" );
+    fprintf( stderr, "    -B\t\tdo not suppress printing of non-ASCII values\n" );
+    fprintf( stderr, "    -L\t\tprint entries in LDIF format (-B is implied)\n" );
+#ifdef LDAP_REFERRALS
+    fprintf( stderr, "    -R\t\tdo not automatically follow referrals\n" );
+#endif /* LDAP_REFERRALS */
+    fprintf( stderr, "    -d level\tset LDAP debugging level to `level'\n" );
+    fprintf( stderr, "    -F sep\tprint `sep' instead of `=' between attribute names and values\n" );
+    fprintf( stderr, "    -S attr\tsort the results by attribute `attr'\n" );
+    fprintf( stderr, "    -f file\tperform sequence of searches listed in `file'\n" );
+    fprintf( stderr, "    -b basedn\tbase dn for search\n" );
+    fprintf( stderr, "    -s scope\tone of base, one, or sub (search scope)\n" );
+    fprintf( stderr, "    -a deref\tone of never, always, search, or find (alias dereferencing)\n" );
+    fprintf( stderr, "    -l time lim\ttime limit (in seconds) for search\n" );
+    fprintf( stderr, "    -z size lim\tsize limit (in entries) for search\n" );
+    fprintf( stderr, "    -D binddn\tbind dn\n" );
+    fprintf( stderr, "    -w passwd\tbind passwd (for simple authentication)\n" );
+#ifdef KERBEROS
+    fprintf( stderr, "    -k\t\tuse Kerberos instead of Simple Password authentication\n" );
+#endif
+    fprintf( stderr, "    -h host\tldap server\n" );
+    fprintf( stderr, "    -p port\tport on ldap server\n" );
+    exit( 1 );
+}
+
+static char    *binddn = LDAPSEARCH_BINDDN;
+static char    *passwd = NULL;
+static char    *base = LDAPSEARCH_BASE;
+static char    *ldaphost = LDAPHOST;
+static int     ldapport = LDAP_PORT;
+static char    *sep = DEFSEP;
+static char    *sortattr = NULL;
+static int     skipsortattr = 0;
+static int     verbose, not, includeufn, allow_binary, vals2tmp, ldif;
+
+main( argc, argv )
+int    argc;
+char   **argv;
+{
+    char               *infile, *filtpattern, **attrs, line[ BUFSIZ ];
+    FILE               *fp;
+    int                        rc, i, first, scope, kerberos, deref, attrsonly;
+    int                        ldap_options, timelimit, sizelimit, authmethod;
+    LDAP               *ld;
+    extern char                *optarg;
+    extern int         optind;
+
+    infile = NULL;
+    deref = verbose = allow_binary = not = kerberos = vals2tmp =
+           attrsonly = ldif = 0;
+#ifdef LDAP_REFERRALS
+    ldap_options = LDAP_OPT_REFERRALS;
+#else /* LDAP_REFERRALS */
+    ldap_options = 0;
+#endif /* LDAP_REFERRALS */
+    sizelimit = timelimit = 0;
+    scope = LDAP_SCOPE_SUBTREE;
+
+    while (( i = getopt( argc, argv,
+#ifdef KERBEROS
+           "KknuvtRABLD:s:f:h:b:d:p:F:a:w:l:z:S:"
+#else
+           "nuvtRABLD:s:f:h:b:d:p:F:a:w:l:z:S:"
+#endif
+           )) != EOF ) {
+       switch( i ) {
+       case 'n':       /* do Not do any searches */
+           ++not;
+           break;
+       case 'v':       /* verbose mode */
+           ++verbose;
+           break;
+       case 'd':
+#ifdef LDAP_DEBUG
+           ldap_debug = lber_debug = atoi( optarg );   /* */
+#else /* LDAP_DEBUG */
+           fprintf( stderr, "compile with -DLDAP_DEBUG for debugging\n" );
+#endif /* LDAP_DEBUG */
+           break;
+#ifdef KERBEROS
+       case 'k':       /* use kerberos bind */
+           kerberos = 2;
+           break;
+       case 'K':       /* use kerberos bind, 1st part only */
+           kerberos = 1;
+           break;
+#endif
+       case 'u':       /* include UFN */
+           ++includeufn;
+           break;
+       case 't':       /* write attribute values to /tmp files */
+           ++vals2tmp;
+           break;
+       case 'R':       /* don't automatically chase referrals */
+#ifdef LDAP_REFERRALS
+           ldap_options &= ~LDAP_OPT_REFERRALS;
+#else /* LDAP_REFERRALS */
+           fprintf( stderr,
+                   "compile with -DLDAP_REFERRALS for referral support\n" );
+#endif /* LDAP_REFERRALS */
+           break;
+       case 'A':       /* retrieve attribute names only -- no values */
+           ++attrsonly;
+           break;
+       case 'L':       /* print entries in LDIF format */
+           ++ldif;
+           /* fall through -- always allow binary when outputting LDIF */
+       case 'B':       /* allow binary values to be printed */
+           ++allow_binary;
+           break;
+       case 's':       /* search scope */
+           if ( strncasecmp( optarg, "base", 4 ) == 0 ) {
+               scope = LDAP_SCOPE_BASE;
+           } else if ( strncasecmp( optarg, "one", 3 ) == 0 ) {
+               scope = LDAP_SCOPE_ONELEVEL;
+           } else if ( strncasecmp( optarg, "sub", 3 ) == 0 ) {
+               scope = LDAP_SCOPE_SUBTREE;
+           } else {
+               fprintf( stderr, "scope should be base, one, or sub\n" );
+               usage( argv[ 0 ] );
+           }
+           break;
+
+       case 'a':       /* set alias deref option */
+           if ( strncasecmp( optarg, "never", 5 ) == 0 ) {
+               deref = LDAP_DEREF_NEVER;
+           } else if ( strncasecmp( optarg, "search", 5 ) == 0 ) {
+               deref = LDAP_DEREF_SEARCHING;
+           } else if ( strncasecmp( optarg, "find", 4 ) == 0 ) {
+               deref = LDAP_DEREF_FINDING;
+           } else if ( strncasecmp( optarg, "always", 6 ) == 0 ) {
+               deref = LDAP_DEREF_ALWAYS;
+           } else {
+               fprintf( stderr, "alias deref should be never, search, find, or always\n" );
+               usage( argv[ 0 ] );
+           }
+           break;
+           
+       case 'F':       /* field separator */
+           sep = strdup( optarg );
+           break;
+       case 'f':       /* input file */
+           infile = strdup( optarg );
+           break;
+       case 'h':       /* ldap host */
+           ldaphost = strdup( optarg );
+           break;
+       case 'b':       /* searchbase */
+           base = strdup( optarg );
+           break;
+       case 'D':       /* bind DN */
+           binddn = strdup( optarg );
+           break;
+       case 'p':       /* ldap port */
+           ldapport = atoi( optarg );
+           break;
+       case 'w':       /* bind password */
+           passwd = strdup( optarg );
+           break;
+       case 'l':       /* time limit */
+           timelimit = atoi( optarg );
+           break;
+       case 'z':       /* size limit */
+           sizelimit = atoi( optarg );
+           break;
+       case 'S':       /* sort attribute */
+           sortattr = strdup( optarg );
+           break;
+       default:
+           usage( argv[0] );
+       }
+    }
+
+    if ( argc - optind < 1 ) {
+       usage( argv[ 0 ] );
+    }
+    filtpattern = strdup( argv[ optind ] );
+    if ( argv[ optind + 1 ] == NULL ) {
+       attrs = NULL;
+    } else if ( sortattr == NULL || *sortattr == '\0' ) {
+        attrs = &argv[ optind + 1 ];
+    } else {
+       for ( i = optind + 1; i < argc; i++ ) {
+           if ( strcasecmp( argv[ i ], sortattr ) == 0 ) {
+               break;
+           }
+       }
+       if ( i == argc ) {
+               skipsortattr = 1;
+               argv[ optind ] = sortattr;
+       } else {
+               optind++;
+       }
+        attrs = &argv[ optind ];
+    }
+
+    if ( infile != NULL ) {
+       if ( infile[0] == '-' && infile[1] == '\0' ) {
+           fp = stdin;
+       } else if (( fp = fopen( infile, "r" )) == NULL ) {
+           perror( infile );
+           exit( 1 );
+       }
+    }
+
+    if ( verbose ) {
+       printf( "ldap_open( %s, %d )\n", ldaphost, ldapport );
+    }
+
+    if (( ld = ldap_open( ldaphost, ldapport )) == NULL ) {
+       perror( ldaphost );
+       exit( 1 );
+    }
+
+    ld->ld_deref = deref;
+    ld->ld_timelimit = timelimit;
+    ld->ld_sizelimit = sizelimit;
+    ld->ld_options = ldap_options;
+
+    if ( !kerberos ) {
+       authmethod = LDAP_AUTH_SIMPLE;
+    } else if ( kerberos == 1 ) {
+       authmethod = LDAP_AUTH_KRBV41;
+    } else {
+       authmethod =  LDAP_AUTH_KRBV4;
+    }
+    if ( ldap_bind_s( ld, binddn, passwd, authmethod ) != LDAP_SUCCESS ) {
+       ldap_perror( ld, "ldap_bind" );
+       exit( 1 );
+    }
+
+    if ( verbose ) {
+       printf( "filter pattern: %s\nreturning: ", filtpattern );
+       if ( attrs == NULL ) {
+           printf( "ALL" );
+       } else {
+           for ( i = 0; attrs[ i ] != NULL; ++i ) {
+               printf( "%s ", attrs[ i ] );
+           }
+       }
+       putchar( '\n' );
+    }
+
+    if ( infile == NULL ) {
+       rc = dosearch( ld, base, scope, attrs, attrsonly, filtpattern, "" );
+    } else {
+       rc = 0;
+       first = 1;
+       while ( rc == 0 && fgets( line, sizeof( line ), fp ) != NULL ) {
+           line[ strlen( line ) - 1 ] = '\0';
+           if ( !first ) {
+               putchar( '\n' );
+           } else {
+               first = 0;
+           }
+           rc = dosearch( ld, base, scope, attrs, attrsonly, filtpattern,
+                   line );
+       }
+       if ( fp != stdin ) {
+           fclose( fp );
+       }
+    }
+
+    ldap_unbind( ld );
+    exit( rc );
+}
+
+
+dosearch( ld, base, scope, attrs, attrsonly, filtpatt, value )
+    LDAP       *ld;
+    char       *base;
+    int                scope;
+    char       **attrs;
+    int                attrsonly;
+    char       *filtpatt;
+    char       *value;
+{
+    char               filter[ BUFSIZ ], **val;
+    int                        rc, first, matches;
+    LDAPMessage                *res, *e;
+
+    sprintf( filter, filtpatt, value );
+
+    if ( verbose ) {
+       printf( "filter is: (%s)\n", filter );
+    }
+
+    if ( not ) {
+       return( LDAP_SUCCESS );
+    }
+
+    if ( ldap_search( ld, base, scope, filter, attrs, attrsonly ) == -1 ) {
+       ldap_perror( ld, "ldap_search" );
+       return( ld->ld_errno );
+    }
+
+    matches = 0;
+    first = 1;
+    while ( (rc = ldap_result( ld, LDAP_RES_ANY, sortattr ? 1 : 0, NULL, &res ))
+           == LDAP_RES_SEARCH_ENTRY ) {
+       matches++;
+       e = ldap_first_entry( ld, res );
+       if ( !first ) {
+           putchar( '\n' );
+       } else {
+           first = 0;
+       }
+       print_entry( ld, e, attrsonly );
+       ldap_msgfree( res );
+    }
+    if ( rc == -1 ) {
+       ldap_perror( ld, "ldap_result" );
+       return( rc );
+    }
+    if (( rc = ldap_result2error( ld, res, 0 )) != LDAP_SUCCESS ) {
+        ldap_perror( ld, "ldap_search" );
+    }
+    if ( sortattr != NULL ) {
+           extern int  strcasecmp();
+
+           (void) ldap_sort_entries( ld, &res,
+                   ( *sortattr == '\0' ) ? NULL : sortattr, strcasecmp );
+           matches = 0;
+           first = 1;
+           for ( e = ldap_first_entry( ld, res ); e != NULLMSG;
+                   e = ldap_next_entry( ld, e ) ) {
+               matches++;
+               if ( !first ) {
+                   putchar( '\n' );
+               } else {
+                   first = 0;
+               }
+               print_entry( ld, e, attrsonly );
+           }
+    }
+
+    if ( verbose ) {
+        printf( "%d matches\n", matches );
+    }
+
+    ldap_msgfree( res );
+    return( rc );
+}
+
+
+print_entry( ld, entry, attrsonly )
+    LDAP       *ld;
+    LDAPMessage        *entry;
+    int                attrsonly;
+{
+    char               *a, *dn, *ufn, tmpfname[ 64 ];
+    int                        i, j, notascii;
+    BerElement         *ber;
+    struct berval      **bvals;
+    FILE               *tmpfp;
+    extern char                *mktemp();
+
+    dn = ldap_get_dn( ld, entry );
+    if ( ldif ) {
+       write_ldif_value( "dn", dn, strlen( dn ));
+    } else {
+       printf( "%s\n", dn );
+    }
+    if ( includeufn ) {
+       ufn = ldap_dn2ufn( dn );
+       if ( ldif ) {
+           write_ldif_value( "ufn", ufn, strlen( ufn ));
+       } else {
+           printf( "%s\n", ufn );
+       }
+       free( ufn );
+    }
+    free( dn );
+
+    for ( a = ldap_first_attribute( ld, entry, &ber ); a != NULL;
+           a = ldap_next_attribute( ld, entry, ber ) ) {
+       if ( skipsortattr && strcasecmp( a, sortattr ) == 0 ) {
+           continue;
+       }
+       if ( attrsonly ) {
+           if ( ldif ) {
+               write_ldif_value( a, "", 0 );
+           } else {
+               printf( "%s\n", a );
+           }
+       } else if (( bvals = ldap_get_values_len( ld, entry, a )) != NULL ) {
+           for ( i = 0; bvals[i] != NULL; i++ ) {
+               if ( vals2tmp ) {
+                   sprintf( tmpfname, "/tmp/ldapsearch-%s-XXXXXX", a );
+                   tmpfp = NULL;
+
+                   if ( mktemp( tmpfname ) == NULL ) {
+                       perror( tmpfname );
+                   } else if (( tmpfp = fopen( tmpfname, "w")) == NULL ) {
+                       perror( tmpfname );
+                   } else if ( fwrite( bvals[ i ]->bv_val,
+                           bvals[ i ]->bv_len, 1, tmpfp ) == 0 ) {
+                       perror( tmpfname );
+                   } else if ( ldif ) {
+                       write_ldif_value( a, tmpfname, strlen( tmpfname ));
+                   } else {
+                       printf( "%s%s%s\n", a, sep, tmpfname );
+                   }
+
+                   if ( tmpfp != NULL ) {
+                       fclose( tmpfp );
+                   }
+               } else {
+                   notascii = 0;
+                   if ( !allow_binary ) {
+                       for ( j = 0; j < bvals[ i ]->bv_len; ++j ) {
+                           if ( !isascii( bvals[ i ]->bv_val[ j ] )) {
+                               notascii = 1;
+                               break;
+                           }
+                       }
+                   }
+
+                   if ( ldif ) {
+                       write_ldif_value( a, bvals[ i ]->bv_val,
+                               bvals[ i ]->bv_len );
+                   } else {
+                       printf( "%s%s%s\n", a, sep,
+                               notascii ? "NOT ASCII" : bvals[ i ]->bv_val );
+                   }
+               }
+           }
+           ber_bvecfree( bvals );
+       }
+    }
+}
+
+
+int
+write_ldif_value( char *type, char *value, unsigned long vallen )
+{
+    char       *ldif;
+
+    if (( ldif = ldif_type_and_value( type, value, (int)vallen )) == NULL ) {
+       return( -1 );
+    }
+
+    fputs( ldif, stdout );
+    free( ldif );
+
+    return( 0 );
+}
diff --git a/clients/ud/Make-template b/clients/ud/Make-template
new file mode 100644 (file)
index 0000000..1cba01c
--- /dev/null
@@ -0,0 +1,100 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1994 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#      ud makefile
+#
+#      Use -DUOFM for University of Michigan specifics like:
+#              if ud should know about noBatchUpdates
+#      Use -DDOS if building for a DOS machine
+#      Use -DNOTERMCAP if there is no termcap library
+#              also need to redefine/undefine the Makefile TERMLIB variable
+#-----------------------------------------------------------------------------
+LDAPSRC        = ../..
+HDIR   = $(LDAPSRC)/include
+LDIR   = $(LDAPSRC)/libraries
+VERSIONFILE = $(LDAPSRC)/build/version
+
+SRCS=  main.c find.c mod.c print.c auth.c util.c help.c\
+       string_to_key.c group.c edit.c globals.c
+OBJS=  main.o find.o mod.o print.o auth.o util.o help.o\
+       string_to_key.o group.o globals.o edit.o
+HDRS=  ud.h
+
+INCLUDES= -I$(HDIR) $(KRBINCLUDEFLAG)
+DEFINES= $(DEFS) -DDEBUG -DCONFIG_FILE=\"$(RUNTIMEETCDIR)/ud.conf\" \
+               -DLDAP_FRIENDLY_MAP_FILE=\"$(RUNTIMEETCDIR)/ldapfriendly\"
+TERMLIB= -ltermcap
+
+CFLAGS= ${INCLUDES} ${DEFINES} ${ACFLAGS}
+LIBS= ${TERMLIB} -lldap -llber $(KRBLIBFLAG) $(KRBLIBS) $(ALIBS)
+
+PURIFY=
+#PURIFY=purify
+
+all: ud
+
+ud : version.o
+       $(PURIFY) ${CC} $(ALDFLAGS) -o $@ version.o ${OBJS} -L${LDIR} ${LIBS}
+
+version.c: ${OBJS} $(LDIR)/libldap/libldap.a
+       $(RM) $@
+       (u=$${USER-root} v=`$(CAT) $(VERSIONFILE)` d=`$(PWD)` h=`$(HOSTNAME)` \
+           t=`$(DATE)`; $(SED) -e "s|%WHEN%|$${t}|" \
+           -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+           -e "s|%VERSION%|$${v}|" \
+           < Version.c > $@)
+
+install: ud FORCE
+       -$(MKDIR) -p $(BINDIR)
+       -mv -f ${BINDIR}/ud ${BINDIR}/ud-
+       $(INSTALL) $(INSTALLFLAGS) -m 775 ud ${BINDIR}
+
+depend: FORCE
+       $(MKDEP) $(INCLUDES) $(DEFINES) $(SRCS)
+
+clean: FORCE
+       $(RM) $(OBJS) core ud tags version.o version.c
+       $(RM) *_pure_*.o ud.pure_hardlink ud.pure_linkinfo
+
+tags: FORCE
+       $(CTAGS) $(SRCS) ${HDRS}
+
+lint: FORCE
+       $(LINT) -Dlint $(INCLUDES) $(DEFINES) $(SRCS) version.c | \
+               egrep -v "string_to_key|but not defined"
+
+5lint: FORCE
+       $(5LINT) -Dlint $(INCLUDES) $(DEFINES) $(SRCS) version.c
+
+links:
+       @$(LN) .src/README .src/etc.ud.conf .src/*.[ch] .
+
+# DO NOT DELETE THIS LINE -- mkdep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+main.o: main.c ../../include/lber.h ../../include/ldap.h
+main.o: ../../include/ldapconfig.h ../../include/portable.h ud.h
+find.o: find.c ../../include/lber.h ../../include/ldap.h ud.h
+mod.o: mod.c ../../include/lber.h ../../include/ldap.h ud.h
+print.o: print.c ../../include/lber.h ../../include/ldap.h ud.h
+auth.o: auth.c ../../include/lber.h ../../include/ldap.h
+auth.o: ../../include/ldapconfig.h ud.h
+util.o: util.c ../../include/lber.h ../../include/ldap.h
+util.o: ../../include/ldapconfig.h ../../include/portable.h ud.h
+help.o: help.c ../../include/lber.h ../../include/ldap.h ud.h
+string_to_key.o: string_to_key.c
+group.o: group.c ../../include/lber.h ../../include/ldap.h
+group.o: ../../include/ldapconfig.h ud.h
+edit.o: edit.c ../../include/lber.h ../../include/ldap.h
+edit.o: ../../include/ldapconfig.h ud.h
+globals.o: globals.c ud.h
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/clients/ud/README b/clients/ud/README
new file mode 100644 (file)
index 0000000..d6ff35f
--- /dev/null
@@ -0,0 +1,31 @@
+Users
+-----
+For users, see the man page on ud.
+
+Installers
+----------
+For installers, see the header file.  Anything that is configurable is
+listed in there as a #define, and the file is pretty well commented.
+
+Kerberos users
+--------------
+If you're going to use Kerberos, be sure that you have a Kerberos config file
+in /etc/krb.conf of the form:
+
+       <realm>
+       <realm> <server-for-realm> [ admin server ]
+
+This should be the realm in which users are going to authenticate, which
+is not necessarily your realm.
+
+You can certainly have other entries in this file, but you'll need at least
+these two.
+
+Also be sure that you have the necessary entries in /etc/services so that
+your client knows on which port to find a Kerberos authentication server.
+An pair of entries like this:
+
+  kerberos        750/udp         kdc             # Kerberos authentication
+  kerberos        750/tcp         kdc             # Kerberos authentication
+
+is fairly typical.
diff --git a/clients/ud/Version.c b/clients/ud/Version.c
new file mode 100644 (file)
index 0000000..c4d8e2c
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 1991, 1992 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+char Version[] = "  X.500 UserDirectory %VERSION% (%WHEN%)\n\t%WHOANDWHERE%\n";
diff --git a/clients/ud/auth.c b/clients/ud/auth.c
new file mode 100644 (file)
index 0000000..be47276
--- /dev/null
@@ -0,0 +1,427 @@
+/*
+ * Copyright (c) 1991, 1992 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <pwd.h>
+#include <string.h>
+#include <ctype.h>
+#include <lber.h>
+#include <ldap.h>
+#include <ldapconfig.h>
+#include "ud.h"
+#ifdef KERBEROS
+#include <sys/types.h>
+#include <krb.h>
+#endif
+
+extern LDAP *ld;               /* our LDAP descriptor */
+extern int verbose;            /* verbosity indicator */
+extern char *mygetpass();      /* getpass() passwds are too short */
+
+#ifdef DEBUG
+extern int debug;              /* debug flag */
+#endif
+
+#ifdef KERBEROS
+static char tktpath[20];       /* ticket file path */
+static int kinit();
+static int valid_tgt();
+#endif
+
+auth(who, implicit)
+char *who;
+int implicit;
+{
+       int rc;                 /* return code from ldap_bind() */
+       char *passwd = NULL;    /* returned by mygetpass() */
+       char **rdns;            /* for fiddling with the DN */
+       int authmethod;
+       int name_provided;      /* was a name passed in? */
+       struct passwd *pw;      /* for getting user id */
+       char uidname[20];
+#ifdef KERBEROS
+       char **krbnames;        /* for kerberos names */
+       int kinited, ikrb;
+       char buf[5];
+       extern int krb_debug;
+#endif
+       LDAPMessage *mp;        /* returned from find() */
+       static char prompt[MED_BUF_SIZE];       /* place for us to sprintf the prompt */
+       static char name[MED_BUF_SIZE]; /* place to store the user's name */
+       static char password[MED_BUF_SIZE];     /* password entered by user */
+       extern struct entry Entry;      /* look here for a name if needed */
+       extern LDAPMessage *find();     /* for looking up 'name' */
+       extern char *search_base;       /* for printing later */
+       extern char *default_bind_object;       /* bind as this on failure */
+       extern void printbase();        /* used to pretty-print a base */
+       extern int bind_status;
+       extern void Free();
+       static void set_bound_dn();
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               fprintf(stderr, "auth(%s, NULL)\n", who);
+#endif
+       name_provided = ( who != NULL );
+
+       /*
+        *  The user needs to bind.  If <who> is not specified, we
+        *  assume that authenticating as user id is what user wants.
+        */
+       if (who == NULL && implicit && (pw = getpwuid((uid_t)geteuid()))
+           != (struct passwd *) NULL) {
+               sprintf(uidname, "uid=%s", pw->pw_name);
+               /* who = pw->pw_name; /* */
+               who = uidname;
+       }
+
+       if ( who == NULL ) {
+               if ( implicit )
+                       printf( "You must first authenticate yourself to the Directory.\n" );
+#ifdef UOFM
+               printf("  What is your name or uniqname? ");
+#else
+               printf("  What is your name or user id? ");
+#endif
+               fflush(stdout);
+               fetch_buffer(name, sizeof(name), stdin);
+               if (name[0] == '\0')
+                       return( -1 );
+               who = name;
+       }
+
+#ifdef DEBUG
+       if (debug & D_AUTHENTICAT)
+               printf("  Authenticating as \"%s\"\n", who);
+#endif
+
+       /*
+        *  Bail out if the name is bogus.  If not, strip off the junk
+        *  at the start of the DN, build a prompt, and get a password 
+        *  from the user.  Then perform the ldap_bind().
+        */
+       if ((mp = find(who, TRUE)) == NULL) {
+               (void) ldap_msgfree(mp);
+               printf("  I could not find \"%s\" in the Directory.\n", who);
+               printf("  I used a search base of ");
+               printbase("", search_base);
+               printf("\n");
+#ifdef DEBUG
+               if (debug & D_AUTHENTICAT)
+                       printf("  Could not find \"%s\"\n", who);
+#endif
+               return(-1);
+       }
+
+       /*
+        *  Fill in the Entry structure.  May be handy later.
+        */
+       (void) parse_answer(mp);
+
+       rdns = ldap_explode_dn(Entry.DN, TRUE);
+       printf("  Authenticating to the directory as \"%s\"...\n", *rdns );
+
+#ifdef KERBEROS
+       /*
+        * First, if the user has a choice of auth methods, ask which
+        * one they want to use.  if they want kerberos, ask which
+        * krbname they want to bind as.
+        */
+
+       if ( (krbnames = ldap_get_values( ld, mp, "krbName" )) != NULL ) {
+               int     choice, hassimple;
+
+               hassimple = (ldap_compare_s( ld, Entry.DN, 
+                               "userPassword", "x" ) == LDAP_COMPARE_FALSE);
+               (void) ldap_msgfree(mp);
+
+               /* if we're running as a server (e.g., out of inetd) */
+               if ( ! isatty( 1 ) ) {
+                       strcpy( tktpath, "/tmp/ud_tktXXXXXX" );
+                       mktemp( tktpath );
+                       krb_set_tkt_string( tktpath );
+               }
+
+               kinited = valid_tgt( krbnames );
+
+               if ( hassimple && !kinited ) {
+                       printf("  Which password would you like to use?\n");
+                       printf("    1 -> X.500 password\n");
+#ifdef UOFM
+                       printf("    2 -> UMICH password (aka Uniqname or Kerberos password)\n");
+#else
+                       printf("    2 -> Kerberos password\n");
+#endif
+
+                       do {
+                               printf("  Enter 1 or 2: ");
+                               fflush(stdout);
+
+                               fetch_buffer(buf, sizeof(buf), stdin);
+                               choice = atoi(buf);
+                       } while (choice != 1 && choice != 2);
+
+                       authmethod = (choice == 1 ? LDAP_AUTH_SIMPLE :
+                           LDAP_AUTH_KRBV4);
+               } else {
+                       authmethod = LDAP_AUTH_KRBV4;
+               }
+       } else {
+               authmethod = LDAP_AUTH_SIMPLE;
+               (void) ldap_msgfree(mp);
+       }
+
+       /*
+        * if they are already kinited, we don't need to ask for a 
+        * password.
+        */
+
+       if ( authmethod == LDAP_AUTH_KRBV4 ) {
+               if ( ! kinited ) {
+                       if ( krbnames[1] != NULL ) {
+                               int     i;
+
+                               /* ask which one to use */
+#ifdef UOFM
+                               printf("  Which UMICH (aka Kerberos or uniqname) name would you like to use?\n");
+#else
+                               printf("  Which Kerberos name would you like to use?\n");
+#endif
+                               for ( i = 0; krbnames[i] != NULL; i++ ) {
+                                       printf( "    %d -> %s\n", i + 1,
+                                           krbnames[i] );
+                               }
+                               do {
+                                       printf("  Enter a number between 1 and %d: ", i );
+                                       fflush( stdout );
+
+                                       fetch_buffer(buf, sizeof(buf), stdin);
+                                       ikrb = atoi(buf) - 1;
+                               } while ( ikrb > i - 1 || ikrb < 0 );
+                       } else {
+                               ikrb = 0;
+                       }
+
+                       /* kinit */
+                       if ( kinit( krbnames[ikrb] ) != 0 ) {
+                               (void) ldap_value_free(rdns);
+                               (void) ldap_value_free(krbnames);
+                               return(-1);
+                       }
+               }
+       } else {
+#endif
+               authmethod = LDAP_AUTH_SIMPLE;
+               sprintf(prompt, "  Enter your X.500 password: ");
+               do {
+                       passwd = mygetpass(prompt);
+               } while (passwd != NULL && *passwd == '\0');
+               if (passwd == NULL) {
+                       (void) ldap_value_free(rdns);
+                       return(0);
+               }
+#ifdef KERBEROS
+       }
+       (void) ldap_value_free(krbnames);
+#endif
+       ldap_flush_cache( ld );
+       rc = ldap_bind_s(ld, Entry.DN, passwd, authmethod);
+       if (rc != LDAP_SUCCESS) {
+               if (ld->ld_errno == LDAP_NO_SUCH_ATTRIBUTE)
+                       fprintf(stderr, "  Entry has no password\n");
+               else if (ld->ld_errno == LDAP_INVALID_CREDENTIALS)
+#ifdef KERBEROS
+                       if ( authmethod == LDAP_AUTH_KRBV4 ) {
+                               fprintf(stderr, "  The Kerberos credentials are invalid.\n");
+                       } else {
+#endif
+                               fprintf(stderr, "  The password you provided is incorrect.\n");
+#ifdef KERBEROS
+                       }
+#endif
+               else
+                       ldap_perror(ld, "ldap_bind_s" );
+               (void) ldap_bind_s(ld, default_bind_object,
+                        (char *) UD_PASSWD, LDAP_AUTH_SIMPLE);
+               if (default_bind_object == NULL)
+                       set_bound_dn(NULL);
+               else
+                       set_bound_dn(default_bind_object);
+               bind_status = UD_NOT_BOUND;
+               if (verbose)
+                       printf("  Authentication failed.\n\n");
+               (void) ldap_value_free(rdns);
+               return(-1);
+       }
+       else if (verbose)
+               printf("  Authentication successful.\n\n");
+       else
+               printf("\n");
+       set_bound_dn(Entry.DN);
+       bind_status = UD_BOUND;
+       if (passwd != NULL)
+               (void) strcpy(password, passwd);
+       (void) ldap_value_free(rdns);
+       return(0);
+}
+
+#ifdef KERBEROS
+
+#define FIVEMINS       ( 5 * 60 )
+#define TGT            "krbtgt"
+
+str2upper( s )
+    char       *s;
+{
+       char    *p;
+
+       for ( p = s; *p != '\0'; ++p ) {
+               if ( islower( *p )) {
+                       *p = toupper( *p );
+               }
+       }
+}
+
+
+static valid_tgt( names )
+    char       **names;
+{
+       int             i;
+       char            name[ ANAME_SZ ], inst[ INST_SZ ], realm[ REALM_SZ ];
+       CREDENTIALS     cred;
+
+       for ( i = 0; names[i] != NULL; i++ ) {
+               if ( kname_parse( name, inst, realm, names[i] ) != KSUCCESS ) {
+                       fprintf( stderr, "Bad format for krbName %s\n",
+                           names[i] );
+                       fprintf( stderr, "Contact x500@umich.edu\n" );
+                       return( 0 );
+               }
+
+#ifdef AFSKERBEROS
+               /*
+                * realm must be uppercase for krb_ routines
+                */
+               str2upper( realm );
+#endif /* AFSKERBEROS */
+
+               /*
+               * check ticket file for a valid ticket granting ticket
+               * my check is: have ticket granting ticket and it is good for
+               * at least 5 more minutes
+               */
+               if ( krb_get_cred( TGT, realm, realm,
+                   &cred ) == KSUCCESS && time( 0 ) + FIVEMINS <
+                   cred.issue_date + (u_char)cred.lifetime * FIVEMINS ) {
+                       return( 1 );
+               }
+       }
+
+       return( 0 );
+}
+
+static char *kauth_name;
+
+/*ARGSUSED*/
+int
+krbgetpass( user, inst, realm, pw, key )
+    char *user, *inst, *realm, *pw;
+    C_Block key;
+{
+       char    *p, lcrealm[ REALM_SZ ], prompt[256], *passwd;
+
+#ifdef UOFM
+       sprintf(prompt, "  Enter the UMICH password (same as Uniqname or Kerberos password)\n  for %s: ", kauth_name );
+#else
+       sprintf(prompt, "  Enter Kerberos password for %s: ", kauth_name );
+#endif
+       do {
+               passwd = mygetpass(prompt);
+       } while (passwd != NULL && *passwd == '\0');
+       if (passwd == NULL) {
+               return(-1);
+       }
+
+#ifdef AFSKERBEROS
+       strcpy( lcrealm, realm );
+       for ( p = lcrealm; *p != '\0'; ++p ) {
+               if ( isupper( *p )) {
+                       *p = tolower( *p );
+               }
+       }
+
+       ka_StringToKey( passwd, lcrealm, key );
+#else /* AFSKERBEROS */
+       string_to_key( passwd, key );
+#endif /* AFSKERBEROS */
+
+       return( 0 );
+}
+
+static kinit( kname )
+    char       *kname;
+{
+       int     rc;
+       char    name[ ANAME_SZ ], inst[ INST_SZ ], realm[ REALM_SZ ];
+
+       kauth_name = kname;
+
+       if ( kname_parse( name, inst, realm, kname ) != KSUCCESS ) {
+               fprintf( stderr, "Bad format for krbName %s\n",
+                   kname );
+               fprintf( stderr, "Contact x500@umich.edu\n" );
+               return( -1 );
+       }
+
+#ifdef AFSKERBEROS
+       /*
+        * realm must be uppercase for krb_ routines
+        */
+       str2upper( realm );
+#endif /* AFSKERBEROS */
+
+       rc = krb_get_in_tkt( name, inst, realm, TGT, realm,
+           DEFAULT_TKT_LIFE, krbgetpass, NULL, NULL );
+
+       if ( rc != KSUCCESS ) {
+               switch ( rc ) {
+               case SKDC_CANT:
+                       fprintf( stderr, "Can't contact Kerberos server for %s\n", realm );
+                       break;
+               default:
+                       fprintf( stderr, "%s: %s\n", name, krb_err_txt[ rc ] );
+                       break;
+               }
+               return( -1 );
+       }
+
+       return( 0 );
+}
+
+destroy_tickets()
+{
+       if ( *tktpath != '\0' ) {
+               unlink( tktpath );
+       }
+}
+#endif
+
+static void set_bound_dn(s)
+char *s;
+{
+       extern void Free();
+       extern char *bound_dn;
+
+       if (bound_dn != NULL)
+               Free(bound_dn);
+       bound_dn = strdup(s);
+}
diff --git a/clients/ud/edit.c b/clients/ud/edit.c
new file mode 100644 (file)
index 0000000..eb8969c
--- /dev/null
@@ -0,0 +1,453 @@
+/*
+ * Copyright (c) 1994  Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <lber.h>
+#include <ldap.h>
+#include <ldapconfig.h>
+#include "ud.h"
+
+extern struct entry Entry; 
+extern int verbose;
+extern LDAP *ld;
+
+extern LDAPMessage *find();
+
+static char *entry_temp_file;
+
+#ifdef DEBUG
+extern int debug;
+#endif
+
+edit(who)
+char *who;
+{
+       LDAPMessage *mp;                        /* returned from find() */
+       char *dn, **rdns;                       /* distinguished name */
+       char name[MED_BUF_SIZE];                /* entry to modify */
+       extern int bind_status;
+       static int load_editor();
+       static int write_entry();
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->edit(%s)\n", who);
+#endif
+       /*
+        *  One must be bound in order to edit an entry.
+        */
+       if (bind_status == UD_NOT_BOUND) {
+               if (auth((char *) NULL, 1) < 0)
+                       return;
+       }
+
+       /*
+        *  First, decide what entry we are going to modify.  If the
+        *  user has not included a name on the modify command line,
+        *  we will use the person who was last looked up with a find
+        *  command.  If there is no value there either, we don't know
+        *  who to modify.
+        *
+        *  Once we know who to modify, be sure that they exist, and
+        *  parse out their DN.
+        */
+       if (who == NULL) {
+               if (verbose) {
+                       printf("  Enter the name of the person or\n");
+                       printf("  group whose entry you want to edit: ");
+               }
+               else
+                       printf("  Edit whose entry? ");
+               fflush(stdout);
+               fetch_buffer(name, sizeof(name), stdin);
+               if (name[0] != '\0')
+                       who = name;
+               else
+                       return;
+       }
+       if ((mp = find(who, TRUE)) == NULL) {
+               (void) ldap_msgfree(mp);
+               printf("  Could not locate \"%s\" in the Directory.\n", who);
+               return;
+       }
+       dn = ldap_get_dn(ld, ldap_first_entry(ld, mp));
+       rdns = ldap_explode_dn(dn, TRUE);
+       Free(dn);
+       if (verbose) {
+               printf("\n  Editing directory entry \"%s\"...\n", *rdns);
+       }
+       parse_answer(mp);
+       (void) ldap_msgfree(mp);
+       (void) ldap_value_free(rdns);
+       if (load_editor() < 0)
+               return;
+       (void) write_entry();
+       (void) unlink(entry_temp_file);
+       ldap_uncache_entry(ld, Entry.DN);
+       return;
+}
+
+static load_editor()
+{
+       FILE *fp;
+       char *cp, *editor = UD_DEFAULT_EDITOR;
+       static char template[MED_BUF_SIZE];
+       extern char * mktemp();
+       extern int isgroup(), fatal();
+       static int print_attrs_and_values();
+       int pid;
+       int status;
+       int rc;
+       void (*handler)();
+       
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->load_editor()\n");
+#endif
+
+       /* write the entry into a temp file */
+       (void) strcpy(template, "/tmp/udEdit.XXXXXX");
+       if ((entry_temp_file = mktemp(template)) == NULL) {
+               perror("mktemp");
+               return(-1);
+       }
+       if ((fp = fopen(entry_temp_file, "w")) == NULL) {
+               perror("fopen");
+               return(-1);
+       }
+       fprintf(fp, "## Directory entry of %s\n", Entry.name);
+       fprintf(fp, "##\n");
+       fprintf(fp, "## Syntax is:\n");
+       fprintf(fp, "## <attribute-name>\n");
+       fprintf(fp, "##         <TAB> <value 1>\n");
+       fprintf(fp, "##         <TAB>   :  :\n");
+       fprintf(fp, "##         <TAB> <value N>\n");
+       fprintf(fp, "## Lines beginning with a hash mark are comments.\n");
+       fprintf(fp, "##\n");
+       fflush(fp);
+       if (isgroup())
+               rc = print_attrs_and_values(fp, Entry.attrs, ATTR_FLAG_GROUP_MOD);
+       else
+               rc = print_attrs_and_values(fp, Entry.attrs, ATTR_FLAG_PERSON_MOD);
+       fclose(fp);
+
+       if ( rc != 0 ) {
+           (void) unlink(entry_temp_file);
+           return( rc );
+       }
+
+       /* edit the temp file with the editor of choice */
+       if ((cp = getenv("EDITOR")) != NULL)
+               editor = cp;
+       if (verbose) {
+               char    *p;
+
+               if (( p = strrchr( editor, '/' )) == NULL ) {
+                       p = editor;
+               } else {
+                       ++p;
+               }
+               printf("  Using %s as the editor...\n", p );
+               sleep(2);
+       }
+       if ((pid = fork()) == 0) {      
+               /* child - edit the Directory entry */
+               (void) signal(SIGINT, SIG_IGN);
+               (void) execlp(editor, editor, entry_temp_file, NULL);
+               /*NOTREACHED*/
+               (void) fatal(editor);   
+       }
+       else if (pid > 0) {
+               /* parent - wait until the child proc is done editing */
+               handler = signal(SIGINT, SIG_IGN);
+               (void) wait(&status);
+               (void) signal(SIGINT, handler);
+       }
+       else {
+               fatal("fork");
+               /*NOTREACHED*/
+       }
+       return(0);
+}
+
+static int print_attrs_and_values(fp, attrs, flag)
+FILE *fp;
+struct attribute attrs[];
+short flag;
+{
+       static int modifiable();
+       register int i, j;
+
+       for (i = 0; attrs[i].quipu_name != NULL; i++) {
+               if (!modifiable(attrs[i].quipu_name, flag|ATTR_FLAG_MAY_EDIT))
+                       continue;
+               fprintf(fp, "%s\n", attrs[i].quipu_name);
+               if ( attrs[i].number_of_values > MAX_VALUES ) {
+                       printf("  The %s attribute has more than %d values.\n",
+                               attrs[i].quipu_name, MAX_VALUES );
+                       printf("  You cannot use the vedit command on this entry.  Sorry!\n" );
+                       return( -1 );
+               }
+               for (j = 0; j < attrs[i].number_of_values; j++)
+                       fprintf(fp, "\t%s\n", attrs[i].values[j]);
+       }
+       return( 0 );
+}
+
+static modifiable(s, flag)
+char *s;
+short flag;
+{
+       register int i;
+       extern struct attribute attrlist[];
+
+       for (i = 0; attrlist[i].quipu_name != NULL; i++) {
+               if (strcasecmp(s, attrlist[i].quipu_name))
+                       continue;
+               if ((attrlist[i].flags & flag) == ATTR_FLAG_NONE)
+                       return(FALSE);
+               return(TRUE);
+       }
+       /* should never be here */
+       return(FALSE);
+}
+
+static write_entry()
+{
+       int i = 0, j, number_of_values = -1;
+
+       FILE *fp;
+       char *cp, line[LARGE_BUF_SIZE], *values[MAX_VALUES], **vp;
+
+       LDAPMod *mods[MAX_ATTRS + 1];
+       LDAPMod *modp = NULL;
+
+       static int ovalues();
+       extern char * code_to_str();
+       extern void free_mod_struct();
+
+       /* parse the file and write the values to the Directory */
+       if ((fp = fopen(entry_temp_file, "r")) == NULL) {
+               perror("fopen");
+               return;
+       }
+       for (;;) {
+               (void) fgets(line, sizeof(line), fp);
+               if (feof(fp))
+                       break;
+               line[strlen(line) - 1] = '\0';          /* kill newline */
+               cp = line;
+               if (*cp == '#')
+                       continue;
+               if (isspace(*cp)) {     /* value */
+                       while (isspace(*cp))
+                               cp++;
+                       values[number_of_values++] = strdup(cp);
+                       if ( number_of_values >= MAX_VALUES ) {
+                               printf("  A maximum of %d values can be handled at one time.  Sorry!\n", MAX_VALUES );
+                               return;
+                       }
+                       continue;
+               }
+               /* attribute */
+               while (isspace(*cp))
+                       cp++;
+               /*
+                *  If the number of values is greater than zero, then we
+                *  know that this is not the first time through this
+                *  loop, and we also know that we have a little bit
+                *  of work to do:
+                *
+                *      o The modify operation needs to be changed from
+                *        a DELETE to a REPLACE
+                *
+                *      o The list of values pointer needs to be changed
+                *        from NULL, to a NULL-terminated list of char
+                *        pointers.
+                */
+               if (number_of_values > 0) {
+                       modp->mod_op = LDAP_MOD_REPLACE;
+                       if ((vp = (char **) Malloc(sizeof(char *) * (number_of_values + 2))) == (char **) NULL) {
+                               fatal("Malloc");
+                               /*NOTREACHED*/
+                       }
+                       modp->mod_values = vp;
+                       for (j = 0; j < number_of_values; j++) {
+                               *vp++ = strdup(values[j]);
+                               (void) Free(values[j]);
+                       }
+                       *vp = NULL;
+               }
+               /*
+                *  If there are no values, and there were no values to begin
+                *  with, then there is nothing to do.
+                */
+               if ((number_of_values == 0) && (ovalues(modp->mod_type) == 0)) {
+#ifdef DEBUG
+                       if (debug & D_MODIFY)
+                               printf(" %s has zero values - skipping\n",
+                                               modp->mod_type);
+#endif
+                       (void) Free(modp->mod_type);
+                       modp->mod_type = strdup(cp);
+                       modp->mod_op = LDAP_MOD_DELETE;
+                       modp->mod_values = NULL;
+                       continue;
+               }
+               /*
+                *  Fetch a new modify structure.
+                *
+                *  Assume a DELETE operation with no values.
+                */
+               if ((modp = (LDAPMod *) Malloc(sizeof(LDAPMod))) == NULL) {
+                       fatal("Malloc");
+                       /*NOTREACHED*/
+               }
+               modp->mod_values = NULL;
+               modp->mod_type = strdup(cp);
+               modp->mod_op = LDAP_MOD_DELETE;
+               mods[i++] = modp;
+               number_of_values = 0;
+       }
+       fclose(fp);
+
+       /* check the last one too */
+       if (number_of_values > 0) {
+               modp->mod_op = LDAP_MOD_REPLACE;
+               /*
+                *  Fetch some value pointers.
+                *
+                *      number_of_values        To store the values
+                *              1               For the NULL terminator
+                *              1               In case we need it to store
+                *                              the RDN as on of the values
+                *                              of 'cn' in case it isn't there
+                */
+               if ((vp = (char **) Malloc(sizeof(char *) * (number_of_values +
+                                                2))) == (char **) NULL) {
+                       fatal("Malloc");
+                       /*NOTREACHED*/
+               }
+               modp->mod_values = vp;
+               for (j = 0; j < number_of_values; j++) {
+                       *vp++ = strdup(values[j]);
+                       (void) Free(values[j]);
+               }
+               *vp = NULL;
+       }
+       else if ((number_of_values == 0) && 
+                               (ovalues(mods[i - 1]->mod_type) == 0)) {
+#ifdef DEBUG
+               if (debug & D_MODIFY)
+                       printf(" %s has zero values - skipping\n",
+                                       mods[i - 1]->mod_type);
+#endif
+               Free(mods[i - 1]->mod_type);
+               Free(mods[i - 1]);
+               i--;
+       }
+       mods[i] = (LDAPMod *) NULL;
+
+       /* 
+        * If one of the mods pointers is 'cn', be sure that the RDN is one
+        * of the values.
+        */
+       for (j = 0; j < i; j++) {
+               if (strcasecmp("cn", mods[j]->mod_type))
+                       continue;
+               /*
+                *  True only if there WERE values, but the person deleted
+                *  them all.
+                */
+               if (mods[j]->mod_values == NULL) {
+                       mods[j]->mod_op = LDAP_MOD_REPLACE;
+                       if ((vp = (char **) Malloc(sizeof(char *) * 2)) == (char **) NULL) {
+                               fatal("Malloc");
+                               /*NOTREACHED*/
+                       }
+                       mods[j]->mod_values = vp;
+                       *vp++ = strdup(Entry.name);
+                       *vp = NULL;
+                       break;
+               }
+               /*
+                *  Be sure that one of the values of 'cn' is the RDN.
+                */
+               for (vp = mods[j]->mod_values; *vp != NULL; vp++) {
+                       if (strcasecmp(*vp, Entry.DN))
+                               continue;
+                       break;
+               }
+               if (*vp == NULL) {
+                       *vp++ = strdup(Entry.name);
+                       *vp = NULL;
+                       break;
+               }
+       }
+#ifdef DEBUG
+       if (debug & D_MODIFY) {
+               register int x, y;
+
+               printf("  ld = 0x%x\n", ld);
+               printf("  dn = [%s]\n", Entry.DN);
+               for (x = 0; mods[x] != (LDAPMod *) NULL; x++) {
+                       printf("  mods[%d]->mod_op = %s\n", 
+                                       x, code_to_str(mods[x]->mod_op));
+                       printf("  mods[%d]->mod_type = %s\n", 
+                                                       x, mods[x]->mod_type);
+                       if (mods[x]->mod_values == NULL)
+                               printf("  mods[%d]->mod_values = NULL\n", x);
+                       else {
+                               for (y = 0; mods[x]->mod_values[y] != NULL; y++)
+                                  printf("  mods[%d]->mod_values[%1d] = %s\n", 
+                                               x, y, mods[x]->mod_values[y]);
+                               printf("  mods[%d]->mod_values[%1d] = NULL\n",
+                                                                       x, y);
+                       }
+                       printf("\n");
+               }
+       }
+#endif
+       if (ldap_modify_s(ld, Entry.DN, mods))
+               mod_perror(ld);
+       else
+               printf("  Modification complete.\n" );
+
+       /* clean up */
+       for (i = 0; mods[i] != NULL; i++)
+               free_mod_struct(mods[i]);
+       return;
+}
+
+static ovalues(attr)
+char *attr;
+{
+       struct attribute *ap;
+
+       /*
+        *  Lookup the attribute with quipu_name 'attr' in the Entry
+        *  structure and return the number of values.
+        */
+       for (ap = Entry.attrs; ap->quipu_name != NULL; ap++) {
+               if (!strcasecmp(ap->quipu_name, attr))
+                       return(ap->number_of_values);
+       }
+       /* should never get to this point unless 'attr' was something odd */
+       return(0);
+}
diff --git a/clients/ud/etc.ud.conf b/clients/ud/etc.ud.conf
new file mode 100644 (file)
index 0000000..4566d6f
--- /dev/null
@@ -0,0 +1,2 @@
+server <your ldap server host name here>
+base   <your X.500 default search base here>
diff --git a/clients/ud/find.c b/clients/ud/find.c
new file mode 100644 (file)
index 0000000..3551c1a
--- /dev/null
@@ -0,0 +1,496 @@
+/*
+ * Copyright (c) 1991, 1992, 1993 
+ * Regents of the University of Michigan.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#ifndef __STDC__
+#include <memory.h>
+#endif
+#include <lber.h>
+#include <ldap.h>
+#include "ud.h"
+
+extern char *search_base;      /* search base */
+extern int verbose;            /* verbose mode flag */
+extern LDAP *ld;               /* our ldap descriptor */
+       
+static int num_picked = 0;     /* used when user picks entry at More prompt */
+
+#ifdef DEBUG
+extern int debug;              /* debug flag */
+#endif
+
+vrfy(dn)
+char *dn;
+{
+       LDAPMessage *results;
+       static char *attrs[2] = { "objectClass", NULL };
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->vrfy(%s)\n", dn);
+#endif
+       /* verify that this DN exists in the directory */
+       (void) ldap_search_s(ld, dn, LDAP_SCOPE_BASE, "objectClass=*", attrs, TRUE, &results);
+       (void) ldap_msgfree(results);
+       if ((ld->ld_errno == LDAP_NO_SUCH_OBJECT) || (ld->ld_errno == LDAP_INVALID_DN_SYNTAX))
+               return(0);
+       else if (ld->ld_errno == LDAP_SUCCESS)
+               return(1);
+       else {
+               ldap_perror(ld, "ldap_search");
+               return(0);
+       }
+}
+       
+
+static LDAPMessage * disambiguate( result, matches, read_attrs, who )
+LDAPMessage *result;
+int matches;
+char **read_attrs;
+char *who;
+{
+       int choice;                     /* entry that user chooses */
+       int i;
+       char *namelist[MAX_NUM_NAMES];  /* names found */
+       char response[SMALL_BUF_SIZE];  /* results from user */
+       char *name = NULL;              /* DN to lookup */
+       LDAPMessage *mp;
+       extern void Free();
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->disambiguate(%x, %d, %x, %s)\n", result, matches, 
+                                                       read_attrs, who);
+#endif
+       /*
+        *  If we are here, it means that we got back multiple answers.
+        */
+       if ((ld->ld_errno == LDAP_TIMELIMIT_EXCEEDED)
+           || (ld->ld_errno == LDAP_SIZELIMIT_EXCEEDED)) {
+               if (verbose) {
+                       printf("  Your query was too general and a limit was exceeded.  The results listed\n");
+                       printf("  are not complete.  You may want to try again with a more refined query.\n\n");
+               }
+               else
+                       printf("  Time or size limit exceeded.  Partial results follow.\n\n");
+       }
+       printf("  %1d names matched \"%s\".\n", matches, who);
+       for (;;) {
+               printf("  Do you wish to see a list of names? ");
+               fflush(stdout);
+               (void) memset(response, 0, sizeof(response));
+               fetch_buffer(response, sizeof(response), stdin);
+               switch (response[0]) {
+               case 'n' :
+               case 'N' :
+               case '\0' :
+               case '\n' :
+                       return(NULL);
+                       /* NOTREACHED */
+               case 'y' :
+               case 'Y' :
+                       print_list(result, namelist, &matches);
+                       if (num_picked == 0)
+                               choice = pick_one(matches);
+                       else
+                               choice = num_picked;
+                       num_picked = 0;
+                       if (choice >= 0)
+                               name = strdup(namelist[choice]);
+                       /*
+                        *  Now free up all of the pointers allocated in
+                        *  namelist.  The print_list() routine that filled
+                        *  in this collection of strings starts at 1, not 0.
+                        */
+                       for (i = 1; namelist[i] != NULL; i++)
+                               Free(namelist[i]);
+                       if (choice < 0) {
+                               if (name != NULL)
+                                       Free(name);
+                               return(NULL);
+                       }
+#ifdef DEBUG
+                       if (debug & D_FIND) {
+                               printf("  Calling ldap_search_s()\n");
+                               printf("     ld = 0x%x\n", ld);
+                               printf("     search base = %s\n", name);
+                               printf("     scope = LDAP_SCOPE_BASE\n");
+                               printf("     filter = objectClass=*\n");
+                               for (i = 0; read_attrs[i] != NULL; i++)
+                                       printf("     read_attrs[%d] = %s\n", i, read_attrs[i]);
+                               printf("     read_attrs[%d] = NULL\n", i);
+                               printf("     attrsonly = FALSE\n");
+                               printf("     &mp = 0x%x\n", &mp);
+                       }
+#endif
+                       if (ldap_search_s(ld, name, LDAP_SCOPE_BASE, "objectClass=*", read_attrs, FALSE, &mp) != LDAP_SUCCESS) {
+                               ldap_perror(ld, "ldap_search_s");
+                               Free(name);
+                               ldap_msgfree(mp);
+                               return(NULL);
+                       }
+                       Free(name);
+                       return(mp);
+                       /* NOTREACHED */
+               default :
+                       printf("  Please enter 'y', 'n', or RETURN.\n");
+                       break;
+               }
+       }
+}
+
+LDAPMessage * find(who, quiet)
+char *who;
+int quiet;
+{
+       register int i, j, k;           /* general ints */
+       int matches;                    /* from ldap_count_entries() */
+       int admonished = FALSE;
+       static int attrs_set = 0;
+       static char *read_attrs[MAX_ATTRS];     /* attrs to use in a read op */
+       static char *search_attrs[MAX_ATTRS];   /* attrs to use in a srch op */
+       static int rc;                  /* return from ldap_search */
+       LDAPMessage *ldtmp, *res;       /* results returned from search */
+       char name[MED_BUF_SIZE];
+       char response[SMALL_BUF_SIZE];
+       char *cp, *dn, **rdns;
+       LDAPFiltInfo *fi;
+       extern LDAPFiltDesc *lfdp;              /* LDAP filter descriptor */
+       extern struct attribute attrlist[];     /* complete list of attrs */
+       extern void Free();
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               fprintf(stderr, "->find(%s)\n", who);
+#endif
+       /* did not specify a 'who' */
+       if (who == NULL) {
+               printf("  Locate whose entry? ");
+               fflush(stdout);
+               fetch_buffer(name, sizeof(name), stdin);
+               if (name[0] != '\0')
+                       who = name;
+               else
+                       return(NULL);
+       }
+       if (attrs_set == 0) {
+               j = k = 0;
+               attrs_set = 1;
+               for (i = 0; attrlist[i].quipu_name != NULL; i++) {
+                       if (attrlist[i].flags & ATTR_FLAG_READ)
+                               read_attrs[j++] = attrlist[i].quipu_name;
+                       if (attrlist[i].flags & ATTR_FLAG_SEARCH)
+                               search_attrs[k++] = attrlist[i].quipu_name;
+               }
+               read_attrs[j] = NULL;
+               search_attrs[k] = NULL;
+       }
+
+       /*
+        *  If the user-supplied name has any commas in it, we
+        *  assume that it is a UFN, and do everything right
+        *  here.  If we don't find it, treat it as NOT a UFN.
+        */
+       if (strchr(who, ',') != NULL) {
+               int     savederef;
+#ifdef DEBUG
+               if (debug & D_FIND)
+                       printf("\"%s\" appears to be a UFN\n", who);
+#endif
+               savederef = ld->ld_deref;
+               ld->ld_deref = LDAP_DEREF_FINDING;
+               if ((rc = ldap_ufn_search_s(ld, who, search_attrs, FALSE, &res)) !=
+                   LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED &&
+                   rc != LDAP_TIMELIMIT_EXCEEDED) {
+                       ldap_perror(ld, "ldap_ufn_search_s");
+                       ld->ld_deref = savederef;
+                       return(NULL);
+               }
+               if ((matches = ldap_count_entries(ld, res)) < 0) {
+                       ldap_perror(ld, "ldap_count_entries");
+                       ld->ld_deref = savederef;
+                       return(NULL);
+               } else if (matches == 1) {
+                       if (ldap_search_s(ld, ldap_get_dn(ld, ldap_first_entry(ld, res)), LDAP_SCOPE_BASE, "objectClass=*", read_attrs, FALSE, &res) != LDAP_SUCCESS) {
+                               if (ld->ld_errno == LDAP_UNAVAILABLE)
+                                       printf("  Could not contact the X.500 server to find \"%s\".\n", who);
+                               else
+                                       ldap_perror(ld, "ldap_search_s");
+                               return(NULL);
+                       }
+                       ld->ld_deref = savederef;
+                       return(res);
+               } else if (matches > 1 ) {
+                       return( disambiguate( ld, res, matches, read_attrs,
+                           who ) );
+               }
+               ld->ld_deref = savederef;
+       }
+
+       /*
+        *  Old users of the MTS *USERDIRECTORY will likely wrap the name
+        *  in quotes.  Not only is this unnecessary, but it also won't work.
+        */
+       for (cp = strchr(who, '"'); cp != NULL; cp = strchr(cp, '"')) {
+               if (!admonished) {
+                       printf("  You do not need to enclose names in quotes.\n");
+                       admonished = TRUE;
+               }
+               *cp++ = ' ';
+               if (*cp == '\0')
+                       break;
+       }
+
+       /*
+        *  It wasn't a UFN, so look it up in the usual method.
+        */
+       for (fi = ldap_getfirstfilter(lfdp, "ud", who); fi != NULL;
+            fi = ldap_getnextfilter(lfdp)) {
+#ifdef DEBUG
+               if (debug & D_FIND)
+                       printf("Searching, filter = %s\n", fi->lfi_filter);
+#endif
+
+               if ((rc = ldap_search_s(ld, search_base, fi->lfi_scope, 
+               fi->lfi_filter, search_attrs, FALSE, &res)) != LDAP_SUCCESS &&
+               rc != LDAP_SIZELIMIT_EXCEEDED && rc != LDAP_TIMELIMIT_EXCEEDED) {
+                       ldap_perror(ld, "ldap_search_s");
+                       ldap_msgfree(res);
+                       return(NULL);
+               }
+               if ((matches = ldap_count_entries(ld, res)) < 0) {
+                       ldap_perror(ld, "ldap_count_entries");
+                       ldap_msgfree(res);
+                       return(NULL);
+               }
+               else if (matches == 1) {
+                       dn = ldap_get_dn(ld, ldap_first_entry(ld, res));
+                       ldap_msgfree(res);
+                       if (!quiet)
+                               printf("  Found one %s match for \"%s\"\n", 
+                                                       fi->lfi_desc, who);
+                       if (!fi->lfi_isexact) {
+                               rdns = ldap_explode_dn(dn, TRUE);
+                               printf("  Do you mean %s? ", *rdns);
+                               (void) ldap_value_free(rdns);
+                               fflush(stdout);
+                               fetch_buffer(response, sizeof(response), stdin);
+                               if ((response[0] == 'n') || (response[0] == 'N'))
+                                       return(NULL);
+                       }
+#ifdef DEBUG
+                       if (debug & D_FIND) {
+                               printf("  Calling ldap_search_s()\n");
+                               printf("     ld = 0x%x\n", ld);
+                               printf("     dn = %s\n", dn);
+                               printf("     scope = LDAP_SCOPE_BASE\n");
+                               printf("     filter = %s\n", "objectClass=*");
+                               for (i = 0; read_attrs[i] != NULL; i++)
+                                       printf("     read_attrs[%d] = %s\n", i, read_attrs[i]);
+                               printf("     read_attrs[%d] = NULL\n", i);
+                               printf("     attrsonly = FALSE\n");
+                               printf("     &results = 0x%x\n", &res);
+                       }
+#endif
+                       if (ldap_search_s(ld, dn, LDAP_SCOPE_BASE, "objectClass=*", read_attrs, FALSE, &res) != LDAP_SUCCESS) {
+                               ldap_perror(ld, "ldap_search_s");
+                               ldap_msgfree(res);
+                               return(NULL);
+                       }
+                       Free(dn);
+                       return(res);
+               }
+               else if (matches > 0) {
+                       ldtmp = disambiguate(res, matches, read_attrs, who);
+                       ldap_msgfree(res);
+                       return(ldtmp);
+               }
+               /* if we're here, there were zero matches */
+               ldap_msgfree(res);
+       }
+       return(NULL);
+}
+
+pick_one(i)
+int i;
+{
+       int n;
+       char user_pick[SMALL_BUF_SIZE];
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->pick_one(%d)\n", i);
+#endif
+       
+       /* make the user pick an entry */
+       for (;;) {
+               printf("  Enter the number of the name you want or Q to quit: ");
+               fflush(stdout);
+               fetch_buffer(user_pick, sizeof(user_pick), stdin);
+               if (user_pick[0] == 'q' || user_pick[0] == 'Q')
+                       return(-1);
+               n = atoi(user_pick);
+               if ((n > 0) && (n <= i))
+                       return(n);
+               printf("  Invalid response\n");
+       }
+       /* NOTREACHED */
+}
+
+print_list(list, names, matches)
+LDAPMessage *list;
+char *names[];
+int *matches;
+{
+       char **rdns, **cpp;
+       extern int lpp;
+       char resp[SMALL_BUF_SIZE];
+       register LDAPMessage *ep;
+       register int i = 1;
+       register int rest = 4;          /* 4, not 1 */
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->print_list(%x, %x, %x)\n", list, names, matches);
+#endif
+       /* print a list of names from which the user will select */
+       for (ep = ldap_first_entry(ld, list); ep != NULL; ep = ldap_next_entry(ld, ep)) {
+               
+               names[i] = ldap_get_dn(ld, ep);
+               rdns = ldap_explode_dn(names[i], TRUE);
+               cpp = ldap_get_values(ld, ep, "title");
+               if (cpp == NULL)
+                       printf(" %3d. %s\n", i, *rdns);
+               else
+                       printf(" %3d. %s, %s\n", i, *rdns, *cpp);
+               ldap_value_free(rdns);
+               ldap_value_free(cpp);
+               i++;
+               if ((rest++ > (lpp - 1)) && (i < *matches)) {
+again:
+                       printf("  More? ");
+                       fflush(stdout);
+                       fetch_buffer(resp, sizeof(resp), stdin);
+                       if ((resp[0] == 'n') || (resp[0] == 'N'))
+                               break;
+                       else if ((num_picked = atoi(resp)) != 0) {
+                               if (num_picked < i)
+                                       break;
+                               else
+                                       goto again;
+                       }
+                       rest = 1;
+               }
+       }
+       *matches = i - 1;
+       names[i] = NULL;
+       return;
+}
+
+find_all_subscribers(sub, group)
+char *sub[];
+char *group;
+{
+       int count;
+       LDAPMessage *result;
+       static char *attributes[] = { "cn", NULL };
+       char filter[MED_BUF_SIZE];
+       register LDAPMessage *ep;
+       register int i = 0;
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->find_all_subscribers(%x, %s)\n", sub, group);
+#endif
+
+       sprintf(filter, "%s=%s", "memberOfGroup", group);
+       if (ldap_search_s(ld, search_base, LDAP_SCOPE_SUBTREE, filter, attributes, FALSE, &result) != LDAP_SUCCESS) {
+               if (ld->ld_errno == LDAP_NO_SUCH_ATTRIBUTE)
+                       return(0);
+               ldap_perror(ld, "ldap_search_s");
+               return(0);
+       }
+       count = ldap_count_entries(ld, result);
+       if (count < 1) {
+               ldap_msgfree(result);
+               return(0);
+       }
+       if ( count > MAX_VALUES ) {
+               printf( "  Only retrieving the first %d subscribers....\n",
+                       MAX_VALUES );
+       }
+
+       for (ep = ldap_first_entry(ld, result); i < MAX_VALUES && ep != NULL; ep = ldap_next_entry(ld, ep)) {
+               sub[i++] = ldap_get_dn(ld, ep);
+#ifdef DEBUG
+               if (debug & D_PARSE)
+                       printf("sub[%d] = %s\n", i - 1, sub[i - 1]);
+#endif
+       }
+       sub[i] = NULL;
+       ldap_msgfree(result);
+       return(count);
+}
+
+char * fetch_boolean_value(who, attr)
+char *who;
+struct attribute attr;
+{
+       LDAPMessage *result;            /* from the search below */
+       register LDAPMessage *ep;       /* entry pointer */
+       register char **vp;             /* for parsing the result */
+       static char *attributes[] = { NULL, NULL };
+
+#ifdef DEBUG
+        if (debug & D_TRACE)
+               printf("->fetch_boolean_value(%s, %s)\n", who, attr.quipu_name);
+#endif
+       attributes[0] = attr.quipu_name;
+       if (ldap_search_s(ld, who, LDAP_SCOPE_BASE, "objectClass=*", attributes, FALSE, &result) != LDAP_SUCCESS) {
+               if (ld->ld_errno == LDAP_NO_SUCH_ATTRIBUTE)
+                       return("FALSE");
+               ldap_perror(ld, "ldap_search_s");
+               ldap_msgfree(result);
+               return(NULL);
+       }
+
+       /*
+        *  We did a read on one name and only asked for one attribute.
+        *  There's no reason to loop through any of these structures.
+        *
+        *  If ldap_first_attribute() returns NULL, then this entry did
+        *  not have this particular attribute.
+        */
+       ep = ldap_first_entry(ld, result);
+       if ((vp = (char **) ldap_get_values(ld, ep, attr.quipu_name)) == NULL) {
+               ldap_msgfree(result);
+               return("FALSE");
+       }
+       else {
+               ldap_msgfree(result);
+               if (!strcasecmp(*vp, "TRUE")) {
+                       ldap_value_free(vp);
+                       return("TRUE");
+               }
+               else if (!strcasecmp(*vp, "FALSE")) {
+                       ldap_value_free(vp);
+                       return("FALSE");
+               }
+               else {
+                       fprintf(stderr, "  Got garbage -> [%s]\n", *vp);
+                       ldap_value_free(vp);
+                       return(NULL);
+               }
+       }
+}
diff --git a/clients/ud/globals.c b/clients/ud/globals.c
new file mode 100644 (file)
index 0000000..121f36b
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 1992, 1993, 1994  Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include "ud.h"
+
+extern void    set_boolean(), 
+               change_field(), 
+#ifdef UOFM
+               set_updates(), 
+#endif
+               mod_addrDN();
+
+struct attribute attrlist[] = {
+
+       /* 
+        *  Field 1 = Quipu name
+        *  Field 2 = String used when printing the field
+        *  Field 3 = function used to modify this field (if any)
+        *  Field 4 = Flags specifying how this field is displayed
+        */
+       { "memberOfGroup", "Subscriptions", NULL, ATTR_FLAG_PERSON | ATTR_FLAG_READ | ATTR_FLAG_IS_A_DN },
+       { "acl", "Access Control", NULL, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ },
+       { "cn", "Aliases", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_SEARCH | ATTR_FLAG_GROUP_MOD },
+       { "title", "Title", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_READ | ATTR_FLAG_SEARCH | ATTR_FLAG_PERSON_MOD },
+       { "postalAddress", "Business address", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_PERSON_MOD | ATTR_FLAG_GROUP_MOD | ATTR_FLAG_IS_MULTILINE },
+       { "telephoneNumber", "Business phone", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_PERSON_MOD | ATTR_FLAG_GROUP_MOD },
+       { "mail", "E-mail address", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_SEARCH | ATTR_FLAG_PERSON_MOD | ATTR_FLAG_MAY_EDIT },
+       { "member", "Members", mod_addrDN, ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_IS_A_DN | ATTR_FLAG_GROUP_MOD },
+       { "homePhone", "Home phone", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_READ  | ATTR_FLAG_PERSON_MOD },
+       { "homePostalAddress", "Home address", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_READ  | ATTR_FLAG_PERSON_MOD | ATTR_FLAG_IS_MULTILINE },
+       { "objectClass", "Object class", NULL, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_SEARCH },
+#ifdef UOFM
+       { "multiLineDescription", "Description", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ  | ATTR_FLAG_PERSON_MOD | ATTR_FLAG_GROUP_MOD | ATTR_FLAG_IS_MULTILINE },
+#endif
+#ifdef KERBEROS
+       { "krbName", "Kerberos name", NULL, ATTR_FLAG_PERSON | ATTR_FLAG_READ },
+#endif
+       { "description", "Brief description", NULL, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ },
+       { "facsimileTelephoneNumber", "Fax number", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ  | ATTR_FLAG_PERSON_MOD | ATTR_FLAG_GROUP_MOD },
+       { "pager", "Pager number", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_READ  | ATTR_FLAG_PERSON_MOD },
+       { "uid", "Uniqname", NULL, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ },
+       { "userPassword", "Password", NULL, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ },
+#ifdef UOFM
+       { "noBatchUpdates", "No batch updates", set_updates, ATTR_FLAG_PERSON | ATTR_FLAG_READ | ATTR_FLAG_PERSON_MOD },
+#endif
+       { "joinable", "Joinable flag", set_boolean, ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_GROUP_MOD },
+       { "associatedDomain", "Associated domain", change_field, ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_GROUP_MOD },
+       { "owner", "Owner", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_IS_A_DN | ATTR_FLAG_GROUP_MOD },
+       { "rfc822ErrorsTo", "Errors to", change_field, ATTR_FLAG_GROUP | ATTR_FLAG_READ },
+       { "ErrorsTo", "Errors to", mod_addrDN, ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_IS_A_DN | ATTR_FLAG_GROUP_MOD },
+       { "rfc822RequestsTo", "Requests to", change_field, ATTR_FLAG_GROUP | ATTR_FLAG_READ },
+       { "RequestsTo", "Requests to", mod_addrDN, ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_IS_A_DN | ATTR_FLAG_GROUP_MOD },
+       { "moderator", "Moderated by", change_field, ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_GROUP_MOD },
+       { "labeledURL", "More Info (URL)", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_GROUP | ATTR_FLAG_READ | ATTR_FLAG_PERSON_MOD | ATTR_FLAG_GROUP_MOD | ATTR_FLAG_IS_A_URL },
+       { "onVacation", "On Vacation", set_boolean, ATTR_FLAG_PERSON | ATTR_FLAG_READ | ATTR_FLAG_PERSON_MOD | ATTR_FLAG_IS_A_BOOL },
+       { "vacationMessage", "Vacation Message", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_READ  | ATTR_FLAG_PERSON_MOD | ATTR_FLAG_IS_MULTILINE },
+       { "drink", "Favorite Beverage", change_field, ATTR_FLAG_PERSON | ATTR_FLAG_READ | ATTR_FLAG_PERSON_MOD },
+       { "lastModifiedBy", "Last modified by", NULL, ATTR_FLAG_GROUP | ATTR_FLAG_PERSON | ATTR_FLAG_IS_A_DN | ATTR_FLAG_READ },
+       { "lastModifiedTime", "Last modified at", NULL, ATTR_FLAG_GROUP | ATTR_FLAG_PERSON | ATTR_FLAG_READ | ATTR_FLAG_IS_A_DATE },
+       { NULL, NULL, NULL, ATTR_FLAG_NONE }
+};
diff --git a/clients/ud/group.c b/clients/ud/group.c
new file mode 100644 (file)
index 0000000..6400617
--- /dev/null
@@ -0,0 +1,1242 @@
+/*
+ * Copyright (c) 1993, 1994  Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <lber.h>
+#include <ldap.h>
+#include <ldapconfig.h>
+#include "ud.h"
+
+extern LDAPMessage * find();
+
+#ifdef DEBUG
+extern int debug;
+#endif
+
+extern char *bound_dn, *group_base;
+extern int verbose, bind_status;
+extern struct entry Entry;
+extern LDAP *ld;
+
+extern void Free();
+
+void add_group(name)
+char *name;
+{
+       register int i, idx = 0, prompt = 0;
+       char tmp[BUFSIZ], dn[BUFSIZ];
+       static LDAPMod *attrs[9];
+       LDAPMod init_rdn,    init_owner,   init_domain,
+               init_errors, init_request, init_joinable;
+       char *init_rdn_value[2], *init_owner_value[2], *init_domain_value[2],
+               *init_errors_value[MAX_VALUES], *init_joinable_value[2],
+               *init_request_value[MAX_VALUES];
+       extern void ldap_flush_cache();
+       extern char * strip_ignore_chars();
+
+#ifdef DEBUG
+       if (debug & D_TRACE) {
+               if (name == NULL)
+                       printf("->add_group(NULL)\n");
+               else
+                       printf("->add_group(%s)\n", name);
+       }
+#endif
+
+       if (bind_status == UD_NOT_BOUND) {
+               if (auth((char *) NULL, 1) < 0) {
+                       return;
+               }
+       }
+
+       /*
+        *  If the user did not supply us with a name, prompt them for
+        *  a name.
+        */
+       if ((name == NULL) || (*name == '\0') || !strcasecmp(name, "group")) {
+               ++prompt;
+               printf("  Group to create? ");
+               fflush(stdout);
+               fetch_buffer(tmp, sizeof(tmp), stdin);
+               if (tmp[0] == '\0')
+                       return;
+               name = strdup(tmp);
+       }
+
+       /* remove quotes, dots, and underscores. */
+       name = strip_ignore_chars(name);
+
+#ifdef UOFM
+       if (isauniqname(name)) {
+               printf(" '%s' could be confused with a U-M uniqname.\n", name);
+               printf(" You can create the group, but you need to make sure that\n");
+               printf(" you reserve the uniqname for use as your groupname\n\n");
+               printf(" Are you sure that you want to do this? ");
+               fflush(stdout);
+               fetch_buffer(tmp, sizeof(tmp), stdin);
+               if (!(tmp[0] == 'y' || tmp[0] == 'Y'))
+                       return;
+               printf("\n Be sure to contact your uniqname administrator to reserve\n");
+               printf(" the uniqname '%s' for use as your group name.\n", name);
+       }
+#endif
+       sprintf(dn, "cn=%s, %s", name, group_base);
+
+       /*
+        *  Make sure that this group does not already exist.
+        */
+       if (vrfy(dn) == TRUE) {
+               printf("  The group \"%s\" already exists.\n", name);
+               return;
+       }
+
+       /*
+        *  Take the easy way out:  Fill in some reasonable values for
+        *  the most important fields, and make the user use the modify
+        *  command to change them, or to give values to other fields.
+        */
+       init_rdn_value[0] = name;
+       init_rdn_value[1] = NULL;
+       init_rdn.mod_op = LDAP_MOD_ADD;
+       init_rdn.mod_type = "cn";
+       init_rdn.mod_values = init_rdn_value;
+       attrs[idx++] = &init_rdn;
+
+       init_owner_value[0] = bound_dn;
+       init_owner_value[1] = NULL;
+       init_owner.mod_op = LDAP_MOD_ADD;
+       init_owner.mod_type = "owner";
+       init_owner.mod_values = init_owner_value;
+       attrs[idx++] = &init_owner;
+
+#ifdef UOFM
+       init_domain_value[0] = "umich.edu";
+#else
+       init_domain_value[0] = ".";
+#endif
+       init_domain_value[1] = NULL;
+       init_domain.mod_op = LDAP_MOD_ADD;
+       init_domain.mod_type = "associatedDomain";
+       init_domain.mod_values = init_domain_value;
+       attrs[idx++] = &init_domain;
+
+       init_errors_value[0] = bound_dn;
+       init_errors_value[1] = NULL;
+       init_errors.mod_op = LDAP_MOD_ADD;
+       init_errors.mod_type = "ErrorsTo";
+       init_errors.mod_values = init_errors_value;
+       attrs[idx++] = &init_errors;
+
+       init_request_value[0] = bound_dn;
+       init_request_value[1] = NULL;
+       init_request.mod_op = LDAP_MOD_ADD;
+       init_request.mod_type = "RequestsTo";
+       init_request.mod_values = init_request_value;
+       attrs[idx++] = &init_request;
+
+       init_joinable_value[0] = "FALSE";
+       init_joinable_value[1] = NULL;
+       init_joinable.mod_op = LDAP_MOD_ADD;
+       init_joinable.mod_type = "joinable";
+       init_joinable.mod_values = init_joinable_value;
+       attrs[idx++] = &init_joinable;
+
+       /* end it with a NULL */
+       attrs[idx] = NULL;
+
+#ifdef DEBUG
+       if (debug & D_GROUPS) {
+               register LDAPMod **lpp;
+               register char **cpp;
+               register int j;
+               extern char * code_to_str();
+               printf("  About to call ldap_add()\n");
+               printf("  ld = 0x%x\n", ld);
+               printf("  dn = [%s]\n", dn);
+               for (lpp = attrs, i = 0; *lpp != NULL; lpp++, i++) {
+                       printf("  attrs[%1d]  code = %s  type = %s\n", i, 
+                               code_to_str((*lpp)->mod_op), (*lpp)->mod_type);
+                       for (cpp = (*lpp)->mod_values, j = 0; *cpp != NULL; cpp++, j++)
+                               printf("    value #%1d = %s\n", j, *cpp);
+                       printf("    value #%1d = NULL\n", j);
+               }
+       }
+#endif
+
+       /*
+        *  Now add this to the X.500 Directory.
+        */
+       if (ldap_add_s(ld, dn, attrs) != 0) {
+               ldap_perror(ld, "  ldap_add_s");
+               printf("  Group not added.\n");
+               if (prompt) Free(name);
+               return;
+       }
+       if (verbose)
+               printf("  Group \"%s\" has been added to the Directory\n",
+                      name);
+
+       /*
+        *  We need to blow away the cache here.
+        *
+        *  Since we first looked up the name before trying to create it,
+        *  and that look-up failed, the cache will falsely claim that this
+        *  entry does not exist.
+        */
+       (void) ldap_flush_cache(ld);
+       if (prompt) Free(name);
+       return;
+}
+
+void remove_group(name)
+char *name;
+{
+       char *dn, tmp[BUFSIZ];
+       static char * bind_and_fetch();
+
+#ifdef DEBUG
+       if (debug & D_TRACE) {
+               if (name == NULL)
+                       printf("->remove_group(NULL)\n");
+               else
+                       printf("->remove_group(%s)\n", name);
+       }
+#endif
+       if ((dn = bind_and_fetch(name)) == NULL)
+               return;
+
+       printf("\n  The group '%s' will be permanently removed from\n",
+               name);
+       printf("  the Directory.  Are you absolutely sure that you want to\n" );        printf("  remove this entire group? ");
+       fflush(stdout);
+       fetch_buffer(tmp, sizeof(tmp), stdin);
+       if (!(tmp[0] == 'y' || tmp[0] == 'Y'))
+               return;
+
+       /*
+        *  Now remove this from the X.500 Directory.
+        */
+       if (ldap_delete_s(ld, dn) != 0) {
+               if (ld->ld_errno == LDAP_INSUFFICIENT_ACCESS)
+                       printf("  You do not own the group \"%s\".\n", name);
+               else
+                       ldap_perror(ld, "  ldap_delete_s");
+               printf("  Group not removed.\n");
+               Free(dn);
+               return;
+       }
+       ldap_uncache_entry(ld, dn);
+       if (verbose)
+           if (name == NULL)
+               printf("  The group has been removed.\n");
+           else
+               printf("  The group \"%s\" has been removed.\n", name);
+       Free(dn);
+       return;
+}
+
+void x_group(action, name)
+int action;
+char *name;
+{
+       char **vp;
+       char *values[2], *group_name;
+       LDAPMod mod, *mods[2];
+       static char *actions[] = { "join", "resign from", NULL };
+       static char * bind_and_fetch();
+
+#ifdef DEBUG
+       if (debug & D_TRACE) {
+               if (name == NULL)
+                       printf("->x_group(%d, NULL)\n", action);
+               else
+                       printf("->x_group(%d, %s)\n", action, name);
+       }
+#endif
+
+       /* the action desired sets the opcode to use */
+       switch (action) {
+       case G_JOIN:
+               mod.mod_op = LDAP_MOD_ADD;
+               break;
+       case G_RESIGN:
+               mod.mod_op = LDAP_MOD_DELETE;
+               break;
+       default:
+               printf("x_group:  %d is not a known action\n", action);
+       }
+
+       if ((group_name = bind_and_fetch(name)) == NULL)
+               return;
+       vp = Entry.attrs[attr_to_index("joinable")].values;
+       if (action == G_JOIN) {
+               if (vp == NULL) {
+                       printf("  No one is permitted to join \"%s\"\n", group_name);
+                       Free(group_name);
+                       return;
+               }
+               if (!strcasecmp(*vp, "FALSE")) {
+                       printf("  No one is permitted to join \"%s\"\n", group_name);
+                       Free(group_name);
+                       return;
+               }
+       }
+
+       /*  fill in the rest of the modification structure */
+       mods[0] = &mod;
+       mods[1] = (LDAPMod *) NULL;
+       values[0] = Entry.DN;
+       values[1] = NULL;
+       mod.mod_type = "memberOfGroup";
+       mod.mod_values = values;
+
+#ifdef DEBUG
+       if (debug & D_GROUPS) {
+               register LDAPMod **lpp;
+               register char **cp;
+               register int i, j;
+               printf("  About to call ldap_modify_s()\n");
+               printf("  ld = 0x%x\n", ld);
+               printf("  dn = [%s]\n", bound_dn);
+               for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) {
+                       printf("  mods[%1d] code = %1d\n", i, (*lpp)->mod_op);
+                       printf("  mods[%1d] type = %s\n", i, (*lpp)->mod_type);
+                       for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++)
+                               printf("  mods[%1d] v[%1d] = %s\n", i, j, *cp);
+                               
+               }
+       }
+#endif
+
+       if (ldap_modify_s(ld, bound_dn, mods)) {
+               if ((action == G_JOIN) && (ld->ld_errno == LDAP_TYPE_OR_VALUE_EXISTS))
+                       printf("  You are already subscribed to \"%s\"\n", group_name);
+               else if ((action == G_RESIGN) && (ld->ld_errno == LDAP_NO_SUCH_ATTRIBUTE))
+                       printf("  You are not subscribed to \"%s\"\n", group_name);
+               else
+                       mod_perror(ld);
+               Free(group_name);
+               return;
+       }
+       ldap_uncache_entry(ld, bound_dn);
+       if (verbose) {
+               switch (action) {
+               case G_JOIN:
+                       printf("  You are now subscribed to \"%s\"\n", group_name);
+                       break;
+               case G_RESIGN:
+                       printf("  You are no longer subscribed to \"%s\"\n", group_name);
+                       break;
+               }
+       }
+       Free(group_name);
+       return;
+}
+
+void bulk_load(group)
+char *group;
+{
+       register int idx_mail, idx_x500;
+       register int count_mail, count_x500;
+       char *values_mail[MAX_VALUES + 1], *values_x500[MAX_VALUES + 1];
+       int added_mail_entries = FALSE, added_x500_entries = FALSE;
+       char s[MED_BUF_SIZE];
+       LDAPMod mod, *mods[2];
+       LDAPMessage *lm;
+       FILE *fp;
+       int len;
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->bulk_load(%s)\n", group);
+#endif
+
+       /* you lose if going through MichNet */
+       if ( !isatty( 1 )) {
+#ifdef UOFM
+               printf("  Not allowed via UM-X500 connections.\n");
+#endif
+               return;
+       }
+
+       /* fetch entries from the file containing the e-mail addresses */
+       printf("\n  File to load? ");
+       fflush(stdout);
+       fetch_buffer(s, sizeof(s), stdin);
+       if (s[0] == '\0') {
+               return;
+               /*NOTREACHED*/
+       }
+       if ((fp = fopen(s, "r")) == NULL) {
+               perror("bulk_load: fopen");
+               return;
+       }
+       if (verbose)
+               printf("  Loading group members from %s\n", s);
+
+       /* load them in MAX_VALUES at a time */
+       for (;;) {
+               for (idx_mail = 0, idx_x500 = 0; 
+                    idx_mail < MAX_VALUES && idx_x500 < MAX_VALUES; ) {
+                       (void) fgets(s, sizeof(s), fp);
+                       if (feof(fp))
+                               break;
+                       len = strlen(s) - 1;
+                       if (len == 0)
+                               continue;
+                       s[len] = '\0';
+                       if (strchr(s, '@'))
+                               values_mail[idx_mail++] = strdup(s);
+                       else {
+                               if ((lm = find(s, !verbose)) == (LDAPMessage *) NULL) {
+                                       printf("  Could not locate \"%s\" -- skipping.\n", s);
+                               }
+                               else {
+                                   parse_answer(lm);
+                                   values_x500[idx_x500++] = strdup(Entry.DN);
+                               }
+                       }
+               }
+               values_mail[idx_mail] = NULL;
+               values_x500[idx_x500] = NULL;
+               count_mail = idx_mail;
+               count_x500 = idx_x500;
+
+               /*
+                *  Add the e-mail addresses.
+                */
+               if (count_mail > 0) {
+                       mods[0] = &mod;
+                       mods[1] = (LDAPMod *) NULL;
+                       mod.mod_type = "mail";
+                       mod.mod_values = values_mail;
+                       if (added_mail_entries)
+                               mod.mod_op = LDAP_MOD_ADD;
+                       else
+                               mod.mod_op = LDAP_MOD_REPLACE;
+
+#ifdef DEBUG
+                       if (debug & D_GROUPS) {
+                       register LDAPMod **lpp;
+                       register char **cp;
+                       register int i, j;
+                       printf("  About to call ldap_modify_s()\n");
+                       printf("  ld = 0x%x\n", ld);
+                       printf("  dn = [%s]\n", group);
+                       for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) {
+                               printf("  mods[%1d] code = %1d\n", i, (*lpp)->mod_op);
+                               printf("  mods[%1d] type = %s\n", i, (*lpp)->mod_type);
+                               for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++)
+                                       printf("  mods[%1d] v[%1d] = %s\n", i, j, *cp);
+                               }
+                       }
+#endif
+                       if (ldap_modify_s(ld, group, mods))
+                               mod_perror(ld);
+                       for (idx_mail--; idx_mail >= 0; idx_mail--)
+                               Free(values_mail[idx_mail]);
+                       ldap_uncache_entry(ld, group);
+                       added_mail_entries = TRUE;
+
+               }
+
+               /*
+                *  Add the X.500 style names.
+                */
+               if (count_x500 > 0) {
+                       mods[0] = &mod;
+                       mods[1] = (LDAPMod *) NULL;
+                       mod.mod_type = "member";
+                       mod.mod_values = values_x500;
+                       if (added_x500_entries)
+                               mod.mod_op = LDAP_MOD_ADD;
+                       else
+                               mod.mod_op = LDAP_MOD_REPLACE;
+
+#ifdef DEBUG
+                       if (debug & D_GROUPS) {
+                       register LDAPMod **lpp;
+                       register char **cp;
+                       register int i, j;
+                       printf("  About to call ldap_modify_s()\n");
+                       printf("  ld = 0x%x\n", ld);
+                       printf("  dn = [%s]\n", group);
+                       for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) {
+                               printf("  mods[%1d] code = %1d\n", i, (*lpp)->mod_op);
+                               printf("  mods[%1d] type = %s\n", i, (*lpp)->mod_type);
+                               for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++)
+                                       printf("  mods[%1d] v[%1d] = %s\n", i, j, *cp);
+                               }
+                       }
+#endif
+                       if (ldap_modify_s(ld, group, mods))
+                               mod_perror(ld);
+                       for (idx_x500--; idx_x500 >= 0; idx_x500--)
+                               Free(values_x500[idx_x500]);
+                       ldap_uncache_entry(ld, group);
+                       added_x500_entries = TRUE;
+
+               }
+
+               /*
+                *  If both counts were less than the maximum number we
+                *  can handle at a time, then we are done.
+                */
+               if ((count_mail < MAX_VALUES) && (count_x500 < MAX_VALUES))
+                       break;
+       }
+       fclose(fp);
+       return;
+}
+
+void purge_group(group)
+char *group;
+{
+       int isclean = TRUE;
+       LDAPMessage *lm;
+       LDAPMod mod, *mods[2];
+       char dn[BUFSIZ], tmp[BUFSIZ], *values[2], **vp, **rdns;
+       extern char * my_ldap_dn2ufn();
+       extern int col_size;
+
+#ifdef DEBUG
+       if (debug & D_TRACE) {
+               if (group == NULL)
+                       printf("->purge_group(NULL)\n");
+               else
+                       printf("->purge_group(%s)\n", group);
+       }
+#endif
+       if (bind_status == UD_NOT_BOUND) {
+               if (auth((char *) NULL, 1) < 0)
+                       return;
+       }
+       /*
+        *  If the user did not supply us with a name, prompt them for
+        *  a name.
+        */
+       if ((group == NULL) || (*group == '\0')) {
+               printf("Group to purge? ");
+               fflush(stdout);
+               fetch_buffer(tmp, sizeof(tmp), stdin);
+               if (tmp[0] == '\0')
+                       return;
+               group = tmp;
+       }
+       sprintf(dn, "cn=%s, %s", group, group_base);
+
+       /* make sure the group in question exists */
+       if ((lm = find(group, FALSE)) == (LDAPMessage *) NULL) {
+               printf("  Could not locate group \"%s\"\n", group);
+               return;
+       }
+       parse_answer(lm);
+       ldap_msgfree(lm);
+
+       /* none of this stuff changes */
+       mods[0] = &mod;
+       mods[1] = (LDAPMod *) NULL;
+
+       values[1] = NULL;
+
+       mod.mod_values = values;
+       mod.mod_type = "member";
+       mod.mod_op = LDAP_MOD_DELETE;
+
+       /*
+        *  Now cycle through all of the names in the "members" part of the
+        *  group (but not the e-mail address part).  Lookup each one, and
+        *  if it isn't found, let the user know so s/he can delete it.
+        */
+       vp = Entry.attrs[attr_to_index("member")].values;
+       if (vp == NULL) {
+               if (verbose)
+                       printf("  \"%s\" has no X.500 members.  There is nothing to purge.\n", group);
+               return;
+       }
+       for (; *vp != NULL; vp++) {
+               char ans[BUFSIZ], *ufn, *label = "Did not find:  ";
+               int len = strlen(label);
+
+               if (vrfy(*vp))
+                       continue;
+               isclean = FALSE;
+               ufn = my_ldap_dn2ufn(*vp);
+               format2(ufn, label, (char *) NULL, 2, 2 + len, col_size);
+ask:
+               printf("  Purge, Keep, Replace, Abort [Keep]? ");
+               fflush(stdout);
+               fetch_buffer(ans, sizeof(ans), stdin);
+               if ((ans[0] == '\0') || !strncasecmp(ans, "Keep", strlen(ans)))
+                       continue;
+               if (!strncasecmp(ans, "Abort", strlen(ans))) {
+                       ldap_uncache_entry(ld, dn);
+                       return;
+               }
+               if (!strncasecmp(ans, "Purge", strlen(ans)) || !strncasecmp(ans, "Replace", strlen(ans))) {
+                       values[0] = *vp;
+#ifdef DEBUG
+                       if (debug & D_GROUPS) {
+                               register LDAPMod **lpp;
+                               register char **cp;
+                               register int i, j;
+                               printf("  About to call ldap_modify_s()\n");
+                               printf("  ld = 0x%x\n", ld);
+                               printf("  dn = [%s]\n", Entry.DN);
+                               for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) {
+                                       printf("  mods[%1d] code = %1d\n", i, (*lpp)->mod_op);
+                                       printf("  mods[%1d] type = %s\n", i, (*lpp)->mod_type);
+                                       for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++)
+                                               printf("  mods[%1d] v[%1d] = %s\n", i, j, *cp);
+                                               
+                               }
+                       }
+#endif
+                       if (ldap_modify_s(ld, Entry.DN, mods))
+                               mod_perror(ld);
+
+                       /* now add the replacement if requested */
+                       if (!strncasecmp(ans, "Purge", strlen(ans)))
+                               continue;
+                       rdns = ldap_explode_dn(*vp, TRUE);
+                       if ((lm = find(*rdns, FALSE)) == NULL) {
+                               printf("  Could not find a replacement for %s; purged only.\n", *rdns);
+                               ldap_msgfree(lm);
+                               ldap_value_free(rdns);
+                               break;
+                       }
+                       values[0] = ldap_get_dn(ld, ldap_first_entry(ld, lm));
+                       mod.mod_op = LDAP_MOD_ADD;
+#ifdef DEBUG
+                       if (debug & D_GROUPS) {
+                               register LDAPMod **lpp;
+                               register char **cp;
+                               register int i, j;
+                               printf("  About to call ldap_modify_s()\n");
+                               printf("  ld = 0x%x\n", ld);
+                               printf("  dn = [%s]\n", Entry.DN);
+                               for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) {
+                                       printf("  mods[%1d] code = %1d\n", i, (*lpp)->mod_op);
+                                       printf("  mods[%1d] type = %s\n", i, (*lpp)->mod_type);
+                                       for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++)
+                                               printf("  mods[%1d] v[%1d] = %s\n", i, j, *cp);
+                                               
+                               }
+                       }
+#endif
+                       if (ldap_modify_s(ld, Entry.DN, mods))
+                               mod_perror(ld);
+                       ldap_msgfree(lm);
+                       ldap_value_free(rdns);
+       
+                       /* set this back to DELETE for other purges */
+                       mod.mod_op = LDAP_MOD_DELETE;
+               }
+               else {
+                       printf("  Did not recognize that answer.\n\n");
+                       goto ask;
+               }
+       }
+       ldap_uncache_entry(ld, Entry.DN);
+       if (isclean)
+               printf("  No entries were purged.\n");
+       return;
+}
+
+void tidy_up()
+{
+       register int i = 0;
+       int found_one = 0;
+       register char **vp;
+       LDAPMessage *lm;
+       static LDAPMod mod;
+       static LDAPMod *mods[2] = { &mod, NULL };
+       static char *values[MAX_VALUES];
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->tidy()\n");
+#endif
+
+       if (bind_status == UD_NOT_BOUND) {
+               if (auth((char *) NULL, 1) < 0) {
+                       return;
+               }
+       }
+
+       /* lookup the user, and see to which groups he has subscribed */
+       vp = ldap_explode_dn(bound_dn, TRUE);
+       if ((lm = find(*vp, TRUE)) == (LDAPMessage *) NULL) {
+               printf("  Could not locate \"%s\"\n", *vp);
+               ldap_value_free(vp);
+               return;
+       }
+       ldap_value_free(vp);
+       parse_answer(lm);
+       ldap_msgfree(lm);
+       vp = Entry.attrs[attr_to_index("memberOfGroup")].values;
+       if (vp == NULL) {
+               printf("  You have not subscribed to any groups.\n");
+               return;
+       }
+
+       /* now, loop through these groups, deleting the bogus */
+       for ( ; *vp != NULL; vp++) {
+               if (vrfy(*vp))
+                       continue;
+               found_one++;
+               printf("  \"%s\" is not a valid group name.\n", *vp);
+               values[i++] = strdup(*vp);
+               if ( i >= MAX_VALUES ) {
+                       printf( "  At most %d invalid groups can be removed at one time; skipping the rest.\n", MAX_VALUES );
+                       break;
+               }
+       }
+       if (found_one == 0) {
+               if (verbose)
+                       printf("  You are not a member of any invalid groups.  There is nothing to tidy.\n");
+               return;
+       }
+
+       /* delete the most heinous entries */
+       values[i] = NULL;
+       mod.mod_values = values;
+       mod.mod_op = LDAP_MOD_DELETE;
+       mod.mod_type = "memberOfGroup";
+       if (ldap_modify_s(ld, bound_dn, mods))
+               mod_perror(ld);
+       ldap_uncache_entry(ld, bound_dn);
+
+       /* tidy up before we finish tidy_up */
+       for ( ; i >= 1; i--)
+               Free(values[i - 1]);
+       return;
+}
+
+/*
+ *  This routine is used to modify lists that can contain either Distinguished
+ *  Names or e-mail addresses.  This includes things like group members,
+ *  the errors-to field in groups, and so on.
+ */
+void mod_addrDN(group, offset)
+char *group;
+int offset;
+{
+       extern struct attribute attrlist[];
+       char s[BUFSIZ], *new_value /* was member */, *values[2];
+       char attrtype[ 64 ];
+       int i;
+       LDAPMod mod, *mods[2];
+       LDAPMessage *mp;
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->mod_addrDN(%s)\n", group);
+#endif
+       /*
+        *  At this point the user can indicate that he wishes to add values
+        *  to the attribute, delete values from the attribute, or replace the 
+        *  current list of values with a new list.  The first two cases
+        *  are very straight-forward, but the last case requires a little
+        *  extra care and work.
+        */
+       if (verbose) {
+               printf("\n");
+               if ( !isatty( 1 ))
+                       format("There are three options available at this point.  You may:  Add additional values; Delete values; or Replace the entire list of values with a new list entered interactively.\n", 75, 2);
+               else
+                       format("There are four options available at this point.  You may:  Add one or more additional values; Delete one or more existing values; Replace the entire list of values with a new list entered interactively; or Bulk load a new list of values from a file, overwriting the existing list.\n", 75, 2);
+       }
+
+       /* initialize the modififier type */
+       mod.mod_type = NULL;
+
+       for (;;) {
+               if ( !isatty( 1 ))
+                       printf("  Do you want to Add, Delete, or Replace? ");
+               else
+                       printf("  Do you want to Add, Delete, Replace, or Bulk load? ");
+               fflush(stdout);
+               fetch_buffer(s, sizeof(s), stdin);
+               if (s[0] == '\0') {
+                       return;
+                       /*NOTREACHED*/
+               }
+               if (!strncasecmp(s, "add", strlen(s))) {
+                       mod.mod_op = LDAP_MOD_ADD;
+                       break;
+               }
+               else if (!strncasecmp(s, "delete", strlen(s))) {
+                       mod.mod_op = LDAP_MOD_DELETE;
+                       break;
+               }
+               else if (!strncasecmp(s, "replace", strlen(s))) {
+                       mod.mod_op = LDAP_MOD_REPLACE;
+                       break;
+               }
+               else if(!strncasecmp(s, "bulk", strlen(s))) {
+                       bulk_load(group);
+                       return;
+               }
+               else if (verbose) {
+                       printf("\n");
+                       if ( !isatty( 1 ))
+                               format("Did not recognize that response.  Please use 'A' to add, 'D' to delete, or 'R' to replace the entire list with a new list\n", 75, 2);
+                       else
+                               format("Did not recognize that response.  Please use 'A' to add, 'D' to delete, 'R' to replace the entire list with a new list, or 'B' to bulk load a new list from a file\n", 75, 2);
+               }
+       }
+       if (mod.mod_op == LDAP_MOD_REPLACE) {
+               if ( verbose && !confirm_action( "The entire existing list will be overwritten with the new values you are about to enter." )) {
+                       printf("\n  Modification halted.\n");
+                       return;
+               }
+       }
+       if (verbose) {
+               printf("\n");
+               format("Values may be specified as a name (which is then looked up in the X.500 Directory) or as a domain-style (i.e., user@domain) e-mail address.  Simply hit the RETURN key at the prompt when finished.\n", 75, 2);
+               printf("\n");
+       }
+
+       for (;;) {
+               printf("%s? ", attrlist[offset].output_string);
+               fflush(stdout);
+               fetch_buffer(s, sizeof(s), stdin);
+               if (s[0] == '\0')
+                       return;
+
+               /*
+                *  If the string the user has just typed has an @-sign in it,
+                *  then we assume it is an e-mail address.  In this case, we
+                *  just store away whatever it is they have typed.
+                *
+                *  If the string had no @-sign, then we look in the Directory,
+                *  make sure it exists, and if it does, we add that.
+                *
+                *  If the string begins with a comma, then strip off the
+                *  comma, and pass it along to the LDAP server.  This is
+                *  the way one can force ud to accept a name.  Handy for
+                *  debugging purposes.
+                */
+               if (*s == ',') {
+                       new_value = s + 1;
+                       mod.mod_type = attrlist[offset].quipu_name;
+               }
+               else if (strchr(s, '@') == NULL) {
+                       if ((mp = find(s, FALSE)) == (LDAPMessage *) NULL) {
+                               printf("  Could not find \"%s\"\n", s);
+                               if (verbose && (mod.mod_op == LDAP_MOD_DELETE)){
+                                       printf("\n");
+                                       format("I could not find anything that matched what you typed.  You might try the \"purge\" command instead.  It is used to purge corrupted or unlocatable entries from a group.", 75, 2);
+                                       printf("\n");
+                               }
+                               continue;
+                       }
+                       parse_answer(mp);
+                       new_value = Entry.DN;
+                       mod.mod_type = attrlist[offset].quipu_name;
+               }
+               else if (mod.mod_op != LDAP_MOD_DELETE) {
+                       /*
+                        * Don't screw around with what the user has typed
+                        * if they are simply trying to delete a rfc822mailbox
+                        * value.
+                        *
+                        * spaces on the left hand side of the e-mail
+                        * address are bad news - we know that there
+                        * must be a @-sign in the string, or else we
+                        * would not be here
+                        *
+                        * note that this means a value like:
+                        *
+                        *      first m. last@host.domain
+                        *
+                        * will be turned into:
+                        *
+                        *      first.m..last@host.domain
+                        *
+                        * and the mailer will need to do the right thing
+                        * with this; alternatively we could add code that
+                        * collapsed multiple dots into a single dot
+                        *
+                        * Don't screw up things like:
+                        *
+                        *      "Bryan Beecher" <bryan@umich.edu>
+                        *       Bryan Beecher  <bryan@umich.edu>
+                        */
+                       register char *cp;
+                       if (strchr(s, '<') == NULL) {
+                               for (cp = s; *cp != '@'; cp++)
+                                       if (isspace(*cp))
+                                               *cp = '.';
+                       }
+                       new_value = s;
+                       strcpy(attrtype, "rfc822");
+                       strcat(attrtype, attrlist[offset].quipu_name);
+                       mod.mod_type = attrtype;
+               }
+               else {
+                       new_value = s;
+                       strcpy(attrtype, "rfc822");
+                       strcat(attrtype, attrlist[offset].quipu_name);
+                       mod.mod_type = attrtype;
+               }
+
+               /*  fill in the rest of the ldap_mod() structure */
+               mods[0] = &mod;
+               mods[1] = (LDAPMod *) NULL;
+
+               values[0] = new_value;
+               values[1] = NULL;
+               mod.mod_values = values;
+
+#ifdef DEBUG
+               if (debug & D_GROUPS) {
+                       register LDAPMod **lpp;
+                       register char **cp;
+                       register int i, j;
+                       printf("  About to call ldap_modify_s()\n");
+                       printf("  ld = 0x%x\n", ld);
+                       printf("  dn = [%s]\n", group);
+                       for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) {
+                               printf("  mods[%1d] code = %1d\n", 
+                                                       i, (*lpp)->mod_op);
+                               printf("  mods[%1d] type = %s\n", 
+                                                       i, (*lpp)->mod_type);
+                               for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++)
+                                       printf("  mods[%1d] v[%1d] = %s\n", 
+                                                               i, j, *cp);
+                       }
+               }
+#endif
+
+               if (my_ldap_modify_s(ld, group, mods)) {
+                       if (ld->ld_errno == LDAP_NO_SUCH_ATTRIBUTE) {
+                               printf("  Could not locate value \"%s\"\n", 
+                                                               new_value);
+                               continue;
+                       }
+                       else {
+                               mod_perror(ld);
+                               return;
+                       }
+               }
+               ldap_uncache_entry(ld, group);
+
+               /*
+                *  If the operation was REPLACE, we now need to "zero out" the
+                *  other "half" of the list (e.g., user specified an e-mail
+                *  address; now we need to clear the DN part of the list).
+                *
+                *  NOTE:  WE HAVE ALREADY DONE HALF OF THE REPLACE ABOVE.
+                *
+                *  Also, change the opcode to LDAP_MOD_ADD and give the user an
+                *  opportunity to add additional members to the group.  We
+                *  only take this branch the very first time during a REPLACE
+                *  operation.
+                */
+               if (mod.mod_op == LDAP_MOD_REPLACE) {
+                       if (!strncmp(mod.mod_type, "rfc822", 6))
+                               mod.mod_type = mod.mod_type + 6;
+                       else {
+                               strcpy(attrtype, "rfc822");
+                               strcat(attrtype, mod.mod_type);
+                               mod.mod_type = attrtype;
+                       }
+                       mods[0] = &mod;
+                       values[0] = NULL;
+                       mod.mod_values = values;
+                       mod.mod_op = LDAP_MOD_DELETE;
+#ifdef DEBUG
+                       if (debug & D_GROUPS) {
+                               register LDAPMod **lpp;
+                               register char **cp;
+                               register int i, j;
+                               printf("  About to call ldap_modify_s()\n");
+                               printf("  ld = 0x%x\n", ld);
+                               printf("  dn = [%s]\n", group);
+                               for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) {
+                                       printf("  mods[%1d] code = %1d\n", 
+                                                       i, (*lpp)->mod_op);
+                                       printf("  mods[%1d] type = %s\n", 
+                                                       i, (*lpp)->mod_type);
+                                       for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++)
+                                               printf("  mods[%1d] v[%1d] = %s\n", i, j, *cp);
+                               }
+                       }
+#endif
+                       if (my_ldap_modify_s(ld, group, mods)) {
+                               /*
+                               *  A "No such attribute" error is no big deal.
+                               *  We only wanted to clear the attribute anyhow.
+                               */
+                               if (ld->ld_errno != LDAP_NO_SUCH_ATTRIBUTE) {
+                                       mod_perror(ld);
+                                       return;
+                               }
+                       }
+                       ldap_uncache_entry(ld, group);
+                       if (verbose)
+                               printf("  \"%s\" has been added\n", new_value);
+                       mod.mod_op = LDAP_MOD_ADD;
+               }
+               else if (verbose && (mod.mod_op == LDAP_MOD_ADD))
+                       printf("  \"%s\" has been added\n", new_value);
+               else if (verbose && (mod.mod_op == LDAP_MOD_DELETE))
+                       printf("  \"%s\" has been removed\n", new_value);
+       }
+}
+
+my_ldap_modify_s(ldap, group, mods)
+LDAP *ldap;
+char *group;
+LDAPMod *mods[];
+{
+       int     was_rfc822member, rc;
+
+       was_rfc822member = 0;
+
+       if (!strcasecmp(mods[0]->mod_type, "rfc822member")) {
+               mods[0]->mod_type = "mail";
+               was_rfc822member = 1;
+       }
+
+       rc = ldap_modify_s(ldap, group, mods);
+
+       if (was_rfc822member)
+           mods[0]->mod_type = "rfc822member";
+
+       return(rc);
+}
+
+void list_groups(who)
+char *who;
+{
+       LDAPMessage *mp;
+       char name[BUFSIZ], filter[BUFSIZ], *search_attrs[2];
+       char *work_area[MAX_NUM_NAMES];
+       char *dn, **rdns;
+       int i, rc;
+       
+
+#ifdef DEBUG
+       if (debug & D_TRACE) {
+               if (who == NULL)
+                       printf("->list_groups(NULL)\n");
+               else
+                       printf("->list_groups(%s)\n", who);
+       }
+#endif
+       /*
+        *  First, decide what entry we are going to list.  If the
+        *  user has not included a name on the list command line,
+        *  we will use the person who was last looked up with a find
+        *  command.
+        *
+        *  Once we know who to modify, be sure that they exist, and
+        *  parse out their DN.
+        */
+       if (who == NULL) {
+               printf("  List groups belonging to whose entry? ");
+               fflush(stdout);
+               fetch_buffer(name, sizeof(name), stdin);
+               if (name[0] != '\0')
+                       who = name;
+               else
+                       return;
+       }
+       if ((mp = find(who, TRUE)) == NULL) {
+               (void) ldap_msgfree(mp);
+               printf("  Could not locate \"%s\" in the Directory.\n", who);
+               return;
+       }
+       dn = ldap_get_dn(ld, ldap_first_entry(ld, mp));
+       ldap_msgfree(mp);
+       rdns = ldap_explode_dn(dn, TRUE);
+       if (verbose)
+               printf("\n  Listing groups belonging to \"%s\"\n", *rdns);
+
+       /* lookup the groups belonging to this person */
+       sprintf(filter, "owner=%s", dn);
+       Free(dn);
+       search_attrs[0] = "cn";
+       search_attrs[1] = NULL;
+       if ((rc = ldap_search_s(ld, UD_WHERE_ALL_GROUPS_LIVE, LDAP_SCOPE_SUBTREE, 
+               filter, search_attrs, FALSE, &mp)) != LDAP_SUCCESS &&
+           rc != LDAP_SIZELIMIT_EXCEEDED && rc != LDAP_TIMELIMIT_EXCEEDED) {
+               ldap_perror(ld, "ldap_search_s");
+               ldap_value_free(rdns);
+               return;
+       }
+       if ((rc = ldap_count_entries(ld, mp)) < 0) {
+               ldap_perror(ld, "ldap_count_entries");
+               ldap_value_free(rdns);
+               return;
+       }
+       if (rc == 0) {
+               printf("  %s owns no groups in this portion of the Directory.\n", *rdns);
+               ldap_value_free(rdns);
+               return;
+       }
+       if (verbose)
+               printf("  %s owns %d groups.\n\n", *rdns, rc);
+       print_list(mp, work_area, &rc);
+       for (i = 1; work_area[i] != NULL; i++)
+               Free(work_area[i]);
+       ldap_msgfree(mp);
+       ldap_value_free(rdns);
+       return;
+}
+
+static char * bind_and_fetch(name)
+char *name;
+{
+       LDAPMessage *lm;
+       char tmp[MED_BUF_SIZE];
+       extern char * strip_ignore_chars();
+
+#ifdef DEBUG
+       if (debug & D_TRACE) {
+               if (name == NULL)
+                       printf("->bind_and_fetch(NULL)\n");
+               else
+                       printf("->bind_and_fetch(%s)\n", name);
+       }
+#endif
+       if (bind_status == UD_NOT_BOUND) {
+               if (auth((char *) NULL, 1) < 0)
+                       return(NULL);
+       }
+
+       /*
+        *  If the user did not supply us with a name, prompt them for
+        *  a name.
+        */
+       if ((name == NULL) || (*name == '\0')) {
+               printf("  Group? ");
+               fflush(stdout);
+               fetch_buffer(tmp, sizeof(tmp), stdin);
+               if (tmp[0] == '\0')
+                       return(NULL);
+               name = tmp;
+       }
+       /* remove quotes, dots, and underscores. */
+       name = strip_ignore_chars(name);
+
+#ifdef DEBUG
+       if (debug & D_GROUPS)
+               printf("Group name = (%s)\n", name);
+#endif
+
+       /* make sure the group in question exists and is joinable */
+       if ((lm = find(name, TRUE)) == (LDAPMessage *) NULL) {
+               printf("  Could not locate group \"%s\"\n", name);
+               return(NULL);
+       }
+       parse_answer(lm);
+       ldap_msgfree(lm);
+
+#ifdef DEBUG
+       if (debug & D_GROUPS)
+               printf("Group DN = (%s)\n", Entry.DN);
+#endif
+       return(strdup(Entry.DN));
+}
+
+void list_memberships(who)
+char *who;
+{
+       LDAPMessage *mp;
+       char name[BUFSIZ], filter[BUFSIZ], *search_attrs[2];
+       char *work_area[MAX_NUM_NAMES];
+       char *dn, **rdns;
+       int i, rc;
+       
+
+#ifdef DEBUG
+       if (debug & D_TRACE) {
+               if (who == NULL)
+                       printf("->list_memberships(NULL)\n");
+               else
+                       printf("->list_memberships(%s)\n", who);
+       }
+#endif
+       /*
+        *  First, decide what entry we are going to list.  If the
+        *  user has not included a name on the list command line,
+        *  we will use the person who was last looked up with a find
+        *  command.
+        *
+        *  Once we know who to modify, be sure that they exist, and
+        *  parse out their DN.
+        */
+       if (who == NULL) {
+               printf("  List memberships containing whose entry? ");
+               fflush(stdout);
+               fetch_buffer(name, sizeof(name), stdin);
+               if (name[0] != '\0')
+                       who = name;
+               else
+                       return;
+       }
+       if ((mp = find(who, TRUE)) == NULL) {
+               (void) ldap_msgfree(mp);
+               printf("  Could not locate \"%s\" in the Directory.\n", who);
+               ldap_msgfree(mp);
+               return;
+       }
+       dn = ldap_get_dn(ld, ldap_first_entry(ld, mp));
+       rdns = ldap_explode_dn(dn, TRUE);
+       if (verbose)
+               printf("\n  Listing memberships of \"%s\"\n", *rdns);
+
+       /* lookup the groups belonging to this person */
+       sprintf(filter, "member=%s", dn);
+       Free(dn);
+       search_attrs[0] = "cn";
+       search_attrs[1] = NULL;
+       ldap_msgfree(mp);
+       if ((rc = ldap_search_s(ld, UD_WHERE_ALL_GROUPS_LIVE, LDAP_SCOPE_SUBTREE, 
+               filter, search_attrs, FALSE, &mp)) != LDAP_SUCCESS &&
+           rc != LDAP_SIZELIMIT_EXCEEDED && rc != LDAP_TIMELIMIT_EXCEEDED) {
+               ldap_perror(ld, "ldap_search_s");
+               ldap_msgfree(mp);
+               ldap_value_free(rdns);
+               return;
+       }
+       if ((rc = ldap_count_entries(ld, mp)) < 0) {
+               ldap_perror(ld, "ldap_count_entries");
+               ldap_msgfree(mp);
+               ldap_value_free(rdns);
+               return;
+       }
+       if (rc == 0) {
+               printf("  %s is not a member of any groups in this portion of the Directory.\n", *rdns);
+               ldap_msgfree(mp);
+               ldap_value_free(rdns);
+               return;
+       }
+       if (verbose)
+               printf("  %s is a member of %d groups.\n\n", *rdns, rc);
+
+       /*
+        *  print_list fills in the char * array starting at 1, not 0
+        */
+       print_list(mp, work_area, &rc);
+       for (i = 1; work_area[i] != NULL; i++)
+               Free(work_area[i]);
+       ldap_msgfree(mp);
+       ldap_value_free(rdns);
+       return;
+}
diff --git a/clients/ud/help.c b/clients/ud/help.c
new file mode 100644 (file)
index 0000000..5a1ff23
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 1992, 1993  Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <lber.h>
+#include <ldap.h>
+#include "ud.h"
+
+#ifdef DEBUG
+extern int debug;
+#endif
+
+print_help(s)
+char *s;
+{
+       int len;                        /* command length */
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->print_help(%s)\n", s);
+#endif
+       if (s == NULL)
+               len = 0;
+       else {
+               len = strlen(s);
+               if (!strcasecmp(s, "commands"))
+                       len = 0;
+       }
+
+       /* print general help, or just on topic 's' if provided */
+       if (len == 0) {
+               printf("\n  Here are brief descriptions of available commands:\n\n");
+               printf("  ?                    To print this list.\n");
+               printf("  bind [who]           To bind (authenticate) to the directory.\n");
+               printf("  cb [where]           To change the search base.\n");
+               printf("  change [entry]       To change information associated with an entry.\n");
+               printf("  create [group]       To create a new group entry.\n");
+               printf("  dereference          To toggle dereferencing of aliases.\n");
+#ifdef UOFM
+               if (isatty( 1 )) {
+#endif
+                       printf("  vedit [entry]        To edit a complete Directory entry using your editor.\n");
+#ifdef UOFM
+               }
+#endif
+               printf("  find [entry]         To find an entry in the directory.\n");
+
+               printf("  groupbase [where]    To change the group base.\n");
+               printf("  help [command]       To display detailed help for a particular command.\n");
+               printf("  join [group]         To subscribe to a group.\n");
+               printf("  list [who]           To list the groups owned by someone.\n");
+               printf("  memberships [who]    To list out the groups in which someone is a member.\n");
+               printf("  purge [group]        To remove obsolete entries from a group.\n");
+               printf("  quit                 To terminate the program.\n");
+               printf("  remove [group]       To remove a group entry.\n");
+               printf("  resign [group]       To unsubscribe from a group.\n");
+               printf("  status               To display directory connection status.\n");
+               printf("  tidy                 To unsubscribe from groups that no longer exist.\n");
+               printf("  verbose              To toggle the verbose switch.\n");
+
+               printf("\n  Type \"help <command-name>\" to get help about a particular command.");
+               printf("\n  Type \"help options\" to get help about options in brackets above.\n");
+#ifdef UOFM
+               printf("\n  Bugs in ud should be reported via e-mail to:  ud-bugs@umich.edu\n" );
+               printf("\n  For more assistance with ud, contact the ITD Consultants by phoning\n" );
+               printf("      764-HELP or by sending e-mail to:  consulting.help@umich.edu\n" );
+#endif /* UOFM */
+       }
+       else if (!strncasecmp("options", s, len)) {
+               printf("\n");
+               format("Most commands need additional information in order to work.  For example, the 'remove' command needs to know the name of the group to remove.  This can be specified along with the 'remove' command, or the program will prompt you for the information.", 75, 2);
+               printf("\n");
+               printf("  [entry]      An entry needs to be specified.  This may be a person or a\n");
+               format("group.  The name can be specified as either a ordinary name (e.g., 'Jane Doe'), or as some other identifying characteristic (e.g., 'uid=babs').", 75, 15);
+               printf("\n");
+               printf("  [group]      A group in the Directory needs to be specified.  This name\n");
+               format("should be specified as a ordinary name (e.g., 'Friends of maX500').", 75, 15);
+               printf("\n");
+               printf("  [where]      A place in the Directory needs to be specified.  This name\n");
+               format("should be specified as an X.500-style name (e.g., 'ou=people, o=University of Michigan, c=United States of America').  In most cases, it is easier to omit the [where] and allow the program to guide you.", 75, 15);
+               printf("\n");
+               printf("  [who]        A person in the Directory needs to be specified.  This name\n");
+               format("can be specified as either a ordinary name (e.g., 'Jane Doe'), or as some other identifying characteristic (e.g., 'uid=babs').", 75, 15);
+       }
+       else if (!strncasecmp("list", s, len)) {
+               printf("  list [who]\n\n");
+               format("Prints out the list of groups owned by the person specified.", 75, 2);
+       }
+       else if (!strncasecmp("memberships", s, len)) {
+               printf("  memberships [who]\n\n");
+               format("Prints out the list of groups in which the person specified is a member.", 75, 2);
+       }
+       else if (!strncasecmp("vedit", s, len)) {
+               printf("  vedit [entry]\n\n");
+               format("Looks up the specified person in the Directory, and then writes this entry into a file.  It then uses the EDITOR environment variable to select an editor, and then loads this file into the editor.  The entry can now be modified in any way desired, and when the editor is exited, the entry will be written back into the Directory.", 75, 2);
+       }
+       else if (!strncasecmp("status", s, len)) {
+               printf("  status\n\n");
+               format("Prints out the current connection status.  Lists the name of the current LDAP server, the current search base, the current group base, and the identity to which you are bound.  If you have not bound as anyone then ud considers you bound as Nobody.  cd is an alias for cb.", 75, 2);
+       }
+       else if (!strncasecmp("groupbase", s, len)) {
+               printf("  groupbase [where]\n\n");
+               format("The syntax and use of this command is identical to the more commonly used 'cb' command.  This command sets the base which is used to create groups in the X.500 Directory.  Setting the base to a certain value does not necessarily grant the person write-access to that part of the Directory in order to successfully create a group.", 75, 2);
+       }
+       else if (!strncasecmp("cd", s, len) || !strncasecmp("cb", s,len)) {
+               printf("  cb [where]\n");
+               printf("  cd [where]\n\n");
+               format("The cb command changes the search base.  By default, this program looks only in the local part of the Directory.  By using the cb command, you can search other parts of the Directory.", 75, 2);
+       printf("\n  Examples:\n");
+       printf("\n            * cb ..\n\n");
+       format("changes the search base so that it is one level higher in the Directory.  Note that if you perform several of these in a row you will move to the root of the Directory tree.", 75, 2);
+       printf("\n            * cb ?\n\n");
+       format("prints out a list of the possible areas to search below the current search base.  This is useful once you have moved high in the tree and wish to snoop about.", 75, 2);
+       printf("\n            * cb default\n\n");
+       format("sets the search base to its original default value.", 75, 2);
+       printf("\n            * cb o=Merit Computer Network, c=US\n\n");
+       format("sets the search base to organization given, the Merit Computer Network in this case.  This comamnd checks the validity of the specified search base, and rejects it if it is not a valid Distinguished Name (DN).  A DN uniquely identifies a portion of the global X.500 namespace.", 75, 2);
+       }
+       else if (!strncasecmp("quit", s, len) || !strncasecmp("stop",s, len)) {
+               printf("  quit\n");
+               printf("  stop\n\n");
+               printf("  Quits the program.  'stop' is an alias for 'quit'.\n");
+       }
+       else if (!strncasecmp("find", s, len) || !strncasecmp("display", s, len) || !strncasecmp("show", s, len)) {
+               printf("  find [entry]\n");
+               printf("  show [entry]\n");
+               printf("  display [entry]\n\n");
+               format("Displays information about the person specified.  If the name specified matches more than one person, one will be presented a list from which to make a choice.  'show' and 'display' are aliases for 'find.'", 75, 2);
+       }
+       else if (!strncasecmp("bind", s, len)) {
+               printf("  bind [who]\n\n");
+               format("Binds (authenticates) to the Directory.  It is generally necessary to bind to the Directory in order to look at privileged entries or to modify an entry.   Allows one to authenticate prior to issuing a 'change' or 'modify' command.  Most often used by administrators to bind to an identity.", 75, 2);
+       }
+       else if (!strncasecmp("modify", s, len) || !strncasecmp("change", s, len)) {
+               printf("  modify [entry]\n");
+               printf("  change [entry]\n\n");
+               format("Changes information associated with an entry in the X.500 Directory.  'change' is an alias for 'modify'.", 75, 2);
+       }
+       else if (!strncasecmp("verbose", s, len)) {
+               printf("  verbose\n\n");
+               format("Turns on long and windy messages which might be useful to new users of this program.  If verbose mode is already on, this turns it off.", 75, 2);
+       }
+       else if (!strncasecmp("dereference", s, len)) {
+               printf("  dereference\n\n");
+               format("Turns off following of aliases when searching, etc.  If alias dereferencing has already been turned off, this turns it back on.", 75, 2);
+       }
+       else if (!strncasecmp("create", s, len)) {
+               printf("  create [group]\n\n");
+               format("Creates a new group in the Directory.", 75, 2);
+       }
+       else if (!strncasecmp("join", s, len) || !strncasecmp("subscribe", s, len)) {
+               printf("  join [group]\n");
+               printf("  subscribe [group]\n\n");
+               format("Adds the person as a subscriber to the specified group.", 75, 2);
+       }
+       else if (!strncasecmp("purge", s, len)) {
+               printf("  purge [group]\n\n");
+               format("Goes through the specified group looking for Distinguished Names that cannot be found.  As it finds each one, it gives the person an opportunity to delete it.", 75, 2);
+       }
+       else if (!strncasecmp("resign", s, len) || !strncasecmp("unsubscribe", s, len)) {
+               printf("  resign [group]\n");
+               printf("  unsubscribe [group]\n\n");
+               format("Deletes the person from the specified group.", 75, 2);
+       }
+       else if (!strncasecmp("remove", s, len)) {
+               printf("  remove [group]\n\n");
+               format("Removes a group from the Directory.", 75, 2);
+       }
+       else if (!strncasecmp("help", s, len)) {
+               format("Prints out a brief description of each command.", 75, 2);
+       }
+       else if (!strncasecmp("tidy", s, len)) {
+               printf("  tidy\n\n");
+               format("Unsubscribes you from non-existent groups.  Useful when you cannot resign from a group because, while your X.500 entry still contains a pointer to it, someone has removed a group of which you were a subscriber.", 75, 2);
+       }
+       else if (*s == '?') {
+               format("Prints out a brief description of each command.  Same as typing 'help help'.", 75, 2);
+       }
+       else {
+               printf("  Don't recognize <%s>\n", s);
+       }
+}
diff --git a/clients/ud/main.c b/clients/ud/main.c
new file mode 100644 (file)
index 0000000..cb2030c
--- /dev/null
@@ -0,0 +1,724 @@
+/*
+ * Copyright (c) 1991, 1992, 1993 
+ * Regents of the University of Michigan.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ *
+ * The University of Michigan would like to thank the following people for
+ * their contributions to this piece of software:
+ *
+ *     Robert Urquhart    <robert@sfu.ca>
+ *     Simon Fraser University, Academic Computing Services
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#if defined(NeXT)
+#include <stdlib.h>
+#include <sys/file.h>
+#else NeXT
+#include <unistd.h>
+#endif NeXT
+#include <pwd.h>
+#include <string.h>
+#ifndef DOS
+#if defined( NeXT ) || defined( ultrix ) || defined( osf1 ) || (defined(SunOS) && SunOS < 40)
+#include <sgtty.h>
+#else /* defined( NeXT ) || defined( ultrix ) etc. */
+#include <termios.h>
+#endif /* defined( NeXT ) || defined( ultrix ) etc. */
+#endif /* !DOS */
+#if defined( aix ) || defined( __NetBSD__ )
+#include <sys/ioctl.h>
+#endif /* aix || __NetBSD__ */
+#include <ctype.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <memory.h>
+#include <lber.h>
+#include <ldap.h>
+#include <ldapconfig.h>
+#include "portable.h"
+#include "ud.h"
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1991, 1992, 1993 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+/*
+ *  Used with change_base() to indicate which base we are changing.
+ */
+#define BASE_SEARCH     0
+#define BASE_GROUPS     1
+
+#define        iscom(x)        (!strncasecmp(x, cmd, strlen(cmd)))
+
+static char *server = NULL;
+static char *config_file = UD_CONFIG_FILE;
+static char *filter_file = FILTERFILE;
+static int ldap_port = LDAP_PORT;
+static int dereference = TRUE;
+
+char *default_bind_object = UD_BINDDN;
+
+char *bound_dn;                        /* bound user's Distinguished Name */
+char *group_base;              /* place in X.500 tree where groups are */
+char *search_base;             /* place in X.500 tree where searches start */
+
+static jmp_buf env;            /* spot to jump to on an interrupt */
+
+int lpp;                       /* lines per page */
+int verbose;                   /* 1 if verbose mode on */
+int col_size;                  /* characters across on the screen */
+int bind_status;               /* user's bind status */
+
+LDAP *ld;                      /* LDAP descriptor */
+LDAPFiltDesc *lfdp;            /* LDAP filter descriptor */
+
+#ifdef DEBUG
+int debug;                     /* debug flag */
+#endif
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+       extern char Version[];                  /* version number */
+       extern char *optarg;                    /* for parsing argv */
+       register int c;                         /* for parsing argv */
+       register char *cp;                      /* for parsing Version */
+       extern void initialize_attribute_strings();
+
+       verbose = 1;
+
+       /*  handle argument list */
+       while ((c = getopt(argc, argv, "c:d:Df:l:p:s:u:vV")) != -1) {
+               switch (c) {
+               case 'l' :
+#ifdef LDAP_DEBUG
+                       ldap_debug = (int) strtol(optarg, (char **) NULL, 0);
+                       lber_debug = ldap_debug;
+#endif
+                       break;
+               case 'd' :
+#ifdef DEBUG
+                       debug = (int) strtol(optarg, (char **) NULL, 0);
+#endif
+                       break;
+               case 's' :
+                       server = strdup(optarg);
+                       break;
+               case 'c' :
+                       filter_file = strdup(optarg);
+                       break;
+               case 'f' :
+                       config_file = optarg;
+                       break;
+               case 'p' :
+                       ldap_port = atoi(optarg);
+                       break;
+               case 'u' :
+                       default_bind_object = strdup(optarg);
+                       break;
+               case 'v' :
+                       verbose = 1;    /* this is the default anyways... */
+                       break;
+               case 'V' :
+                       verbose = 0;
+                       break;
+               case 'D' :
+                       printf("\n\n  Debug flag values\n\n");
+                       printf("    1  function trace\n");
+                       printf("    2  find() information\n");
+                       printf("    4  group information\n");
+                       printf("    8  mod() information\n");
+                       printf("   16  parsing information\n");
+                       printf("   32  output information\n");
+                       printf("   64  authentication information\n");
+                       printf("  128  initialization information\n\n");
+                       format("These are masks, and may be added to form multiple debug levels.  For example, '-d 35' would perform a function trace, print out information about the find() function, and would print out information about the output routines too.", 75, 2);
+                       exit(0);
+               default:
+                       fprintf(stderr, "Usage: %s [-c filter-config-file] [-d debug-level] [-l ldap-debug-level] [-s server] [-p port] [-V]\n", argv[0]);
+                       exit(-1);
+                       /* NOTREACHED */
+               }
+       }
+
+       /* just print the first line of Version[] */
+       cp = strchr(Version, '\t');
+       if (cp != NULL)
+               *cp = '\0';
+       printf(Version);
+       fflush( stdout );
+
+       initialize_client();
+       initialize_attribute_strings();
+
+       /* now tackle the user's commands */
+       do_commands();
+       /* NOTREACHED */
+}
+
+do_commands()
+{
+       LDAPMessage *mp;                        /* returned by find() */
+       register char *cp;                      /* misc char pointer */
+       register char *ap;                      /* misc char pointer */
+       static char buf[MED_BUF_SIZE];          /* for prompting */
+       static char cmd[MED_BUF_SIZE];          /* holds the command */
+       static char input[MED_BUF_SIZE];        /* buffer for input */
+       extern LDAPMessage *find();
+       extern void purge_group(), add_group(), remove_group(), x_group(),
+               tidy_up(), list_groups(), list_memberships(), edit();
+       extern char *nextstr();
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->do_commands()\n");
+#endif
+       if (verbose) 
+               printf("\n  Enter a command.  If you need help, type 'h' or '?' and hit RETURN.\n\n");
+       /* jump here on an interrupt */
+       (void) setjmp(env);
+       for (;;) {
+               printf("* ");
+               fflush(stdout);
+               cp = input;
+/* Temporary kludge - if cp is null, dumps core under Solaris */
+               if (cp == NULL)
+                       break;
+               fetch_buffer(input, sizeof(input), stdin);
+               if (*input == '\0') {
+                       putchar('\n');
+                       continue;
+               }
+               while (isspace(*cp))
+                       cp++;   
+               ap = cmd;
+               if (memset(cmd, '\0', sizeof(cmd)) == NULL)
+                       fatal("memset");
+               while (!isspace(*cp) && (*cp != '\0'))
+                       *ap++ = *cp++;
+               if (iscom("status"))
+                       status();
+               else if (iscom("stop") || iscom("quit"))
+                       break;
+               else if (iscom("cb") || iscom("cd") || iscom("moveto")) {
+                       while (isspace(*cp) && (*cp != '\0')) 
+                               cp++;
+                       if (!strncasecmp(cp, "base", 4))
+                               cp += 4;
+                       change_base(BASE_SEARCH, &search_base, nextstr(cp));
+               }
+               else if (iscom("memberships"))
+                       (void) list_memberships(nextstr(cp));
+               else if (iscom("list"))
+                       (void) list_groups(nextstr(cp));
+               else if (iscom("groupbase"))
+                       change_base(BASE_GROUPS, &group_base, nextstr(cp));
+               else if (iscom("find") || iscom("display") || iscom("show")) {
+                       cp = nextstr(cp);
+                       if ((mp = find(cp, FALSE)) != NULL) {
+                               parse_answer(mp);
+                               print_an_entry();
+                               ldap_msgfree(mp);
+                       }
+                       else
+                               printf(" Could not find \"%s\".\n", cp);
+               }
+#ifdef UOFM
+               else if (iscom("vedit") && isatty( 1 )) {
+#else
+               else if (iscom("vedit")) {
+#endif
+                       (void) edit(nextstr(cp));
+               }
+               else if (iscom("modify") || iscom("change") || iscom("alter"))
+                       (void) modify(nextstr(cp));
+               else if (iscom("bind") || iscom("iam"))
+                       (void) auth(nextstr(cp), 0);
+               else if ((cmd[0] == '?') || iscom("help"))
+                       print_help(nextstr(cp));
+               else if (iscom("join") || iscom("subscribe")) 
+                       (void) x_group(G_JOIN, nextstr(cp));
+               else if (iscom("resign") || iscom("unsubscribe"))
+                       (void) x_group(G_RESIGN, nextstr(cp));
+               else if (!strncasecmp("create", cmd, strlen(cmd)))
+                       add_group(nextstr(cp));
+               else if (!strncasecmp("remove", cmd, strlen(cmd)))
+                       remove_group(nextstr(cp));
+               else if (!strncasecmp("purge", cmd, strlen(cmd)))
+                       purge_group(nextstr(cp));
+               else if (!strncasecmp("verbose", cmd, strlen(cmd))) {
+                       verbose = 1 - verbose;
+                       if (verbose)
+                               printf("  Verbose mode has been turned on.\n");
+               }
+               else if (!strncasecmp("dereference", cmd, strlen(cmd))) {
+                       dereference = 1 - dereference;
+                       if (dereference == 1)
+                               ld->ld_deref = LDAP_DEREF_ALWAYS;
+                       else
+                               ld->ld_deref = LDAP_DEREF_NEVER;
+               }
+               else if (!strncasecmp("tidy", cmd, strlen(cmd)))
+                       tidy_up();
+               else if (cmd[0] == '\0')
+                       putchar('\n');
+               else
+                       printf("  Invalid command.  Type \"help commands.\"\n");
+       }
+       printf(" Thank you!\n");
+       
+       ldap_unbind(ld);
+#ifdef KERBEROS
+       destroy_tickets();
+#endif
+       exit(0);
+       /* NOTREACHED */
+}
+
+status()
+{
+       void printbase();
+       register char **rdns;
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->status()\n");
+#endif
+       printf("  Current server is %s", server);
+       if ( ld != NULL && ld->ld_host != NULL && strcasecmp( ld->ld_host,
+           server ) != 0 )
+               printf( " (%s)", ld->ld_host );
+       putchar( '\n' );
+       printbase("  Search base is ", search_base);
+       printbase("  Group  base is ", group_base);
+       if ( bound_dn != NULL ) {
+               rdns = ldap_explode_dn(bound_dn, TRUE);
+               printf("  Bound as \"%s\"\n", *rdns);
+               ldap_value_free(rdns);
+       } else {
+               printf("  Bound as Nobody\n" );
+       }
+       printf( "  Verbose mode is %sabled\n", ( verbose ? "en" : "dis" ));
+       if ( ld != NULL ) {
+               printf( "  Aliases are %sbeing dereferenced\n", ( ld->ld_deref == LDAP_DEREF_ALWAYS ) ? "" : "not" );
+       }
+}
+
+change_base(type, base, s)
+int type;
+char **base, *s;
+{
+       register char *cp;                      /* utility pointers */
+       char **rdns;                            /* for parsing */
+       char *output_string;                    /* for nice output */
+       int num_picked;                         /* # of selected base */
+       int j;                                  /* used with num_picked */
+       int i = 1;                              /* index into choices array */
+       int matches;                            /* # of matches found */
+       int rest = 1;                           /* # left to display */
+       char tmp[MED_BUF_SIZE];                 /* temporary buffer */
+       static char *choices[MED_BUF_SIZE];     /* bases from which to choose */
+       static char resp[SMALL_BUF_SIZE];       /* for prompting user */
+       static char buf[MED_BUF_SIZE];
+       void printbase();
+       static char *attrs[] = { "objectClass", NULL };
+       LDAPMessage *mp;                        /* results from a search */
+       LDAPMessage *ep;                        /* for going thru bases */
+       extern char * friendly_name();
+       extern void StrFreeDup();
+       extern void Free();
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->change_base(%s, %s)\n", s, s);
+#endif
+       /*
+        *  If s is NULL we need to prompt the user for an argument.
+        */
+       while (s == NULL) {
+               if (verbose) {
+                       printf("  You need to specify how the base is to be changed.  Valid choices are:\n");
+                       printf("     ?       - list the choices immediately below this level\n");
+                       printf("     ..      - move up one level in the Directory tree\n");
+                       printf("     root    - move to the root of the Directory tree\n");
+                       printf("     default - move to the default level built into this program\n");
+                       printf("     <entry> - move to the entry specified\n");
+               }
+               printf("  Change base to? ");
+               fflush(stdout);
+               fetch_buffer(buf, sizeof(buf), stdin);
+               if ((buf != NULL) && (buf[0] != '\0'))
+                       s = buf;
+       }
+
+       /* set the output string */
+       if (type == BASE_SEARCH)
+               output_string = "  Search base is now ";
+       else if (type == BASE_GROUPS)
+               output_string = "  Group base is now ";
+
+       if (!strcasecmp(s, "root")) {
+               StrFreeDup(base, NULL);
+               printbase("  Search base is ", *base);
+               return;
+       }
+
+       /*
+        *  User wants to ascend one level in the X.500 tree.
+        *  Easy:  Just strip off the first element of the
+        *  current search base, unless it's the root, in
+        *  which case we just do nothing.
+        */
+       if (!strcasecmp(s, "..")) {
+               if (*base == NULL) {
+                       printf("  You are already at the root\n");
+                       return;
+               }
+               cp = strchr(*base, '=');
+               cp++;
+               /*
+                *  If there isn't a second "=" in the base, then this was
+                *  a one element base, and so now it should be NULL.
+                */
+               if ((cp = strchr(cp, '=')) == NULL)
+                       StrFreeDup(base, NULL);
+               else {
+                       /*
+                        *  Back up to the start of this
+                        *
+                        *      attr=value
+                        *
+                        *  sequence now that 'cp' is pointing to the '='.
+                        */
+                       while(!isspace(*cp))
+                               cp--;
+                       cp++;
+                       /*
+                        *  Goofy, but need to do it this way since both *base
+                        *  and cp point into the same chunk of memory, and
+                        *  we want to free *base, but keep part of it around.
+                        */
+                       cp = strdup(cp);
+                       StrFreeDup(base, cp);
+                       Free(cp);
+               }
+               printbase(output_string, *base);
+               return;
+       }
+
+       /* user wants to see what is directly below this level */
+       if (*s == '?') {
+               /*
+                *  Fetch the list of entries directly below this level.
+                *  Once we have the list, we will print it for the user, one
+                *  screenful at a time.  At the end of each screen, we ask
+                *  the user if they want to see more.  They can also just
+                *  type a number at that point too.
+                */
+               if (ldap_search_s(ld, *base, LDAP_SCOPE_ONELEVEL, "(|(objectClass=quipuNonLeafObject)(objectClass=externalNonLeafObject))", attrs, FALSE, &mp) != LDAP_SUCCESS) {
+                       if ((ld->ld_errno == LDAP_TIMELIMIT_EXCEEDED) ||
+                           (ld->ld_errno == LDAP_SIZELIMIT_EXCEEDED)) {
+                               if (verbose) {
+                                       printf("  Your query was too general and a limit was exceeded.  The results listed\n");
+                                       printf("  are not complete.  You may want to try again with a more refined query.\n\n");
+                               }
+                               else
+                                       printf("  Time or size limit exceeded.  Partial results follow.\n\n");
+                       } else {
+                               ldap_perror(ld, "ldap_search_s");
+                               return;
+                       }
+               }
+               if ((matches = ldap_count_entries(ld, mp)) < 1) {
+                       printf("  There is nothing below this level.\n");
+                       (void) ldap_msgfree(mp);
+                       return;
+               }
+               num_picked = 0;
+               printf(" There are %d choices:\n", matches);
+               for (ep = ldap_first_entry(ld, mp); ep != NULL; ep = ldap_next_entry(ld, ep)) {
+                       /*
+                        *  Put the last component of the DN into 'lastDN'.
+                        *  If we are at the root level, convert any country
+                        *  codes to recognizable names for printing.
+                        */
+                       choices[i] = ldap_get_dn(ld, ep);
+                       rdns = ldap_explode_dn(choices[i], TRUE);
+                       printf(" %2d. %s\n", i, friendly_name(*rdns));
+                       (void) ldap_value_free(rdns);
+                       i++;
+                       if ((rest++ > (lpp - 3)) && (i < matches)) {
+                               printf("More? ");
+                               fflush(stdout);
+                               fetch_buffer(resp, sizeof(resp), stdin);
+                               if ((resp[0] == 'n') || (resp[0] == 'N'))
+                                       break;
+                               else if (((num_picked = atoi(resp)) != 0) && (num_picked < i))
+                                       break;
+                               rest = 1;
+                       }
+               }
+               for (;;) {
+                       if (num_picked != 0) {
+                               j = num_picked;
+                               num_picked = 0;
+                       }
+                       else {
+                               printf(" Which number? ");
+                               fflush(stdout);
+                               fetch_buffer(resp, sizeof(resp), stdin);
+                               j = atoi(resp);
+                       }
+                       if (j == 0) {
+                               (void) ldap_msgfree(mp);
+                               for (i = 0; i < matches; i++)
+                                       Free(choices[i]);
+                               return;
+                       }
+                       if ((j < 1) || (j >= i))
+                               printf(" Invalid number\n");
+                       else {
+                               StrFreeDup(base, choices[j]);
+                               printbase(output_string, *base);
+                               (void) ldap_msgfree(mp);
+                               for (i = 0; choices[i] != NULL; i++)
+                                       Free(choices[i]);
+                               return;
+                       }
+               }
+       }
+       /* set the search base back to the original default value */
+       else if (!strcasecmp(s, "default")) {
+               if (type == BASE_SEARCH)
+                       StrFreeDup(base, UD_BASE);
+               else if (type == BASE_GROUPS)
+                       StrFreeDup(base, UD_WHERE_GROUPS_ARE_CREATED);
+               printbase(output_string, *base);
+       }
+       /* they typed in something -- see if it is legit */
+       else {
+               /* user cannot do something like 'cb 33' */
+               if (atoi(s) != 0) {
+                       printf("  \"%s\" is not a valid search base\n", s);
+                       printf("  Base unchanged.\n");
+                       printf("  Try using 'cb ?'\n");
+                       return;
+               }
+               /* was it a fully-specified DN? */
+               if (vrfy(s)) {
+                       StrFreeDup(base, s);
+                       printbase(output_string, *base);
+                       return;
+               }
+               /* was it a RDN relative to the current base? */
+               sprintf(tmp, "ou=%s, %s", s, *base);
+               if (vrfy(tmp)) {
+                       StrFreeDup(base, tmp);
+                       printbase(output_string, *base);
+                       return;
+               }
+               printf("  \"%s\" is not a valid base\n  Base unchanged.\n", s);
+       }
+}
+
+initialize_client()
+{
+       FILE *fp;                               /* for config file */
+       static char buffer[MED_BUF_SIZE];       /* for input */
+       struct passwd *pw;                      /* for getting the home dir */
+       register char *cp;                      /* for fiddling with buffer */
+       char *term;                             /* for tty set-up */
+       char *config;                           /* config file to use */
+       static char bp[1024];                   /* for tty set-up */
+       extern SIG_FN attn();                   /* ^C signal handler */
+       extern char *getenv();
+       extern void Free();
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->initialize_client()\n");
+#endif
+       /*
+        *  A per-user config file has precedence over any system-wide
+        *  config file, if one exists.
+        */
+       if ((pw = getpwuid((uid_t) geteuid())) == (struct passwd *) NULL)
+               config = config_file;
+       else {
+               if (pw->pw_dir == NULL)
+                       config = config_file;
+               else {
+                       sprintf(buffer, "%s/%s", pw->pw_dir,
+                           UD_USER_CONFIG_FILE);
+                       if (access(buffer, R_OK) == 0)
+                               config = buffer;
+                       else
+                               config = config_file;
+               }
+       }
+#ifdef DEBUG
+       if (debug & D_INITIALIZE)
+               printf("Using config file %s\n", config);
+#endif
+
+       /*
+        *  If there is a config file, read it.
+        *
+        *  Could have lines that look like this:
+        *
+        *      server <ip-address or domain-name>
+        *      base   <default search base>
+        *      groupbase <default place where groups are created>
+        *
+        */
+       if ((fp = fopen(config, "r")) != NULL) {
+               while (fgets(buffer, sizeof(buffer), fp) != NULL) {
+                       buffer[strlen(buffer) - 1] = '\0';
+                       if (!strncasecmp(buffer, "server", 6)) {
+                               if (server != NULL)
+                                       continue;
+                               cp = buffer + 6;
+                               while (isspace(*cp))
+                                       cp++;
+                               if ((*cp == '\0') || (*cp == '\n'))
+                                       continue;
+                               server = strdup(cp);
+                       }
+                       else if (!strncasecmp(buffer, "base", 4)) {
+                               cp = buffer + 4;
+                               while (isspace(*cp))
+                                       cp++;
+                               if ((*cp == '\0') || (*cp == '\n'))
+                                       continue;
+                               search_base = strdup(cp);
+                       }
+                       else if (!strncasecmp(buffer, "groupbase", 9)) {
+                               cp = buffer + 9;
+                               while (isspace(*cp))
+                                       cp++;
+                               if ((*cp == '\0') || (*cp == '\n'))
+                                       continue;
+                               group_base = strdup(cp);
+                       }
+                       else
+                               fprintf(stderr, "?? -> %s\n", buffer);
+               }
+       }
+       if (group_base == NULL)
+               group_base = strdup(UD_WHERE_GROUPS_ARE_CREATED);
+       if (search_base == NULL)
+               search_base = strdup(UD_BASE);
+       if (server == NULL)
+               server = strdup(LDAPHOST);
+
+       /*
+        *  Set up our LDAP connection.  The values of retry and timeout
+        *  are meaningless since we will immediately be doing a null bind
+        *  because we want to be sure to use TCP, not UDP.
+        */
+       if ((ld = ldap_open(server, ldap_port)) == NULL) {
+               fprintf(stderr, "  The X.500 Directory is temporarily unavailable.  Please try again later.\n");
+               exit(0);
+               /* NOTREACHED */
+       }
+       if (ldap_bind_s(ld, (char *) default_bind_object, (char *) UD_PASSWD,
+           LDAP_AUTH_SIMPLE) != LDAP_SUCCESS) {
+               fprintf(stderr, "  The X.500 Directory is temporarily unavailable.  Please try again later.\n");
+               if (ld->ld_errno != LDAP_UNAVAILABLE)
+                       ldap_perror(ld, "  ldap_bind_s");
+               exit(0);
+               /* NOTREACHED */
+       }
+       ld->ld_deref = LDAP_DEREF_ALWAYS;
+       bind_status = UD_NOT_BOUND;
+       if ( default_bind_object != NULL ) {
+               bound_dn = strdup(default_bind_object);
+       } else {
+               bound_dn = NULL;
+       }
+
+       /* enabled local caching of ldap results, 15 minute lifetime */
+#ifdef DOS
+       ldap_enable_cache( ld, 60 * 15, 100 * 1024 );   /* 100k max memory */
+#else /* DOS */
+       ldap_enable_cache( ld, 60 * 15, 0 );            /* no memory limit */
+#endif /* DOS */
+
+       /* initialize the search filters */
+       if ((lfdp = ldap_init_getfilter(filter_file)) == NULL) {
+               fprintf(stderr, "  Problem with ldap_init_getfilter\n");
+               fatal(filter_file);
+               /*NOTREACHED*/
+       }
+
+       /* terminal initialization stuff goes here */
+       lpp = DEFAULT_TTY_HEIGHT;
+       col_size = DEFAULT_TTY_WIDTH;
+
+       (void) signal(SIGINT, attn);
+
+#if !defined(DOS) && !defined(NOTERMCAP)
+       {
+       struct winsize win;                     /* for tty set-up */
+       extern SIG_FN chwinsz();                /* WINSZ signal handler */
+
+       if (((term = getenv("TERM")) == NULL) || (tgetent(bp, term) <= 0))
+               return;
+       else {
+               if (ioctl(fileno(stdout), TIOCGWINSZ, &win) < 0) {
+                       lpp = tgetnum("li");
+                       col_size = tgetnum("co");
+               }
+               else {
+                       if ((lpp = win.ws_row) == 0)
+                               lpp = tgetnum("li");
+                       if ((col_size = win.ws_col) == 0)
+                               col_size = tgetnum("co");
+                       if ((lpp <= 0) || tgetflag("hc"))
+                               lpp = DEFAULT_TTY_HEIGHT;
+                       if ((col_size <= 0) || tgetflag("hc"))
+                               col_size = DEFAULT_TTY_WIDTH;
+               }
+       }
+       (void) signal(SIGWINCH, chwinsz);
+
+       }
+#endif
+}
+
+SIG_FN attn()
+{
+       fflush(stderr);
+       fflush(stdout);
+       printf("\n\n  INTERRUPTED!\n");
+#if defined(DOS) || defined(SYSV)
+       (void) signal(SIGINT, attn);
+#endif
+       longjmp(env, 1);
+}
+
+#if !defined(DOS) && !defined(NOTERMCAP)
+SIG_FN chwinsz() 
+{
+       struct winsize win;
+
+       (void) signal(SIGWINCH, SIG_IGN);
+       if (ioctl(fileno(stdout), TIOCGWINSZ, &win) != -1) {
+               if (win.ws_row != 0)
+                       lpp = win.ws_row;
+               if (win.ws_col != 0)
+                       col_size = win.ws_col;
+       }
+       (void) signal(SIGWINCH, chwinsz);
+}
+#endif
diff --git a/clients/ud/mod.c b/clients/ud/mod.c
new file mode 100644 (file)
index 0000000..ef7099e
--- /dev/null
@@ -0,0 +1,814 @@
+/*
+ * Copyright (c) 1991,1993  Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <lber.h>
+#include <ldap.h>
+#ifndef __STDC__
+#include <memory.h>
+#endif
+#include <sys/types.h>
+#include "ud.h"
+
+extern struct entry Entry; 
+extern int verbose;
+extern LDAP *ld;
+
+extern LDAPMessage *find();
+
+#ifdef DEBUG
+extern int debug;
+#endif
+
+modify(who)
+char *who;
+{
+#ifdef UOFM
+       void set_updates();     /* routine to modify noBatchUpdates */
+#endif
+       LDAPMessage *mp;        /* returned from find() */
+       char *dn;               /* distinguished name */
+       char **rdns;            /* for fiddling with the DN */
+       char name[MED_BUF_SIZE];        /* entry to modify */
+       int displayed_choices = 0;
+       static char ans[SMALL_BUF_SIZE];        /* for holding user input */
+#ifdef UOFM
+       static char printed_warning = 0;        /* for use with the */
+       struct attribute no_batch_update_attr;
+       extern char * fetch_boolean_value();
+#endif
+       int is_a_group;         /* TRUE if it is; FALSE otherwise */
+       extern void Free();
+       extern int bind_status;
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->modify(%s)\n", who);
+#endif
+       /*
+        *  Require them to bind first if the are modifying a group.
+        */
+       if (bind_status == UD_NOT_BOUND) {
+               if (auth((char *) NULL, 1) < 0)
+                       return;
+       }
+
+       /*
+        *  First, decide what entry we are going to modify.  If the
+        *  user has not included a name on the modify command line,
+        *  we will use the person who was last looked up with a find
+        *  command.  If there is no value there either, we don't know
+        *  who to modify.
+        *
+        *  Once we know who to modify, be sure that they exist, and
+        *  parse out their DN.
+        */
+       if (who == NULL) {
+               if (verbose) {
+                       printf("  Enter the name of the person or\n");
+                       printf("  group whose entry you want to modify: ");
+               }
+               else
+                       printf("  Modify whose entry? ");
+               fflush(stdout);
+               fetch_buffer(name, sizeof(name), stdin);
+               if (name[0] != '\0')
+                       who = name;
+               else
+                       return;
+       }
+       if ((mp = find(who, TRUE)) == NULL) {
+               (void) ldap_msgfree(mp);
+               printf("  Could not locate \"%s\" in the Directory.\n", who);
+               return;
+       }
+       dn = ldap_get_dn(ld, ldap_first_entry(ld, mp));
+       rdns = ldap_explode_dn(dn, TRUE);
+       if (verbose)
+               printf("\n  Modifying Directory entry of \"%s\"\n", *rdns);
+
+#ifdef UOFM
+       /*
+        *  If verbose mode is turned on and the user has not set a value
+        *  for noBatchUpdates, warn them that what they are about to do
+        *  may be overwritten automatically by that Stinkbug.
+        */
+       no_batch_update_attr.quipu_name = "noBatchUpdates";
+       (void) fetch_boolean_value(dn, no_batch_update_attr);
+       if (verbose && !printed_warning && (ld->ld_errno == LDAP_NO_SUCH_ATTRIBUTE)) {
+               printed_warning = 1;
+               printf("\n  WARNING!\n");
+               printf("  You are about to make a modification to an X.500 entry\n");
+               printf("  that has its \"automatic updates\" field set to ON.\n");
+               printf("  This means that the entry will be automatically updated\n");
+               printf("  each month from official University sources like the\n");
+               printf("  Personnel Office.  With \"automatic updates\" set to ON,\n");
+               printf("  the following fields will be overwritten each month:\n");
+               printf("         Title, home address and phone,\n");
+               printf("         business address and phone\n");
+               printf("  If you modify any of these fields, you may want to change\n");
+               printf("  the \"automatic updates\" field to OFF so that your\n");
+               printf("  changes will not be overwritten.  You may change this\n");
+               printf("  setting by choosing \"u\" at the \"Modify what?\" prompt\n");
+       }
+#endif
+
+       /*
+        *  Current values for user 'who' are being held in 'mp'. We
+        *  should parse up that buffer and fill in the Entry structure.
+        *  Once we're done with that, we can find out which fields the
+        *  user would like to modify.
+        */
+       parse_answer(mp);
+       is_a_group = isgroup();
+       (void) ldap_msgfree(mp);
+       printf("  You now need to specify what field you'd like to modify.\n");
+       for (;;) {
+               if ( verbose || !displayed_choices ) {
+                       printf("\n  Choices are:\n");
+                       printf("  -----------------------\n");
+                       print_mod_list(is_a_group);
+                       printf("\n  Pressing Return will cancel the process.\n");
+                       displayed_choices = 1;
+               }
+               printf("\n  Modify what? ");
+               fflush(stdout);
+               fetch_buffer(ans, sizeof(ans), stdin);
+               if (ans[0] == '\0')
+                       break;
+               perform_action(ans, dn, is_a_group);
+               if ((mp = find(*rdns, TRUE)) == NULL)
+                       break;
+               parse_answer(mp);
+               (void) ldap_msgfree(mp);
+       }
+       (void) Free(dn);
+       ldap_value_free(rdns);
+       return;
+}
+
+/* generic routine for changing any field */
+void change_field(who, attr)
+char *who;                     /* DN of entry we are changing */
+struct attribute attr;         /* attribute to change */
+{
+
+#define        IS_MOD(x)       (!strncasecmp(resp, (x), strlen(resp)))
+                               
+       char *get_value();              /* routine to extract values */
+       static char buf[MED_BUF_SIZE];  /* for printing things */
+       static char resp[SMALL_BUF_SIZE];       /* for user input */
+       char *prompt, *prompt2, *more;
+       register int i;                         /* for looping thru values */
+       static LDAPMod mod;
+       static LDAPMod *mods[2] = { &mod };     /* passed to ldap_modify */
+       static char *values[MAX_VALUES];        /* passed to ldap_modify */
+       extern void Free();
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->change_field(%x, %s)\n", attr, who);
+#endif
+       /*
+        *  If there is no current value associated with the attribute,
+        *  then this is the easy case.  Collect one (or more) attributes
+        *  from the user, and then call ldap_modify_s() to write the changes
+        *  to the LDAP server.
+        */
+       for (i = 0; i < MAX_VALUES; i++)
+               values[i] = NULL;
+       if (attr.values == (char **) NULL) {
+               printf("\n  No current \"%s\"\n", attr.output_string);
+               values[0] = get_value(attr.quipu_name, "Enter a value");
+               if ( values[0] == NULL )
+                       return;
+               mod.mod_op = LDAP_MOD_REPLACE;
+               mod.mod_type = attr.quipu_name;
+               mod.mod_values = values;
+               for (i = 1; i < MAX_VALUES; i++) {
+                       printf("  Do you wish to add an additional value? ");
+                       fflush(stdout);
+                       fetch_buffer(resp, sizeof(resp), stdin);
+                       if ((resp[0] == 'y') || (resp[0] == 'Y'))
+                               values[i] = get_value(attr.quipu_name, "Enter an additional value");
+                       else
+                               break;
+               }
+#ifdef DEBUG
+               if (debug & D_MODIFY) {
+                       printf("  ld = 0x%x\n", ld);
+                       printf("  who = [%s]\n", who);
+                       printf("  mods[0]->mod_op = %1d\n", mods[0]->mod_op);
+                       printf("  mods[0]->mod_type = %s\n", mods[0]->mod_type);
+                       for (i = 0; mods[0]->mod_values[i] != NULL; i++)
+                               printf("  mods[0]->mod_values[%1d] = %s\n", i, mods[0]->mod_values[i]);
+               }
+#endif
+               if (ldap_modify_s(ld, who, mods)) {
+                       mod_perror(ld);
+                       return;
+               }
+               else if (verbose)
+                       printf("  Modification of '%s' complete.\n", attr.output_string);
+               ldap_uncache_entry( ld, who );
+               for (i--; i > 0; i--)
+                       (void) Free(values[i]);
+       }
+       /*
+        *  There are values for this attribute already.  In this case,
+        *  we want to allow the user to delete all existing values,
+        *  add additional values to the ones there already, or just
+        *  delete some of the values already present.  DIXIE does not
+        *  handle modifications where the attribute occurs on the LHS
+        *  more than once.  So to delete entries and add entries, we
+        *  need to call ldap_modify() twice.
+        */
+       else {
+               /*
+                *  If the attribute holds values which are DNs, print them
+                *  in a most pleasant way.
+                */
+               sprintf(buf, "%s:  ", attr.output_string);
+               if (!strcmp(attr.quipu_name, "owner"))
+                       (void) print_DN(attr);
+               else
+                       (void) print_values(attr);
+
+               if (verbose) {
+                       printf("  You may now:\n");
+                       printf("    Add additional values to the existing ones, OR\n");
+                       printf("    Clear all values listed above, OR\n");
+                       printf("    Delete one of the values listed above, OR\n");
+                       printf("    Replace all of the values above with new ones.\n");
+               }
+               printf("\n  Add, Clear, Delete, or Replace? ");
+               fflush(stdout);
+               fetch_buffer(resp, sizeof(resp), stdin);
+
+               /*
+                *  Bail if they just hit the RETURN key.
+                */
+               if (resp[0] == '\0') {
+                       if (verbose)
+                               printf("\n  No changes made.\n");
+                       return;
+               }
+
+               /*
+                *  If the want to clear the values, just do it.
+                */
+               mod.mod_type = attr.quipu_name;
+               mod.mod_values = values;
+               if (IS_MOD("clear")) {
+                       mod.mod_op = LDAP_MOD_DELETE;
+                       mod.mod_values = NULL;
+                       if ( verbose && !confirm_action( "All existing values will be removed." )) {
+                               printf("  Modification halted.\n");
+                               return;
+                       }
+#ifdef DEBUG
+                       if (debug & D_MODIFY) {
+                               printf("Clearing attribute '%s'\n", attr.quipu_name);
+                               printf("who = [%s]\n", who);
+                               printf("mod = [%d] [%s] [%x]\n", mod.mod_op,
+                                       mod.mod_type, mod.mod_values);
+                       }
+#endif
+                       if (ldap_modify_s(ld, who, mods)) {
+                               mod_perror(ld);
+                               return;
+                       }
+                       else if (verbose)
+                               printf("  '%s' has been cleared.\n", attr.output_string);
+                       ldap_uncache_entry( ld,  who );
+                       return;
+               }
+
+               if (IS_MOD("add")) {
+                       prompt = "Enter the value you wish to add";
+                       more = "  Add an additional value? ";
+                       prompt2 = "Enter another value you wish to add";
+                       mod.mod_op = LDAP_MOD_ADD;
+               }
+               else if (IS_MOD("delete")) {
+                       prompt = "Enter the value you wish to delete";
+                       more = "  Delete an additional value? ";
+                       prompt2 = "Enter another value you wish to delete";
+                       mod.mod_op = LDAP_MOD_DELETE;
+               }
+               else if (IS_MOD("replace")) {
+                       prompt = "Enter the new value";
+                       more = "  Add an additional value? ";
+                       prompt2 = "Enter another value you wish to add";
+                       mod.mod_op = LDAP_MOD_REPLACE;
+                       if ( verbose && !confirm_action( "All existing values will be overwritten with the new values you are about to enter." )) {
+                               printf("  Modification halted.\n");
+                               return;
+                       }
+
+               }
+               else {
+                       printf("  No changes made.\n");
+                       return;
+               }
+
+               values[0] = get_value(attr.quipu_name, prompt);
+               for (i = 1; i < MAX_VALUES; i++) {
+                       printf(more);
+                       fflush(stdout);
+                       fetch_buffer(resp, sizeof(resp), stdin);
+                       if ((resp[0] == 'y') || (resp[0] == 'Y'))
+                               values[i] = get_value(attr.quipu_name, prompt2);
+                       else
+                               break;
+               }
+
+               /* if the first value in the value-array is NULL, bail */
+               if (values[0] == NULL) {
+                       if (verbose)
+                               printf("  No modification made.\n");
+                       return;
+               }
+#ifdef DEBUG
+               if (debug & D_MODIFY) {
+                       printf("  ld = 0x%x\n", ld);
+                       printf("  who = [%s]\n", who);
+                       printf("  mods[0]->mod_op = %1d\n", mods[0]->mod_op);
+                       printf("  mods[0]->mod_type = %s\n", mods[0]->mod_type);
+                       for (i = 0; mods[0]->mod_values[i] != NULL; i++)
+                               printf("  mods[0]->mod_values[%1d] = %s\n", i, mods[0]->mod_values[i]);
+               }
+#endif
+               if (ldap_modify_s(ld, who, mods)) {
+                       mod_perror(ld);
+                       return;
+               }
+               else if (verbose)
+                       printf("  Modifications to '%s' complete.\n", attr.output_string);
+               ldap_uncache_entry( ld, who );
+               for (i--; i > 0; i--)
+                       (void) Free(values[i]);
+       }
+       return;
+}
+
+/*
+ *  These are used to size the buffers we use when collecting values that
+ *  can cross more than one line.
+ */
+#define LINE_SIZE       80
+#define MAX_LINES       6
+#define MAX_DESC_LINES  24
+#define INTL_ADDR_LIMIT        30
+
+char *get_value(id, prompt)
+char *id, *prompt;
+{
+       char *cp;               /* for the Malloc() */
+       int count;              /* line # of new value -- if multiline */
+       int multiline = 0;      /* 1 if this value is multiline */
+       static char line[LINE_SIZE];    /* raw line from user */
+       static char buffer[MAX_DESC_LINES * LINE_SIZE]; /* holds ALL of the 
+                                                          lines we get */
+       extern void * Malloc();
+       static char * get_URL();
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->get_value(%s, %s)\n", id, prompt);
+#endif
+       /* if this is a URL, have another routine handle this */
+       if (!strcmp(id, "labeledURL"))
+               return(get_URL());
+
+       /*
+        *  To start with, we have one line of input from the user.
+        *
+        *  Addresses and multiline description can span multiple lines.
+        *  Other attributes may not.
+        */
+       count = 1;
+       (void) memset(buffer, 0, sizeof(buffer));
+#ifdef UOFM
+       if (!strcmp(id, "postalAddress") || !strcmp(id, "homePostalAddress") || !strcmp(id, "multiLineDescription") || !strcmp(id, "vacationMessage")) 
+#else
+       if (!strcmp(id, "postalAddress") || !strcmp(id, "homePostalAddress"))
+#endif
+               multiline = 1;
+       printf("\n  %s:\n", prompt);
+
+       /* fetch lines */
+       for (;;) {
+               if (multiline)
+                       printf(" %1d: ", count);
+               else
+                       printf("  > ");
+               fflush(stdout);
+               fetch_buffer(line, sizeof(line), stdin);
+
+               if (line[0] == '\0')
+                       break;
+#ifdef UOFM
+               /*
+                *  Screen out dangerous e-mail addresses of the form:
+                *
+                *              user@umich.edu
+                *
+                * and addresses that have no '@' symbol at all.
+                */
+               if (!strcmp(id, "mail")) {
+                       int i;
+                       char *tmp, *tmp2;
+
+                       /* if this is a group, don't worry */
+                       if (isgroup())
+                               goto mail_is_good;
+
+                       /* if this address is not @umich.edu, don't worry */
+                       /* ...unless there is no '@' at all! */
+                       tmp = strdup(line);
+                       if ((tmp2 = strrchr(tmp, '@')) == NULL) {
+                       printf("\n");
+                       format("The address you entered is not a valid e-mail address.  E-mail addresses should be of the form \"local@domain\", e.g. bjensen@b.imap.itd.umich.edu", 75, 2 );
+                               goto mail_is_bad;
+                       }
+                       
+                       *tmp2 = '\0';
+                       tmp2++;
+                       if (strcasecmp(tmp2, "umich.edu"))
+                               goto mail_is_good;
+
+                       /* if not of the form uid@umich.edu, don't worry */
+                       if ((i = attr_to_index("uid")) < 0)
+                               goto mail_is_good;
+                       if (strcasecmp(tmp, *(Entry.attrs[i].values)))
+                               goto mail_is_good;
+                       printf("\n");
+                       format("An e-mail address of the form uniqname@umich.edu is not the form that you want registered in the Directory.  This form is the one to use on business cards, for example, but the Directory should contain your real e-mail address; that is, the address where you really read your mail.", 75, 2);
+
+mail_is_bad:
+                       printf("\n");
+                       printf("  Please enter a legal e-mail address (or press RETURN to stop)\n");
+                       continue;
+               }
+mail_is_good:
+#endif
+
+               /*
+                *  If the attribute which we are gathering is a "owner"
+                *  then we should lookup the name.  The user is going to
+                *  either have to change the search base before doing the
+                *  modify, or the person is going to have to be within the
+                *  scope of the current search base, or they will need to
+                *  type in a UFN.
+                */
+               if (!strcmp(id, "owner")) {
+                       LDAPMessage *lmp, *elmp;
+                       char *tmp;
+                       
+                       lmp = find(line, FALSE);
+                       if (lmp == (LDAPMessage *) NULL) {
+                               printf("  Could not find \"%s\" in the Directory\n", line);
+                               if (verbose) 
+                                       format("Owners of groups must be valid entries in the X.500 Directory.  The name you have typed above could not be found in the X.500 Directory.", 72, 2);
+                               return(NULL);
+                       }
+                       elmp = ldap_first_entry(ld, lmp);
+                       if (lmp == (LDAPMessage *) NULL) {
+                               ldap_perror(ld, "ldap_first_entry");
+                               return(NULL);
+                       }
+                       tmp = ldap_get_dn(ld, elmp);
+                       strcpy(buffer, tmp);
+                       (void) ldap_msgfree(lmp);
+                       break;
+               }
+
+               if (!strcmp(id, "postalAddress") || !strcmp(id, "homePostalAddress")) {
+                       if (strlen(line) > INTL_ADDR_LIMIT) {
+                               printf("  The international standard for addresses only allows for 30-character lines\n");
+                               printf("  Please re-enter your last line.\n");
+                               continue;
+                       }
+               }
+
+               /*
+                *  Separate lines of multiline attribute values with
+                *  dollar signs.  Copy this line into the buffer we
+                *  use to collect up all of the user-supplied input
+                *  lines.  If this is not a multiline attribute, we
+                *  are done.
+                */
+               if (count++ > 1)
+                       (void) strcat(buffer, "$");
+               (void) strcat(buffer, line);
+               if (!multiline)
+                       break;
+               if ((count > MAX_LINES) && (!strcmp(id, "postalAddress") || !strcmp(id, "homePostalAddress"))) {
+                       printf("  The international standard for addresses only allows for six lines\n");
+                       break;
+               }
+#ifdef UOFM
+               if ((count > MAX_DESC_LINES) && !strcmp(id, "multiLineDescription")) {
+                       printf("  We only allow %d lines of description\n", MAX_DESC_LINES);
+                       break;
+               }
+#endif
+       }
+       if (buffer[0] == '\0')
+               return(NULL);
+#ifdef DEBUG
+       if (debug & D_MODIFY)
+               printf("  Value is [%s]\n", buffer);
+#endif
+       cp = (char *) Malloc((unsigned) (strlen(buffer) + 1));
+       strcpy(cp, buffer);
+       return(cp);
+}
+
+void set_boolean(who, attr)
+char *who;                     /* DN of entry we are changing */
+struct attribute attr;         /* boolean attribute to change */
+{
+       char *cp, *s;
+       extern char * fetch_boolean_value();
+       static char response[16];
+       static char *newsetting[2] = { NULL, NULL };
+       LDAPMod mod, *mods[2];
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->set_boolean(%s, %s)\n", who, attr.quipu_name);
+#endif
+       mods[0] = &mod;
+       mods[1] = (LDAPMod *) NULL;
+       mod.mod_op = LDAP_MOD_REPLACE;
+       mod.mod_type = attr.quipu_name;
+       mod.mod_values = newsetting;
+
+       /* fetch the current setting */
+       if ((cp = fetch_boolean_value(who, attr)) == NULL)
+               return;
+       if (!strcmp(cp, "TRUE"))
+               newsetting[0] = "FALSE";
+       else if (!strcmp(cp, "FALSE"))
+               newsetting[0] = "TRUE";
+       else {
+               printf("  This field needs to be set to either TRUE or to FALSE.\n");
+               printf("  \"%s\" is not a legal value.  Please set this field to either TRUE or to FALSE.\n", cp);
+               newsetting[0] = "FALSE";
+       }
+
+       /* see if they want to change it */
+       printf("\n");
+       printf("  The current value of this field is %s.\n", cp);
+       printf("  Should I change the value of this field to %s?\n", 
+                                                       newsetting[0]);
+       printf("  Please enter Y for yes, N for no, or RETURN to cancel:  ");
+       fflush(stdout);
+       (void) fetch_buffer(response, sizeof(response), stdin);
+       for (s = response; isspace(*s); s++)
+                       ;
+       if ((*s == 'y') || (*s == 'Y')) {
+               if (ldap_modify_s(ld, who, mods)) {
+                       mod_perror(ld);
+                       return;
+               }
+               else if (verbose)
+                       printf("  Setting has been changed\n");
+               ldap_uncache_entry(ld, who);
+               return;
+       }
+       if (verbose)
+               printf("  Setting has not been changed\n");
+}
+
+#ifdef UOFM
+
+void set_updates(who)
+char *who;
+{
+       char *cp, *s;
+       extern char * fetch_boolean_value();
+       static char response[16];
+       static char value[6];
+       static char *newsetting[2] = { value, NULL };
+       LDAPMod mod, *mods[2];
+       struct attribute attr;
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->set_updates(%s)\n", who);
+#endif
+       mods[0] = &mod;
+       mods[1] = (LDAPMod *) NULL;
+       mod.mod_op = LDAP_MOD_REPLACE;
+       mod.mod_type = "noBatchUpdates";
+       mod.mod_values = newsetting;
+       /* explain what the implications are */
+       if (verbose) {
+               printf("\n  By default, updates that are received from the Personnel\n");
+               printf("  Office and the Office of the Registrar are applied to all\n");
+               printf("  entries in the X.500 database each month.  Sometimes this\n");
+               printf("  feature is undesirable.  For example, if you maintain your\n");
+               printf("  entry in the X.500 database manually, you may not want to\n");
+               printf("  have these updates applied to your entry, possibly overwriting\n");
+               printf("  correct information with out-dated information.\n\n");
+       }
+
+       /* fetch the current setting */
+       attr.quipu_name = "noBatchUpdates";
+       if ((cp = fetch_boolean_value(who, attr)) == NULL)
+               return;
+       if (!strcmp(cp, "TRUE"))
+               printf("  Automatic updates are currently turned OFF\n");
+       else if (!strcmp(cp, "FALSE"))
+               printf("  Automatic updates are currently turned ON\n");
+       else {
+               fprintf(stderr, "  Unknown update flag -> [%s]\n", cp);
+               return;
+       }
+
+       /* see if they want to change it */
+       printf("\n  Change this setting [no]? ");
+       fflush(stdout);
+       (void) fetch_buffer(response, sizeof(response), stdin);
+       for (s = response; isspace(*s); s++)
+                       ;
+       if ((*s == 'y') || (*s == 'Y')) {
+               if (!strcmp(cp, "TRUE"))
+                       strcpy(value, "FALSE");
+               else
+                       strcpy(value, "TRUE");
+               if (ldap_modify_s(ld, who, mods)) {
+                       mod_perror(ld);
+                       return;
+               }
+               else if (verbose)
+                       printf("  Setting has been changed\n");
+               ldap_uncache_entry( ld, who );
+               return;
+       }
+       if (verbose)
+               printf("  Setting has not been changed\n");
+}
+
+#endif
+
+print_mod_list(group)
+int group;
+{
+       register int i, j = 1;
+       extern struct attribute attrlist[];
+
+       if (group == TRUE) {
+           for (i = 0; attrlist[i].quipu_name != NULL; i++) {
+               if (attrlist[i].flags & ATTR_FLAG_GROUP_MOD) {
+                       printf("  %2d ->  %s\n", j, attrlist[i].output_string);
+                       j++;
+               }
+           }
+       } else {
+           for (i = 0; attrlist[i].quipu_name != NULL; i++) {
+               if (attrlist[i].flags & ATTR_FLAG_PERSON_MOD) {
+                       printf("  %2d ->  %s\n", j, attrlist[i].output_string);
+                       j++;
+               }
+           }
+       }
+       printf("   ? ->  Print this list\n\n");
+       printf("  Press the RETURN key without typing a number to quit.\n");
+#ifdef UOFM
+       if (group == FALSE)
+               printf("  To add nicknames, send mail to x500-nicknames@umich.edu\n");
+#endif
+}
+                       
+perform_action(choice, dn, group)
+char choice[];
+char *dn;
+int group;
+{
+       int selection;
+       register int i, j = 1;
+       extern struct attribute attrlist[];
+       extern void mod_addrDN(), change_field(), set_boolean();
+
+       selection = atoi(choice);
+       if (selection < 1) {
+               printf("\n  Choices are:\n");
+               printf("  -----------------------\n");
+               print_mod_list(group);
+               return(1);
+               /* NOTREACHED */
+       }
+
+       if (group == TRUE) {
+           for (i = 0; attrlist[i].quipu_name != NULL; i++) {
+               if (attrlist[i].flags & ATTR_FLAG_GROUP_MOD) {
+                       if (j == selection)
+                               break;
+                       j++;
+               }
+           }
+       } else {
+           for (i = 0; attrlist[i].quipu_name != NULL; i++) {
+               if (attrlist[i].flags & ATTR_FLAG_PERSON_MOD) {
+                       if (j == selection)
+                               break;
+                       j++;
+               }
+           }
+       }
+
+       if (attrlist[i].quipu_name == NULL) {
+               printf("\n  Choices are:\n");
+               printf("  -----------------------\n");
+               print_mod_list(group);
+               return(1);
+               /* NOTREACHED */
+       }
+       if (attrlist[i].mod_func == change_field)
+               (*attrlist[i].mod_func)(dn, Entry.attrs[attr_to_index(attrlist[i].quipu_name)]);
+       else if (attrlist[i].mod_func == mod_addrDN)
+               (*attrlist[i].mod_func)(dn, i);
+       else if (attrlist[i].mod_func == set_boolean)
+               (*attrlist[i].mod_func)(dn, Entry.attrs[attr_to_index(attrlist[i].quipu_name)]);
+       else
+               (*attrlist[i].mod_func)(dn);
+       return(0);
+}
+
+static char * get_URL()
+{
+       char *rvalue, label[MED_BUF_SIZE], url[MED_BUF_SIZE];
+       static int check_URL();
+       extern void * Malloc();
+
+       if (verbose) {
+               printf("  First, enter the URL.  (Example: http://www.us.itd.umich.edu/users/).\n");
+               printf("  The URL may be up to %d characters long.\n", MED_BUF_SIZE);
+       }
+       for (;;) {
+               printf("  URL: ");
+               fflush(stdout);
+               (void) fetch_buffer(url, sizeof(url), stdin);
+               if (*url == '\0')
+                       continue;
+               if (check_URL(url) == 0)
+                       break;
+               printf("  A URL may not have any spaces or tabs in it.  Please re-enter your URL.\n\n");
+       }
+       if (verbose)
+               printf("\n  Now please enter a descriptive label for this URL\n");
+       do {
+               printf("  Label: ");
+               fflush(stdout);
+               (void) fetch_buffer(label, sizeof(label), stdin);
+       } while (label[0] == '\0');
+       rvalue = (char *) Malloc((unsigned) (strlen(url) + 2 + strlen(label)));
+       sprintf(rvalue, "%s %s", url, label);
+       return((char *) rvalue);
+}
+
+static check_URL(url)
+char *url;
+{
+       register char *cp;
+
+       for (cp = url; *cp != '\n' && *cp != '\0'; cp++) {
+               if (isspace(*cp))
+                       return(-1);
+                       /*NOTREACHED*/
+       }
+       *cp = '\0';
+       return(0);
+}
+
+
+mod_perror( LDAP *ld )
+{
+       if ( ld == NULL || ( ld->ld_errno != LDAP_UNAVAILABLE &&
+           ld->ld_errno != LDAP_UNWILLING_TO_PERFORM )) {
+               ldap_perror( ld, "modify" );
+               return;
+       }
+
+       fprintf( stderr, "\n  modify: failed because part of the online directory is not able\n" );
+       fprintf( stderr, "  to be modified right now" );
+       if ( ld->ld_errno == LDAP_UNAVAILABLE ) {
+               fprintf( stderr, " or is temporarily unavailable" );
+       }
+       fprintf( stderr, ".\n  Please try again later.\n" );
+}
diff --git a/clients/ud/print.c b/clients/ud/print.c
new file mode 100644 (file)
index 0000000..4185bda
--- /dev/null
@@ -0,0 +1,653 @@
+/*
+ * Copyright (c) 1991, 1993 
+ * Regents of the University of Michigan.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#ifndef __STDC__
+#include <memory.h>
+#endif
+#include <time.h>
+#include <lber.h>
+#include <ldap.h>
+#include "ud.h"
+
+#ifdef DEBUG
+extern int debug;
+#endif
+
+struct entry Entry;
+extern LDAP *ld;
+
+extern void * Malloc();
+extern void Free();
+extern char * my_ldap_dn2ufn();
+
+/*
+ *  When displaying entries, display only these attributes, and in this
+ *  order.
+ */
+static char *person_attr_print_order[] = {
+       "cn",
+       "mail",
+       "telephoneNumber",
+       "facsimileTelephoneNumber",
+       "pager",
+       "postalAddress",
+       "title",
+       "uid",
+       "multiLineDescription",
+       "homePhone",
+       "homePostalAddress",
+       "drink",
+       "labeledURL",
+       "onVacation",
+       "vacationMessage",
+       "memberOfGroup",
+       "lastModifiedBy",
+       "lastModifiedTime",
+       NULL
+};
+
+static char *group_attr_print_order[] = {
+       "cn",
+       "facsimileTelephoneNumber",
+       "telephoneNumber",
+       "postalAddress",
+       "multiLineDescription",
+       "joinable",
+       "associatedDomain",
+       "owner",
+       "moderator",
+       "ErrorsTo",
+       "rfc822ErrorsTo",
+       "RequestsTo",
+       "rfc822RequestsTo",
+       "member",
+       "mail",
+       "labeledURL",
+       "lastModifiedBy",
+       "lastModifiedTime",
+       NULL
+};
+
+parse_answer(s)
+LDAPMessage *s;
+{
+       int idx;
+       char **rdns;
+       BerElement *cookie;
+       register LDAPMessage *ep;
+       register char *ap;
+       void clear_entry();
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->parse_answer(%x)\n", s);
+#endif
+
+       clear_entry();
+
+#ifdef DEBUG
+       if (debug & D_PARSE)
+               printf(" Done clearing entry\n");
+#endif
+       for (ep = ldap_first_entry(ld, s); ep != NULL; ep = ldap_next_entry(ld, ep)) {
+#ifdef DEBUG
+               if (debug & D_PARSE)
+                       printf(" Determining DN and name\n");
+#endif
+               Entry.DN = ldap_get_dn(ld, ep);
+#ifdef DEBUG
+               if (debug & D_PARSE)
+                       printf(" DN = %s\n", Entry.DN);
+#endif
+               rdns = ldap_explode_dn(Entry.DN, TRUE);
+#ifdef DEBUG
+               if (debug & D_PARSE)
+                       printf(" Name = %s\n", *rdns);
+#endif
+               Entry.name = strdup(*rdns);
+               ldap_value_free(rdns);
+               for (ap = ldap_first_attribute(ld, ep, &cookie); ap != NULL; ap = ldap_next_attribute(ld, ep, cookie)) {
+
+#ifdef DEBUG
+                       if (debug & D_PARSE)
+                               printf("parsing ap = %s\n", ap);
+#endif
+                       if ((idx = attr_to_index(ap)) < 0) {
+                               printf("  Unknown attribute \"%s\"\n", ap);
+                               continue;
+                       }
+                       add_value(&(Entry.attrs[idx]), ep, ap);
+               }
+       }
+#ifdef DEBUG
+       if (debug & D_PARSE)
+               printf(" Done parsing entry\n");
+#endif
+}
+
+add_value(attr, ep, ap)
+struct attribute *attr;
+LDAPMessage *ep;
+char *ap;
+{
+       register int i = 0;
+       char **vp, **tp, **avp;
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->add_value(%x, %x, %s)\n", attr, ep, ap);
+#endif
+       vp = (char **) ldap_get_values(ld, ep, ap);
+
+       /*
+        *  Fill in the attribute structure for this attribute.  This
+        *  stores away the values (using strdup()) and the count.  Terminate
+        *  the list with a NULL pointer.
+        *
+        *  attr->quipu_name has already been set during initialization.
+        */
+       if ((attr->number_of_values = ldap_count_values(vp)) > 0) {
+               attr->values = (char **) Malloc((unsigned) ((attr->number_of_values + 1) * sizeof(char *)));
+               avp = attr->values;
+
+               for (i = 1, tp = vp; *tp != NULL; i++, tp++) {
+#ifdef DEBUG
+                       if (debug & D_PARSE)
+                               printf("  value #%d  %s\n", i, *tp);
+#endif
+                       /*
+                        *  The 'name' field of the Entry structure already has
+                        *  has the first part of the DN copied into it.  Thus,
+                        *  we don't need to save it away here again.  Also, by
+                        *  tossing it away here, we make printing this info out
+                        *  a bit easier later.
+                        */
+                       if (!strcmp(ap, "cn") && !strcmp(*tp, Entry.name)) {
+                               attr->number_of_values--;
+                               continue;
+                       }
+                       *avp++ = strdup(*tp);
+               }
+               *avp = NULL;
+       }
+       ldap_value_free(vp);
+}
+
+print_an_entry()
+{
+       int n = 0, i, idx;
+       char is_a_group, **order;
+       char *sub_list[MAX_VALUES], buf[SMALL_BUF_SIZE];
+       extern int col_size, isaurl(), isadn();
+       static char *time2text();
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->print_an_entry()\n");
+#endif
+       printf(" \"%s\"\n", Entry.name);
+       
+       /*
+        *  If the entry is a group, find all of the subscribers to that
+        *  group.  A subscriber is an entry that *points* to a group entry,
+        *  and a member is an entry that is included as part of a group
+        *  entry.
+        *
+        *  We also need to select the appropriate output format here.
+        */
+       is_a_group = isgroup();
+       if (is_a_group) {
+               order = (char **) group_attr_print_order;
+               n = find_all_subscribers(sub_list, Entry.DN);
+#ifdef DEBUG
+               if (debug & D_PRINT)
+                       printf(" Group \"%s\" has %d subscribers\n", 
+                                                               Entry.name, n);
+#endif
+       }
+       else
+               order = (char **) person_attr_print_order;
+
+       for (i = 0; order[i] != NULL; i++) {
+               idx = attr_to_index(order[i]);
+#ifdef DEBUG
+               if (debug & D_PRINT) {
+                       printf("  ATTR #%2d = %s [%s] (%d values)\n", i + 1,
+                               Entry.attrs[idx].output_string,
+                               Entry.attrs[idx].quipu_name,
+                               Entry.attrs[idx].number_of_values);
+               }
+#endif
+               if (idx < 0)
+                       continue;
+               if (Entry.attrs[idx].number_of_values == 0)
+                       continue;
+               if (isadn(order[i]))
+                       print_DN(Entry.attrs[idx]);
+               else if (isaurl(order[i]))
+                       print_URL(Entry.attrs[idx]);
+               else if (isadate(order[i])) {
+                       /* fix time and date, then call usual routine */
+                       Entry.attrs[idx].values[0] = 
+                               time2text(Entry.attrs[idx].values[0], FALSE);
+                       print_values(Entry.attrs[idx]);
+               }
+               else
+                       print_values(Entry.attrs[idx]);
+       }
+
+       /*
+        *  If it is a group, then we should print the subscriber list (if
+        *  there are any).  If there are a lot of them, prompt the user
+        *  before printing them.
+        */
+       if (is_a_group && (n > 0)) {
+               char *label = "Subscribers:         ";
+
+               if (n > TOO_MANY_TO_PRINT) {
+                       printf("  There are %d subscribers.  Print them? ", n);
+                       fflush(stdout);
+                       fetch_buffer(buf, sizeof(buf), stdin);
+                       if (!((buf[0] == 'y') || (buf[0] == 'Y')))
+                               return;
+               }
+               format2((char *) my_ldap_dn2ufn(sub_list[n - 1]), label, (char *) NULL, 2, 
+                                               2 + strlen(label) + 1, col_size); 
+               for (n--; n > 0; n--)
+                       format2((char *) my_ldap_dn2ufn(sub_list[n - 1]), (char *) NULL, 
+                               (char *) NULL, 2 + strlen(label), 
+                               2 + strlen(label) + 2, col_size); 
+       }
+
+       return;
+}
+
+#define OUT_LABEL_LEN  20
+
+/* prints the values associated with an attribute */
+print_values(A)
+struct attribute A;
+{
+       register int i, k;
+       register char *cp, **vp;
+       char out_buf[MED_BUF_SIZE], *padding = NULL;
+       int lead;
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->print_values(%x)\n", A);
+#endif
+       if (A.number_of_values == 0)
+               return;
+       if ((vp = A.values) == NULL)
+               return;
+
+       /*
+        *  Pad out the output string label so that it fills the
+        *  whole field of length OUT_LABEL_LEN.
+        */
+       out_buf[0] = '\0';
+       i = OUT_LABEL_LEN - strlen(A.output_string);
+       if (i < 0) {
+               printf("Output string for \"%s\" is too long.  Maximum length is %d characters\n", A.quipu_name, OUT_LABEL_LEN);
+               return;
+       }
+       if (isgroup() && !strcmp(A.quipu_name, "mail") && (Entry.attrs[attr_to_index("member")].number_of_values == 0)) {
+               A.output_string = "Members";
+               i = OUT_LABEL_LEN - strlen(A.output_string);
+               padding = (char *) Malloc((unsigned) (i + 1));
+               (void) memset(padding, ' ', i);
+               *(padding + i) = '\0';
+               sprintf(out_buf, "%s:%s", A.output_string, padding);
+       }
+       else if (!(isgroup() && !strcmp(A.quipu_name, "mail") && (Entry.attrs[attr_to_index("member")].number_of_values > 0))) {
+               padding = (char *) Malloc((unsigned) (i + 1));
+               (void) memset(padding, ' ', i);
+               *(padding + i) = '\0';
+               sprintf(out_buf, "%s:%s", A.output_string, padding);
+       }
+       /*
+        *  If this happens to be a group, then do not print the output
+        *  string if we have already printed out some members.
+        */
+       else if (isgroup() && !strcmp(A.quipu_name, "mail") && (Entry.attrs[attr_to_index("member")].number_of_values > 0)) {
+               padding = (char *) Malloc((unsigned) (OUT_LABEL_LEN + 2));
+               (void) memset(padding, ' ', OUT_LABEL_LEN + 1);
+               *(padding + OUT_LABEL_LEN + 1) = '\0';
+               sprintf(out_buf, "%s", padding);
+       }
+       lead = strlen(out_buf) + 2;
+
+       printf("  %s", out_buf);
+       for (i = 0; *vp != NULL; i++, vp++) {
+               if (i > 0) {
+                       if (!strncmp(A.output_string, "Home a", 6) || !strncmp(A.output_string, "Business a", 10)) {
+                               printf("  %s", out_buf);
+                       }
+                       else {
+                               for (k = lead; k > 0; k--)
+                                       putchar(' ');
+                       }
+               }
+               for (cp = *vp; *cp != '\0'; cp++) {
+                       switch (*cp) {
+                       case '$' :
+                               if (!strncmp(A.output_string, "Home a", 6) || !strncmp(A.output_string, "Business a", 10) || !strcmp(A.quipu_name, "multiLineDescription")) {
+                                       putchar('\n');
+                                       for (k = lead; k > 0; k--)
+                                               putchar(' ');
+                                       while (isspace(*(cp + 1)))
+                                               cp++;
+                               }
+                               else
+                                       putchar(*cp);
+                               break;
+                       case '\n' :
+                               putchar('%');
+                               putchar('\n');
+                               break;
+                       default:
+                               putchar(*cp);
+                       }
+               }
+               putchar('\n');
+       }
+       if (padding != NULL)
+               Free(padding);
+       return;
+}
+
+/* prints the DN's associated with an attribute */
+print_DN(A)
+struct attribute A;
+{
+       int i, lead;
+       register char **vp;
+       char out_buf[MED_BUF_SIZE], *padding = NULL;
+       extern int col_size;
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->print_DN(%x)\n", A);
+#endif
+       if (A.number_of_values == 0)
+               return;
+       /*
+        *  Pad out the output string label so that it fills the
+        *  whole field of length OUT_LABEL_LEN.
+        */
+       i = OUT_LABEL_LEN - strlen(A.output_string);
+       if (i > 0) {
+               padding = (char *) Malloc((unsigned) (i + 1));
+               (void) memset(padding, ' ', i);
+               *(padding + i) = '\0';
+               sprintf(out_buf, "%s:%s", A.output_string, padding);
+               (void) Free(padding);
+       }
+       lead = strlen(out_buf) + 2;
+
+       vp = A.values;
+       format2((char *) my_ldap_dn2ufn(*vp), out_buf, (char *) NULL, 2, lead + 1, col_size); 
+       for (vp++; *vp != NULL; vp++) {
+               format2((char *) my_ldap_dn2ufn(*vp), (char *) NULL, (char *) NULL, lead, 
+                       lead + 1, col_size); 
+       }
+       return;
+}
+
+void clear_entry()
+{
+       register int i;
+       extern struct attribute attrlist[];
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->clear_entry()\n");
+       if ((debug & D_PRINT) && (Entry.name != NULL))
+               printf(" Clearing entry \"%s\"\n", Entry.name);
+#endif
+       if (Entry.DN != NULL)
+               Free(Entry.DN);
+       if (Entry.name != NULL)
+               Free(Entry.name);
+       Entry.may_join = FALSE;
+       Entry.subscriber_count = -1;
+       Entry.DN = Entry.name = NULL;
+
+       /*  clear all of the values associated with all attributes */
+       for (i = 0; attrlist[i].quipu_name != NULL; i++) {
+#ifdef DEBUG
+               if (debug & D_PRINT)
+                       printf(" Clearing attribute \"%s\" -- ", 
+                               Entry.attrs[i].quipu_name);
+#endif
+               if (Entry.attrs[i].values == NULL) {
+#ifdef DEBUG
+                       if (debug & D_PRINT)
+                               printf(" no values, skipping\n");
+#endif
+                       continue;
+               }
+#ifdef DEBUG
+               if (debug & D_PRINT)
+                       printf(" freeing %d values\n", 
+                                       Entry.attrs[i].number_of_values);
+#endif
+               Entry.attrs[i].number_of_values = 0;
+               ldap_value_free(Entry.attrs[i].values);
+               Entry.attrs[i].values = (char **) NULL;
+
+               /*
+                *  Note:  We do not clear either of the char * fields
+                *  since they will always be applicable.
+                */
+       }
+}
+
+attr_to_index(s)
+char *s;
+{
+       register int i;
+       extern struct attribute attrlist[];
+
+       for (i = 0; attrlist[i].quipu_name != NULL; i++)
+               if (!strcasecmp(s, attrlist[i].quipu_name))
+                       return(i);
+       return(-1);
+}
+
+void initialize_attribute_strings()
+{
+       register int i;
+       extern struct entry Entry;
+       extern struct attribute attrlist[];
+
+       for (i = 0; attrlist[i].quipu_name != NULL; i++)
+               Entry.attrs[i].quipu_name = attrlist[i].quipu_name;
+       for (i = 0; attrlist[i].quipu_name != NULL; i++)
+               Entry.attrs[i].output_string = attrlist[i].output_string;
+}
+
+/* prints the URL/label pairs associated with an attribute */
+print_URL(A)
+struct attribute A;
+{
+       int i, lead;
+       register char **vp;
+       char out_buf[MED_BUF_SIZE], *padding = NULL;
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->print_URL(%x)\n", A);
+#endif
+       if (A.number_of_values == 0)
+               return;
+       /*
+        *  Pad out the output string label so that it fills the
+        *  whole field of length OUT_LABEL_LEN.
+        */
+       i = OUT_LABEL_LEN - strlen(A.output_string);
+       if (i > 0) {
+               padding = (char *) Malloc((unsigned) (i + 1));
+               (void) memset(padding, ' ', i);
+               *(padding + i) = '\0';
+               sprintf(out_buf, "%s:%s", A.output_string, padding);
+       }
+       lead = strlen(out_buf) + 2;
+
+       vp = A.values;
+       print_one_URL(*vp, 2, out_buf, lead);
+       for (vp++; *vp != NULL; vp++)
+               print_one_URL(*vp, lead, (char *) NULL, lead);
+       if (padding != NULL)
+               Free(padding);
+       return;
+}
+
+print_one_URL(s, label_lead, tag, url_lead)
+char *s;
+int label_lead;
+char *tag;
+int url_lead;
+{
+       register int i;
+       char c, *cp, *url;
+       extern int col_size;
+       extern void Free();
+
+       for (cp = s; !isspace(*cp) && (*cp != '\0'); cp++)
+               ;
+       c = *cp;
+       *cp = '\0';
+       url = strdup(s);
+       *cp = c;
+       if (*cp != '\0') {
+               for (cp++; isspace(*cp); cp++)
+                       ;
+       }
+       else
+               cp = "(no description available)";
+       format2(cp, tag, (char *) NULL, label_lead, label_lead + 1, col_size);
+       for (i = url_lead + 2; i > 0; i--)
+               printf(" ");
+       printf("%s\n", url);
+       Free(url);
+}
+
+
+#define GET2BYTENUM( p )       (( *p - '0' ) * 10 + ( *(p+1) - '0' ))
+
+static char *
+time2text( char *ldtimestr, int dateonly )
+{
+    struct tm          t;
+    char               *p, *timestr, zone, *fmterr = "badly formatted time";
+    time_t             gmttime;
+    static long                gtime();
+
+    memset( (char *)&t, 0, sizeof( struct tm ));
+    if ( strlen( ldtimestr ) < 13 ) {
+       return( fmterr );
+    }
+
+    for ( p = ldtimestr; p - ldtimestr < 12; ++p ) {
+       if ( !isdigit( *p )) {
+           return( fmterr );
+       }
+    }
+
+    p = ldtimestr;
+    t.tm_year = GET2BYTENUM( p ); p += 2;
+    t.tm_mon = GET2BYTENUM( p ) - 1; p += 2;
+    t.tm_mday = GET2BYTENUM( p ); p += 2;
+    t.tm_hour = GET2BYTENUM( p ); p += 2;
+    t.tm_min = GET2BYTENUM( p ); p += 2;
+    t.tm_sec = GET2BYTENUM( p ); p += 2;
+
+    if (( zone = *p ) == 'Z' ) {       /* GMT */
+       zone = '\0';    /* no need to indicate on screen, so we make it null */
+    }
+
+    gmttime = gtime( &t );
+    timestr = ctime( &gmttime );
+
+    timestr[ strlen( timestr ) - 1 ] = zone;   /* replace trailing newline */
+    if ( dateonly ) {
+       strcpy( timestr + 11, timestr + 20 );
+    }
+
+    Free ( ldtimestr );
+    return( strdup( timestr ) );
+}
+
+
+/* gtime.c - inverse gmtime */
+
+#if !defined( MACOS ) && !defined( _WIN32 ) && !defined( DOS )
+#include <sys/time.h>
+#endif /* !MACOS */
+
+/* gtime(): the inverse of localtime().
+       This routine was supplied by Mike Accetta at CMU many years ago.
+ */
+
+int    dmsize[] = {
+    31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+#define        dysize(y)       \
+       (((y) % 4) ? 365 : (((y) % 100) ? 366 : (((y) % 400) ? 365 : 366)))
+
+#define        YEAR(y)         ((y) >= 100 ? (y) : (y) + 1900)
+
+/* \f */
+
+static long    gtime ( struct tm *tm )
+{
+    register int    i,
+                    sec,
+                    mins,
+                    hour,
+                    mday,
+                    mon,
+                    year;
+    register long   result;
+
+    if ((sec = tm -> tm_sec) < 0 || sec > 59
+           || (mins = tm -> tm_min) < 0 || mins > 59
+           || (hour = tm -> tm_hour) < 0 || hour > 24
+           || (mday = tm -> tm_mday) < 1 || mday > 31
+           || (mon = tm -> tm_mon + 1) < 1 || mon > 12)
+       return ((long) -1);
+    if (hour == 24) {
+       hour = 0;
+       mday++;
+    }
+    year = YEAR (tm -> tm_year);
+
+    result = 0L;
+    for (i = 1970; i < year; i++)
+       result += dysize (i);
+    if (dysize (year) == 366 && mon >= 3)
+       result++;
+    while (--mon)
+       result += dmsize[mon - 1];
+    result += mday - 1;
+    result = 24 * result + hour;
+    result = 60 * result + mins;
+    result = 60 * result + sec;
+
+    return result;
+}
diff --git a/clients/ud/string_to_key.c b/clients/ud/string_to_key.c
new file mode 100644 (file)
index 0000000..1d6649c
--- /dev/null
@@ -0,0 +1,257 @@
+#ifdef KERBEROS
+/*
+ * $Source: /usr/local/src/ldap/clients/ud/RCS/string_to_key.c,v $
+ * $Author: lsloan $
+ *
+ * Copyright 1985, 1986, 1987, 1988, 1989 by the Massachusetts Institute
+ * of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * These routines perform encryption and decryption using the DES
+ * private key algorithm, or else a subset of it-- fewer inner loops.
+ * (AUTH_DES_ITER defaults to 16, may be less.)
+ *
+ * Under U.S. law, this software may not be exported outside the US
+ * without license from the U.S. Commerce department.
+ *
+ * The key schedule is passed as an arg, as well as the cleartext or
+ * ciphertext.  The cleartext and ciphertext should be in host order.
+ *
+ * These routines form the library interface to the DES facilities.
+ *
+ *     spm     8/85    MIT project athena
+ */
+
+#ifndef        lint
+static char rcsid_string_to_key_c[] =
+"$Id: string_to_key.c,v 1.5 1995/11/09 20:29:55 lsloan Exp $";
+#endif
+
+#include <mit-copyright.h>
+#include <stdio.h>
+#include <des.h>
+/* #include "des_internal.h" */
+#if 1
+#include <krb.h>
+#endif
+
+extern int des_debug;
+extern int des_debug_print();
+extern void des_fixup_key_parity();
+
+#ifndef AFSKERBEROS
+#define WORLDPEACEINOURTIME
+#endif
+
+#if defined(WORLDPEACEINOURTIME) /* Use original, not ifs version */
+/*
+ * convert an arbitrary length string to a DES key
+ */
+int
+des_string_to_key(str,key)
+    char *str;
+    register des_cblock *key;
+{
+    register char *in_str;
+    register unsigned temp,i;
+    register int j;
+    register long length;
+    static unsigned char *k_p;
+    static int forward;
+    register char *p_char;
+    static char k_char[64];
+    static des_key_schedule key_sked;
+    extern unsigned long des_cbc_cksum();
+
+    in_str = str;
+    forward = 1;
+    p_char = k_char;
+    length = strlen(str);
+
+    /* init key array for bits */
+    memset(k_char, 0, sizeof(k_char));
+
+#ifdef DEBUG
+    if (des_debug)
+       fprintf(stdout,
+               "\n\ninput str length = %d  string = %s\nstring = 0x ",
+               length,str);
+#endif
+
+    /* get next 8 bytes, strip parity, xor */
+    for (i = 1; i <= length; i++) {
+       /* get next input key byte */
+       temp = (unsigned int) *str++;
+#ifdef DEBUG
+       if (des_debug)
+           fprintf(stdout,"%02x ",temp & 0xff);
+#endif
+       /* loop through bits within byte, ignore parity */
+       for (j = 0; j <= 6; j++) {
+           if (forward)
+               *p_char++ ^= (int) temp & 01;
+           else
+               *--p_char ^= (int) temp & 01;
+           temp = temp >> 1;
+       } while (--j > 0);
+
+       /* check and flip direction */
+       if ((i%8) == 0)
+           forward = !forward;
+    }
+
+    /* now stuff into the key des_cblock, and force odd parity */
+    p_char = k_char;
+    k_p = (unsigned char *) key;
+
+    for (i = 0; i <= 7; i++) {
+       temp = 0;
+       for (j = 0; j <= 6; j++)
+           temp |= *p_char++ << (1+j);
+       *k_p++ = (unsigned char) temp;
+    }
+
+    /* fix key parity */
+    des_fixup_key_parity(key);
+
+    /* Now one-way encrypt it with the folded key */
+    (void) des_key_sched(key,key_sked);
+    (void) des_cbc_cksum((des_cblock *)in_str,key,length,key_sked,key);
+    /* erase key_sked */
+    memset((char *)key_sked, 0, sizeof(key_sked));
+
+    /* now fix up key parity again */
+    des_fixup_key_parity(key);
+
+    if (des_debug)
+       fprintf(stdout,
+               "\nResulting string_to_key = 0x%x 0x%x\n",
+               *((unsigned long *) key),
+               *((unsigned long *) key+1));
+}
+
+#else /* Use ifs version */
+
+#if 0
+#include <stdio.h>
+    /* These two needed for rxgen output to work */
+#include <sys/types.h>
+#include <rx/xdr.h>
+#include <afs/cellconfig.h>
+#include <afs/auth.h>
+
+#include "/usr/andy/kauth/kauth.h"
+#include "/usr/andy/kauth/kautils.h"
+#endif
+
+/* This defines the Andrew string_to_key function.  It accepts a password
+   string as input and converts its via a one-way encryption algorithm to a DES
+   encryption key.  It is compatible with the original Andrew authentication
+   service password database. */
+
+static void Andrew_StringToKey (str, cell, key)
+  char          *str;
+  char          *cell;                  /* cell for password */
+  des_cblock *key;
+{   char  password[8+1];                /* crypt is limited to 8 chars anyway */
+    int   i;
+    int   passlen;
+
+    memset(key, 0, sizeof(des_cblock));
+    memset(password, 0, sizeof(password));
+
+    strncpy (password, cell, 8);
+    passlen = strlen (str);
+    if (passlen > 8) passlen = 8;
+
+    for (i=0; i<passlen; i++)
+        password[i] = str[i] ^ cell[i];
+
+    for (i=0;i<8;i++)
+        if (password[i] == '\0') password[i] = 'X';
+
+    /* crypt only considers the first 8 characters of password but for some
+       reason returns eleven characters of result (plus the two salt chars). */
+    strncpy(key, crypt(password, "#~") + 2, sizeof(des_cblock));
+
+    /* parity is inserted into the LSB so leftshift each byte up one bit.  This
+       allows ascii characters with a zero MSB to retain as much significance
+       as possible. */
+    {   char *keybytes = (char *)key;
+        unsigned int temp;
+
+        for (i = 0; i < 8; i++) {
+            temp = (unsigned int) keybytes[i];
+            keybytes[i] = (unsigned char) (temp << 1);
+        }
+    }
+    des_fixup_key_parity (key);
+}
+
+static void StringToKey (str, cell, key)
+  char          *str;
+  char          *cell;                  /* cell for password */
+  des_cblock *key;
+{   des_key_schedule schedule;
+    char temp_key[8];
+    char ivec[8];
+    char password[BUFSIZ];
+    int  passlen;
+
+    strncpy (password, str, sizeof(password));
+    if ((passlen = strlen (password)) < sizeof(password)-1)
+        strncat (password, cell, sizeof(password)-passlen);
+    if ((passlen = strlen(password)) > sizeof(password)) passlen = sizeof(password);
+
+    memcpy(ivec, "kerberos", 8);
+    memcpy(temp_key, "kerberos", 8);
+    des_fixup_key_parity (temp_key);
+    des_key_sched (temp_key, schedule);
+    des_cbc_cksum (password, ivec, passlen, schedule, ivec);
+
+    memcpy(temp_key, ivec, 8);
+    des_fixup_key_parity (temp_key);
+    des_key_sched (temp_key, schedule);
+    des_cbc_cksum (password, key, passlen, schedule, ivec);
+
+    des_fixup_key_parity (key);
+}
+
+/* static */  void
+ka_StringToKey (str, cell, key)
+  char          *str;
+  char          *cell;                  /* cell for password */
+  des_cblock   *key;
+{   char  realm[REALM_SZ];
+
+#if NOWAYOUTTODAY
+    long  code;
+    /* code = ka_CellToRealm (cell, realm, 0/*local*/); */
+    if (code) strcpy (realm, "");
+    else lcstring (realm, realm, sizeof(realm)); /* for backward compatibility */
+#else
+       (void)strcpy(realm, cell);
+#endif
+
+    if (strlen(str) > 8) StringToKey (str, realm, key);
+    else Andrew_StringToKey (str, realm, key);
+}
+
+/*
+ * convert an arbitrary length string to a DES key
+ */
+int
+des_string_to_key(str,key)
+    char *str;
+    register des_cblock *key;
+{
+       /* NB: i should probably call routine to get local cell here */
+       ka_StringToKey(str, "umich.edu", key);
+       return 0;
+}
+
+#endif /* Use IFS Version */
+
+#endif /* kerberos */
diff --git a/clients/ud/ud.h b/clients/ud/ud.h
new file mode 100644 (file)
index 0000000..40b6ecf
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 1991, 1992, 1993 
+ * Regents of the University of Michigan.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#ifdef DOS
+#include "protoud.h"
+#define strncasecmp(a, b, n)   strnicmp(a, b, n)
+#define strcasecmp(a, b)       stricmp(a, b)
+#define MAX_VALUES     8
+#else
+#define MAX_VALUES     1000
+#endif /* end of DOS ifdef */
+
+/*****************************************************************************
+ **
+ **            Limits which ud imposes.  Also subject to change.
+ **
+ *****************************************************************************/
+/*
+ *  Names are parsed somewhat like 'awk' parses them.  This is the
+ *  maximum number of components we store away.
+ *
+ *  The isnamesepartor() macro should return TRUE if x is equal to one of the
+ *  characters that delimits name fields.  The ignorechar() macro should
+ *  return TRUE if it is equal to a character that should be ignored when
+ *  parsing names.
+ */
+#define MAX_NAME_COMPS         8
+#define isnamesepartor(x)      (isspace(x))
+#define isignorechar(x)                (((x) == '.') || ((x) == '_'))
+
+/*
+ *  Quite often a search will turn up more than one match.  When it does we
+ *  print out a list of the matches, and ask the user to select the one that
+ *  s/he wants.  This defines how many we will save and show.
+ */
+#define MAX_NUM_NAMES          128
+
+/*
+ *  When a user displays a group, we will automatically print out this many
+ *  members and subscribers.  If the number is greater than this, we will
+ *  prompt the user before printing them.
+ */
+#define TOO_MANY_TO_PRINT      16
+
+/*
+ *  This is the default size of a tty if we can't figure out the actual size.
+ */
+#define DEFAULT_TTY_HEIGHT     24
+#define DEFAULT_TTY_WIDTH      80
+
+/*
+ *  The number of attributes we know about must be less than this number.
+ *  Don't add lots of attributes to the list in globals.c without checking
+ *  this number too.
+ */
+#define MAX_ATTRS      64
+
+/*****************************************************************************
+ **
+ **            No user servicable parts beyond this point.
+ **
+ *****************************************************************************/
+
+/*
+ *  Generic buffer sizes.
+ */
+#define SMALL_BUF_SIZE          16
+#define MED_BUF_SIZE           128
+#define LARGE_BUF_SIZE         512
+
+/*
+ *  Used to specify the operation in x_group().
+ */
+#define G_JOIN         0
+#define G_RESIGN       1
+
+/*
+ *  Authentication method we will be using.
+ */
+#ifdef KERBEROS
+#define UD_AUTH_METHOD         LDAP_AUTH_KRBV4
+#else
+#define UD_AUTH_METHOD         LDAP_AUTH_SIMPLE
+#endif
+
+/*
+ *  TRUE and FALSE - just in case we need them.
+ */
+#ifndef TRUE
+#define TRUE  1
+#define FALSE 0
+#endif
+
+/*
+ *  Bound status.
+ */
+#define UD_NOT_BOUND   0       /* bound only as the default defined above */
+#define UD_BOUND       1       /* bound as an actual Directory entity */
+
+/* 
+ *  Debug masks.
+ */
+#define        D_TRACE         0x0001
+#define        D_FIND          0x0002
+#define D_GROUPS       0x0004
+#define D_MODIFY       0x0008
+#define D_PARSE                0x0010
+#define D_PRINT                0x0020
+#define D_AUTHENTICAT  0x0040
+#define D_INITIALIZE   0x0080
+
+/*
+ *  Used in the flags field of an attribute structure.
+ */
+#define ATTR_FLAG_NONE         0x0000
+#define ATTR_FLAG_PERSON       0x0001
+#define ATTR_FLAG_GROUP                0x0002
+#define ATTR_FLAG_PERSON_MOD   0x0010
+#define ATTR_FLAG_GROUP_MOD    0x0020
+#define ATTR_FLAG_MAY_EDIT     0x0040
+#define ATTR_FLAG_SEARCH       0x0100
+#define ATTR_FLAG_READ         0x0200
+#define ATTR_FLAG_IS_A_DATE    0x0800
+#define ATTR_FLAG_IS_A_DN      0x1000
+#define ATTR_FLAG_IS_A_URL     0x2000
+#define ATTR_FLAG_IS_A_BOOL    0x4000
+#define ATTR_FLAG_IS_MULTILINE 0x8000
+
+/*
+ *  These are the structures we use when parsing an answer we get from the LDAP
+ *  server.
+ */
+struct attribute {
+       char *quipu_name;
+       char *output_string;
+       void (*mod_func)();
+       unsigned short flags;
+       int number_of_values;
+       char **values;
+};
+
+struct entry {
+       char may_join;
+       int  subscriber_count;
+       char *DN;
+       char *name;
+       struct attribute attrs[MAX_ATTRS];
+};
diff --git a/clients/ud/util.c b/clients/ud/util.c
new file mode 100644 (file)
index 0000000..2edb5aa
--- /dev/null
@@ -0,0 +1,662 @@
+/*
+ * Copyright (c) 1992, 1993  Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <signal.h>
+#include <string.h>
+#ifdef DOS
+#include <malloc.h>
+#endif
+#include <memory.h>
+#if defined( NeXT )
+#include <stdlib.h>
+#endif
+#include <ctype.h>
+#include <errno.h>
+#include <lber.h>
+#include <ldap.h>
+#include <ldapconfig.h>
+#if !defined(DOS) && !defined( VMS)
+#include <sys/types.h>
+#endif
+#include "portable.h"
+#ifdef USE_TERMIOS
+#include <termios.h>
+#else /* USE_TERMIOS */
+#include <sgtty.h>
+#endif /* USE_TERMIOS */
+#include "ud.h"
+
+#if defined(VMS)
+#define getch getchar
+#endif
+
+#ifdef DEBUG
+extern int debug;
+#endif
+
+char * mygetpass(prompt)
+char *prompt;
+{
+#if defined(DOS) || defined(VMS)
+       static char buf[256];
+       int i, c;
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->mygetpass(%s)\n", prompt);
+#endif
+       printf("%s", prompt);
+       i = 0;
+       while ( (c = getch()) != EOF && c != '\n' && c != '\r' )
+               buf[i++] = c;
+       if ( c == EOF )
+               return( NULL );
+       buf[i] = '\0';
+       return (buf);
+#else
+       int no_pass = 0;
+       char i, j, k;
+       TERMIO_TYPE ttyb;
+       TERMFLAG_TYPE flags;
+       static char pbuf[513];
+       register char *p;
+       register int c;
+       FILE *fi;
+       SIG_FN (*sig)();
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->mygetpass(%s)\n", prompt);
+#endif
+       /*
+        *  Stolen from the getpass() routine.  Can't use the plain
+        *  getpass() for two reasons.  One is that X.500 passwords
+        *  can be really, really long - much longer than 8 chars.
+        *  The second is that we like to make this client available
+        *  out of inetd via a Merit asynch port, and we need to be
+        *  able to do telnet control codes to turn on and off line
+        *  blanking.
+        */
+       if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL)
+               fi = stdin;
+       else
+               setbuf(fi, (char *)NULL);
+       sig = signal(SIGINT, SIG_IGN);
+       if (fi != stdin) {
+               if (GETATTR(fileno(fi), &ttyb) < 0)
+                       perror("GETATTR");
+       }
+       flags = GETFLAGS( ttyb );
+       SETFLAGS( ttyb, flags & ~ECHO );
+       if (fi != stdin) {
+               if (SETATTR(fileno(fi), &ttyb) < 0)
+                       perror("SETATTR");
+       }
+
+       /*  blank the line if through Merit */
+       if (fi == stdin) {
+               printf("%c%c%c", 255, 251, 1);
+               fflush(stdout);
+               (void) scanf("%c%c%c", &i, &j, &k);
+               fflush(stdin);
+       }
+
+       /* fetch the password */
+       fprintf(stdout, "%s", prompt); 
+       fflush(stdout);
+       for (p=pbuf; (c = getc(fi))!='\n' && c!=EOF;) {
+               if (c == '\r')
+                       break;
+               if (p < &pbuf[512])
+                       *p++ = c;
+       }
+       if (c == EOF)
+               no_pass = 1;
+       else {
+               *p = '\0';
+               if (*(p - 1) == '\r')
+                       *(p - 1) = '\0';
+       }
+
+       /*  unblank the line if through Merit */
+       if (fi == stdin) {
+               printf("%c%c%c", 255, 252, 1);
+               fflush(stdout);
+               (void) scanf("%c%c%c", &i, &j, &k);
+               fflush(stdin);
+               printf("\n"); fflush(stdout);
+       }
+       fprintf(stdout, "\n"); 
+       fflush(stdout);
+
+       /* tidy up */
+       SETFLAGS( ttyb, flags );
+       if (fi != stdin) {
+               if (SETATTR(fileno(fi), &ttyb) < 0)
+                       perror("SETATTR");
+       }
+       (void) signal(SIGINT, sig);
+       if (fi != stdin)
+               (void) fclose(fi);
+       else
+               i = getchar();
+       if (no_pass)
+               return(NULL);
+       return(pbuf);
+#endif /* DOS */
+}
+
+void printbase(lead, s)
+char *lead, *s;
+{
+       register char **cp;
+       char **rdns;
+       char * friendly_name();
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->printbase(%s, %s)\n", lead, s);
+#endif
+       if (s == NULL) {
+               printf("%sroot\n", lead);
+               return;
+       }
+       printf("%s", lead);
+       rdns = ldap_explode_dn(s, TRUE);
+       for (cp = rdns; ; ) {
+               printf("%s", friendly_name(*cp));
+               cp++;
+               if (*cp == NULL) {
+                       printf("\n");
+                       break;
+               }
+               else
+                       printf(", ");
+       }
+       ldap_value_free(rdns);
+       return;
+}
+
+fetch_buffer(buffer, length, where)
+char *buffer;
+int length;
+FILE *where;
+{
+       extern LDAP *ld;
+       register int i;
+       char *p;
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->fetch_buffer(%x, %d, %x)\n", buffer, length, where);
+#endif
+       /*
+        *  Fetch a buffer and strip off any leading or trailing non-printing
+        *  characters, namely newlines and carriage returns.
+        */
+       if (fgets(buffer, length, where) == NULL) {
+               if (feof(where))
+                       errno = 0;       /* so fatal() doesn't bitch */
+               fatal("fgets");
+       }
+       for (i = strlen(buffer) - 1; i >= 0 && !isprint(buffer[i]); i--)
+               buffer[i] = '\0';
+
+       p = buffer;
+       while ( *p != '\0' ) {
+               if ( isprint( *p )) {
+                       ++p;
+               } else {
+                       strcpy( p, p + 1 ); 
+               }
+       }
+
+}
+
+fatal(s)
+char *s;
+{
+       void exit();
+
+       if (errno != 0)
+               perror(s);
+#ifdef KERBEROS
+       destroy_tickets();
+#endif
+       exit(-1);
+}
+
+isgroup()
+{
+       extern struct entry Entry;
+       char **vp;
+       register int i;
+       int group = FALSE;
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->isgroup()\n");
+#endif
+       if ((i = attr_to_index("objectClass")) == -1)
+               return(FALSE);
+       vp = Entry.attrs[i].values;
+       for (i = 0; *vp != NULL; vp++) {
+#ifdef DEBUG
+               i++;
+               if (debug & D_GROUPS)
+                       printf("class #%1d: (%s)\n", i, *vp);
+#endif
+               if (!strcmp(*vp, "rfc822MailGroup"))
+                       group = TRUE;
+       }
+       return(group);
+}
+
+/*
+ *  Print out the string 's' on a field of 'width' chracters.  Each line
+ *  should be indented 'lead' characters.
+ */
+format(str, width, lead)
+char *str;
+int width, lead;
+{
+       char *s, *original, *leader = "";
+       register char *cp;
+       void * Malloc();
+       void Free();
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("->format(%s, %d, %d)\n", str, width, lead);
+#endif
+       if (lead >= width) {
+               fprintf(stderr, "  Cannot format (%s, %d, %d)\n", str, width, lead);
+               return;
+       }
+       if (lead > 0) {
+               leader = (char *) Malloc((unsigned) (lead + 1));
+               (void) memset(leader, ' ', lead);
+               *(leader + lead) = '\0';
+       }
+
+       /*
+        *  Some compilers get really unhappy with this function since it
+        *  fiddles around with the first argument, which could be a string
+        *  constant.  We do a strdup() here so we can do whatever the hell
+        *  we want.
+        */
+       s = original = strdup(str);
+       for (;;) {
+               if ((strlen(s) + lead) < width) {
+                       printf("%s%s\n", leader, s);
+                       Free(leader);
+                       Free(original);
+                       return; 
+                       /*NOTREACHED*/
+               }
+               cp = s + width - lead;
+               while (!isspace(*cp) && (cp != s))
+                       cp--;
+               *cp = '\0';
+               while (isspace(*s))
+                       s++;
+               printf("%s%s\n", leader, s);
+               s = cp + 1;
+       }
+}
+
+/*
+ *  Print out the string 's' on a field of 'width' chracters.  The first line
+ *  should be indented 'first_indent' spaces, then followed by 'first_tag', 
+ *  and then followed by the first line of 's'.  Subsequent lines should be
+ *  indented 'indent' spaces, then followed by 'tag', and then followed by
+ *  subsequent lines of 's'.
+ */
+format2(s, first_tag, tag, first_indent, indent, width)
+char *s, *first_tag, *tag;
+int first_indent, indent, width;
+{
+       char c, *fi, *i;
+       register char *cp;
+       void * Malloc();
+       void Free();
+
+       if (first_tag == NULL)
+               first_tag = "";
+       if (tag == NULL)
+               tag = "";
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("format2(\"%s\", \"%s\", \"%s\", %1d, %1d, %1d)\n", s, 
+                               first_tag, tag, first_indent, indent, width);
+#endif
+
+       /* make sure the indents are sane */
+       if ((first_indent >= width) || (indent >= width)) {
+               fprintf(stderr, "  Cannot format:  indent too large\n");
+               return;
+       }
+
+       /* make the indentations */
+       if (first_indent > 0) {
+               fi = (char *) Malloc((unsigned) (first_indent + 1));
+               (void) memset(fi, ' ', first_indent);
+               *(fi + first_indent) = '\0';
+       }
+       else
+               fi = "";
+       if (indent > 0) {
+               i = (char *) Malloc((unsigned) (indent + 1));
+               (void) memset(i, ' ', indent);
+               *(i + indent) = '\0';
+       }
+       else
+               i = "";
+
+       /* now do the first line */
+       if ((strlen(s) + strlen(first_tag) + first_indent) < width) {
+               printf("%s%s%s\n", fi, first_tag, s);
+               Free(fi);
+               Free(i);
+               return; 
+               /*NOTREACHED*/
+       }
+
+       /*
+        *  's' points to the beginning of the string we want to print.
+        *  We point 'cp' to the end of the maximum amount of text we
+        *  can print (i.e., total width less the indentation and the
+        *  length of the tag).  Once we have set 'cp' initially we
+        *  back it up to the first space character.
+        */
+       cp = s + width - first_indent - strlen(first_tag);
+       while (!isspace(*cp) && (cp != s))
+               cp--;
+
+       /*
+        *  Once there, we change that space character to a null, print the
+        *  string, and then restore the space character.
+        */
+       c = *cp;
+       *cp = '\0';
+       printf("%s%s%s\n", fi, first_tag, s);
+       *cp = c;
+
+       /*
+        *  Since 'cp' may have been set to a space initially (and so no
+        *  back-tracking was performed), it could have a space after it
+        *  as well.  We should gobble up all of these since we don't want
+        *  unexpected leading blanks.
+        */  
+       for (s = cp + 1; isspace(*s); s++)
+               ;
+
+       /* now do all of the other lines */
+       for (;;) {
+               if ((strlen(s) + strlen(tag) + indent) < width) {
+                       printf("%s%s%s\n", i, tag, s);
+                       Free(fi);
+                       Free(i);
+                       return; 
+                       /*NOTREACHED*/
+               }
+               cp = s + width - indent - strlen(tag);
+               while (!isspace(*cp) && (cp != s))
+                       cp--;
+               c = *cp;
+               *cp = '\0';
+               printf("%s%s%s\n", i, tag, s);
+               s = cp + 1;
+               *cp = c;                        /* don't mess up 's' */
+       }
+}
+
+#define IN_A_QUOTE   0
+#define OUT_OF_QUOTE 1
+
+char * strip_ignore_chars(cp)
+char *cp;
+{
+       int had_a_comma = FALSE;
+       int flag = OUT_OF_QUOTE;
+       register char *rcp, *cp1;
+       char *tmp;
+       void * Malloc();
+       void Free();
+
+#ifdef DEBUG
+       if (debug & D_TRACE)
+               printf("strip_ignore_chars(%s)\n", cp);
+#endif
+       for (rcp = cp; *rcp != '\0'; rcp++)
+               if (isignorechar(*rcp) || (*rcp == '"'))
+                       break;
+       if (*rcp == '\0')
+               return(cp);
+
+       cp1 = tmp = (char *) Malloc((unsigned) strlen(cp));
+       for (rcp = cp; *rcp != '\0'; rcp++) {
+               /* toss quotes and flip the flag */
+               if (*rcp == '"')
+                       flag = OUT_OF_QUOTE - flag;
+               else if (isignorechar(*rcp)) {
+                       if (flag == OUT_OF_QUOTE)
+                               *cp1++ = ' ';
+                       else
+                               *cp1++ = *rcp;
+               }
+               else if (*rcp == ',') {
+                       *cp1++ = *rcp;
+                       had_a_comma = TRUE;
+               }
+               else 
+                       *cp1++ = *rcp;
+       }
+       *cp1 = '\0';
+
+       /* re-quote the name if it had a comma in it */
+       if (had_a_comma == TRUE) {
+               rcp = cp1 = (char *) Malloc((unsigned) (strlen(tmp) + 3));
+               *rcp++ = '"';
+               *rcp = '\0';
+               strcat(rcp, tmp);
+               strcat(rcp, "\"");
+               Free(tmp);
+               tmp = cp1;
+       }
+       return(tmp);
+}
+
+char * code_to_str(i)
+{
+       switch(i) {
+       case LDAP_MOD_ADD : return("ADD");
+       case LDAP_MOD_DELETE : return("DELETE");
+       case LDAP_MOD_REPLACE : return("REPLACE");
+       default : return("?????");
+       }
+}
+
+char * friendly_name(s)
+char *s;
+{
+       static FriendlyMap *map = NULL;
+       static char *cp;
+
+       cp = ldap_friendly_name(FRIENDLYFILE, s, &map);
+       if (cp == NULL)
+               return(s);
+       return(cp);
+}
+
+#ifdef UOFM
+
+/* return TRUE if s has the syntax of a uniqname */
+isauniqname(s)
+char *s;
+{
+       int i = strlen(s);
+
+       if ((i < 3) || (i > 8))         /* uniqnames are 3-8 chars */
+               return(FALSE);
+       if (!isalpha(*s))               /* uniqnames begin with a letter */
+               return(FALSE);
+       for ( ; *s != '\0'; s++)        /* uniqnames are alphanumeric */
+               if (!isalnum(*s))
+                       return(FALSE);
+       return(TRUE);
+}
+#endif
+
+/* return TRUE if this attribute should be printed as a DN */
+isadn(s)
+char *s;
+{
+       register int i;
+       extern struct attribute attrlist[];
+
+       for (i = 0; attrlist[i].quipu_name != NULL; i++)
+               if (!strcasecmp(s, attrlist[i].quipu_name))
+                       break;
+       if (attrlist[i].flags & ATTR_FLAG_IS_A_DN)
+               return(TRUE);
+       return(FALSE);
+}
+
+char * my_ldap_dn2ufn(s)
+char *s;
+{
+       register char **cpp;
+       static char short_DN[BUFSIZ];
+
+       if (strstr(s, UD_BASE) == NULL)
+               return(ldap_dn2ufn(s));
+       cpp = ldap_explode_dn(s, TRUE);
+       sprintf(short_DN, "%s, %s", *cpp, *(cpp + 1));
+       ldap_value_free(cpp);
+       return(short_DN);
+}
+
+/* return TRUE if this attribute should be printed as a URL */
+isaurl(s)
+char *s;
+{
+       register int i;
+       extern struct attribute attrlist[];
+
+       for (i = 0; attrlist[i].quipu_name != NULL; i++)
+               if (!strcasecmp(s, attrlist[i].quipu_name))
+                       break;
+       if (attrlist[i].flags & ATTR_FLAG_IS_A_URL)
+               return(TRUE);
+       return(FALSE);
+}
+
+/* return TRUE if this attribute should be printed as a date and time */
+isadate(s)
+char *s;
+{
+       register int i;
+       extern struct attribute attrlist[];
+
+       for (i = 0; attrlist[i].quipu_name != NULL; i++)
+               if (!strcasecmp(s, attrlist[i].quipu_name))
+                       break;
+       if (attrlist[i].flags & ATTR_FLAG_IS_A_DATE)
+               return(TRUE);
+       return(FALSE);
+}
+
+void * Malloc(size)
+unsigned int size;
+{
+       void *void_ptr;
+
+       void_ptr = (void *) malloc(size);
+       if (void_ptr == NULL) {
+               perror("malloc");
+               exit(-1);
+               /*NOTREACHED*/
+       }
+       return(void_ptr);
+}
+
+void Free(ptr)
+char *ptr;
+{
+       extern int free();
+
+       if (free(ptr) < 0) {
+               perror("free");
+               exit(-1);
+               /*NOTREACHED*/
+       }
+       return;
+}
+
+char * nextstr(s)
+char *s;
+{
+       while (isspace(*s) && (*s != '\0'))
+               s++;
+       if (s == NULL)
+               return(NULL);
+       if (*s == '\0')
+               return(NULL);
+       return(s);
+}
+
+void free_mod_struct(modp)
+LDAPMod *modp;
+{
+       void Free();
+
+       if (modp->mod_values != NULL)
+               (void) ldap_value_free(modp->mod_values);
+       Free(modp->mod_type);
+       Free(modp);
+}
+
+void StrFreeDup(ptr, new_value)
+char **ptr, *new_value;
+{
+       void Free();
+
+       if (*ptr != NULL)
+               Free(*ptr);
+       if (new_value == NULL)
+               *ptr = NULL;
+       else
+               *ptr = strdup(new_value);
+}
+
+
+confirm_action( msg )
+       char    *msg;
+{ 
+        char   tmp[SMALL_BUF_SIZE];
+       int     i;
+
+       if ( msg != NULL ) {
+               putchar( '\n' );
+               format( msg, 75, 2 );
+       }
+
+       printf("\n  Is this OK? ");
+       fflush(stdout);
+       tmp[0] = '\0';
+       fetch_buffer(tmp, sizeof(tmp), stdin);
+       i = strlen(tmp);
+       return( i > 0 &&
+           ( !strncasecmp(tmp, "YES", i) || !strncasecmp(tmp, "OK", i)));
+}
diff --git a/contrib/README b/contrib/README
new file mode 100644 (file)
index 0000000..488b167
--- /dev/null
@@ -0,0 +1,23 @@
+LDAP contrib README
+
+Contributed code lives underneath this contrib directory.  It is not as
+well-integrated into the LDAP build process as the rest of the LDAP
+distribution.  Please see the README files in each contrib subdirectory
+for build instructions.
+
+Current contributions:
+
+    saucer     General purpose command-line LDAP client, modeled
+               after ISODE's DISH (DIrectory SHell) client.
+               Contributed by Eric Rosenquist.  See saucer/README
+               and its man page for more information.
+
+    web500gw   HTTP gateway for X.500, modeled after go500gw.
+               Contributed by Frank Richter.  See web500gw/README
+               for more information.
+
+    whois++    WHOIS++ gateway to X.500.  Contributed by Mark Prior.
+               See whois++/README for more information.
+
+
+Please send your contributions to ldap-support@umich.edu
diff --git a/contrib/saucer/Make-template b/contrib/saucer/Make-template
new file mode 100644 (file)
index 0000000..cdd9233
--- /dev/null
@@ -0,0 +1,54 @@
+# Makefile for LDAP "saucer" client
+
+HDIR   = $(LDAPSRC)/include
+INSTMAN        = $(MANDIR)/man$(SECT)
+LDAPSRC        = ../..
+LDIR   = $(LDAPSRC)/libraries
+SECT   = 1
+VERFILE        = $(LDAPSRC)/build/version
+
+CFLAGS = -I$(HDIR) $(DEFINES) $(ACFLAGS)
+SRCS   = main.c
+OBJS   = $(SRCS:.c=.o)
+LIBS   = -lldap -llber $(KRBLIBFLAG) $(KRBLIBS) $(ALIBS)
+
+all:   saucer
+
+saucer:        $(OBJS)
+       $(CC) $(ALDFLAGS) -o $@ $(OBJS) -L$(LDIR) $(LIBS)
+
+protoize: $(SRCS)
+       protoize -c "$(CFLAGS)" $(SRCS)
+
+unprotoize: $(SRCS)
+       unprotoize -c "$(CFLAGS)" $(SRCS)
+
+install:       saucer FORCE
+       -$(MKDIR) -p $(BINDIR)
+       $(INSTALL) $(INSTALLFLAGS) -m 755 saucer $(BINDIR)
+       -$(MKDIR) -p $(INSTMAN)
+       @TMPMAN=/tmp/ldapman.$$$$; \
+       VERSION=`$(CAT) $(VERFILE)`; \
+       for page in *.$(SECT); do \
+           $(SED) -e 's%ETCDIR%$(ETCDIR)%' -e "s%LDVERSION%$$VERSION%" \
+                   $$page > $$TMPMAN; \
+           echo "installing $(INSTMAN)/$$page"; \
+           $(INSTALL) $(INSTALLFLAGS) -m 644 $$TMPMAN $(INSTMAN)/$$page; \
+       done; \
+       $(RM) $$TMPMAN
+
+lint:   FORCE
+       $(LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+5lint:  FORCE
+       $(5LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+clean:  FORCE
+       $(RM) *.o core a.out saucer
+
+depend: FORCE
+       $(MKDEP) $(INCLUDES) $(DEFINES) $(SRCS)
+
+links:
+       @$(LN) .src/*.[ch] .
+
diff --git a/contrib/saucer/README b/contrib/saucer/README
new file mode 100644 (file)
index 0000000..f45dd8e
--- /dev/null
@@ -0,0 +1,41 @@
+This directory contains a set of files that build a simple LDAP client
+program.  The program is command-line oriented and uses a syntax and
+command set roughly similar to ISODE's DISH program, hence it is
+named "saucer" (i.e. a very small "dish" :-)
+
+To build saucer, make sure the top-level LDAP 'make' has created all
+of the makefiles from their templates (you can force this by typing
+"make makefiles" in the LDAP root directory).  Then cd into
+contrib/saucer and type make.  With luck, saucer will compile and
+link without any warnings or errors.  You can then install it by
+doing an "su" and typing "make install".  This will copy the binary
+to the directory you specified for LDAP binaries, and the man page
+will be placed in the appropriate man directory.
+
+Saucer runs from the Unix command line with the following arguments:
+
+  saucer [-h host] [-p portnumber] [-u X500UserName]
+         [-c credentials] [-d debug-level]
+
+If no options are given, saucer will attempt to connect to an LDAP
+daemon on the local host and default port (389), and will attempt to
+bind anonymously.
+
+Typing "help" at saucer's command prompt will yield:
+
+Cmd? help
+Supported commands are:
+  help
+  list
+  moveto
+  quit
+  search
+  set
+  show
+
+You can get syntactical help for a command by typing "help <command>".
+Detailed instructions are available from the saucer man page.
+
+Any comments or questions should be directed to:
+
+      Eric.Rosenquist@strataware.com
diff --git a/contrib/saucer/main.c b/contrib/saucer/main.c
new file mode 100644 (file)
index 0000000..b664c5a
--- /dev/null
@@ -0,0 +1,690 @@
+/*
+ * Copyright (c) 1994, Strata Software Limited, Ottawa, Ontario, Canada.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to Eric Rosenquist and Strata Software Limited. The SSL name
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided "as is" without express or implied warranty.
+ *
+ *
+ * 'saucer' LDAP command-line client source code.
+ *
+ * Author: Eric Rosenquist, 1994.
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <lber.h>
+#include <ldap.h>
+
+#define DN_MAXLEN      4096
+
+typedef struct {
+       char    *cmd;
+       int             (*func)();
+       char    *help_msg;
+} CMDTABLE;
+
+typedef enum {
+       CMD_HELP,
+       CMD_LIST,
+       CMD_MOVETO,
+       CMD_QUIT,
+       CMD_SEARCH,
+       CMD_SET,
+       CMD_SHOW
+} COMMAND;
+
+char           *attrs_null[] = { "0.10", NULL };
+char           *credentials;
+char           default_dn[DN_MAXLEN];
+char           *hostname = "127.0.0.1";
+LDAP           *ld;
+extern char    *optarg;
+extern int     opterr;
+extern int     optind;
+int                    option;
+int                    portnum = LDAP_PORT;
+char           *progname;
+char           true_filter[] = "objectClass=*";        /* Always succeeds */
+char           *username;
+
+int                    cmd_help(char **cmdargv, int cmdargc);
+int                    cmd_list(char **cmdargv, int cmdargc);
+int                    cmd_moveto(char **cmdargv, int cmdargc);
+int                    cmd_quit(char **cmdargv, int cmdargc);
+int                    cmd_search(char **cmdargv, int cmdargc);
+int                    cmd_set(char **cmdargv, int cmdargc);
+int                    cmd_show(char **cmdargv, int cmdargc);
+char           *make_dn(char *dn, int relative);
+char           *skip_to_char(register char *s, register int c);
+char           *skip_to_whitespace(register char *s);
+char           *skip_whitespace(register char *s);
+FILE           *user_tailor(void);
+
+static char    *binary_attrs[] = { "audio", "jpegPhoto", "personalSignature", "photo" };
+
+CMDTABLE       cmdtable[] = {
+       "help"  , cmd_help  , "[command]",
+       "list"  , cmd_list  , "[RDN-or-DN] [-absolute]",
+       "moveto", cmd_moveto, "[RDN-or-DN] [-absolute]",
+       "quit"  , cmd_quit  , "",
+       "search", cmd_search, "<filter> [-object RDN-or-DN] [-absolute]\n\t\t[-scope base|onelevel|subtree]",
+       "set"   , cmd_set   , "[-aliasderef never|search|find|always] [-sizelimit N] [-timelimit seconds]",
+       "show"  , cmd_show  , "[RDN-or-DN] [-absolute]"
+};
+
+
+int bind_user(void)
+{
+       if (ldap_simple_bind_s(ld, username, credentials) != LDAP_SUCCESS) {
+               ldap_perror(ld, progname);
+               return 0;
+       }
+       if (username)
+               printf("Bound to ldap server as `%s' (%s authentication)\n", username,
+                          credentials ? "simple" : "no");
+       else
+               puts("Bound anonymously to ldap server");
+
+       return 1;
+}
+
+int cmd_help(char **cmdargv, int cmdargc)
+{
+       int             i;
+
+       if (cmdargc == 2) {
+               for (i = 0; i < sizeof(cmdtable) / sizeof(cmdtable[0]); i++)
+                       if (strncasecmp(cmdargv[1], cmdtable[i].cmd, strlen(cmdargv[1])) == 0) {
+                               show_syntax(i);
+                               return 0;
+                       }
+               cmdargc = 1;    /* Command not found - make it display the list of commands */
+       }
+
+       if (cmdargc == 1) {
+               puts("\nType 'help <command>' for help on a particular command.\n\n"
+                        "Supported commands are:");
+               for (i = 0; i < sizeof(cmdtable) / sizeof(cmdtable[0]); i++)
+                       printf("  %s\n", cmdtable[i].cmd);
+               puts("\nArguments to commands are separated by whitespace.  Single (')\n"
+                        "or double (\") quotes must be used around arguments that contain\n"
+                        "embedded whitespace characters.\n");
+       } else
+               show_syntax(CMD_HELP);
+
+       return 0;
+}
+
+int cmd_list(char **cmdargv, int cmdargc)
+{
+       char            *dn      = NULL;
+       int                     errflag  = 0;
+       int                     i;
+       static char     *opts[]  = { "absolute" };
+       int                     relative = 1;
+       LDAPMessage     *result;
+
+       for (i = 1; i < cmdargc; i++) {
+               if (cmdargv[i][0] == '-') {
+                       switch (table_lookup(cmdargv[i] + 1, opts, sizeof(opts) / sizeof(opts[0]))) {
+                       case 0:
+                               relative = 0;
+                               break;
+                       default:
+                               errflag = 1;
+                       }
+               } else {
+                       if (dn)
+                               errflag = 1;
+                       else
+                               dn = cmdargv[i];
+               }
+       }
+
+       if (errflag) {
+               show_syntax(CMD_LIST);
+               return 0;
+       }
+
+       if (ldap_search(ld, make_dn(dn, relative), LDAP_SCOPE_ONELEVEL,
+                                       true_filter, attrs_null, 1) == -1) {
+               ldap_perror(ld, progname);
+               return 0;
+       }
+
+       if (ldap_result(ld, LDAP_RES_ANY, 1, (struct timeval *)0, &result) == -1) {
+               ldap_perror(ld, progname);
+               return 0;
+       }
+
+       display_search_results(result);
+               
+       return 0;
+}
+
+int cmd_moveto(char **cmdargv, int cmdargc)
+{
+       char            *dn      = NULL;
+       int                     errflag  = 0;
+       char            **exploded_dn;
+       int                     i;
+       static char     *opts[]  = { "absolute" };
+       int                     relative = 1;
+
+       for (i = 1; i < cmdargc; i++) {
+               if (cmdargv[i][0] == '-') {
+                       switch (table_lookup(cmdargv[i] + 1, opts, sizeof(opts) / sizeof(opts[0]))) {
+                       case 0:
+                               relative = 0;
+                               break;
+                       default:
+                               errflag = 1;
+                       }
+               } else {
+                       if (dn)
+                               errflag = 1;
+                       else
+                               dn = cmdargv[i];
+               }
+       }
+
+       if (errflag) {
+               show_syntax(CMD_MOVETO);
+               return 0;
+       }
+
+       if (dn) {
+               if (is_whitespace(dn))
+                       default_dn[0] = 0;
+               else {
+                       if (strcmp(dn, "..") == 0) {
+                               /* Move up one level */
+                               if (exploded_dn = ldap_explode_dn(default_dn, 0)) {
+                                       if (exploded_dn[0]) {
+                                               char    **rdn;
+
+                                               default_dn[0] = 0;
+                                               for (rdn = exploded_dn + 1; *rdn; rdn++) {
+                                                       if (default_dn[0])
+                                                               strcat(default_dn, ", ");
+                                                       strcat(default_dn, *rdn);
+                                               }
+                                       }
+                                       ldap_value_free(exploded_dn);
+                               }
+                       } else {
+                               /* Use ldap_explode_dn() to parse the string & test its syntax */
+                               if (exploded_dn = ldap_explode_dn(dn, 1)) {
+                                       if (relative  &&  !is_whitespace(default_dn)) {
+                                               char    buf[DN_MAXLEN];
+
+                                               strcpy(default_dn, strcat(strcat(strcpy(buf, dn), ", "), default_dn));
+                                       } else
+                                               strcpy(default_dn, dn);
+                                       ldap_value_free(exploded_dn);
+                               } else
+                                       puts("Invalid distinguished name.");
+                       }
+               }
+       }
+
+       printf("Distinguished name suffix is `%s'\n", default_dn);
+
+       return 0;
+}
+
+int cmd_quit(char **cmdargv, int cmdargc)
+{
+       return 1;
+}
+
+int cmd_search(char **cmdargv, int cmdargc)
+{
+       char            *dn           = NULL;
+       int                     errflag       = 0;
+       char            *filter       = NULL;
+       int                     i, j;
+       static char     *opts[]       = { "absolute", "object", "scope" };
+       int                     relative      = 1;
+       LDAPMessage     *result;
+       static char     *scope_opts[] = { "base", "onelevel", "subtree" };
+       static int      scope_vals[]  = { LDAP_SCOPE_BASE, LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBTREE };
+       static int      search_scope  = LDAP_SCOPE_ONELEVEL;
+
+       for (i = 1; i < cmdargc; i++) {
+               if (cmdargv[i][0] == '-') {
+                       switch (table_lookup(cmdargv[i] + 1, opts, sizeof(opts) / sizeof(opts[0]))) {
+                       case 0:
+                               relative = 0;
+                               break;
+                       case 1:
+                               if (++i < cmdargc)
+                                       dn = cmdargv[i];
+                               else
+                                       errflag = 1;
+                               break;
+                       case 2:
+                               if ((++i < cmdargc)  &&
+                                       (j = table_lookup(cmdargv[i], scope_opts, sizeof(scope_opts) / sizeof(scope_opts[0]))) >= 0)
+                                       search_scope = scope_vals[j];
+                               else
+                                       errflag = 1;
+                               break;
+                       default:
+                               errflag = 1;
+                       }
+               } else {
+                       if (filter)
+                               errflag = 1;
+                       else
+                               filter = cmdargv[i];
+               }
+       }
+
+       if (errflag  ||  !filter) {
+               show_syntax(CMD_SEARCH);
+               return 0;
+       }
+
+       if (ldap_search(ld, make_dn(dn, relative), search_scope, filter, attrs_null, 0) == -1) {
+               ldap_perror(ld, progname);
+               return 0;
+       }
+
+       if (ldap_result(ld, LDAP_RES_ANY, 1, (struct timeval *)0, &result) == -1) {
+               ldap_perror(ld, progname);
+               return 0;
+       }
+
+       display_search_results(result);
+               
+       return 0;
+}
+
+int cmd_set(char **cmdargv, int cmdargc)
+{
+       static char     *alias_opts[] = { "never", "search", "find", "always" };
+       int                     errflag       = 0;
+       int                     i, j;
+       static char     *opts[]       = { "aliasderef", "sizelimit", "timelimit" };
+
+       for (i = 1; i < cmdargc; i++) {
+               if (cmdargv[i][0] == '-') {
+                       switch (table_lookup(cmdargv[i] + 1, opts, sizeof(opts) / sizeof(opts[0]))) {
+                       case 0:
+                               if ((++i < cmdargc)  &&
+                                       (j = table_lookup(cmdargv[i], alias_opts, sizeof(alias_opts) / sizeof(alias_opts[0]))) >= 0)
+                                       ld->ld_deref = j;
+                               else
+                                       errflag = 1;
+                               break;
+                       case 1:
+                               if (++i < cmdargc)
+                                       ld->ld_sizelimit = atoi(cmdargv[i]);
+                               else
+                                       errflag = 1;
+                               break;
+                       case 2:
+                               if (++i < cmdargc)
+                                       ld->ld_timelimit = atoi(cmdargv[i]);
+                               else
+                                       errflag = 1;
+                               break;
+                       default:
+                               errflag = 1;
+                       }
+               } else
+                       errflag = 1;
+       }
+
+       if (errflag)
+               show_syntax(CMD_SET);
+       else
+               printf("Alias dereferencing is %s, Sizelimit is %d entr%s, Timelimit is %d second%s.\n",
+                          alias_opts[ld->ld_deref],
+                          ld->ld_sizelimit, ld->ld_sizelimit == 1 ? "y" : "ies",
+                          ld->ld_timelimit, ld->ld_timelimit == 1 ? ""  : "s");
+
+       return 0;
+}
+
+int cmd_show(char **cmdargv, int cmdargc)
+{
+       char            *dn      = NULL;
+       LDAPMessage     *entry;
+       int                     errflag  = 0;
+       int                     i;
+       static char     *opts[]  = { "absolute" };
+       int                     relative = 1;
+       LDAPMessage     *result;
+
+       for (i = 1; i < cmdargc; i++) {
+               if (cmdargv[i][0] == '-') {
+                       switch (table_lookup(cmdargv[i] + 1, opts, sizeof(opts) / sizeof(opts[0]))) {
+                       case 0:
+                               relative = 0;
+                               break;
+                       default:
+                               errflag = 1;
+                       }
+               } else {
+                       if (dn)
+                               errflag = 1;
+                       else
+                               dn = cmdargv[i];
+               }
+       }
+
+       if (errflag) {
+               show_syntax(CMD_SHOW);
+               return 0;
+       }
+
+       if (ldap_search(ld, make_dn(dn, relative), LDAP_SCOPE_BASE, true_filter, NULL, 0) == -1) {
+               ldap_perror(ld, progname);
+               return 0;
+       }
+
+       if (ldap_result(ld, LDAP_RES_ANY, 1, (struct timeval *)0, &result) == -1) {
+               ldap_perror(ld, progname);
+               return 0;
+       }
+
+       display_search_results(result);
+               
+       return 0;
+}
+
+display_search_results(LDAPMessage *result)
+{
+       BerElement      *cookie;
+       int                     i;
+       LDAPMessage     *entry;
+       int                     maxname;
+       char            *s;
+
+       for (entry = ldap_first_entry(ld, result); entry; entry = ldap_next_entry(ld, entry)) {
+               if (s = ldap_get_dn(ld, entry)) {
+                       printf("  %s\n", s);
+                       free(s);
+               }
+
+               /* Make one pass to calculate the length of the longest attribute name */
+               maxname = 0;
+               for (s = ldap_first_attribute(ld, entry, &cookie); s; s = ldap_next_attribute(ld, entry, cookie))
+                       if ((i = strlen(s)) > maxname)
+                               maxname = i;
+
+               /* Now print the attributes and values */
+               for (s = ldap_first_attribute(ld, entry, &cookie); s; s = ldap_next_attribute(ld, entry, cookie)) {
+                       char    **values;
+
+                       if (table_lookup(s, binary_attrs, sizeof(binary_attrs) / sizeof(binary_attrs[0])) >= 0)
+                               continue;       /* Skip this attribute - it's binary */
+
+                       printf("    %-*s - ", maxname, s);
+
+                       /* Now print each of the values for the given attribute */
+                       if (values = ldap_get_values(ld, entry, s)) {
+                               char    **val;
+
+                               for (val = values; *val; ) {
+                                       char    *nl;
+                                       char    *v = *val;
+
+                                       /* Watch out for values that have embedded \n characters */
+                                       while (nl = strchr(v, '\n')) {
+                                               *nl = 0;
+                                               puts(v);
+                                               v = nl + 1;
+                                               if (*v)
+                                                       printf("    %*s", maxname + 3, "");
+                                       }
+                                       if (*v)
+                                               puts(v);
+                                       if (*++val)
+                                               printf("    %*s", maxname + 3, "");
+                               }
+                               ldap_value_free(values);
+                       } else
+                               putchar('\n');
+               }
+       }
+
+       if (ldap_result2error(ld, result, 0))
+               ldap_perror(ld, progname);
+}
+
+int do_command(char *cmd)
+{
+       char    *cmdargv[128];
+       int             cmdargc = 0;
+       int             i;
+
+       /* Tokenize the input command, allowing for quoting */
+       for (;;) {
+               cmd = skip_whitespace(cmd);
+               if (!cmd  ||  !*cmd)
+                       break;  /* end of input */
+
+               cmdargv[cmdargc++] = cmd;
+               if (*cmd == '\''  ||  *cmd == '"') {
+                       cmdargv[cmdargc - 1]++;         /* Skip over the opening quote */
+                       cmd = skip_to_char(cmd + 1, *cmd);
+                       if (!cmd  ||  !*cmd) {
+                               puts("Command is missing a trailing quote");
+                               return 0;
+                       }
+                       *cmd++ = 0;
+               } else {
+                       cmd = skip_to_whitespace(cmd);
+                       if (cmd  &&  *cmd)
+                               *cmd++ = 0;
+               }
+       }
+
+#ifdef DEBUG
+       printf("cmdargc = %d\n", cmdargc);
+       for (i = 0; i < cmdargc; i++)
+               puts(cmdargv[i]);
+#endif
+       
+       if (cmdargv[0][0] == '?')
+               return cmd_help(cmdargv, cmdargc);
+
+       for (i = 0; i < sizeof(cmdtable) / sizeof(cmdtable[0]); i++)
+               if (strncasecmp(cmdargv[0], cmdtable[i].cmd, strlen(cmdargv[0])) == 0)
+                       return (*cmdtable[i].func)(cmdargv, cmdargc);
+
+       if (!is_whitespace(cmdargv[0])) {
+               printf("Unrecognized command - %s\n", cmdargv[0]);
+               cmd_help(cmdargv, 1);
+       }
+
+       return 0;
+}
+
+void do_commands(FILE *file)
+{
+       char    cmd_buf[BUFSIZ];
+       int             tty = isatty(fileno(file));
+
+       for (;;) {
+               if (tty)
+                       printf("Cmd? ");
+               if (!fgets(cmd_buf, sizeof(cmd_buf), file))
+                       break;
+               if (do_command(cmd_buf))
+                       break;
+       }
+}
+
+int is_whitespace(register char *s)
+{
+       if (!s)
+               return 1;
+
+       while (*s  &&  isspace(*s))
+               ++s;
+
+       return !*s;
+}
+
+int main(int argc, char **argv)
+{
+       int             error_flag = 0;
+       FILE    *rc;
+
+       progname = argv[0];
+       while ((option = getopt(argc, argv, "h:p:u:c:d:")) != EOF)
+               switch (option) {
+               case 'c':
+                       credentials = optarg;
+                       break;
+               case 'd':
+#ifdef LDAP_DEBUG
+                       lber_debug = atoi(optarg);
+                       ldap_debug = atoi(optarg);
+#endif
+                       break;
+               case 'h':
+                       hostname = optarg;
+                       break;
+               case 'p':
+                       portnum = atoi(optarg);
+                       break;
+               case 'u':
+                       username = optarg;
+                       break;
+               case '?':
+                       error_flag = 1;
+               }
+
+       if (error_flag) {
+               fprintf(stderr, "usage: %s [-h host] [-p portnumber] [-u X500UserName]\n\t[-c credentials] [-d debug-level]\n",
+                               progname);
+               exit(2);
+       }
+
+       rc = user_tailor();
+
+       if (!(ld = ldap_open(hostname, portnum))) {
+               fprintf(stderr, "%s: unable to connect to server at host `%s' on port %d\n",
+                               progname, hostname, portnum);
+               exit(2);
+       }
+
+       if (!bind_user())
+               return 1;
+
+       if (rc) {
+               do_commands(rc);
+               fclose(rc);
+       }
+       do_commands(stdin);
+
+       ldap_unbind(ld);
+
+       return 0;
+}
+
+char *make_dn(char *dn, int relative)
+{
+       static char     dn_buf[DN_MAXLEN];
+       char            *s;
+
+       if (!dn)
+               dn = "";
+
+       if (!default_dn[0]  ||  !relative)
+               return dn;
+
+       if (!dn[0])
+               return default_dn;
+
+       return strcat(strcat(strcpy(dn_buf, dn), ", "), default_dn);
+}
+
+show_syntax(int cmdnum)
+{
+       printf("Syntax: %s %s\n", cmdtable[cmdnum].cmd, cmdtable[cmdnum].help_msg);
+}
+
+char *skip_to_char(register char *s, register int c)
+{
+       if (!s)
+               return s;
+
+       while (*s  &&  *s != c)
+               ++s;
+
+       return s;
+}
+
+char *skip_to_whitespace(register char *s)
+{
+       if (!s)
+               return s;
+
+       while (*s  &&  !isspace(*s))
+               ++s;
+
+       return s;
+}
+
+char *skip_whitespace(register char *s)
+{
+       if (!s)
+               return s;
+
+       while (*s  &&  isspace(*s))
+               ++s;
+
+       return s;
+}
+
+int table_lookup(char *word, char **table, int table_count)
+{
+       register int    i;
+       int                             wordlen;
+
+       if (!word  ||  !*word)
+               return -1;
+
+       wordlen = strlen(word);
+
+       for (i = 0; i < table_count; i++)
+               if (strncasecmp(word, table[i], wordlen) == 0)
+                       return i;
+       return -1;
+}
+
+FILE *user_tailor(void)
+{
+       char    rcfile[BUFSIZ];
+
+       rcfile[0] = 0;
+
+#ifdef unix
+       {
+#include <pwd.h>
+               struct passwd   *pwent;
+
+               if (pwent = getpwuid(getuid()))
+                       strcat(strcpy(rcfile, pwent->pw_dir), "/");
+               strcat(rcfile, ".saucerrc");
+       }
+#else
+       strcpy(rcfile, "saucer.rc");
+#endif
+
+       return fopen(rcfile, "r");
+}
diff --git a/contrib/saucer/sample.saucerrc b/contrib/saucer/sample.saucerrc
new file mode 100644 (file)
index 0000000..b3d2e47
--- /dev/null
@@ -0,0 +1,2 @@
+set -aliasderef always -sizelimit 25 -timelimit 30
+moveto "o=Enterprise Solutions Limited, c=CA"
diff --git a/contrib/saucer/saucer.1 b/contrib/saucer/saucer.1
new file mode 100644 (file)
index 0000000..37a6a23
--- /dev/null
@@ -0,0 +1,186 @@
+.TH SAUCER 1 "December 3 1994" "U-M LDAP LDVERSION"
+.UC 6
+.SH NAME
+saucer \- interactive X.500 Directory client program
+.SH SYNOPSIS
+\fBsaucer\fR [-h \fIhost\fR] [-p \fIportnumber\fR] [-u \fIX500UserName\fR]
+[-c \fIcredentials\fR] [-d \fIdebug-level\fR]
+.SH DESCRIPTION
+\fIsaucer\fR is used to navigate and perform searches on an X.500
+Directory via the Lightweight Directory Access Protocol (LDAP).
+.SH OPTIONS
+.TP 5
+.B \-h hostname
+Used to specify the name or IP number of an LDAP host to which saucer
+should connect.  If this flag is omitted, \fI127.0.0.1\fR is used.
+.TP 5
+.B \-p portnumber
+Used to specify the TCP port number of the LDAP daemon on the server
+host.  If this flag is omitted, the LDAP default port number
+(\fI389\fR) is used.
+.TP 5
+.B \-u X500UserName
+Specifies the X.500 name to be used when binding to the directory
+server.  It must be in the form specified by RFC 1485, for example:
+
+\fB"cn=George Castanza, o=Vandelay Industries, c=US"\fR
+
+Don't forget to put quotes around the name if it contains blanks.
+.TP 5
+.B \-c credentials
+Specifies the credentials, i.e. the password, to be used when binding
+to the directory server.  If this flag is omitted but a name is given
+with the \fB-u\fR flag, an unauthenticated bind will be attempted.  If
+neither flag is given, an anonymous bind will be attempted.
+.TP 5
+.B \-d debug-level
+Sets the LDAP debug mask to the numeric value specified.  This flag is
+only used if saucer was compiled with the LDAP_DEBUG flag.
+.SH COMMANDS
+\fIsaucer\fR commands consist of a keyword followed by zero or more
+arguments.  Commands and arguments can be shortened to any number of
+characters; the entered text is matched against the available keywords
+in ascending alphabetical order.  For example, entering the command
+\fB"s"\fR will be interpreted by \fIsaucer\fR as the \fBsearch\fR
+command, and \fB"sh"\fR will be interpreted as the \fBshow\fR command.
+The \fBset\fR command cannot be abbreviated since both \fB"s"\fR and
+\fB"se"\fR will be interpreted as the \fBsearch\fR command.
+
+Arguments to commands are separated by whitespace (blanks or tabs), so
+any values that contain whitespace (such as X.500 names) need to be
+enclosed in single or double quotes.
+
+Arguments can be entered in any order.  If the same argument appears
+more than once in a command, the last value is used and the others are
+ignored.
+
+Directory names are by default assumed to be relative to the
+\fIcurrent location\fR, which is set with the \fBmoveto\fR command.
+All commands that accept a directory name have an optional
+\fI-absolute\fR flag which causes \fIsaucer\fR to interpret the name
+as a complete X.500 name rather than one that is relative to the
+current location.
+.SS "help [command]"
+Provides brief online help giving the available commands and their syntax.
+
+If \fIcommand\fR is specified, the syntax for the command is shown.
+``help'' by itself simply provides a list of the available commands.
+.SS "list [RDN/DN] [-absolute]"
+Displays the names of a directory node's subordinates.
+
+If an \fIRDN/DN\fR is given, it specifies the entry whose subordinates
+are to be listed.  In its absence, the current location (see the
+\fBmoveto\fR command) is used.  The \fI-absolute\fR argument controls
+whether the \fIRDN/DN\fR is a complete directory name or is relative
+to the current location.
+.SS "moveto [RDN/DN] [-absolute]"
+Displays or modifies \fIsaucer\fR's \fIcurrent location\fR in the
+directory.  Without arguments, the current location is displayed.
+If an \fIRDN/DN\fR is given, the current location is modified
+and the new value is displayed.
+
+The \fI-absolute\fR flag causes \fIsaucer\fR to treat the entered
+\fIRDN/DN\fR as a complete directory name and to use it as the
+new current location.  Without the \fI-absolute\fR flag, the
+name is assumed to be relative to the previous location.
+
+The special value \fB".."\fR is recognized by \fIsaucer\fR as a
+valid name and causes the current location to be moved one level
+up (towards the root) in the directory.
+.SS quit
+Unbinds from the directory and exits \fIsaucer\fR.
+.SS "search <filter> [-object RDN/DN] [-absolute] [-scope <scope>]"
+Searches the directory for entries which match the \fI<filter>\fR
+expression.  For more information on the syntax of the \fI<filter>\fR
+argument, see "RFC 1588 - A String Representation of LDAP Search
+Filters".
+
+If the \fI-object\fR argument is used, it specifies the base of the
+directory search.  In its absence, the current location (see the
+\fBmoveto\fR command) is used as the search base.  The \fI-absolute\fR
+argument controls whether the \fIRDN/DN\fR given with the
+\fI-object\fR flag is a complete directory name or is relative to the
+current location.
+
+The \fI-scope\fR argument controls the depth of the search.  It
+accepts one of the keywords \fIbase\fR, \fIonelevel\fR, or
+\fIsubtree\fR to search within the base object, its immediate
+children, or all of its subordinates respectively.  The search depth
+is preserved across commands, so subsequent searches will use the
+previously entered depth setting if a new one is not given.
+\fISaucer\fR defaults to a \fIonelevel\fR search depth at startup.
+.SS "set [-aliasderef <deref>] [-sizelimit N] [-timelimit seconds]"
+Displays or modifies settings which apply to all directory operations
+issued by \fIsaucer\fR.  Without arguments, the current settings are
+displayed.  If options are given, the settings are changed and the new
+values are displayed.
+
+The \fI-aliasderef <deref>\fR argument controls how the directory
+handles alias entries that it encounters.  The value of \fI<deref>\fR
+must be one of \fInever\fR, \fIsearch\fR, \fIfind\fR, or \fIalways\fR.
+
+A value of \fInever\fR tells the directory not to follow through any
+aliases it encounters.
+
+A value of \fIfind\fR tells the directory to follow through an alias
+if it occurs as the base of a \fBlist\fR, \fBsearch\fR, or \fBshow\fR
+command.
+
+A value of \fIsearch\fR tells the directory to follow through an alias
+when performing a \fBsearch\fR command.  In other words, when
+performing a search, the attributes of the entry an alias points to
+will be tested against the filter expression rather than the alias
+itself.
+
+A value of \fIalways\fR combines the meanings of the \fIfind\fR and
+\fIsearch\fR values, i.e., aliases are always dereferenced before
+being acted upon.
+
+The \fI-sizelimit N\fR argument sets the maximum number of entries
+that will be returned by directory for \fBlist\fR and \fBsearch\fR
+commands to \fIN\fR.  The directory server itself may impose a limit,
+in which case the lesser of the two limits is used.  A value of
+\fI0\fR may be used to request as many entries as possible.
+
+The \fI-timelimit seconds\fR argument sets the maximum amount of time
+allowed for a \fBlist\fR, \fBsearch\fR, or \fBshow\fR command.  Note
+that this value is simply passed to the directory server, so the
+enforcement of the time limit is up to the server.  A value of \fI0\fR
+may be used to request no time limit.
+.SS "show [RDN/DN] [-absolute]"
+Displays the attributes of a directory entry.
+
+If an \fIRDN/DN\fR is given, it specifies the entry whose attributes
+are to be shown.  In its absence, the current location (see the
+\fBmoveto\fR command) is used.  The \fI-absolute\fR argument controls
+whether the \fIRDN/DN\fR is a complete directory name or is relative
+to the current location.
+
+The attributes \fIaudio\fR, \fIjpegPhoto\fR, \fIpersonalSignature\fR,
+and \fIphoto\fR are known by \fIsaucer\fR to be binary values and are
+therefore not displayed.  Other attributes which have binary encodings
+will be displayed by \fIsaucer\fR and will probably appear as garbage
+on the screen.
+.SH FILES
+~/.saucerrc    The saucer startup command file.
+.SH "SEE ALSO"
+ldap(3), RFC 1485, RFC 1588
+.SH DIAGNOSTICS
+\fIsaucer\fR uses the ldap_perror() routine to print a message
+whenever an error is returned by the Directory server or the LDAP
+library.
+.SH "TO DO"
+The new LDAP 3.1 ldap_XXX2text() routines should be used instead of
+the code built into saucer.
+
+The ability to read the X500UserName and credentials from the
+~/.saucerrc file should be added.  There should also be a way to have
+saucer prompt the user for their password.
+
+Attribute types which are binary are hard-coded into saucer.  Ideally
+saucer should also try to detect which ones aren't displayable at
+runtime.
+.SH AUTHOR
+Eric Rosenquist, Enterprise Solutions Limited.
+.br
+Eric.Rosenquist@esltd.com
diff --git a/contrib/web500gw/README b/contrib/web500gw/README
new file mode 100644 (file)
index 0000000..cca2bfc
--- /dev/null
@@ -0,0 +1,11 @@
+At the time of this release, the web500gw World Wide Web/HTTP to
+X.500/LDAP gateway is between major releases.  Rather than include
+outdated sources, we have included pointers to sites maintained by the
+author so that you can obtain the latest web500gw sources yourself:
+
+    home page URL:  http://www.tu-chemnitz.de/~fri/web500gw/
+     ftp site URL:  ftp://isode.tu-chemnitz.de/pub/other-src/
+
+Any comments of questions should be directed to:
+
+    Frank.Richter@hrz.tu-chemnitz.de
diff --git a/contrib/whois++/BUGS b/contrib/whois++/BUGS
new file mode 100644 (file)
index 0000000..70739bb
--- /dev/null
@@ -0,0 +1,37 @@
+This is not really a bugs list (would I admit to having bugs? :-) but a
+limitations list.
+
+This implementation attempts to implement most of the proposed whois++
+interface but those sections that conflict with the underlying X.500 service
+are not implemented. This includes such things as the indexing service. While
+it would be possible to provide this functionality it is likely that a
+production X.500 Directory will have restrictions on access to the Directory
+in order to prevent "trawling" of data. It is unlikely that such a site
+would wish to allow an indexing server carte blanche access to it's data in
+order to index it.
+
+The current version also doesn't support multiple languages, this is not
+because I don't think it's a good idea (I do), but rather due to my wish to
+get this thing out of the door! As a result of this attributes are returned
+using their X.500 attribute names rather than using "whois++" names. Once
+the code to do multi-lingual support has been integrated these attributes
+will be returned in the natural language specified by the client.
+
+Some responses are returned as system messages, and some are returned as
+normal messages (with or without a leading space). At present there is no
+real consistancy, which is a result of me coding whatever I thought was best
+at the time. The current draft lacks adequate direction (except for search
+results) as to the format of responses but once this has been fixed I will
+correct the code.
+
+I am using a beta version of the LDAP beta code (possibly not the latest
+version) to develop this code but you should be able to use any of the
+University of Michigan releases, although the patches to the main Makefile
+may need some tweaking.
+
+This program has only really been tested with Ultrix although John Farrell
+of the ISODE Consortium threw it at SunOS for me so it may work with other
+Unix variants but there are no guarantees.
+
+Mark Prior
+26 April 93
diff --git a/contrib/whois++/INSTALL b/contrib/whois++/INSTALL
new file mode 100644 (file)
index 0000000..b612369
--- /dev/null
@@ -0,0 +1,65 @@
+I assume that you have already obtained the LDAP libraries and installed
+them in the appropriate place. This kit should fit into the directory
+structure created by LDAP. You should use the root.Makefile.diffs file to
+patch the LDAP Makefile so that it knows how to build whois++. This may fail
+depending on what version of LDAP you have but the rejections should be
+trival to fix (hopefully UMich will release a new version RSN).
+
+This program makes use of a number of definitions defined in the main LDAP
+Makefile but it also has a number of it's own definitions that you will
+have to modify (all definitions are located in the Makefile).
+
+CONFIG_DIRECTORY       At present the configuration directory only contains
+       the template directory. The files in this directory contain the
+       attribute fields to return when a template is returned. The objectClass
+       of an object determines the whois++ template.
+
+HELP_DIRECTORY         The server has a number of help files that it may
+       display when queried by a client. These files are stored under the
+       specific language.
+
+LDAPHOST               Which host is running a ldap server. This program
+       communicates to the X.500 Directory via LDAP so you must be able to
+       identify a host that is able to provide this communication.
+
+FACILITY               Some error diagnostics are reported via syslog, as is
+       normal queries if logging is enabled. This variable specifies which
+       facility to use. I use local3 so I can create a separate log file just
+       for whois++ but you may wish to log under daemon.
+
+SYSLIBS                        Any additional libraries required. Ultrix requires -li
+       to get the Internationalisation support. I also use -lsyslog in order
+       to link with a 4.3BSD style syslog rather than the ancient syslog that
+       DEC normally ship with Ultrix.
+
+INTERNATIONAL          Define this is you have POSIX international support.
+       At present this is only used for displaying dates so it's not really
+       important but I intend to use this facility to support the language
+       constraint in a future release.
+       Available under Ultrix but not SunOS.
+
+Once you have modified these variable you should be able to just type "make",
+if you are in the whois++ directory, or "make ldap-whois++" from the main
+LDAP directory. All going well there should be no problems so "make install",
+or "make inst-whois++".
+
+You should now copy the tailor file (whois++dtailor) to the ETCDIR and modify
+the base statement to indicate to whois++ where in the DIT whois++ should base
+its searches. You may also wish to define a user and password if you need to
+authenticate the server.
+
+Modify /etc/inetd.conf to include the new whois++ service with a line such as
+       whois stream tcp nowait ETCDIR/whois++d whois++d
+where ETCDIR is the value of your ETCDIR variable.
+You might like to add the -l flag (if you want to log queries) and -i if you
+have an info attribute in the base entry (this will be displayed as a system
+message).
+
+Now send a HUP (or kill and restart) /etc/inetd.
+
+Note that if you turn on RFC931 lookups you will need the rfc931.c
+module from Wietse Venema's log_tcp package (archie should be able to find
+you a copy).
+
+Mark Prior
+mrp@itd.adelaide.edu.au
diff --git a/contrib/whois++/Makefile b/contrib/whois++/Makefile
new file mode 100644 (file)
index 0000000..a2f9b2e
--- /dev/null
@@ -0,0 +1,81 @@
+#
+# Configuration parameters, can be overridden in config file
+#
+LDAPSRC                = ../..
+CONFIG_DIRECTORY       =       $(ETCDIR)/whois++
+HELP_DIRECTORY =       /usr/local/isode/help/whois++
+LDAPHOST       = "localhost"
+#
+# Where to stuff the man page
+MANDIR         = /usr/local/isode/man
+MANSEC         = 8
+#
+# Syslog facility to log queries under, using info serverity level
+#
+FACILITY       = LOG_LOCAL3
+#
+# Additional system libraries
+# Under Ultrix I use the 4.3 syslog, hence the additional syslog library
+#
+#SYSLIBS       = -li -lsyslog
+#
+# If you want RFC931 logging you must have log_tcp source available
+#
+SRCS   = whois++.c command.c config.c describe.c help.c output.c template.c \
+         util.c version.c # /local/src/log_tcp/rfc931.c
+HDRS   = whois++.h
+OBJS   = ${SRCS:.c=.o}
+HOST   = `hostname`
+# This returns a date such as "26 April 1993", unfortunately SunOS doesn't
+# understand the %B abd %Y macros so you may need to change this.
+#DATE  = `date +'%d %B %Y'`
+DATE   = `date +'%D'`  # this gives 4/26/93 format
+REVISION       = 2
+
+DEFINES = -DETCDIR=\"$(ETCDIR)\" -DBUILD="\"$(USER)@$(HOST) on $(DATE)\"" \
+         -DCONFIG_DIRECTORY=\"$(CONFIG_DIRECTORY)\" -DMAIN \
+         -DHELP_DIRECTORY=\"$(HELP_DIRECTORY)\" -DREVISION="$(REVISION)" \
+         -DPROTOCOL="\"[FIRST DRAFT - 15 April 1993]\"" -DRELEASE=\"BETA\" \
+         -DFACILITY=$(FACILITY) -DDEFAULT_LDAPHOST=\"$(LDAPHOST)\" # -DRFC931
+
+CFLAGS = -I$(LDAPSRC)/include -I/usr/local/include $(ACFLAGS)
+LIBS   = -L$(LDAPSRC)/libraries/libldap -lldap -L$(LDAPSRC)/libraries/liblber \
+        -llber $(SYSLIBS) $(KRBLIBFLAG) $(KRBLIBS)
+
+all:   whois++d
+
+whois++d:      $(OBJS) $(LDAPSRC)/libraries/libldap/libldap.a
+       $(CC) $(ALDFLAGS) -o $@ $(OBJS) $(LIBS)
+
+whois++.o:     whois++.c $(HDRS)
+       $(CC) $(CFLAGS) $(DEFINES) -c whois++.c
+
+install:       inst-whois++
+
+inst-whois++:  $(ETCDIR)/whois++d
+       -mkdir -p $(CONFIG_DIRECTORY)
+       cp -r templates $(CONFIG_DIRECTORY)
+       -mkdir -p $(HELP_DIRECTORY)
+       cp -r helpfiles/* $(HELP_DIRECTORY)
+       sed -e 's#ETCDIR#$(ETCDIR)#' whois++d.man > $(MANDIR)/man$(MANSEC)/whois++d.$(MANSEC)
+       @echo "Don't forget to modify and install the tailor file"
+
+$(ETCDIR)/whois++d:    whois++d
+       install -c -m 755 whois++d $(ETCDIR)
+
+lint:;
+       lint $(SRCS)
+
+5lint:;
+       /usr/5bin/lint $(SRCS)
+
+clean:;
+       rm -f *.o core a.out whois++d
+
+depend:;
+       ../mkdep $(CFLAGS) $(SRCS)
+
+# DO NOT DELETE THIS LINE -- mkdep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/contrib/whois++/README b/contrib/whois++/README
new file mode 100644 (file)
index 0000000..f480669
--- /dev/null
@@ -0,0 +1,23 @@
+This is a DUA interface, using LDAP, that conforms to the latest (not yet)
+Internet Draft for the Whois++ Architecture. It does NOT support the indexing
+service also proposed under Whois++.
+
+It is a gateway to X.500 (similar to the finger and gopher gateways) which
+allows the user to access the directory via a mechanism that they are
+comfortable with and/or have access to. The real Directory Service (and the
+only practical large scale distributed directory service) is provided by the
+underlying X.500 service. This implementation is not an endorsement of Whois++
+but I recognise that there are users whose only interface to a directory
+service is via a whois client. It therefore attempts to service these users,
+much like the other two gateways.
+
+Comments on the Whois++ specification should be sent to the IETF Whois and
+Network Information Lookup Service (WNILS) Working Group. The e-mail address
+of the group is ietf-wnils@ucdavis.edu, to be added to the mailing list send
+a request to ietf-wnils-request@ucdavis.edu. Comments about this program
+should be directed to the discussion list ldap-whois++@itd.adelaide.edu.au,
+(send a message to ldap-whois++-request@itd.adelaide.edu.au to join). I will
+post bug fix announcements to this list.
+
+Mark Prior
+6 May 93
diff --git a/contrib/whois++/TODO b/contrib/whois++/TODO
new file mode 100644 (file)
index 0000000..67ce90a
--- /dev/null
@@ -0,0 +1,9 @@
+               Things to do list (well the start of one anyway :-)
+
+. Test on something other than Ultrix
+. Finish the multilingual support.
+. Make the parser for the query "language" more error resistant
+. Do a real parser for the config file
+. More help files
+. Think about multi charset, although this is probably an issue for LDAP
+. Kerberos authentication
diff --git a/contrib/whois++/command.c b/contrib/whois++/command.c
new file mode 100644 (file)
index 0000000..7c57b8b
--- /dev/null
@@ -0,0 +1,748 @@
+#if !defined(lint)
+static char copyright[] = "Copyright 1992 The University of Adelaide";
+#endif
+
+/*
+ *                     C O M M A N D
+ *
+ * Author:     Mark R. Prior
+ *             Communications and Systems Branch
+ *             Information Technology Division
+ *             The University of Adelaide
+ * E-mail:     mrp@itd.adelaide.edu.au
+ * Date:       October 1992
+ * Version:    1.8
+ * Description:
+ *             Interpret the command sent by the client
+ *
+ * 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 Adelaide. 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.
+ */
+
+#include "whois++.h"
+
+extern char    *index(), *rindex();
+
+#define        isspecial(c)    ( (c) == ',' || (c) == ';' || (c) == ':' || (c) == '=' )
+
+static char    **component = NULL;
+static int     numberOfComponents;
+static int     components = 10;
+
+static int getToken( token )
+char   *token;
+
+{
+       static char     *buffer = NULL;
+       static int      idx;
+       char            ch;
+       fd_set          readfds;
+       struct timeval  timeout;
+       int             i, status, tablesize;
+
+       if ( buffer == NULL ) {
+               tablesize = getdtablesize();
+               timeout.tv_sec = 60;
+               timeout.tv_usec = 0;
+               FD_ZERO( &readfds );
+               FD_SET( fileno( stdin ), &readfds );
+
+               if ( (status = select( tablesize, &readfds, 0, 0, &timeout )) <= 0 ) {
+                       if ( status < 0 )
+                               printFormatted( lineLength, TRUE, stdout,
+                                       "select: %s", strerror( errno ) );
+                       else
+                               printFormatted( lineLength, TRUE, stdout,
+                                       "Connection timed out waiting for input." );
+                       exit( 1 );
+               }
+/**/           /*
+                * We really should determine how many characters are
+                * waiting for us and then malloc that amount rather than
+                * just guessing!
+                */
+               if ( ( buffer = (char *)malloc(BUFSIZ) ) == NULL
+                       || fgets( buffer, BUFSIZ, stdin ) == NULL ) {
+                       *token = '\0';
+                       return EOF;
+               }
+               idx = 0;
+               i = strlen( buffer );
+               while ( i-- > 0 && ( buffer[i] == '\r' || buffer[i] == '\n' ) )
+                       buffer[i] = '\0';
+               if ( log )
+                       syslog( LOG_INFO, "Whois++ Query: %s", buffer );
+       }
+       while ( buffer[idx] != '\0' && isspace( buffer[idx] ) )
+               idx++;
+       token[0] = buffer[idx++];
+       token[1] = '\0';
+       switch ( token[0] ) {
+       case '\0':
+               strcpy( token, "<end of line>" );
+               free( buffer );
+               buffer = NULL;
+               return EOF;
+
+       case '^':
+               return TEMPLATE;
+
+       case '!':
+               return HANDLE;
+
+       case '.':
+               return ATTRIBUTE;
+
+       case '#':
+               return VALUE;
+
+       case '*':
+               return SEARCH_ALL;
+
+       case '?':
+               return HELP;
+
+       case ':':
+               return COLON;
+
+       case ';':
+               return SEMICOLON;
+
+       case ',':
+               return COMMA;
+
+       case '=':
+               return EQUALS;
+
+       case '"':
+               i = 0;
+               do {
+                       ch = buffer[idx++];
+                       if ( ch == '\\' && buffer[idx] != '\0' )
+                               token[i++] = buffer[idx++];
+                       else
+                               token[i++] = ch;
+               } while ( ch != '\0' && ch != '"' );
+               if ( ch == '\0' ) {
+                       printFormatted( lineLength, TRUE, stdout,
+                               "Trailing \" missing" );
+                       idx--;
+               }
+               token[--i] = '\0';
+               return SEARCH;
+
+       default:
+               i = 1;
+               do {
+                       ch = buffer[idx++];
+                       if ( ch == '\\' && buffer[idx] != '\0' )
+                               token[i++] = buffer[idx++];
+                       else
+                               token[i++] = ch;
+               } while ( ch != '\0' && !isspace( ch ) && !isspecial( ch ) );
+               token[--i] = '\0';
+               idx--;
+/**/           /*
+                * The following is a brute force lookup, once the names
+                * have settled down this should change to a hash table,
+                * or something similar.
+                */
+               if ( EQ( token, "help" ) )
+                       return HELP;
+               else if ( EQ( token, "list" ) )
+                       return LIST;
+               else if ( EQ( token, "show" ) )
+                       return SHOW;
+               else if ( EQ( token, "constraints" ) )
+                       return CONSTRAINTS;
+               else if ( EQ( token, "describe" ) )
+                       return DESCRIBE;
+               else if ( EQ( token, "version" ) )
+                       return VERSION;
+               else if ( EQ( token, "template" ) )
+                       return TEMPLATE;
+               else if ( EQ( token, "handle" ) )
+                       return HANDLE;
+               else if ( EQ( token, "attribute" ) )
+                       return ATTRIBUTE;
+               else if ( EQ( token, "value" ) )
+                       return VALUE;
+               else if ( EQ( token, "full" ) )
+                       return FULL;
+               else if ( EQ( token, "abridged" ) )
+                       return ABRIDGED;
+               else if ( EQ( token, "summary" ) )
+                       return SUMMARY;
+               else if ( EQ( token, "format" ) )
+                       return FORMAT;
+               else if ( EQ( token, "hold" ) )
+                       return HOLD;
+               else if ( EQ( token, "maxhits" ) )
+                       return MAXHITS;
+               else if ( EQ( token, "match" ) )
+                       return MATCH;
+               else if ( EQ( token, "linelength" ) )
+                       return LINE_LENGTH;
+               else if ( EQ( token, "command" ) )
+                       return COMMAND;
+               else if ( EQ( token, "trace" ) )
+                       return TRACE;
+               else
+                       return SEARCH;
+       }
+}
+
+static int term( token, value, attribute, specifier, soundex )
+int    token;
+char   *value, *attribute;
+int    *specifier, *soundex;
+{
+       char    buffer[BUFSIZ], temp[BUFSIZ];
+       int     iterations;
+
+       *soundex = FALSE;
+       switch ( token ) {
+       case ATTRIBUTE: /* . */
+       case VALUE:     /* # */
+       case HANDLE:    /* ! */
+       case TEMPLATE:  /* ^ */
+       case SEARCH_ALL:/* * */
+               *specifier = token;
+               if ( strlen( value ) > 1 ) {
+                       /* fullname used, so expect an equals sign */
+                       if ( getToken( buffer ) != EQUALS ) {
+                               printFormatted( lineLength, TRUE, stdout,
+                                       "\"=\" expected" );
+                               return ERROR;
+                       } else
+                               token = getToken( value );
+               } else 
+                       token = getToken( value );
+               if ( token != COMMA && token != SEMICOLON && token != EQUALS
+                       && token != COLON && token != EOF ) {
+                       token = getToken( buffer );
+                       break;
+               }
+
+       case COMMA:
+       case SEMICOLON:
+       case EQUALS:
+       case COLON:
+       case EOF:
+               printFormatted( lineLength, TRUE, stdout,
+                       "Expected search string but got \"%s\"", buffer );
+               return ERROR;
+
+       default:
+               *specifier = SEARCH_ALL;
+               if ( ( token = getToken( buffer ) ) == EQUALS ) {
+                       strcpy( attribute, value );
+                       token = getToken( value );
+                       if ( token == COMMA || token == SEMICOLON
+                               || token == COLON || token == EOF ) {
+                               printFormatted( lineLength, TRUE, stdout,
+                                       "Syntax error, string expected." );
+                               return ERROR;
+                       }
+                       token = getToken( buffer );
+               }
+       }
+
+       while ( token != COMMA && token != SEMICOLON && token != COLON
+               && token != EOF ) {
+               if ( *value != '\0' )
+                       strcat( value, " " );
+               strcat( value, buffer );
+               token = getToken( buffer );
+       }
+       iterations = 2;
+       while ( token == COMMA ) {
+               token = getToken( buffer );
+               switch ( token ) {
+               case MATCH:
+                       iterations = 0;
+                       if ( ( token = getToken( buffer ) ) != EQUALS ) {
+                               printFormatted( lineLength, TRUE, stdout,
+                                       "\"=\" expected" );
+                       } else
+                               token = getToken( buffer );
+                       if ( EQ( buffer, "exact" ) )
+                               *soundex = FALSE;
+                       else if ( EQ( buffer, "fuzzy" ) )
+                               *soundex = TRUE;
+                       else
+                               printFormatted( lineLength, TRUE, stdout,
+                                       "Unrecognised search type" );
+                       token = getToken( buffer );
+                       break;
+
+               default:
+                       if ( iterations == 0 ) {
+                               /* obviously an unrecognised constraint */
+                               printFormatted( lineLength, TRUE, stdout,
+                                       "Constraint \"%s\" not supported",
+                                       buffer );
+                               while ( ( token = getToken( buffer ) ) != EOF
+                                       && token != COMMA && token != COLON
+                                       && token != SEMICOLON )
+                                       ;
+                       } else {
+                               strcpy( temp, buffer );
+                               token = getToken( buffer );
+                               if ( token == EQUALS ) {
+                                       iterations = 0;
+                                       printFormatted( lineLength, TRUE, stdout,
+                                               "Constraint \"%s\" not supported",
+                                               buffer );
+                               }
+                               while ( token != EOF && token != SEMICOLON
+                                       && token != COLON && token != COMMA ) {
+                                       if ( iterations > 0 ) {
+                                               strcat( temp, " " );
+                                               strcat( temp, buffer );
+                                       }
+                                       token = getToken( buffer );
+                               }
+                               if ( iterations > 0 ) {
+                                       printFormatted( lineLength, TRUE, stdout,
+                                               "Assuming \"%s\" part of query and not an unrecognised constraint.", temp );
+                                       strcat( value, "," );
+                                       strcat( value, temp );
+                               }
+                       }
+                       break;
+
+               }
+               iterations--;
+       }
+       if ( *value == '\0' ) {
+               printFormatted( lineLength, TRUE, stdout,
+                       "Value not specified" );
+               return ERROR;
+       }
+       if ( *specifier == NULL )
+               *specifier = SEARCH_ALL;
+       return token;
+}
+
+static int processTerm( specifier, soundex, buffer, attribute, value )
+int    specifier, soundex;
+char   *buffer, *attribute, *value;
+
+{
+       char    *s, *t;
+       char    query[BUFSIZ];
+       char    **reallocResult;
+
+       switch ( specifier ) {
+       case SEARCH_ALL:
+               if ( numberOfComponents+3 >= components ) {
+                       components += 10;
+                       reallocResult = (char **)realloc(component, sizeof(char **)*components);
+                       if ( reallocResult == NULL ) {
+                               printFormatted( lineLength, TRUE, stdout,
+                                       "Realloc failed" );
+                               return ERROR;
+                       } else
+                               component = reallocResult;
+               }
+               if ( attribute != NULL && *attribute != '\0' ) {
+                       /* The user obviously knows what they are doing */
+                       sprintf( query, "(%s%s%s)", attribute,
+                               (soundex)?"~=":"=", buffer );
+               } else {
+                       if ( ( s = index( buffer, ',' ) ) != NULL ) {
+                               *s++ = '\0';
+                               while ( *s && isspace( *s ) )
+                                       s++;
+                               sprintf( query, "(sn%s%s)",
+                                       (soundex)?"~=":"=", buffer );
+                               component[numberOfComponents++] = strdup( query );
+                               /* let's just make sure there is no title */
+                               if ( ( t = rindex( s, ',' ) ) != NULL ) {
+                                       *t++ = '\0';
+                                       while ( *t && isspace( *t ) )
+                                               t++;
+                                       sprintf( query, "(personalTitle%s%s)",
+                                               (soundex)?"~=":"=", t );
+                                       component[numberOfComponents++] = strdup( query );
+                               }
+                               sprintf( query, "%s %s", s, buffer );
+                               strcpy( buffer, query );
+                       } else if ( strncasecmp( buffer, "first ", 6 ) == 0 ) {
+                               sprintf( query, "%s *", &buffer[6] );
+                               strcpy( buffer, query );
+                       }
+                       if ( ( s = index( buffer, '@' ) ) != NULL ) {
+                               *s++ = '\0';
+                               if ( *buffer == '\0' ) /* no username */
+                                       sprintf( query, "(mail=*@%s)", s );
+                               else if ( *s == '\0' ) /* no host */
+                                       sprintf( query, "(|(mail=%s@*)(userid=%s))",
+                                               buffer, buffer );
+                               else
+                                       sprintf( query, "(mail=%s@%s)",
+                                               buffer, s );
+                               if ( soundex )
+                                       printFormatted( lineLength, TRUE, stdout,
+                                               "Fuzzy matching not supported on e-mail address queries" );
+                       } else if ( index( buffer, ' ' ) == NULL ) {
+                               sprintf( query,
+                                       "(|(sn%s%s)(userid%s%s)(l%s%s)(ou%s%s)\
+(&(cn%s%s)(!(objectClass=person))))",
+                                       (soundex)?"~=":"=", buffer,
+                                       (soundex)?"~=":"=", buffer,
+                                       (soundex)?"~=":"=", buffer,
+                                       (soundex)?"~=":"=", buffer,
+                                       (soundex)?"~=":"=", buffer );
+                       } else {
+#if defined(UOFA)
+                               sprintf( query, "(|(l%s%s)(ou%s%s)(preferredName%s%s)",
+                                       (soundex)?"~=":"=", buffer,
+                                       (soundex)?"~=":"=", buffer,
+                                       (soundex)?"~=":"=", buffer );
+#else
+                               sprintf( query, "(|(l%s%s)(ou%s%s)",
+                                       (soundex)?"~=":"=", buffer,
+                                       (soundex)?"~=":"=", buffer );
+#endif
+                               /*
+                                * If LDAP and/or Quipu didn't strip spaces
+                                * then this would be different but as it does
+                                * this is easy :-) but it also means we might
+                                * get false hits.
+                                */
+                               if ( soundex ) {
+                                       strcat( query, "(cn~=" );
+                                       strcat( query, buffer );
+                               } else {
+                                       strcat( query, "(cn=*" );
+                                       strcat( query, strtok( buffer, " " ) );
+                                       while ( ( s = strtok( NULL, " " ) ) != NULL ) {
+                                               strcat( query, " * " );
+                                               strcat( query, s );
+                                       }
+                               }
+                               strcat( query, "))" );
+                       }
+               }
+               component[numberOfComponents++] = strdup( query );
+               break;
+
+       case ATTRIBUTE:
+               if ( numberOfComponents+1 >= components ) {
+                       components += 10;
+                       reallocResult = (char **)realloc(component, sizeof(char **)*components);
+                       if ( reallocResult == NULL ) {
+                               printFormatted( lineLength, TRUE, stdout,
+                                       "Realloc failed" );
+                               return ERROR;
+                       } else
+                               component = reallocResult;
+               }
+               if ( *value != '\0' ) {
+                       sprintf( query, "(%s%s%s)", buffer,
+                               (soundex)?"~=":"=", value );
+                       component[numberOfComponents++] = strdup( query );
+                       *value = '\0';
+               } else {
+                       if ( *attribute != '\0' ) {
+                               sprintf( query, "(%s%s*)", attribute,
+                                       (soundex)?"~=":"=" );
+                               component[numberOfComponents++] = strdup( query );
+                       }
+                       strcpy( attribute, buffer );
+               }
+               break;
+
+       case TEMPLATE:
+               if ( numberOfComponents+1 >= components ) {
+                       components += 10;
+                       reallocResult = (char **)realloc(component, sizeof(char **)*components);
+                       if ( reallocResult == NULL ) {
+                               printFormatted( lineLength, TRUE, stdout,
+                                       "Realloc failed" );
+                               return ERROR;
+                       } else
+                               component = reallocResult;
+               }
+               sprintf( query, "(objectClass%s%s)",
+                       (soundex)?"~=":"=", templateToObjectClass( buffer ) );
+               component[numberOfComponents++] = strdup( query );
+               break;
+
+       case VALUE:
+               if ( *attribute != '\0' ) {
+                       if ( numberOfComponents+1 >= components ) {
+                               components += 10;
+                               reallocResult = (char **)realloc(component, sizeof(char **)*components);
+                               if ( reallocResult == NULL ) {
+                                       printFormatted( lineLength, TRUE, stdout,
+                                               "Realloc failed" );
+                                       return ERROR;
+                               } else
+                                       component = reallocResult;
+                       }
+                       sprintf( query, "(%s%s%s)", attribute,
+                               (soundex)?"~=":"=", buffer );
+                       component[numberOfComponents++] = strdup( query );
+                       *attribute = '\0';
+               } else {
+                       if ( *value != '\0' )
+                               printFormatted( lineLength, TRUE, stdout,
+                                       "Ignoring old value (%s)", value );
+                       strcpy( value, buffer );
+               }
+               break;
+
+       case HANDLE:
+               if ( numberOfComponents+1 >= components ) {
+                       components += 10;
+                       reallocResult = (char **)realloc(component, sizeof(char **)*components);
+                       if ( reallocResult == NULL ) {
+                               printFormatted( lineLength, TRUE, stdout,
+                                       "Realloc failed" );
+                               return ERROR;
+                       } else
+                               component = reallocResult;
+               }
+               component[numberOfComponents++] = strdup( buffer );
+               return READ;
+
+       }
+       return SEARCH;
+}
+
+int    parseCommand( query )
+char   *query;
+{
+       /*
+        * This procedure reads the string sent by the user and breaks it
+        * down into command to execute.
+        */
+       char    buffer[BUFSIZ], attribute[BUFSIZ], objectClass[BUFSIZ],
+               value[BUFSIZ];
+       char    **reallocResult;
+       int     command, specificName, length, token, i, j, specifier, soundex;
+       int     trace = FALSE;
+
+       switch ( command = getToken( buffer ) ) {
+       case COMMAND:
+       case CONSTRAINTS:
+       case DESCRIBE:
+       case VERSION:
+               /* <command> */
+               token = getToken( buffer );
+               break;
+
+       case HELP:
+       case LIST:
+               /* <command> [ <string> ] */
+               if ( ( token = getToken( buffer ) ) != EOF && token != COLON ) {
+                       strcpy( query, buffer );
+                       token = getToken( buffer );
+               } else
+                       *query = '\0';
+               break;
+
+       case SHOW:
+               /* "show" <string> */
+               if ( ( token = getToken( buffer ) ) != EOF && token != COLON ) {
+                       strcpy( query, buffer );
+                       token = getToken( buffer );
+               } else {
+                       printFormatted( lineLength, TRUE, stdout,
+                               "Show must have a parameter" );
+                       return ERROR;
+               }
+               break;
+
+       default:
+               /* <term> [ ";" <term> ] */
+               *attribute = '\0';
+               *value = '\0';
+               soundex = FALSE;
+               numberOfComponents = 0;
+               if ( ( component = (char **)malloc(sizeof(char **)*components) ) == NULL ) {
+                       printFormatted( lineLength, TRUE, stdout,
+                               "Malloc failed" );
+                       return ERROR;
+               }
+               if ( ( token = term( command, buffer, attribute, &specifier,
+                       &soundex ) ) != ERROR )
+                       command = processTerm( specifier, soundex, buffer,
+                               attribute, value );
+               else
+                       return ERROR;
+               if ( token == SEMICOLON ) {
+                       if ( command == READ ) {
+                               printFormatted( lineLength, TRUE, stdout,
+                                       "Multiple components on a Handle query not supported." );
+                               return ERROR;
+                       }
+                       do {
+                               soundex = FALSE;
+                               token = getToken( buffer );
+                               token = term( token, buffer, attribute,
+                                       &specifier, &soundex );
+                               command = processTerm( specifier, soundex,
+                                       buffer, attribute, value );
+                               if ( command == READ ) {
+                                       printFormatted( lineLength, TRUE, stdout,
+                                               "Multiple components on a Handle query not supported." );
+                                       return ERROR;
+                               } else if ( command == ERROR )
+                                       return ERROR;
+                       } while ( token == SEMICOLON );
+               }
+               /*
+                * Need to tidy up outstanding single value or attribute terms
+                */
+               if ( *attribute != '\0' ) {
+                       if ( numberOfComponents+1 >= components ) {
+                               components += 10;
+                               reallocResult = (char **)realloc(component, sizeof(char **)*components);
+                               if ( reallocResult == NULL ) {
+                                       printFormatted( lineLength, TRUE, stdout,
+                                               "Realloc failed" );
+                                       return ERROR;
+                               } else
+                                       component = reallocResult;
+                       }
+                       sprintf( query, "(%s%s*)", attribute,
+                               (soundex)?"~=":"=" );
+                       component[numberOfComponents++] = strdup( query );
+               }
+               if ( *value != '\0' )
+                       if ( processTerm( SEARCH_ALL, soundex, value, NULL, NULL ) == ERROR )
+                               return ERROR;
+               if ( numberOfComponents == 0 ) {
+                       printFormatted( lineLength, TRUE, stdout,
+                               "NULL query." );
+                       return ERROR;
+               } else if ( numberOfComponents == 1 )
+                       strcpy( query, component[0] );
+               else {
+                       strcpy( query, "(&" );
+                       for ( i = 0; i < numberOfComponents; i++ )
+                               strcat( query, component[i] );
+                       strcat( query, ")" );
+               }
+               free( component );
+               break;
+
+       }
+       if ( token == COLON ) { /* global constraints */
+               do {
+                       token = getToken( buffer );
+                       switch ( token ) {
+                       case FORMAT:
+                               if ( ( token = getToken( buffer ) ) != EQUALS ) {
+                                       printFormatted( lineLength, TRUE, stdout, "\"=\" expected" );
+                               } else
+                                       token = getToken( buffer );
+                               switch ( token ) {
+                               case FULL:
+                               case ABRIDGED:
+                               case HANDLE:
+                               case SUMMARY:
+                                       if ( outputFormat != NULL )
+                                               printFormatted( lineLength, TRUE, stdout, "Only one response format can be specified." );
+                                       else
+                                               outputFormat = token;
+                                       break;
+
+                               default:
+                                       printFormatted( lineLength, TRUE, stdout, "Unrecognised format specifier" );
+                               }
+                               token = getToken( buffer );
+                               break;
+
+                       case HOLD:
+                               holdConnection = TRUE;
+                               token = getToken( buffer );
+                               break;
+
+                       case MAXHITS:
+                               if ( ( token = getToken( buffer ) ) != EQUALS ) {
+                                       printFormatted( lineLength, TRUE, stdout, "\"=\" expected" );
+                               } else
+                                       token = getToken( buffer );
+                               if ( (maxHits = atoi( buffer )) < 1 
+                                       || maxHits > maximumSize ) {
+                                       printFormatted( lineLength, TRUE, stdout, "Invalid maxhits value, defaulting to %s", maximumSize );
+                                       maxHits = maximumSize;
+                               }
+                               token = getToken( buffer );
+                               break;
+
+                       case LANGUAGE:
+                               if ( ( token = getToken( buffer ) ) != EQUALS ) {
+                                       printFormatted( lineLength, TRUE, stdout, "\"=\" expected" );
+                               } else
+                                       token = getToken( buffer );
+/**/                           /* need to save this value and lookup locale */
+                               printFormatted( lineLength, TRUE, stdout,
+                                       "Language not currently implemented" );
+                               token = getToken( buffer );
+                               break;
+
+                       case LINE_LENGTH:
+                               if ( ( token = getToken( buffer ) ) != EQUALS ) {
+                                       printFormatted( lineLength, TRUE, stdout, "\"=\" expected" );
+                               } else
+                                       token = getToken( buffer );
+                               lineLength = atoi( buffer );
+                               if ( lineLength < MIN_LINE_LENGTH
+                                       || lineLength > MAX_LINE_LENGTH ) {
+                                       printFormatted( lineLength, TRUE, stdout, "Invalid line length, using default %d", DEFAULT_LINE_LENGTH );
+                                       lineLength = DEFAULT_LINE_LENGTH;
+                               }
+                               token = getToken( buffer );
+                               break;
+
+                       case TRACE:
+                               trace = TRUE;
+                               token = getToken( buffer );
+                               break;
+
+                       default:
+                               printFormatted( lineLength, TRUE, stdout, "Unrecognised global constraint \"%s\"", buffer );
+                               while ( ( token = getToken( buffer ) ) != EOF
+                                       && token != COMMA )
+                                       ;
+                               break;
+
+                       }
+               } while ( token == COMMA );
+       }
+       if ( token != EOF ) {
+               printFormatted( lineLength, TRUE, stdout,
+                       "Data following \"%s\" ignored.", buffer );
+               while ( ( token = getToken( buffer ) ) != EOF )
+                       ;
+       }
+       if ( trace && ( command == READ || command == SEARCH ) )
+               switch (command) {
+               case READ:
+                       printFormatted( lineLength, TRUE, stdout,
+                               "Attempting to read \"%s\"", query );
+                       break;
+
+               case SEARCH:
+                       printFormatted( lineLength, TRUE, stdout,
+                               "Searching using LDAP query %s", query );
+                       break;
+
+               }
+       return command;
+}
diff --git a/contrib/whois++/config.c b/contrib/whois++/config.c
new file mode 100644 (file)
index 0000000..3c1387d
--- /dev/null
@@ -0,0 +1,226 @@
+#if !defined(lint)
+static char copyright[] = "Copyright 1992 The University of Adelaide";
+#endif
+
+/*
+ *                     C O N F I G
+ *
+ * Author:     Mark R. Prior
+ *             Communications and Systems Branch
+ *             Information Technology Division
+ *             The University of Adelaide
+ * E-mail:     mrp@itd.adelaide.edu.au
+ * Date:       October 1992
+ * Version:    1.7
+ * Description:
+ *             Process the configuration file.
+ *
+ * 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 Adelaide. 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.
+ */
+
+#include "whois++.h"
+
+static struct {
+       char    *str;
+       int     cmd;
+       } commands[] = {
+#define CMD_BASE       1
+               "base",         CMD_BASE,
+#define        CMD_LDAP        2
+               "ldaphost",     CMD_LDAP,
+#define CMD_HELPDIR    3
+               "helpdir",      CMD_HELPDIR,
+#define        CMD_USER        4
+               "user",         CMD_USER,
+#define        CMD_PASSWORD    5
+               "password",     CMD_PASSWORD,
+#define CMD_CONFIGDIR  6
+               "configdir",    CMD_CONFIGDIR,
+#define CMD_CONTACT    7
+               "contact",      CMD_CONTACT,
+#define        CMD_HOSTNAME    8
+               "hostname",     CMD_HOSTNAME,
+#define        CMD_LANGUAGE    9
+               "language",     CMD_LANGUAGE,
+#define        CMD_BANNER      10
+               "banner",       CMD_BANNER,
+#define        CMD_TEMPLATE    11
+               "template",     CMD_TEMPLATE,
+               NULL,           NULL
+       };
+
+static nextLine(fp)
+FILE   *fp;
+{
+       /*
+        * We probably should check that the user hasn't put anything else
+        * on the line but I can't be bothered!
+        */
+       register int c;
+
+       while ((c = getc(fp)) != EOF && c != '\n')
+               ;
+}
+
+/*
+ * Get next word, skipping blanks & comments.
+ */
+static int     getWord(buffer, size, fp)
+char           *buffer;
+int            size;
+FILE           *fp;
+{
+       char    *cp;
+       int     c, string;
+
+       string = 0;
+       cp = buffer;
+       while ((c = getc(fp)) != EOF) {
+               if (c == '#') {
+                       while ((c = getc(fp)) != EOF && c != '\n')
+                               ;
+                       continue;
+               }
+               if (c == '\n') {
+                       if (cp != buffer)
+                               ungetc(c, fp);
+                       break;
+               } else if (c == '\\') {
+                       c = getc(fp);
+                       if (c == EOF)
+                               c = '\n';
+               } else if (c == '"') {
+                       string = !string;
+                       continue;
+               }
+               if (!string && isspace(c)) {
+                       while (isspace(c = getc(fp)) && c != '\n')
+                               ;
+                       ungetc(c, fp);
+                       if (cp != buffer)       /* Trailing whitespace */
+                               break;
+                       continue;               /* Leading whitespace */
+               }
+               if (cp >= buffer+size-1)
+                       break;
+               *cp++ = c;
+       }
+       *cp = '\0';
+       return (cp != buffer);
+}
+
+void   readConfiguration( config )
+FILE   *config;
+
+{
+       char            buffer[BUFSIZ];
+       char            *s;
+       int             i;
+
+       /*
+        * A procedure to read in the configuration parameters.
+        * At the moment this is just a "quick hack" and it should be
+        * replaced in the next version by a proper scanner.
+        */
+
+       while ( getWord( buffer, BUFSIZ, config ) != NULL ) {
+               for ( i = 0; commands[i].str != NULL; i++ )
+                       if ( EQ( buffer, commands[i].str ) )
+                               break;
+               if ( commands[i].str == NULL ) {
+                       printFormatted( lineLength, TRUE, stdout,
+                               "Unrecognised command <%s>", buffer );
+                       exit( 1 );
+               }
+               if ( getWord( buffer, BUFSIZ, config ) == NULL ) {
+                       printFormatted( lineLength, TRUE, stdout,
+                               "value missing in configuration file" );
+                       exit( 1 );
+               }
+               switch ( commands[i].cmd ) {
+               case CMD_BASE:
+                       base = strdup( buffer );
+                       break;
+
+               case CMD_LDAP:
+                       ldaphost = strdup( buffer );
+                       break;
+
+               case CMD_HELPDIR:
+                       helpDir = strdup( buffer );
+                       break;
+
+               case CMD_USER:
+                       user = strdup( buffer );
+                       break;
+
+               case CMD_PASSWORD:
+                       password = strdup( buffer );
+                       break;
+
+               case CMD_CONFIGDIR:
+                       configDir = strdup( buffer );
+                       break;
+
+               case CMD_CONTACT:
+                       contact = strdup( buffer );
+                       break;
+
+               case CMD_HOSTNAME:
+                       hostname = strdup( buffer );
+                       break;
+
+               case CMD_LANGUAGE:
+                       defaultLanguage = lowerCase( strdup( buffer ) );
+                       break;
+
+               case CMD_BANNER:
+                       banner = strdup( buffer );
+                       break;
+
+               case CMD_TEMPLATE:
+                       if ( templateTranslationTable == NULL
+                               && ( templateTranslationTable = (table *)malloc(sizeof(table)*tableSize) ) == NULL ) {
+                               printFormatted( lineLength, TRUE, stdout,
+                                       "Malloc failed" );
+                               exit( 1 );
+                       } else if ( numberOfTemplates+1 == tableSize ) {
+                               tableSize += TABLE_INCREMENT;
+                               if ( ( templateTranslationTable = (table *)realloc(templateTranslationTable, sizeof(table)*tableSize) ) == NULL ) {
+                                       printFormatted( lineLength, TRUE, stdout,
+                                               "Realloc failed" );
+                                       exit( 1 );
+                               }
+                       }
+                       templateTranslationTable[numberOfTemplates].key =
+                               lowerCase( strdup( buffer ) );
+                       if ( getWord( buffer, BUFSIZ, config ) == NULL ) {
+                               printFormatted( lineLength, TRUE, stdout,
+                                       "objectClass missing in config file" );
+                               exit( 1 );
+                       }
+                       templateTranslationTable[numberOfTemplates].value =
+                               lowerCase( strdup( buffer ) );
+                       numberOfTemplates++;
+                       break;
+
+               default:
+                       printFormatted( lineLength, TRUE, stdout,
+                               "Attribute <%s> not recognised.",
+                               buffer );
+                       break;
+
+               }
+               nextLine( config );
+       }
+}
diff --git a/contrib/whois++/describe.c b/contrib/whois++/describe.c
new file mode 100644 (file)
index 0000000..eb019fe
--- /dev/null
@@ -0,0 +1,229 @@
+#if !defined(lint)
+static char copyright[] = "Copyright 1992 The University of Adelaide";
+#endif
+
+/*
+ *                     D E S C R I B E
+ *
+ * Author:     Mark R. Prior
+ *             Communications and Systems Branch
+ *             Information Technology Division
+ *             The University of Adelaide
+ * E-mail:     mrp@itd.adelaide.edu.au
+ * Date:       October 1992
+ * Version:    1.7
+ * Description:
+ *             A module implementing the describe whois++ command.
+ *
+ * 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 Adelaide. 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.
+ */
+
+#include "whois++.h"
+
+int    displayDescribe( ld, organisation )
+LDAP   *ld;
+char   *organisation;
+{
+
+       int             i, len1, len2;
+       LDAPMessage     *result, *entry;
+       char            *value, *ptr;
+       char            **values;
+       static char     *masterDSA[] = { "masterDSA", NULL };
+       static char     *manager[] = { "manager", NULL };
+       static char     *roleOccupant[] = { "roleOccupant", NULL };
+       static char     *attributes[] = { "postalAddress", "telephoneNumber",
+                       "facsimileTelephoneNumber", "mail", "lastModifiedBy",
+#if defined(UOFA)
+                       "preferredName",
+#endif
+                       NULL };
+       extern char     *index();
+
+       if ( !EQ( language, "english" ) ) 
+               printFormatted( lineLength, TRUE, stdout,
+                       "The output of the DESCRIBE command must be in english \
+according to the IAFA services template." );
+
+       printFormatted( lineLength, FALSE, stdout,
+               "%-19s Whois++", "Service-Name:" );
+       if ( hostname != NULL )
+               printFormatted( lineLength, FALSE, stdout, "%-19s %s",
+                       "Primary-Name:", hostname );
+       else
+               printFormatted( lineLength, FALSE, stdout,
+                       "%-19s <unknown>", "Primary-Name:" );
+       printFormatted( lineLength, FALSE, stdout,
+               "%-19s Whois++ service using LDAP to access a Quipu based",
+               "Description:" );
+       printFormatted( lineLength, FALSE, stdout,
+               "%-19s X.500 Directory Service.", "" );
+       printFormatted( lineLength, FALSE, stdout,
+               "%-19s whois++ protocol on tcp port 43", "Access-Protocol:" );
+       printFormatted( lineLength, FALSE, stdout,
+               "%-19s whois, x.500, ldap", "Keywords:" );
+       printFormatted( lineLength, FALSE, stdout,
+               "%-19s 24 hours a day, 7 days a week", "Access-Times:" );
+       printFormatted( lineLength, FALSE, stdout,
+               "%-19s Open Access", "Policy:" );
+       printFormatted( lineLength, FALSE, stdout,
+               "%-19s ", "URI:" );
+       if ( contact == NULL ) {
+               /*
+                * The contact hasn't identified themselves in the tailor file
+                * so lets try to work it out by finding out who manages the
+                * DSA that masters the organisation's entry!
+                */
+               if ( debug > 2 )
+                       printFormatted( lineLength, TRUE, stdout,
+                               "No contact info provided, searching ..." );
+               ldap_search_s( ld, organisation, LDAP_SCOPE_BASE,
+                       "objectclass=*", masterDSA, 0, &result );
+               if ( ld->ld_errno != LDAP_SUCCESS ) {
+                       printFormatted( lineLength, FALSE, stdout,
+                               "%-19s <Unknown>", "Contact:" );
+                       return TRUE;
+               }
+               if ( debug > 2 )
+                       printFormatted( lineLength, TRUE, stdout,
+                               "Looking for the master DSA ..." );
+               if ( (values = ldap_get_values( ld, result, "masterDSA" )) == NULL
+                       || values[0] == NULL ) {
+                       printFormatted( lineLength, FALSE, stdout,
+                               "%-19s <Unknown>", "Contact:" );
+                       return TRUE;
+               }
+               if ( debug > 2 )
+                       printFormatted( lineLength, TRUE, stdout,
+                               "Searching for the DSA manager ..." );
+               ldap_search_s( ld, values[0], LDAP_SCOPE_BASE, "objectclass=*",
+                       manager, 0, &result );
+               if ( ld->ld_errno != LDAP_SUCCESS ) {
+                       printFormatted( lineLength, FALSE, stdout,
+                               "%-19s <Unknown>", "Contact:" );
+                       printFormatted( lineLength, TRUE, stdout,
+                               "Search failed, %s",
+                               ldap_err2string( ld->ld_errno ) );
+                       return TRUE;
+               }
+               if ( (values = ldap_get_values( ld, result, "manager" )) == NULL ) {
+                       printFormatted( lineLength, FALSE, stdout,
+                               "%-19s <Unknown>", "Contact:" );
+                       return TRUE;
+               }
+               if ( debug > 2 )
+                       printFormatted( lineLength, TRUE, stdout,
+                               "Retrieving the DSA manager's entry ..." );
+               /*
+                * we have at least one manager for this DSA but which one is
+                * the "correct" one to list?
+                */
+               len1 = strlen( organisation );
+               for ( i = 0; values[i] != NULL; i++ )
+                       if ( strlen( values[i] ) >= len1 ) {
+                               len2 = strlen( values[i] );
+                               if ( EQ( organisation, &values[i][len2-len1] ) )
+                                       contact = strdup( values[i] );
+                       }
+               ldap_value_free( values );
+               if ( contact == NULL ) {
+                       printFormatted( lineLength, FALSE, stdout,
+                               "%-19s <Unknown>", "Contact:" );
+                       if ( debug )
+                               printFormatted( lineLength, TRUE, stdout,
+                                       "Cannot find a suitable manager" );
+                       return TRUE;
+               }
+               ldap_search_s( ld, contact, LDAP_SCOPE_BASE, "objectclass=*",
+                       roleOccupant, 0, &result );
+               if ( ld->ld_errno != LDAP_SUCCESS ) {
+                       printFormatted( lineLength, FALSE, stdout,
+                               "%-19s <Unknown>", "Contact:" );
+                       printFormatted( lineLength, TRUE, stdout,
+                               "Search failed, %s",
+                               ldap_err2string( ld->ld_errno ) );
+                       return TRUE;
+               }
+               if ( (values = ldap_get_values( ld, result, "roleOccupant" )) != NULL
+                       || values[0] == NULL ) {
+                       free( contact );
+                       /* Just pick one! */
+                       contact = strdup( values[0] );
+                       ldap_value_free( values );
+               }
+               if ( debug > 2 )
+                       printFormatted( lineLength, TRUE, stdout,
+                               "The contact is %s", contact );
+       }
+       ldap_search_s( ld, contact, LDAP_SCOPE_BASE, "objectclass=*", 
+               attributes, 0, &result );
+       if ( ld->ld_errno != LDAP_SUCCESS ) {
+               printFormatted( lineLength, FALSE, stdout, "%-19s <Unknown>",
+                       "Contact:" );
+               printFormatted( lineLength, TRUE, stdout,
+                       "Read for \"%s\" returned error, %s", contact,
+                       ldap_err2string( ld->ld_errno ) );
+       }
+#if defined(UOFA)
+       if ( (values = ldap_get_values( ld, result, "preferredName" )) != NULL
+               && values[0] != NULL ) {
+               printFormatted( lineLength, FALSE, stdout, "%-19s %s",
+                       "Contact:", values[0] );
+               ldap_value_free( values );
+       } else {
+#endif
+               value = strdup( ldap_dn2ufn( ldap_get_dn( ld, result ) ) );
+               if ( (ptr = index( value, ',' )) != NULL )
+                       *ptr = '\0';
+               printFormatted( lineLength, FALSE, stdout, "%-19s %s",
+                       "Contact:", value );
+#if defined(UOFA)
+       }
+#endif
+       if ( ( values = ldap_get_values( ld, result, "postalAddress" )) != NULL ) {
+               for ( i = 0; values[i] != NULL; i++ ) {
+                       printFormatted( lineLength, FALSE, stdout, "%-19s %s",
+                               "Postal-Address:",
+                               strtok( values[i], "$" ) );
+                       while ( ( ptr = strtok( NULL, "$" ) ) != NULL )
+                               printFormatted( lineLength, FALSE, stdout,
+                                       "%-19s%s", "", ptr );
+               }
+               ldap_value_free( values );
+       }
+       if ( ( values = ldap_get_values( ld, result, "telephoneNumber" )) != NULL ) {
+               for ( i = 0; values[i] != NULL; i++ )
+                       printFormatted( lineLength, FALSE, stdout, "%-19s %s",
+                               "Telephone:", values[i] );
+               ldap_value_free( values );
+       }
+       if ( ( values = ldap_get_values( ld, result, "facsimileTelephoneNumber" )) != NULL ) {
+               for ( i = 0; values[i] != NULL; i++ )
+                       printFormatted( lineLength, FALSE, stdout, "%-19s %s",
+                               "Fax:", values[i] );
+               ldap_value_free( values );
+       }
+       if ( ( values = ldap_get_values( ld, result, "mail" )) != NULL ) {
+               for ( i = 0; values[i] != NULL; i++ )
+                       printFormatted( lineLength, FALSE, stdout, "%-19s %s",
+                               "Electronic-Address:", values[i] );
+               ldap_value_free( values );
+       }
+       if ( ( values = ldap_get_values( ld, result, "lastModifiedBy" )) != NULL ) {
+               for ( i = 0; values[i] != NULL; i++ )
+                       printFormatted( lineLength, FALSE, stdout,
+                               "%-19s \"%s\"", "Modified-By:", values[i] );
+               ldap_value_free( values );
+       }
+       return FALSE;
+}
diff --git a/contrib/whois++/help.c b/contrib/whois++/help.c
new file mode 100644 (file)
index 0000000..d18f4b0
--- /dev/null
@@ -0,0 +1,89 @@
+#if !defined(lint)
+static char copyright[] = "Copyright 1992 The University of Adelaide";
+#endif
+
+/*
+ *                     H E L P
+ *
+ * Author:     Mark R. Prior
+ *             Communications and Systems Branch
+ *             Information Technology Division
+ *             The University of Adelaide
+ * E-mail:     mrp@itd.adelaide.edu.au
+ * Date:       October 1992
+ * Version:    1.7
+ * Description:
+ *             The Help module
+ *
+ * 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 Adelaide. 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.
+ */
+
+#include "whois++.h"
+
+void   needHelp( reason )
+char   *reason;
+{
+       char            filename[MAXPATHLEN];
+       char            buffer[BUFSIZ];
+       int             i;
+       DIR             *dir;
+       struct dirent   *entry;
+       FILE            *help;
+
+       if ( reason == NULL || *reason == '\0' ) {
+               sprintf( filename, "%s/%s/general", helpDir, language );
+               if ( ( help = fopen( filename, "r" ) ) == NULL ) {
+                       printFormatted( lineLength, TRUE, stdout,
+                               "Sorry cannot open general information help file" );
+                       return;
+               }
+       } else {
+               sprintf( filename, "%s/%s/%s", helpDir, language,
+                       lowerCase( reason ) );
+               if ( ( help = fopen( filename, "r" ) ) == NULL ) {
+                       sprintf( filename, "%s/%s/%s", helpDir, defaultLanguage,
+                               lowerCase( reason ) );
+                       if ( ( help = fopen( filename, "r" ) ) == NULL ) {
+                               printFormatted( lineLength, TRUE, stdout,
+                                       "Sorry cannot open help file for topic \"%s\"",
+                                       reason );
+                               return;
+                       } else {
+                               printFormatted( lineLength, TRUE, stdout,
+                                       "Sorry no help in %s, using default language (%s).",
+                                       language, defaultLanguage );
+                       }
+               }
+       }
+       while ( fgets( buffer, BUFSIZ, help ) != NULL ) {
+               i = strlen( buffer );
+               while ( i-- > 0 && ( buffer[i] == '\n' || buffer[i] == '\r' ) )
+                       buffer[i] = '\0';
+               printFormatted( lineLength, FALSE, stdout, "%s", buffer );
+       }
+       fclose( help );
+       if ( reason == NULL || *reason == '\0' ) {
+               sprintf( filename, "%s/%s", helpDir, language );
+               if ( ( dir = opendir( filename ) ) == NULL )
+                       return;
+               printFormatted( lineLength, FALSE, stdout, "" );
+               printFormatted( lineLength, FALSE, stdout,
+                       "Further information is available on the following topics" );
+               for ( entry = readdir( dir ); entry != NULL; entry = readdir( dir ) )
+                       if ( !EQ(entry->d_name, "." ) && !EQ(entry->d_name, ".." ) )
+                               printFormatted( lineLength, FALSE, stdout,
+                                       " %s", lowerCase( entry->d_name ) );
+               closedir( dir );
+       }
+       return;
+}
diff --git a/contrib/whois++/helpfiles/english/command b/contrib/whois++/helpfiles/english/command
new file mode 100644 (file)
index 0000000..776848b
--- /dev/null
@@ -0,0 +1 @@
+List the commands supported by this server.
diff --git a/contrib/whois++/helpfiles/english/commands b/contrib/whois++/helpfiles/english/commands
new file mode 100644 (file)
index 0000000..15d47d6
--- /dev/null
@@ -0,0 +1,9 @@
+The whois++ query langauge contains a number of mandatory commands which all
+servers should support but there are also a number of optional commands. In
+order that a client can find out what commands are supported by a server
+there is a mandatory command called "command" that should provide a list of 
+all commands supported by the server. If you wish to use a command that is
+optional you may wish to use the "command" command to find out if the server
+supports it.
+
+This server only supports the mandatory commands.
diff --git a/contrib/whois++/helpfiles/english/constraints b/contrib/whois++/helpfiles/english/constraints
new file mode 100644 (file)
index 0000000..3c52b9f
--- /dev/null
@@ -0,0 +1,39 @@
+Constraints are a mechanism for modifying the behaviour of the query and are
+divided into two classes (local or global) depending on the scope of the 
+modification. Local contraints may appear attached to each term in a query,
+whereas global contraints apply to the entire query and so are listed after
+the actual query (separated from the query by a colon).
+
+This implementation supports the following constraints -
+1. Local constraints
+   a. match=(exact|fuzzy)
+      The directory is either searched for an exact match of the value
+      specified or soundex style matching is attempted.
+      If you wish to attempt substring matching you should include a "*" in
+      your search string.
+      Default=exact
+
+2. Global constraints
+   a. format=(full|abridged|handle|summary)
+      This specifies the format of the response returned by the query.
+      Normally the format used is controlled by the number of matches but this
+      constraint may be used to override the default.
+   b. hold
+      The connection is held open for a maximum of 60 seconds for further
+      queries, normally the connection is closed after each query.
+   c. language=<string>
+      Return any diagnostics in the natural language specified.
+      Default=english
+   d. linelength=<value>
+      This constraint allows you to indicate the maximum length of lines you
+      can display via your client.
+      Default=80
+   e. maxhits=<value>
+      The intent of this constraint is to limit the number of hits returned.
+      Unfortunately in the context of the server communicating with an X.500
+      server this is generally not possible as the DSA will define the
+      maximum number of entries it wishes to return. It is still of some use
+      if you wish to constrain the value to less than the value that the
+      X.500 directory would normally return.
+      The default value is dependant on the value configured by the Directory
+      Administrator into the DSA.
diff --git a/contrib/whois++/helpfiles/english/describe b/contrib/whois++/helpfiles/english/describe
new file mode 100644 (file)
index 0000000..ecb0ab3
--- /dev/null
@@ -0,0 +1,5 @@
+The describe command returns information about this service, formatted
+according to the IAFA Services template. This information will include a
+description of the service, access policy, and a contract for the person
+who manages the Directory.
+
diff --git a/contrib/whois++/helpfiles/english/general b/contrib/whois++/helpfiles/english/general
new file mode 100644 (file)
index 0000000..73f05bf
--- /dev/null
@@ -0,0 +1,7 @@
+You have connected to a server that implements the new WHOIS++ specification.
+
+This service is provided via an underlying X.500 Directory Service and so
+this server is really only a read-only DUA interface to the X.500 Directory.
+
+A "technical" description of this service may be obtained by using the
+"describe" command, this will also list a contact for this service.
diff --git a/contrib/whois++/helpfiles/english/help b/contrib/whois++/helpfiles/english/help
new file mode 100644 (file)
index 0000000..518a3c2
--- /dev/null
@@ -0,0 +1,30 @@
+This is an experimental implementation of a whois++ service being proposed
+by the IETF's WNILS (Whois and Network Information Lookup Service) Working
+Group. It uses a (Quipu 8.0 based) X.500 Directory Service as it's
+information source.
+
+The whois++ server communicates with the Directory via LDAP (Lightweight
+Directory Access Protocol), using the libraries developed by the University
+of Michigan. All user search queries are transformed into LDAP queries that
+are passed to the X.500 Directory service for resolution.
+
+For "normal" whois style queries we make a number of assumptions on the
+attributes of interest depending on the format of the query. If you only
+supply a single token it is assumed that you wish to search for a family
+name or userid. Multiple tokens imply a search on a full name (commonName
+in X.500-speak). We also support e-mail lookups as described in the
+original whois RFC (RFC954) however wildcard style searches may be
+constrained by the X.500 Directory service.
+
+Example queries 
+a. ng =>
+       (|(sn=ng)(userid=ng)(l=ng)(ou=ng)(&(cn=ng)(!(objectClass=person))))
+b. zhongyi li =>
+       (|(l=zhongyi li)(ou=zhongyi li)(preferredName=zhongyi li)\
+               (cn=*zhongyi * li))
+c. mrp@ =>
+       (|(mail=mrp@*)(userid=mrp))
+
+You can also use structured whois++ queries that specify the attribute to
+search as well as value. Searching using uncommon attributes attributes may
+be restricted by the X.500 Directory system.
diff --git a/contrib/whois++/helpfiles/english/list b/contrib/whois++/helpfiles/english/list
new file mode 100644 (file)
index 0000000..aba4d3f
--- /dev/null
@@ -0,0 +1,3 @@
+The list command returns a list of the whois++ template types that may be
+returned as a result of a query. You can use the show command to return
+further information about these templates.
diff --git a/contrib/whois++/helpfiles/english/search b/contrib/whois++/helpfiles/english/search
new file mode 100644 (file)
index 0000000..5cb36f6
--- /dev/null
@@ -0,0 +1,33 @@
+There are 4 different search styles possible when using a whois++ server.
+
+The first of these styles is the familiar whois style query, where your
+client supplies a number of tokens and these tokens are converted into a
+LDAP search query for processing by the X.500 Directory system.
+
+Example queries 
+a. ng =>
+       (|(sn=ng)(userid=ng)(l=ng)(ou=ng)(&(cn=ng)(!(objectClass=person))))
+
+b. Snoke, Robert Lee =>
+       (&(sn=Snoke)(|(l=Robert Lee Snoke)(ou=Robert Lee Snoke)\
+               (preferredName=Robert Lee Snoke)(cn=*Robert * Lee * Snoke)))
+
+c. mrp@ =>
+       (|(mail=mrp@*)(userid=mrp))
+
+As you can see no attribute information was supplied by the client and so
+the server must "guess" what information is required. X.500 uses the
+attribute cn (commonName) fairly generically to name entries so this is used
+in constructing queries. It is assumed that most queries will relate to a
+search for a person so the query is composed in such a way to emphasise this
+assumption. If only one token is supplied this is assumed to be a family
+name whereas if more than one token is supplied this assumed to be the full
+name, in order to distinguish the family name you may use the "," syntax as
+per example (b).
+
+E-mail lookups as described in the original whois RFC (RFC954) are also
+supported however wildcard style searches may be constrained by the X.500
+Directory service.
+
+The other search styles involve the use of attributes, where the client
+specifies the type of the data that it wishes to search for.
diff --git a/contrib/whois++/helpfiles/english/show b/contrib/whois++/helpfiles/english/show
new file mode 100644 (file)
index 0000000..ddbc7de
--- /dev/null
@@ -0,0 +1,2 @@
+The show command returns a list of attributes that can be returned if a
+record of that template type is returned as a result of a query.
diff --git a/contrib/whois++/helpfiles/english/version b/contrib/whois++/helpfiles/english/version
new file mode 100644 (file)
index 0000000..8211af4
--- /dev/null
@@ -0,0 +1,3 @@
+The version command provides version number information and should be quoted
+when reporting any problems with the server. The information returned will
+include the version of the protocol as well as the program's revision number.
diff --git a/contrib/whois++/output.c b/contrib/whois++/output.c
new file mode 100644 (file)
index 0000000..6ebe649
--- /dev/null
@@ -0,0 +1,358 @@
+#if !defined(lint)
+static char copyright[] = "Copyright 1992 The University of Adelaide";
+#endif
+
+/*
+ *                     O U T P U T
+ *
+ * Author:     Mark R. Prior
+ *             Communications and Systems Branch
+ *             Information Technology Division
+ *             The University of Adelaide
+ * E-mail:     mrp@itd.adelaide.edu.au
+ * Date:       October 1992
+ * Version:    1.7
+ * Description:
+ *             The Output routines
+ *
+ * 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 Adelaide. 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.
+ */
+
+#include <varargs.h>
+#include "whois++.h"
+
+extern char *index(), *rindex();
+
+static displayEntry();
+static printAttribute();
+
+static char    *selectObjectClass( ld, entry )
+LDAP           *ld;
+LDAPMessage    *entry;
+
+{
+       static char     *objectClass[] = { "objectClass", NULL };
+       LDAPMessage     *result;
+       char            *dn, *template;
+       char            **val;
+       int             i;
+
+       template = NULL;
+       dn = strdup( ldap_get_dn( ld, entry ) );
+       ldap_search_s( ld, dn, LDAP_SCOPE_BASE, "objectclass=*", objectClass,
+               0, &result );
+       if ( ld->ld_errno != LDAP_SUCCESS ) {
+               printFormatted( lineLength, TRUE, stdout,
+                       "Read on object \"%s\" failed, %s",
+                       dn, ldap_err2string( ld->ld_errno ) );
+               free( dn );
+               return;
+       } else
+               free( dn );
+       if ( ( val = ldap_get_values( ld, result, "objectClass" ) ) == NULL )
+               return;
+       for ( i = 0 ; val[i] != NULL ; i++ )
+               if ( specifyAttributes( lowerCase( val[i] ) ) != NULL ) {
+                       template = strdup( val[i] );
+                       break;
+               }
+       ldap_value_free( val );
+       return template;
+}
+
+int            displayResult( ld, result, outputFormat )
+LDAP           *ld;
+LDAPMessage    *result;
+int            outputFormat;
+
+{
+       int             i, matches, number = 0;
+       char            *dn;
+       LDAPMessage     *e;
+       char            *objectClass;
+       char            **attributes, **objectClassTable;
+
+       matches = ldap_count_entries( ld, result );
+       if ( log )
+               syslog( LOG_INFO, "%d match(es) to query", matches );
+       if ( matches == 0 ) {
+               printFormatted( lineLength, TRUE, stdout, "No matches found." );
+               return FALSE;
+       }
+       if ( outputFormat == NULL ) {
+               if ( matches == 1 )
+                       outputFormat = FULL;
+               else if ( matches <= ABRIDGED_LIMIT )
+                       outputFormat = HANDLE;
+               else
+                       outputFormat = SUMMARY;
+       }
+       switch (outputFormat) {
+       case FULL:
+               printFormatted( lineLength, FALSE, stdout,
+                       "#FULL %d", matches );
+               for ( e = ldap_first_entry( ld, result ); e != NULL;
+                       e = ldap_next_entry( ld, e ) ) {
+                       objectClass = selectObjectClass( ld, e );
+                       dn = ldap_get_dn( ld, e );
+                       printFormatted( lineLength, FALSE, stdout,
+                               "#%s \"%s\"",
+                               objectClassToTemplate( objectClass ), dn );
+                       displayEntry( ld, dn,
+                               specifyAttributes( objectClass ) );
+                       if ( objectClass != NULL )
+                               free( objectClass );
+               }
+               printFormatted( lineLength, FALSE, stdout, "#END" );
+               break;
+
+       case ABRIDGED:
+               /*
+                * As the DN contains most of the information wanted in 
+                * ABRIDGED format we use HANDLE format even if the client
+                * really specified ABRIDGED.
+                */
+               printFormatted( lineLength, TRUE, stdout,
+                       "Abridged format is not really supported, the handle \
+supplies most of the information specified in the abridged format description \
+so we use the handle format instead." );
+
+       case HANDLE:
+               printFormatted( lineLength, FALSE, stdout,
+                       "#HANDLE %d", matches );
+               for ( e = ldap_first_entry( ld, result ); e != NULL;
+                       e = ldap_next_entry( ld, e ) ) {
+                       objectClass = selectObjectClass( ld, e );
+                       printFormatted( lineLength, FALSE, stdout, " \"%s\" %s",
+                               ldap_get_dn( ld, e ),
+                               objectClassToTemplate( objectClass ) );
+                       if ( objectClass != NULL )
+                               free( objectClass );
+               }
+               printFormatted( lineLength, FALSE, stdout, "#END" );
+               break;
+
+       case SUMMARY:
+               printFormatted( lineLength, FALSE, stdout, "#SUMMARY" );
+               printFormatted( lineLength, FALSE, stdout, " matches:   %d",
+                       matches );
+               e = ldap_first_entry( ld, result );
+               objectClass = selectObjectClass( ld, e );
+               if ( ( objectClassTable = (char **)malloc(sizeof(char **)*matches) ) == NULL ) {
+                       printFormatted( lineLength, TRUE, stdout, 
+                               "Malloc failed" );
+                       break;
+               }
+               objectClassTable[number++] = objectClass;
+               printFormatted( lineLength, FALSE, stdout, " templates: %s",
+                       objectClassToTemplate( objectClass ) );
+               while ( ( e = ldap_next_entry( ld, e ) ) != NULL ) {
+                       objectClass = selectObjectClass( ld, e );
+                       /* have we printed this before? If not do it now */
+                       for ( i = 0; i < number; i++ ) 
+                               if ( EQ( objectClass, objectClassTable[i] ) )
+                                       break;
+                       if ( i < number ) {
+                               if ( objectClass != NULL )
+                                       free( objectClass );
+                       } else {
+                               objectClassTable[number++] = objectClass;
+                               printFormatted( lineLength, FALSE, stdout,
+                                       "            %s",
+                                       objectClassToTemplate( objectClass ) );
+                       }
+               }
+               printFormatted( lineLength, FALSE, stdout, "#END" );
+               for ( i = 0; i < number; i++ )
+                       if ( objectClassTable[i] != NULL )
+                               free( objectClassTable[i] );
+               free( objectClassTable );
+               break;
+
+       }
+       return TRUE;
+}
+
+static displayEntry( ld, dn, attributes )
+LDAP   *ld;
+char   *dn, *attributes[];
+{
+       char            *ufn;
+       int             i;
+       char            *s, *department;
+       LDAPMessage     *result, *entry;
+
+       ldap_search_s( ld, dn, LDAP_SCOPE_BASE, "objectclass=*", attributes,
+               0, &result );
+       if ( ld->ld_errno != LDAP_SUCCESS ) {
+               printFormatted( lineLength, TRUE, stdout,
+                       "Read on object \"%s\" failed, %s", dn,
+                       ldap_err2string( ld->ld_errno ) );
+               return;
+       }
+
+       entry = ldap_first_entry( ld, result );
+
+       if ( entry == NULL ) {
+               /* something very weird has happened */
+               printFormatted( lineLength, TRUE, stdout,
+                       "Possible conflict with ACLs for \"%s\"", dn );
+               return;
+       }
+
+       /*
+        * Get the UFN version of the DN and then cut it up into
+        * name and department.
+        */
+       ufn = ldap_dn2ufn( dn );
+       if ( ( s = index( ufn, ',' ) ) != NULL ) {
+               *s++ = '\0';
+               while ( *s != '\0' && isspace( *s ) )
+                       s++;
+               department = s;
+               while ( s != NULL && *s != '\0' && !EQ( s, organisation ) )
+                       if ( ( s = index( s, ',' ) ) != NULL ) {
+                               s++;
+                               while ( *s != '\0' && isspace( *s ) )
+                                       s++;
+                       }
+               if ( s != NULL )
+                       if ( s != department ) {
+                               while ( isspace( *--s ) )
+                                       ;
+                               *s = '\0';
+                       } else
+                               department = NULL;
+       } else
+               department = NULL;
+
+/**/   /*
+        * Name, Organization, Department, Organization-Type, and Handle
+        * should be read in from language dictionary rather than hard coded.
+        */
+       printFormatted( lineLength, FALSE, stdout, " %-19s %s", "Name", ufn );
+       if ( department != NULL && *department != '\0' )
+               printFormatted( lineLength, FALSE, stdout,
+                       " %-19s %s", "Department", department );
+       printFormatted( lineLength, FALSE, stdout, " %-19s %s",
+               "Organization", organisation );
+       if ( category != NULL )
+               for ( i = 0; category[i] != NULL; i++ )
+                       printFormatted( lineLength, FALSE, stdout, " %-19s %s",
+                               "Organization-type", category[i] );
+       for ( i = 0; attributes != NULL && attributes[i] != NULL; i++ ) {
+               printAttribute( ld, attributes[i], entry );
+       }
+       printFormatted( lineLength, FALSE, stdout, " %-19s \"%s\"",
+               "Handle", dn );
+
+       free( ufn );
+}
+
+char *attributeLabel( attribute )
+char   *attribute;
+
+{
+/**/   /* need to get printable string from language dictionary */
+       return attribute;
+}
+
+static printAttribute( ld, attribute, entry )
+LDAP           *ld;
+char           *attribute;
+LDAPMessage    *entry;
+{
+       char    **val;
+       char    *tag, *ptr;
+       int     i;
+
+/**/   /*
+        * We really should determine whether the attribute value needs line
+        * processing or not rather than just hard coding in a couple of cases
+        * but for the moment we will ignore the problem.
+        */
+       if ( ( val = ldap_get_values( ld, entry, attribute )) == NULL )
+               return;
+
+       tag = attributeLabel( attribute );
+       for ( i = 0; val[i] != NULL; i++ )
+               if ( EQ( attribute, "lastModifiedTime" ) )
+                       printFormatted( lineLength, FALSE, stdout, " %-19s %s",
+                               tag, convertTime( val[i], locale ) );
+               else if ( EQ( attribute, "postalAddress" )
+                       || EQ( attribute, "homePostalAddress" ) ) {
+                       printFormatted( lineLength, FALSE, stdout, " %-19s %s",
+                               tag, strtok( val[i], "$" ) );
+                       while ( ( ptr = strtok( NULL, "$" ) ) != NULL )
+                               printFormatted( lineLength, FALSE, stdout,
+                                       " %-19s%s", "", ptr );
+               } else
+                       printFormatted( lineLength, FALSE, stdout, " %-19s %s",
+                               tag, val[i] );
+
+       ldap_value_free( val );
+}
+
+printFormatted( lineLength, systemMessage, output, format, va_alist )
+int    lineLength, systemMessage;
+FILE   *output;
+char   *format;
+va_dcl
+
+{
+       va_list ap;
+       char    buffer[BUFSIZ];
+       char    *head, *p, *q;
+       char    *tag;
+       int     count;
+
+       if ( systemMessage ) {
+               lineLength--;
+               tag = "% ";
+       } else
+               tag = "";
+       va_start( ap );
+       vsprintf( buffer, format, ap );
+       va_end( ap );
+       if ( strlen( buffer ) < lineLength )
+               fprintf( output, "%s%s\r\n", tag, buffer );
+       else {
+               head = buffer;
+               do {
+                       count = strlen( tag );
+                       for ( q = head; *q && *q != ' '; q++ )
+                               count++;
+                       if ( *q == NULL ) {
+                               fprintf( output, "%s%s\r\n", tag, head );
+                               break;
+                       } else if ( count > lineLength ) {
+                               *q++ = '\0';
+                               fprintf( output, "%s%s\r\n", tag, head );
+                               head = q;
+                       } else {
+                               do {
+                                       p = q++;
+                                       count++;
+                                       for (; *q && *q != ' '; q++ )
+                                               count++;
+                               } while ( *p != '\0' && count <= lineLength );
+                               if ( *p != '\0' )
+                                       *p++ = '\0';
+                               fprintf( output, "%s%s\r\n", tag, head );
+                               head = p;
+                       }
+                       if ( !systemMessage )
+                               tag = "+ ";
+               } while ( *head != NULL );
+       }
+}
diff --git a/contrib/whois++/root.Makefile.diff b/contrib/whois++/root.Makefile.diff
new file mode 100644 (file)
index 0000000..c79d2f6
--- /dev/null
@@ -0,0 +1,83 @@
+*** Makefile-dist      Fri Apr 23 15:29:24 1993
+--- Makefile   Fri Apr 23 15:33:04 1993
+***************
+*** 86,92 ****
+  
+  LDIRS        = libldap liblber                        # library directories
+  SDIRS        = ldapd                                  # server directories
+! CDIRS        = finger gopher ud rcpt500 whois mail500 # client directories
+  ALLDIRS      = $(CDIRS) $(SDIRS) $(LDIRS)
+  
+  VERSION      = 2.0   # set this to be the same as what's in ./version
+--- 86,92 ----
+  
+  LDIRS        = libldap liblber                        # library directories
+  SDIRS        = ldapd                                  # server directories
+! CDIRS        = finger gopher ud rcpt500 whois mail500 whois++ # client directories
+  ALLDIRS      = $(CDIRS) $(SDIRS) $(LDIRS)
+  
+  VERSION      = 2.0   # set this to be the same as what's in ./version
+***************
+*** 99,105 ****
+  
+  lib-only: lber-library ldap-library
+  
+! others: ldap-finger ldap-gopher ldap-ud ldap-rcpt500 ldap-whois ldap-mail500
+  
+  lber-library:
+       @echo "cd liblber; $(MAKE) all"
+--- 99,106 ----
+  
+  lib-only: lber-library ldap-library
+  
+! others: ldap-finger ldap-gopher ldap-ud ldap-rcpt500 ldap-whois ldap-mail500 \
+!      ldap-whois++
+  
+  lber-library:
+       @echo "cd liblber; $(MAKE) all"
+***************
+*** 181,186 ****
+--- 182,194 ----
+               ETCDIR=$(ETCDIR) CC=$(CC) \
+               all)
+  
++ ldap-whois++:
++      @echo "cd whois++; $(MAKE) all"
++      @(cd whois++; $(MAKE) ACFLAGS="$(ACFLAGS)" ALDFLAGS="$(ALDFLAGS)" \
++              KRBLIBFLAG=$(KRBLIBFLAG) KRBLIBS="$(KRBLIBS)" \
++              ETCDIR=$(ETCDIR) CC=$(CC) \
++              all)
++ 
+  #
+  # rules to install the software
+  #
+***************
+*** 188,194 ****
+  install: inst-include inst-server inst-lberlib inst-ldaplib inst-man
+  
+  inst-others: inst-finger inst-gopher inst-ud inst-rcpt500 inst-whois \
+!              inst-mail500
+  
+  inst-lib: inst-lberlib inst-ldaplib
+  
+--- 196,202 ----
+  install: inst-include inst-server inst-lberlib inst-ldaplib inst-man
+  
+  inst-others: inst-finger inst-gopher inst-ud inst-rcpt500 inst-whois \
+!              inst-mail500 inst-whois++
+  
+  inst-lib: inst-lberlib inst-ldaplib
+  
+***************
+*** 231,236 ****
+--- 239,248 ----
+  inst-whois:
+       @echo "cd whois; $(MAKE) install"
+       @( cd whois; $(MAKE) ETCDIR=$(ETCDIR) install )
++ 
++ inst-whois++:
++      @echo "cd whois++; $(MAKE) inst-whois++"
++      @( cd whois++; $(MAKE) ETCDIR=$(ETCDIR) inst-whois++ )
+  
+  inst-mail500:
+       @echo "cd mail500; $(MAKE) install"
diff --git a/contrib/whois++/template.c b/contrib/whois++/template.c
new file mode 100644 (file)
index 0000000..771fe98
--- /dev/null
@@ -0,0 +1,169 @@
+#if !defined(lint)
+static char copyright[] = "Copyright 1992 The University of Adelaide";
+#endif
+
+/*
+ *                     T E M P L A T E
+ *
+ * Author:     Mark R. Prior
+ *             Communications and Systems Branch
+ *             Information Technology Division
+ *             The University of Adelaide
+ * E-mail:     mrp@itd.adelaide.edu.au
+ * Date:       October 1992
+ * Version:    1.7
+ * Description:
+ *             This module deals with whois++ templates
+ *
+ * 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 Adelaide. 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.
+ */
+
+#include "whois++.h"
+
+void   showTemplate( template )
+char   *template;
+
+{
+       char    filename[MAXPATHLEN], buffer[BUFSIZ];
+       FILE    *description;
+       int     i;
+
+       if ( template == NULL || *template == '\0' )
+               return;
+       sprintf( filename, "%s/templates/%s", configDir, template );
+       if ( ( description = fopen( filename, "r" ) ) == NULL ) 
+               printFormatted( lineLength, TRUE, stdout,
+                       "Cannot find template %s", template );
+       else {
+               while ( fgets( buffer, BUFSIZ, description ) != NULL ) {
+                       i = strlen( buffer );
+                       while ( i-- > 0 &&
+                               ( buffer[i] == '\n' || buffer[i] == '\r' ) )
+                               buffer[i] = '\0';
+                       printFormatted( lineLength, FALSE, stdout,
+                               " %s", buffer );
+               }
+               fclose( description );
+       }
+}
+
+void   listTemplates( query )
+char   *query;
+
+{
+       char            filename[MAXPATHLEN];
+       DIR             *dir;
+       struct dirent   *entry;
+
+       if ( query == NULL || *query == '\0' ) {
+               sprintf( filename, "%s/templates", configDir );
+               if ( ( dir = opendir( filename ) ) == NULL ) {
+                       printFormatted( lineLength, TRUE, stdout,
+                               "Cannot access template descriptions - %s",
+                               strerror( errno ) );
+                       return;
+               }
+               for ( entry = readdir( dir ); entry != NULL; entry = readdir( dir ) )
+                       if ( !EQ(entry->d_name, "." ) && !EQ(entry->d_name, ".." ) )
+                               printFormatted( lineLength, FALSE, stdout,
+                                       " %s", lowerCase( entry->d_name ) );
+               closedir( dir );
+       } else {
+               sprintf( filename, "%s/templates/%s", configDir, query );
+               if ( fopen( filename, "r" ) == NULL )
+                       printFormatted( lineLength, TRUE, stdout,
+                               "No such template (%s)", query );
+               else
+                       printFormatted( lineLength, FALSE, stdout,
+                               " %s", query );
+       }
+}
+
+char   **specifyAttributes( objectClass )
+char   *objectClass;
+
+{
+       FILE    *description;
+       char    filename[MAXPATHLEN], buffer[BUFSIZ];
+       char    **attributes;
+       int     max = ATTRIBUTE_INCREMENT;
+       int     i, number = 0;
+
+       if ( objectClass == NULL || *objectClass == '\0' )
+               return NULL;
+       sprintf( filename, "%s/templates/%s", configDir,
+               lowerCase( objectClass ) );
+       if ( ( description = fopen( filename, "r" ) ) == NULL ) 
+               return NULL;
+       if ( ( attributes = (char **)malloc( max*sizeof(char *) ) ) == NULL ) {
+               printFormatted( lineLength, TRUE, stdout,
+                       "Error while attempting to create attribute list - %s",
+                       strerror( errno ) );
+               return NULL;
+       }
+       while ( fgets( buffer, BUFSIZ, description ) != NULL ) {
+               i = strlen( buffer );
+               while ( i-- > 0 && ( buffer[i] == '\n' || buffer[i] == '\r' ) )
+                       buffer[i] = '\0';
+               attributes[number++] = strdup( buffer );
+               if ( number == max ) {
+                       max += ATTRIBUTE_INCREMENT;
+                       if ( ( attributes = (char **)realloc( attributes, max*sizeof(char *)) ) == NULL ) {
+                               printFormatted( lineLength, TRUE, stdout,
+                                       "Error while attempting to extend attribute list - %s",
+                                       strerror( errno ) );
+                               return NULL;
+                       }
+               }
+       }
+       attributes[number] = NULL;
+       fclose( description );
+       return attributes;
+}
+
+char   *templateToObjectClass( template )
+char   *template;
+
+{
+       int     i;
+
+       if ( template == NULL || *template == '\0' ) {
+               printFormatted( lineLength, TRUE, stdout,
+                       "Unrecognised template" );
+               return "unrecognised";
+       }
+       for ( i = 0; i < numberOfTemplates; i++ )
+               if ( EQ( template, templateTranslationTable[i].key ) )
+                       return templateTranslationTable[i].value;
+       printFormatted( lineLength, TRUE, stdout,
+               "Template (%s) not recognised, assuming that it is already an objectClass",
+               template );
+       return template;
+}
+
+char   *objectClassToTemplate( objectClass )
+char   *objectClass;
+
+{
+       int     i;
+
+       if ( objectClass == NULL || *objectClass == '\0' ) {
+               printFormatted( lineLength, TRUE, stdout,
+                       "Unrecognised template" );
+               return "unrecognised";
+       }
+       for ( i = 0; i < numberOfTemplates; i++ )
+               if ( EQ( objectClass, templateTranslationTable[i].value ) )
+                       return templateTranslationTable[i].key;
+       return objectClass;
+}
diff --git a/contrib/whois++/templates/applicationentity b/contrib/whois++/templates/applicationentity
new file mode 100644 (file)
index 0000000..2561bff
--- /dev/null
@@ -0,0 +1,2 @@
+description
+lastModifiedBy
diff --git a/contrib/whois++/templates/organizationalrole b/contrib/whois++/templates/organizationalrole
new file mode 100644 (file)
index 0000000..5b8c563
--- /dev/null
@@ -0,0 +1 @@
+roleOccupant
diff --git a/contrib/whois++/templates/organizationalunit b/contrib/whois++/templates/organizationalunit
new file mode 100644 (file)
index 0000000..db7acbb
--- /dev/null
@@ -0,0 +1,2 @@
+telephoneNumber
+facsimileTelephoneNumber
diff --git a/contrib/whois++/templates/person b/contrib/whois++/templates/person
new file mode 100644 (file)
index 0000000..8a418da
--- /dev/null
@@ -0,0 +1,12 @@
+telephoneNumber
+streetAddress
+facsimileTelephoneNumber
+roomNumber
+title
+mail
+info
+lastModifiedBy
+lastModifiedTime
+homePhone
+homePostalAddress
+preferredName
diff --git a/contrib/whois++/util.c b/contrib/whois++/util.c
new file mode 100644 (file)
index 0000000..8431878
--- /dev/null
@@ -0,0 +1,167 @@
+#if !defined(lint)
+static char copyright[] = "Copyright 1992 The University of Adelaide";
+#endif
+
+/*
+ *                     U T I L
+ *
+ * Author:     Mark R. Prior
+ *             Communications and Systems Branch
+ *             Information Technology Division
+ *             The University of Adelaide
+ * E-mail:     mrp@itd.adelaide.edu.au
+ * Date:       November 1992
+ * Version:    1.7
+ * Description:
+ *             Some routines that I use in most my LDAP playthings :-)
+ *
+ * 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 Adelaide. 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.
+ */
+
+#include <stdio.h>
+#include <signal.h>
+#include <ctype.h>
+#if defined(SYS5) || defined(XOS_2)
+#include <termio.h>
+#else
+#include <sgtty.h>
+#endif
+#include <time.h>
+#if defined(INTERNATIONAL)
+#include <langinfo.h>
+#include <locale.h>
+#endif
+
+static void    handler();
+
+char   *lowerCase( string )
+char   *string;
+
+{
+       char    *s;
+
+       for ( s = string; s != NULL && *s != '\0'; s++ )
+               if ( isupper( *s ) )
+                       *s = tolower( *s );
+       return string;
+}
+
+char   *convertTime( date, locale )
+char   *date, *locale;
+
+{
+       /*
+        * A quick hack to convert the time from the format Quipu uses into
+        * a more normal representation.
+        */
+       struct tm       *tm;
+       time_t          time;
+       static char     result[BUFSIZ];
+       int             UTCOffset;
+
+       /*
+        * Get local timezone information, we need to apply this to the 
+        * zulu time that Quipu uses later.
+        */
+       time = 0;
+       tm = localtime(&time);
+       UTCOffset = tm->tm_gmtoff;
+       sscanf( date, "%2d%2d%2d%2d%2d%2dZ",
+               &tm->tm_year, &tm->tm_mon, &tm->tm_mday, 
+               &tm->tm_hour, &tm->tm_min, &tm->tm_sec );
+       tm->tm_mon--;
+       tm->tm_isdst = 0;
+       tm->tm_gmtoff = 0;
+       time = mktime(tm);
+       time += UTCOffset;
+       tm = localtime(&time);
+#if defined(INTERNATIONAL)
+       setlocale(LC_TIME, locale);
+       strftime(result, sizeof(result), nl_langinfo(D_T_FMT), tm);
+#else
+       strftime(result, sizeof(result), "%c", tm);
+#endif
+       return result;
+}
+
+static long    interrupt;
+
+char   *getPassword( prompt )
+char   *prompt;
+
+{
+#if defined(SYS5) || defined(XOS_2)
+       struct termios  ttyb;
+#else
+       struct sgttyb   ttyb;
+#endif
+       FILE            *input;
+       struct sigvec   ovec, vec;
+       void            handler();
+       unsigned long   flags;
+       int             c, idx;
+       static char     buffer[BUFSIZ + 1];
+
+       if ( ( input = fopen( "/dev/tty", "r" ) ) == NULL )
+               input = stdin;
+       else
+               setbuf( input, (char *) NULL );
+       vec.sv_handler = handler;
+       vec.sv_mask = 0;
+       vec.sv_flags = SV_INTERRUPT;
+       sigvec( SIGINT, &vec, &ovec );
+       interrupt = 0;
+#if defined(SYS5) || defined(XOS_2)
+       ioctl( fileno( input ), TCGETS, &ttyb );
+       flags = ttyb.c_lflag;
+       ttyb.c_lflags &= ~ ( ECHO | ECHOE | ECHOK | ECHONL );
+       ioctl( fileno( input ), TCSETSF, &ttyb );
+#else
+       ioctl( fileno( input ), TIOCGETP, &ttyb );
+       flags = ttyb.sg_flags;
+       ttyb.sg_flags &= ~ ECHO;
+       ioctl( fileno( input ), TIOCSETN, &ttyb );
+#endif
+       fputs( prompt, stderr );
+       idx = 0;
+       while ( !interrupt && ( c = getc( input ) ) != EOF ) {
+               if ( c == '\n' || c == '\r' )
+                       break;
+               if ( idx < BUFSIZ )
+                       buffer[idx++] = c;
+       }
+       if ( interrupt )
+               buffer[0] = '\0';
+       else
+               buffer[idx] = '\0';
+#if defined(SYS5) || defined(XOS_2)
+       ttyb.c_lflag = flags;
+       ioctl( fileno( input ), TCSETSW, &ttyb );
+#else
+       ttyb.sg_flags = flags;
+       ioctl( fileno( input ), TIOCSETN, &ttyb );
+#endif
+       putc( '\n', stderr );
+       sigvec( SIGINT, &ovec, (struct sigvec *) NULL );
+       if ( input != stdin )
+               fclose( input );
+       if ( interrupt )
+               kill( getpid(), SIGINT );
+       return buffer;
+}
+
+static void    handler()
+
+{
+       ++interrupt;
+}
diff --git a/contrib/whois++/version.c b/contrib/whois++/version.c
new file mode 100644 (file)
index 0000000..4c74763
--- /dev/null
@@ -0,0 +1,35 @@
+#if !defined(lint)
+static char copyright[] = "Copyright 1992 The University of Adelaide";
+#endif
+
+/*
+ *                     V E R S I O N
+ *
+ * Author:     Mark R. Prior
+ *             Communications and Systems Branch
+ *             Information Technology Division
+ *             The University of Adelaide
+ * E-mail:     mrp@itd.adelaide.edu.au
+ * Date:       October 1992
+ * Version:    1.7
+ * Description:
+ *             Provide a minor revision number
+ *
+ * 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 Adelaide. 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.
+ */
+
+char   *version()
+
+{
+       return "1.7";
+}
diff --git a/contrib/whois++/whois++.c b/contrib/whois++/whois++.c
new file mode 100644 (file)
index 0000000..ce80719
--- /dev/null
@@ -0,0 +1,417 @@
+#if !defined(lint)
+static char copyright[] = "Copyright 1992 The University of Adelaide";
+#endif
+
+/*
+ *                     W H O I S + +
+ *
+ * Author:     Mark R. Prior
+ *             Communications and Systems Branch
+ *             Information Technology Division
+ *             The University of Adelaide
+ * E-mail:     mrp@itd.adelaide.edu.au
+ * Date:       October 1992
+ * Version:    1.7
+ * Description:
+ *     This is an experimental implementation of the proposed IETF
+ *     WNILS WG update to the whois/nicname protocol (whois++).
+ *
+ * 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 Adelaide. 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.
+ */
+
+#include "whois++.h"
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+static initialise();
+
+main( argc, argv )
+int    argc;
+char   **argv;
+{
+       FILE                    *tailorFile, *bannerFile;
+       char                    tailor[MAXPATHLEN];
+       char                    query[BUFSIZ], buffer[BUFSIZ];
+       char                    *s, *hostname, *remote;
+       char                    **info;
+       int                     i, printInfo = FALSE;
+       extern char             *optarg;
+       LDAP                    *ld;
+       LDAPMessage             *result, *entry;
+       int                     timelimit = DEFAULT_TIMELIMIT;
+       struct hostent          *hp;
+       static struct sockaddr  sa;
+       struct sockaddr_in      *sin = (struct sockaddr_in *) (&sa);
+       int                     length = sizeof(sa);
+       static char             options[] = "[-b searchbase] [-d debug ] \
+[-h ldaphost ] [-i] [-l] [-s sizelimit] [-t timelimit] [-T tailorfile ] \
+[-u user] [-v]";
+       static char             *attributes[] =
+                                       { "businessCategory", "info", NULL };
+
+       if ( (program = strrchr( argv[0], '/' )) == NULL )
+               program = strdup( argv[0] );
+       else
+               program = strdup( program + 1 );
+
+#if defined(LOG_DAEMON)
+       openlog(program, LOG_PID, FACILITY );
+#else
+       openlog(program, LOG_PID );
+#endif
+
+       initialise();
+
+       sprintf( tailor, "%s/%stailor", ETCDIR, program );
+       if ( (tailorFile = fopen( tailor, "r" )) != NULL ) {
+               readConfiguration( tailorFile );
+               fclose( tailorFile );
+       }
+
+       while ( (i = getopt( argc, argv, "b:d:h:ils:t:T:u:v?" )) != EOF ) {
+               switch ( i ) {
+               case 'b':       /* search base */
+                       base = strdup( optarg );
+                       break;
+
+               case 'd':       /* debug */
+                       debug = atoi( optarg );
+                       break;
+
+               case 'h':       /* ldap host */
+                       ldaphost = strdup( optarg );
+                       break;
+
+               case 'i':       /* print info attribute */
+                       printInfo = TRUE;
+                       break;
+
+               case 'l':       /* enable logging via syslog */
+                       log = TRUE;
+                       break;
+
+               case 's':       /* size limit */
+                       if ( ( maxHits = atoi( optarg ) ) < 1 ) {
+                               fprintf( stderr, "%s: Invalid maxhits value\n",
+                                       program );
+                               syslog( LOG_ERR, "Invalid maxhits value" );
+                               exit( 1 );
+                       }
+                       maximumSize = maxHits;
+                       break;
+
+               case 't':       /* time limit */
+                       timelimit = atoi( optarg );
+                       break;
+
+               case 'T':       /* tailor file */
+                       if ( (tailorFile = fopen( optarg, "r" )) != NULL ) {
+                               readConfiguration( tailorFile );
+                               fclose( tailorFile );
+                       } else {
+                               perror( program );
+                               exit( 1 );
+                       }
+                       break;
+
+               case 'u':       /* user to bind as */
+                       user = strdup( optarg );
+                       break;
+
+               case 'v':       /* version */
+                       fprintf( stderr, "%s: %s %d.%s\n",
+                               program, RELEASE, REVISION, version() );
+                       exit( 0 );
+
+               default:        /* usage message, don't "fail" if ? */
+                       fprintf( stderr, "usage: %s %s\n", program, options );
+                       exit( i != '?' );
+               }
+       }
+
+       language = defaultLanguage;
+
+       /*
+        * We can cope without knowing most things but we do need to know
+        * where to start looking!
+        */
+       if ( base == NULL ) {
+               syslog( LOG_ERR, "No base specified" );
+               fprintf( stderr, "%s: No base specified.\n", program );
+               exit( 1 );
+       }
+
+       if ( ! debug ) {
+               if ( getpeername(0, &sa, &length) < 0) {
+                       perror( "getpeername" );
+                       exit( 1 );
+               }
+               if ( log ) {
+                       if ( ( hp = gethostbyaddr((char *) &sin->sin_addr,
+                               sizeof(sin->sin_addr), AF_INET) ) != 0 ) {
+                               hostname = strdup( hp->h_name );
+                               if ( ( hp = gethostbyname( hostname ) ) == 0 ) {
+                                       free( hostname );
+                                       hostname = strdup( inet_ntoa(sin->sin_addr) );
+                               }
+                       } else
+                               hostname = strdup( inet_ntoa(sin->sin_addr) );
+#if defined(RFC931)
+                       remote = rfc931_name( sin );
+#else
+                       remote = NULL;
+#endif
+                       syslog( LOG_INFO, "Connection from %s%s%s [%s]",
+                               (remote)?remote:"", (remote)?"@":"",
+                               hostname, inet_ntoa(sin->sin_addr) );
+               }
+       }
+
+       if ( (ld = ldap_open( ldaphost, LDAP_PORT )) == NULL ) {
+               printFormatted( lineLength, TRUE, stdout,
+                       "Connection to LDAP port on %s has failed", ldaphost );
+               syslog( LOG_ERR, "Connection to LDAP port on %s has failed",
+                       ldaphost );
+               exit( 1 );
+       }
+       ld->ld_timelimit = timelimit;
+       ld->ld_sizelimit = maxHits;
+       ld->ld_deref = LDAP_DEREF_FINDING;
+
+       ldap_simple_bind_s( ld, user, password );
+       switch ( ld->ld_errno ) {
+       case LDAP_SUCCESS:
+               break;
+
+       case LDAP_UNAVAILABLE:
+               printFormatted( lineLength, TRUE, stdout,
+                       "Sorry, the X.500 service is temporarily unavailable. \
+Please try again later." );
+               syslog( LOG_NOTICE, "X.500 service temporarily unavailable" );
+               exit( 1 );
+
+       default:
+               printFormatted( lineLength, TRUE, stdout,
+                       "Bind to Directory failed, %s",
+                       ldap_err2string( ld->ld_errno ) );
+               syslog( LOG_ERR, "Bind to Directory failed, %s",
+                       ldap_err2string( ld->ld_errno ) );
+               exit( 1 );
+
+       }
+
+       ldap_search_s( ld, base, LDAP_SCOPE_BASE, "objectclass=*",
+               attributes, 0, &result );
+       if ( ld->ld_errno != LDAP_SUCCESS ) {
+               printFormatted( lineLength, TRUE, stdout,
+                       "Read of entry \"%s\" failed, %s",
+                       base, ldap_err2string( ld->ld_errno ) );
+               exit( 1 );
+       }
+       entry = ldap_first_entry( ld, result );
+       organisation = strdup( ldap_dn2ufn( ldap_get_dn( ld, entry ) ) );
+       category = ldap_get_values( ld, entry, "businessCategory" );
+
+       printFormatted( lineLength, FALSE, stdout,
+               "Whois++ Service at %s.", ldap_dn2ufn( base ) );
+       printFormatted( lineLength, FALSE, stdout,
+               "For more information about this service send the \"help\" command." );
+
+       if ( printInfo && ( info = ldap_get_values( ld, entry, "info" ) ) != NULL ) {
+               for ( i = 0; info[i] != NULL; i++ ) {
+                       printFormatted( lineLength, FALSE, stdout, "" );
+                       printFormatted( lineLength, TRUE, stdout,
+                               "%s", info[i] );
+               }
+               ldap_value_free( info );
+       }
+       if ( banner != NULL && ( bannerFile = fopen( banner, "r" ) ) != NULL ) {
+               printFormatted( lineLength, FALSE, stdout, "" );
+               while ( fgets( buffer, BUFSIZ, bannerFile ) != NULL ) {
+                       i = strlen( buffer );
+                       while ( i-- > 0 && ( buffer[i] == '\n' || buffer[i] == '\r' ) )
+                               buffer[i] = '\0';
+                       printFormatted( lineLength, TRUE, stdout, "%s", buffer );
+               }
+               fclose( bannerFile );
+       }
+       printFormatted( lineLength, FALSE, stdout, "" );
+
+       do {
+               *query = '\0';
+               holdConnection = FALSE;
+               switch ( parseCommand( query ) ) {
+               case READ:
+                       /* No need to search, just read the entry given! */
+                       ldap_search_s( ld, query, LDAP_SCOPE_BASE,
+                               "objectclass=*", NULL, 0, &result );
+                       switch( ld->ld_errno ) {
+                       case LDAP_SUCCESS:
+                               break;
+               
+                       case LDAP_NO_SUCH_OBJECT:
+/**/                           /* PROBABLY WANT SPECIAL PROCESSING HERE */
+
+                       default:
+                               printFormatted( lineLength, TRUE, stdout,
+                                       "Read failed, %s",
+                                       ldap_err2string( ld->ld_errno ) );
+                               return 1;
+
+                       }
+                       displayResult( ld, result, outputFormat );
+                       break;
+
+               case SEARCH:
+                       if ( debug > 2 )
+                               fprintf( stderr, "LDAP Query %s\n", query );
+                       if ( log )
+                               syslog( LOG_INFO, "LDAP Query %s", query );
+
+                       ld->ld_sizelimit = maxHits;
+                       ldap_search_s( ld, base, LDAP_SCOPE_SUBTREE, query,
+                               NULL, 0, &result );
+                       switch ( ld->ld_errno ) {
+                       case LDAP_SUCCESS:
+                               break;
+
+                       case LDAP_SIZELIMIT_EXCEEDED:
+                               printFormatted( lineLength, TRUE, stdout,
+                                       "Partial results only - a size limit \
+was exceeded, only %d entries returned", ldap_count_entries( ld, result ) );
+                               break;
+
+                       case LDAP_TIMELIMIT_EXCEEDED:
+                               printFormatted( lineLength, TRUE, stdout,
+                                       "Partial results only - a time limit \
+was exceeded." );
+                               break;
+
+                       default:
+                               printFormatted( lineLength, TRUE, stdout,
+                                       "Search failed, %s",
+                                       ldap_err2string( ld->ld_errno ) );
+                               exit( 1 );
+
+                       }
+                       displayResult( ld, result, outputFormat );
+                       break;
+
+               case HELP:
+                       needHelp( lowerCase( query ) );
+                       break;
+
+               case DESCRIBE:
+                       displayDescribe( ld, base );
+                       break;
+
+               case VERSION:
+                       printFormatted( lineLength, TRUE, stdout,
+                               "Whois++ Protocol version %s", PROTOCOL );
+                       printFormatted( lineLength, TRUE, stdout,
+                               "Program version %s %d.%s",
+                               RELEASE, REVISION, version() );
+                       printFormatted( lineLength, TRUE, stdout,
+                               "Default language is %s", defaultLanguage );
+                       printFormatted( lineLength, TRUE, stdout,
+                               "Built by %s", BUILD );
+                       break;
+
+               case LIST:
+                       listTemplates( lowerCase( query ) );
+                       break;
+
+               case SHOW:
+                       showTemplate( lowerCase( query ) );
+                       break;
+
+               case CONSTRAINTS:
+                       printFormatted( lineLength, TRUE, stdout, 
+                               "This implementation supports the following constraints." );
+                       printFormatted( lineLength, TRUE, stdout, 
+                               "Local constraints are" );
+                       printFormatted( lineLength, TRUE, stdout, 
+                               "    match=(exact|fuzzy)" );
+                       printFormatted( lineLength, TRUE, stdout, 
+                               "Global constraints are" );
+                       printFormatted( lineLength, TRUE, stdout, 
+                               "    format=(full|abridged|handle|summary)" );
+                       printFormatted( lineLength, TRUE, stdout, 
+                               "    hold" );
+                       printFormatted( lineLength, TRUE, stdout, 
+                               "    language=<string>" );
+                       printFormatted( lineLength, TRUE, stdout, 
+                               "    linelength=<number>" );
+                       printFormatted( lineLength, TRUE, stdout, 
+                               "    maxhits=<number>" );
+                       break;
+
+               case COMMAND:
+                       printFormatted( lineLength, TRUE, stdout,
+                               "Commands supported by this implementation are" );
+                       printFormatted( lineLength, TRUE, stdout,
+                               "    command" );
+                       printFormatted( lineLength, TRUE, stdout,
+                               "    constraints" );
+                       printFormatted( lineLength, TRUE, stdout,
+                               "    describe" );
+                       printFormatted( lineLength, TRUE, stdout,
+                               "    help" );
+                       printFormatted( lineLength, TRUE, stdout,
+                               "    list" );
+                       printFormatted( lineLength, TRUE, stdout,
+                               "    show" );
+                       printFormatted( lineLength, TRUE, stdout,
+                               "    version" );
+                       break;
+
+               case ERROR:
+                       break;
+
+               }
+       } while ( holdConnection );
+       closelog();
+       ldap_unbind( ld );
+}
+
+static initialise()
+
+{
+       char    buffer[BUFSIZ];
+
+       debug = FALSE;
+       maxHits = DEFAULT_SIZELIMIT;
+       maximumSize = maxHits;
+       outputFormat = NULL;
+       lineLength = DEFAULT_LINE_LENGTH;
+       ldaphost = DEFAULT_LDAPHOST;
+       defaultLanguage = DEFAULT_LANGUAGE;
+       locale = "";
+       base = NULL;
+       contact = NULL;
+       if ( gethostname( buffer, BUFSIZ ) == 0 )
+               hostname = strdup( buffer );
+       else
+               hostname = NULL;
+       user = NULL;
+       password = NULL;
+       helpDir = HELP_DIRECTORY;
+       configDir = CONFIG_DIRECTORY;
+       organisation = NULL;
+       banner = NULL;
+       log = FALSE;
+       numberOfTemplates = 0;
+       tableSize = TABLE_INCREMENT;
+       templateTranslationTable = NULL;
+}
diff --git a/contrib/whois++/whois++.h b/contrib/whois++/whois++.h
new file mode 100644 (file)
index 0000000..fe22ee1
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ *                     W H O I S + +
+ *
+ * Author:     Mark R. Prior
+ *             Communications and Systems Branch
+ *             Information Technology Division
+ *             The University of Adelaide
+ * E-mail:     mrp@itd.adelaide.edu.au
+ * Date:       October 1992
+ * Copyright:  (C) 1992, The University of Adelaide
+ * Version:    1.7
+ * Description:
+ *     This is an experimental implementation of the proposed IETF
+ *     WNILS WG update to the whois/nicname protocol (whois++).
+ *
+ * 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 Adelaide. 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.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <dirent.h>
+#if defined(INTERNATIONAL)
+#include <langinfo.h>
+#include <locale.h>
+#include <nl_types.h>
+#endif
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include "syslog.h"
+#include "lber.h"
+#include "ldap.h"
+
+#define        EQ(x,y)         (strcasecmp(x,y) == 0)
+
+#if defined(sun)
+extern int     sys_nerr;
+extern char    *sys_errlist[];
+#define strerror(_e)   ( ( ( (_e) >= 0 ) && ( (_e) < sys_nerr ) ) ? \
+               sys_errlist[(_e)] : "Undocumented error code" )
+#endif
+
+#if !defined(TRUE)
+#define        TRUE                    1
+#define        FALSE                   0
+#endif
+
+#if defined(MAIN)
+#define        EXTERN
+#else
+#define        EXTERN                  extern
+#endif
+
+#if !defined(ABRIDGED_LIMIT)
+#define        ABRIDGED_LIMIT          10
+#endif
+#if !defined(DEFAULT_LDAPHOST)
+#define DEFAULT_LDAPHOST       "localhost"
+#endif
+#if !defined(DEFAULT_SIZELIMIT)
+#define DEFAULT_SIZELIMIT      50
+#endif
+#if !defined(DEFAULT_TIMELIMIT)
+#define DEFAULT_TIMELIMIT      60
+#endif
+#if !defined(HELP_DIRECTORY)
+#define HELP_DIRECTORY         "/usr/local/isode/help/whois++"
+#endif
+#if !defined(CONFIG_DIRECTORY)
+#define        CONFIG_DIRECTORY        "/usr/local/isode/etc/whois++"
+#endif
+#if !defined(DEFAULT_LANGUAGE)
+#define        DEFAULT_LANGUAGE        "english"
+#endif
+
+#define        ATTRIBUTE_INCREMENT     10
+#define        TABLE_INCREMENT         10
+#define        DEFAULT_LINE_LENGTH     80
+#define MIN_LINE_LENGTH                40
+#define        MAX_LINE_LENGTH         200
+
+/*
+ * Tokens
+ */
+#define        HELP            1
+#define        LIST            2
+#define        DESCRIBE        3
+#define        VERSION         4
+#define        SHOW            5
+#define        CONSTRAINTS     6
+#define        SEARCH          7
+#define        TEMPLATE        8
+#define        HANDLE          9
+#define        ATTRIBUTE       10
+#define        VALUE           11
+#define        SEARCH_ALL      12
+#define        COMMA           13
+#define        ERROR           14
+#define        EQUALS          15
+#define        COLON           16
+#define        SEMICOLON       17
+#define        FULL            18
+#define        ABRIDGED        19
+#define        SUMMARY         20
+#define        READ            21
+#define        LANGUAGE        22
+#define        FORMAT          23
+#define        HOLD            24
+#define        MAXHITS         25
+#define        MATCH           26
+#define        LINE_LENGTH     27
+#define        COMMAND         28
+#define TRACE          29
+
+typedef        struct {
+       char    *key;
+       char    *value;
+       } table;
+
+EXTERN int             debug, outputFormat, lineLength, holdConnection, log;
+EXTERN int             maxHits, numberOfTemplates, tableSize, maximumSize;
+EXTERN char            *program, *ldaphost, *language, *locale, *base;
+EXTERN char            *contact, *hostname, *user, *password, *helpDir;
+EXTERN char            *configDir, *organisation, *defaultLanguage;
+EXTERN char            *banner;
+EXTERN char            **category;
+EXTERN table           *templateTranslationTable;
+
+extern int             displayDescribe(), parseCommand();
+extern void            needHelp();
+extern void            showTemplate(), listTemplates();
+extern char            **specifyAttributes();
+extern char            *lowerCase(), *version(), *attributeLabel();
+extern char            *rfc931_name();
diff --git a/contrib/whois++/whois++d.man b/contrib/whois++/whois++d.man
new file mode 100644 (file)
index 0000000..be51b63
--- /dev/null
@@ -0,0 +1,162 @@
+.\" Copyright (c) 1993 The University of Adelaide.
+.\" 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 Adelaide. 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.
+.\"
+.\"    @(#)whois++d.man        1.5
+.\"
+.TH WHOIS++D 8 "26 April 1993"
+.SH NAME
+whois++d \- Whois++ white pages server
+.SH SYNOPSIS
+.B whois++d
+[
+.B \-b
+.I basename
+] [
+.B \-d
+.I debuglevel
+] [
+.B \-h
+.I ldaphost
+] [
+.B \-i
+] [
+.B \-l
+] [
+.B \-s
+.I maxhits
+] [
+.B \-t
+.I timelimit
+] [
+.B \-T
+.I tailorfile
+] [
+.B \-u
+.I user
+] [
+.B \-v
+] [
+.B \-?
+]
+.SH DESCRIPTION
+.I Whois++d
+is an implementation of the new whois++ white pages server. The server is in
+reality a DUA interface that uses the lightweight directory access protocol
+[RFC????] to communicate with an X.500 Directory System Agent (DSA) via a
+.MS ldapd 8
+server. The whois++ architecture (and command format) is described in an
+Internet Draft of the IETF's WNILS Working Group.
+
+By default
+.I whois++d
+reads it's configuration information from a tailor file (whois++dtailor)
+located in the
+.IR ETCDIR
+but this may be supplemented by command line options, including the
+specification of a secondary tailor file.
+.PP
+Options are:
+.TP
+.B \-b
+Specify the base for all queries, this must be specified either via the 
+commandline or (more normally) via the tailor file.
+.TP
+.B \-d
+Print debugging information.
+A number after the ``d'' determines the level of messages printed.
+.TP
+.B \-h
+Specify the host running the 
+.MS ldapd 8
+server.
+.TP
+.B \-i
+If the entry for the ``base'' of the searches has an info attribute then
+print it as part of the welcome banner.
+.TP
+.B \-l
+Enable logging of queries via syslog.
+.TP
+.B \-s
+Specify the maximum number of entries you wish returned as a result of a
+search. This is normally controlled by the DSA but if this is not possible
+then it can be restricted via this option.
+.TP
+.B \-t
+Specify a timelimit for queries to the DSA. Note this is
+.B not
+the timeout limit between queries when using the
+.I hold
+constraint.
+.TP
+.B \-T
+Specify an additional tailor file. Useful if you only have a binary and the
+default location is not what you consider to be a ``normal'' place.
+.TP
+.B \-u
+Specify the user's DN to use when binding to the directory.
+.TP
+.B \-v
+Return the version number of this server and then exit.
+.TP
+.B \-?
+Print a list of valid commandline options and then exit.
+.SH "CONFIGURATION FILE"
+When started 
+.B whois++d
+reads it's configuration file before processing any command line options.
+The configuration commands that may be included in this tailor file are
+.IP banner
+Specify a file to display as a welcome message.
+.IP base
+This specifies the entry within the DIT where searches will commence. This is
+normally set to the organisation's entry.
+.IP configdir
+Identifies where the configuration files may be found, currently only used
+for the template descriptions.
+.IP contact
+This is the distinguished name of the person responsible for this service, and
+whose entry will be displayed if the client uses the `describe' query. If this
+is not defined in the configuration file it defaults to the DSA manager.
+.IP helpdir
+This directory contains the multi-lingual help files. There should be a
+subdirectory for each language supported and within these subdirectories
+are helpfiles that are displayed by the server. At a minimum there should be
+an english directory containing a `general' helpfile (which contains
+introductory information).
+.IP hostname
+Used when the server is queried using the `describe' command. If not specified
+it will default to the local hostname.
+.IP language
+Specify the default language to be used when producing diagnostic messages.
+.IP ldaphost
+This specifies the host running a ldap server which can be used to communicate
+with the X.500 DSA.
+.IP password
+The password to use then binding to the X.500 DSA.
+.IP template
+The whois++ template name is not always the same as the X.500 object class
+so this option allows the two values to be associated with each other. The
+two values are template-name and objectclass-name.
+.IP user
+The LDAP distinguished name of the user to use when binding to the directory.
+This is optional but the DSA may restrict the information available to the
+whois++ server unless it authenticates itself.
+.NT
+Multi-lingual support is not available yet.
+.SH FILES
+ETCDIR/whois++dtailor  whois++ server tailor file
+.SH "SEE ALSO"
+ldapd(8)
diff --git a/contrib/whois++/whois++dtailor b/contrib/whois++/whois++dtailor
new file mode 100644 (file)
index 0000000..0456051
--- /dev/null
@@ -0,0 +1,5 @@
+base           "o=The University of Adelaide, c=AU"
+template       user            person
+template       service         applicationEntity
+template       department      organizationalUnit
+template       role            organizationalRole
diff --git a/doc/Make-template b/doc/Make-template
new file mode 100644 (file)
index 0000000..1dea71c
--- /dev/null
@@ -0,0 +1,95 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1994 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP doc Makefile
+#
+#-----------------------------------------------------------------------------
+
+############################################################################
+#                                                                          #
+# You should not have to edit anything below this point                    #
+#                                                                          #
+############################################################################
+
+all:   FORCE
+       @echo "making all in `$(PWD)`"
+       @for i in *; do \
+           if [ -d $$i -a $$i != "RCS" ]; then \
+               echo; echo "  cd $$i; $(MAKE) $(MFLAGS) all"; \
+               ( cd $$i; $(MAKE) $(MFLAGS) all ); \
+           fi; \
+       done
+
+
+install:       FORCE
+       @echo "making install in `$(PWD)`"
+       @for i in *; do \
+           if [ -d $$i -a $$i != "RCS" ]; then \
+               echo; echo "  cd $$i; $(MAKE) $(MFLAGS) install"; \
+               ( cd $$i; $(MAKE) $(MFLAGS) install ); \
+           fi; \
+       done
+
+
+clean: FORCE
+       @echo "making clean in `$(PWD)`"
+       @for i in *; do \
+           if [ -d $$i -a $$i != "RCS" ]; then \
+               echo; echo "  cd $$i; $(MAKE) $(MFLAGS) clean"; \
+               ( cd $$i; $(MAKE) $(MFLAGS) clean ); \
+           fi; \
+       done
+
+
+veryclean:     clean
+
+
+depend:        FORCE
+       @echo "making depend in `$(PWD)`"
+       @for i in *; do \
+           if [ -d $$i -a $$i != "RCS" ]; then \
+               echo; echo "  cd $$i; $(MAKE) $(MFLAGS) depend"; \
+               ( cd $$i; $(MAKE) $(MFLAGS) depend ); \
+           fi; \
+       done
+
+
+lint:  FORCE
+       @echo "making lint in `$(PWD)`"
+       @for i in *; do \
+           if [ -d $$i -a $$i != "RCS" ]; then \
+               echo; echo "  cd $$i; $(MAKE) $(MFLAGS) lint"; \
+               ( cd $$i; $(MAKE) $(MFLAGS) lint ); \
+           fi; \
+       done
+
+
+5lint: FORCE
+       @echo "making 5lint in `$(PWD)`"
+       @for i in *; do \
+           if [ -d $$i -a $$i != "RCS" ]; then \
+               echo; echo "  cd $$i; $(MAKE) $(MFLAGS) 5lint"; \
+               ( cd $$i; $(MAKE) $(MFLAGS) 5lint ); \
+           fi; \
+       done
+
+
+links:
+       @echo "making links in `$(PWD)`"; \
+       for i in .src/*; do \
+           if [ -d $$i -a $$i != ".src/RCS" ]; then \
+               d=`basename $$i`; \
+               ( $(MKDIR) $$d; cd $$d; $(LN) ../.src/$$d .src; \
+                 $(LN) ../.src/$$d/Make-template . ; \
+                 $(MAKE) $(MFLAGS) MKDIR="$(MKDIR)" LN="$(LN)" \
+                   -f Make-template links ) ; \
+           fi; \
+       done
diff --git a/doc/guides/Make-template b/doc/guides/Make-template
new file mode 100644 (file)
index 0000000..f54d68a
--- /dev/null
@@ -0,0 +1,29 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1994 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP doc/guides makefile
+#
+#-----------------------------------------------------------------------------
+
+all:   FORCE
+
+install:       FORCE
+
+lint:  FORCE
+
+5lint: FORCE
+
+clean: FORCE
+
+depend:        FORCE
+
+links:
+       @$(LN) .src/*.txt .
diff --git a/doc/man/Make-template b/doc/man/Make-template
new file mode 100644 (file)
index 0000000..e975170
--- /dev/null
@@ -0,0 +1,84 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1994 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP doc/man makefile
+#
+#-----------------------------------------------------------------------------
+
+############################################################################
+#                                                                          #
+# You should not have to edit anything below this point                    #
+#                                                                          #
+############################################################################
+
+all:   FORCE
+       @echo "making all in `$(PWD)`"
+       @for i in *; do \
+           if [ -d $$i -a $$i != "RCS" ]; then \
+               echo; echo "  cd $$i; $(MAKE) $(MFLAGS) all"; \
+               ( cd $$i; $(MAKE) $(MFLAGS) all ); \
+           fi; \
+       done
+
+
+#
+# rules to install the software
+#
+
+install:       FORCE
+       @echo "making install in `$(PWD)`"
+       @for i in *; do \
+           if [ -d $$i -a $$i != "RCS" ]; then \
+               echo; echo "  cd $$i; $(MAKE) $(MFLAGS) install"; \
+               ( cd $$i; $(MAKE) $(MFLAGS) install ); \
+           fi; \
+       done
+
+#
+# rules to make clean
+#
+
+clean: FORCE
+       @echo "making clean in `$(PWD)`"
+       @for i in *; do \
+           if [ -d $$i -a $$i != "RCS" ]; then \
+               echo; echo "  cd $$i; $(MAKE) $(MFLAGS) clean"; \
+               ( cd $$i; $(MAKE) $(MFLAGS) clean ); \
+           fi; \
+       done
+
+veryclean:     clean
+
+#
+# rules to make depend
+#
+#
+
+depend:        FORCE
+       @echo "making depend in `$(PWD)`"
+       @for i in *; do \
+           if [ -d $$i -a $$i != "RCS" ]; then \
+               echo; echo "  cd $$i; $(MAKE) $(MFLAGS) depend"; \
+               ( cd $$i; $(MAKE) $(MFLAGS) depend ); \
+           fi; \
+       done
+
+links:
+       @echo "making links in `$(PWD)`"; \
+       for i in .src/*; do \
+           if [ -d $$i -a $$i != ".src/RCS" ]; then \
+               d=`basename $$i`; \
+               ( $(MKDIR) $$d; cd $$d; $(LN) ../.src/$$d .src; \
+                 $(LN) ../.src/$$d/Make-template . ; \
+                 $(MAKE) $(MFLAGS) MKDIR="$(MKDIR)" LN="$(LN)" \
+                   -f Make-template links ) ; \
+           fi; \
+       done
diff --git a/doc/man/man1/Make-template b/doc/man/man1/Make-template
new file mode 100644 (file)
index 0000000..dfc4a51
--- /dev/null
@@ -0,0 +1,52 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1994 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP man1 makefile
+#
+#-----------------------------------------------------------------------------
+
+LDAPSRC= ../../..
+SECT=1
+INSTDIR=$(MANDIR)/man$(SECT)
+VERSIONFILE = $(LDAPSRC)/build/version
+
+all:   FORCE
+
+install:       FORCE
+       -$(MKDIR) -p $(INSTDIR)
+       @TMPMAN=/tmp/ldapman.$$$$; \
+       VERSION=`$(CAT) $(VERSIONFILE)`; \
+       for page in *.$(SECT); do \
+           $(SED) -e 's%ETCDIR%$(RUNTIMEETCDIR)%' -e "s%LDVERSION%$$VERSION%" \
+                   $$page > $$TMPMAN; \
+           echo "installing $(INSTDIR)/$$page"; \
+           $(INSTALL) $(INSTALLFLAGS) -m 644 $$TMPMAN $(INSTDIR)/$$page; \
+           if [ -f "$$page.links" ]; then \
+               for link in `$(CAT) $$page.links`; do \
+                   echo ".so man$(SECT)/$$page" > $$TMPMAN; \
+                   echo "installing $(INSTDIR)/$$link as link to $$page"; \
+                   $(INSTALL) $(INSTALLFLAGS) -m 644 $$TMPMAN \
+                           $(INSTDIR)/$$link; \
+               done; \
+           fi; \
+       done; \
+       $(RM) $$TMPMAN
+
+clean: FORCE
+
+depend:        FORCE
+
+lint:  FORCE
+
+5lint: FORCE
+
+links:
+       @$(LN) .src/*.$(SECT) .src/*links .
diff --git a/doc/man/man1/ldapdelete.1 b/doc/man/man1/ldapdelete.1
new file mode 100644 (file)
index 0000000..ea2f472
--- /dev/null
@@ -0,0 +1,109 @@
+.TH LDAPDELETE 1 "13 November 1995" "U-M LDAP LDVERSION"
+.SH NAME
+ldapdelete \- ldap delete entry tool
+.SH SYNOPSIS
+.B ldapdelete
+.B [\-n]
+.B [\-v]
+.B [\-k]
+.B [\-K]
+.B [\-c]
+.B [\-d debuglevel]
+.B [\-f file]
+.B [\-D binddn]
+.B [\-w passwd]
+.B [\-h ldaphost]
+.B [\-p ldapport]
+.B [dn]...
+.SH DESCRIPTION
+.I ldapdelete
+is a shell-accessible interface to the
+.BR ldap_delete (3)
+library call.
+.LP
+.B ldapdelete
+opens a connection to an LDAP server, binds, and deletes one or more
+entries.  If one or more \fIdn\fP arguments are provided, entries with
+those Distinguished Names are deleted.  Each \fIdn\fP should be a
+string-represented DN as defined in RFC 1779.  If no \fIdn\fP arguments
+are provided, a list of DNs is read from standard input (or from
+\fIfile\fP if the -f flag is used).
+.SH OPTIONS
+.TP
+.B \-n
+Show what would be done, but don't actually delete entries.  Useful for
+debugging in conjunction with -v.
+.TP
+.B \-v
+Use verbose mode, with many diagnostics written to standard output.
+.TP
+.B \-k
+Use Kerberos authentication instead of simple authentication.  It is
+assumed that you already have a valid ticket granting ticket. This option
+only has effect if
+. B ldapdelete
+is compiled with KERBEROS defined.
+.TP
+.B \-K
+Same as \-k, but only does step 1 of the kerberos bind.  This is useful
+when connecting to a slapd and there is no x500dsa.hostname principal
+registered with your kerberos servers.
+.TP
+.B \-c
+Continuous operation mode.  Errors  are  reported,  but
+.B ldapdelete
+will  continue  with  deletions.   The default is to exit after
+reporting an error.
+.TP
+.B \-d debuglevel
+Set the LDAP debugging level to \fIdebuglevel\fP.
+.B ldapdelete
+must be compiled with LDAP_DEBUG defined for this option to have any effect.
+.TP
+.B \-f file
+Read a series of lines from \fIfile\fP, performing one LDAP search for
+each line.  In this case, the \fIfilter\fP given on the command line
+is treated as a pattern where the first occurrence of \fB%s\fP is
+replaced with a line from \fIfile\fP.
+.TP
+.B \-D binddn
+Use \fIbinddn\fP to bind to the X.500 directory. \fIbinddn\fP should be
+a string-represented DN as defined in RFC 1779.
+.TP
+.B \-w passwd
+Use \fIpasswd\fP as the password for simple authentication.
+.TP
+.B \-h ldaphost
+Specify an alternate host on which the ldap server is running.
+.TP
+.B \-p ldapport
+Specify an alternate TCP port where the ldap server is listening.
+.SH EXAMPLE
+The following command:
+.LP
+.nf
+    ldapdelete "cn=Delete Me, o=University of Michigan, c=US"
+.fi
+.LP
+will attempt to delete the entry named with commonName "Delete Me"
+directly below the University of Michigan organizational entry.  Of
+course it would probably be necessary to supply a \fIbinddn\fP and
+\fIpasswd\fP for deletion to be allowed (see the -D and -w options).
+.SH DIAGNOSTICS
+Exit status is 0 if no errors occur.  Errors result in a non-zero exit
+status and a diagnostic message being written to standard error.
+.SH "SEE ALSO"
+.BR ldapadd (1),
+.BR ldapmodify (1),
+.BR ldapmodrdn (1),
+.BR ldapsearch (1),
+.BR ldap (3),
+.BR ldap_delete (3)
+.LP
+Kille, S.,
+.IR "A String Representation of Distinguished Names",
+.SM RFC
+1779,
+ISODE Consortium, March 1995.
+.SH BUGS
+There is no interactive mode, but there probably should be.
diff --git a/doc/man/man1/ldapmodify.1 b/doc/man/man1/ldapmodify.1
new file mode 100644 (file)
index 0000000..3ffbe59
--- /dev/null
@@ -0,0 +1,301 @@
+.TH LDAPMODIFY 1 "13 November 1995" "U-M LDAP LDVERSION"
+.SH NAME
+ldapmodify, ldapadd \- ldap modify entry and ldap add entry tools
+.SH SYNOPSIS
+.B ldapmodify
+.B [\-a]
+.B [\-b]
+.B [\-c]
+.B [\-r]
+.B [\-n]
+.B [\-v]
+.B [\-k]
+.B [\-d debuglevel]
+.B [\-D binddn]
+.B [\-w passwd]
+.B [\-h ldaphost]
+.B [\-p ldapport]
+.B [\-f file]
+.LP
+.B ldapadd
+.B [\-b]
+.B [\-c]
+.B [\-r]
+.B [\-n]
+.B [\-v]
+.B [\-k]
+.B [\-K]
+.B [\-d debuglevel]
+.B [\-D binddn]
+.B [\-w passwd]
+.B [\-h ldaphost]
+.B [\-p ldapport]
+.B [\-f file]
+.SH DESCRIPTION
+.B ldapmodify
+is a shell-accessible interface to the
+.BR ldap_modify (3)
+and
+.BR ldap_add (3)
+library calls.
+.B ldapadd
+is implemented as a hard link to the ldapmodify tool.  When invoked as
+.B ldapadd
+the -a (add new entry) flag is turned on automatically.
+.LP
+.B ldapmodify
+opens a connection to an LDAP server, binds, and modifies or adds entries.
+The entry information is read from standard input or from \fIfile\fP through
+the use of the -f option.
+.SH OPTIONS
+.TP
+.B \-a
+Add new entries.  The default for
+.B ldapmodify
+is to modify existing entries.  If invoked as
+.BR ldapadd ,
+this flag is always set.
+.TP
+.B \-b
+Assume that any values that start with a `/' are binary values and that
+the actual value is in a file whose path is specified in the place where
+values normally appear.
+.TP
+.B \-c
+Continuous operation mode.  Errors are reported, but
+.B ldapmodify
+will continue with modifications.  The default is to exit after
+reporting an error.
+.TP
+.B \-r
+Replace existing values by default.
+.TP
+.B \-n
+Show what would be done, but don't actually modify entries.  Useful for
+debugging in conjunction with -v.
+.TP
+.B \-v
+Use verbose mode, with many diagnostics written to standard output.
+.TP
+.B \-k
+Use Kerberos authentication instead of simple authentication.  It is
+assumed that you already have a valid ticket granting ticket.  You must
+compile with KERBEROS defined for this option to have any effect.
+.TP
+.B \-K
+Same as \-k, but only does step 1 of the kerberos bind.  This is useful
+when connecting to a slapd and there is no x500dsa.hostname principal
+registered with your kerberos servers.
+.TP
+.B \-F
+Force application of all changes regardless of the contents of input
+lines that begin with
+.I replica:
+(by default, replica: lines are compared against the LDAP server host
+and port in use to decide if a replog record should actually be applied).
+.TP
+.B \-d debuglevel
+Set the LDAP debugging level to \fIdebuglevel\fP.
+.B ldapmodify
+must be compiled with LDAP_DEBUG defined for this option to have any effect.
+.TP
+.B \-f file
+Read the entry modification information from \fIfile\fP instead of from
+standard input.
+.TP
+.B \-D binddn
+Use \fIbinddn\fP to bind to the X.500 directory. \fIbinddn\fP should be
+a string-represented DN as defined in RFC 1779.
+.TP
+.B \-w passwd
+Use \fIpasswd\fP as the password for simple authentication.
+.TP
+.B \-h ldaphost
+Specify an alternate host on which the ldap server is running.
+.TP
+.B \-p ldapport
+Specify an alternate TCP port where the ldap server is listening.
+.SH INPUT FORMAT
+The contents of \fIfile\fP (or standard input if no \-f flag is given on
+the command line) should conform to the format defined in
+.BR slapd.replog (5),
+with the exceptions noted below.
+.LP
+If the first line of a record consists of a decimal number (entry id),
+it is ignored.
+.LP
+Lines that begin with "replica:" are matched against the LDAP server host
+and port in use to decide if a particular replog record should be applied.
+Any other lines that precede the "dn:" line are ignored.
+The -F flag can be used to force
+.I ldapmodify
+to apply all of the replog changes, regardless of the presence or
+absence of any "replica:" lines.
+.LP
+If no "changetype:" line is present, the default is "add" if the -a
+flag is set (or if the program was invoked as
+.I ldapmodify)
+and "modify" otherwise.
+.LP
+If changetype is "modify" and no "add:", "replace:", or "delete:" lines
+appear, the default is "replace" if the -r flag is set and "add"
+otherwise.
+.LP
+Note that the above exceptions to the
+.BR slapd.replog (5)
+format allow
+.BR ldif (5)
+entries to be used as input to
+.I ldapmodify
+or
+.I ldapadd.
+.SH ALTERNATIVE INPUT FORMAT
+An alternative input format is supported for compatibility with older
+versions of
+.I ldapmodify.
+This format consists of one or more entries separated by blank lines,
+where each entry looks like:
+.LP
+.nf
+    Distinguished Name (DN)
+    attr=value
+    [attr=value ...]
+.fi
+.LP
+where \fIattr\fP is the name of the attribute and \fIvalue\fP is the
+value.
+.LP
+By default, values are added.  If the
+.RI \- r
+command line flag is
+given, the default is to replace existing values with the new one.
+Note that it is permissible for a given attribute to appear more than
+once (for example, to add more than one value for an attribute).  Also
+note that you can use a trailing `\\' to continue values across lines and
+preserve newlines in the value itself (this is useful for modifying
+QUIPU iattr attributes among others).
+.LP
+.I attr
+should be preceded by a \fB-\fP to remove a value.  The `=' and
+value should be omitted to remove an entire attribute.
+.LP
+.I attr
+should be preceded by a \fB+\fP to add a value in the presence of the
+\-r flag.
+.LP
+.SH EXAMPLES
+Assuming that the file
+.B /tmp/entrymods
+exists and has the contents:
+.LP
+.nf
+    dn: cn=Modify Me, o=University of Michigan, c=US
+    changetype: modify
+    replace: mail
+    mail: modme@terminator.rs.itd.umich.edu
+    -
+    add: title
+    title: Grand Poobah
+    -
+    add: jpegPhoto
+    jpegPhoto: /tmp/modme.jpeg
+    -
+    delete: description
+    -
+.fi
+.LP
+the command:
+.LP
+.nf
+    ldapmodify -b -r -f /tmp/entrymods
+.fi
+.LP
+will replace the contents of the "Modify Me" entry's
+.I mail
+attribute with the value "modme@terminator.rs.itd.umich.edu", add a
+.I title
+of "Grand Poobah", and the contents of the file "/tmp/modme.jpeg"
+as a
+.IR jpegPhoto ,
+and completely remove the
+.I description
+attribute.
+The same modifications as above can be performed using the older
+.I ldapmodify
+inout format:
+.LP
+.nf
+    cn=Modify Me, o=University of Michigan, c=US
+    mail=modme@terminator.rs.itd.umich.edu
+    +title=Grand Poobah
+    +jpegPhoto=/tmp/modme.jpeg
+    -description
+.fi
+.LP
+and the command:
+.LP
+.nf
+    ldapmodify -b -r -f /tmp/entrymods
+.fi
+.LP
+Assuming that the file
+.B /tmp/newentry
+exists and has the contents:
+.LP
+.nf
+    dn: cn=Barbara Jensen, o=University of Michigan, c=US
+    objectClass: person
+    cn: Barbara Jensen
+    cn: Babs Jensen
+    sn: Jensen
+    title: the world's most famous mythical manager
+    mail: bjensen@terminator.rs.itd.umich.edu
+    uid: bjensen
+.LP
+the command:
+.LP
+.nf
+    ldapadd -f /tmp/entrymods
+.fi
+.LP
+will add a new entry for Babs Jensen, using the values from the
+file
+.B /tmp/newentry.
+.LP
+Assuming that the file
+.B /tmp/newentry
+exists and has the contents:
+.LP
+.nf
+    dn: cn=Barbara Jensen, o=University of Michigan, c=US
+    changetype: delete
+.LP
+the command:
+.LP
+.nf
+    ldapmodify -f /tmp/entrymods
+.fi
+.LP
+will remove Babs Jensen's entry.
+.SH DIAGNOSTICS
+Exit status is 0 if no errors occur.  Errors result in a non-zero exit
+status and a diagnostic message being written to standard error.
+.SH "SEE ALSO"
+.BR ldapadd (1),
+.BR ldapdelete (1),
+.BR ldapmodrdn (1),
+.BR ldapsearch (1),
+.BR ldap (3),
+.BR ldap_add (3),
+.BR ldap_delete (3),
+.BR ldap_modify (3),
+.BR ldap_modrdn (3),
+.BR slapd.replog (5)
+.LP
+Kille, S.,
+.IR "A String Representation of Distinguished Names",
+.SM RFC
+1779,
+ISODE Consortium, March 1995.
+.SH BUGS
+There is no interactive mode, but there probably should be.
diff --git a/doc/man/man1/ldapmodify.1.links b/doc/man/man1/ldapmodify.1.links
new file mode 100644 (file)
index 0000000..eb4fb76
--- /dev/null
@@ -0,0 +1 @@
+ldapadd.1
diff --git a/doc/man/man1/ldapmodrdn.1 b/doc/man/man1/ldapmodrdn.1
new file mode 100644 (file)
index 0000000..8468e7a
--- /dev/null
@@ -0,0 +1,132 @@
+.TH LDAPMODRDN 1 "13 November 1995" "U-M LDAP LDVERSION"
+.SH NAME
+ldapmodrdn \- ldap modify entry RDN tool
+.SH SYNOPSIS
+.B ldapmodrdn
+.B [\-r]
+.B [\-n]
+.B [\-v]
+.B [\-k]
+.B [\-K]
+.B [\-c]
+.B [\-d debuglevel]
+.B [\-D binddn]
+.B [\-w passwd]
+.B [\-h ldaphost]
+.B [\-p ldapport]
+.B [\-f file] [dn rdn]
+.SH DESCRIPTION
+.B ldapmodrdn
+is a shell-accessible interface to the
+.BR ldap_modrdn2 (3)
+library call.
+.LP
+.B ldapmodrdn
+opens a connection to an LDAP server, binds, and modifies the RDN of entries.
+The entry information is read from standard input, from \fIfile\fP through
+the use of the
+.RI \- f
+option, or from the command-line pair \fIdn\fP and
+\fIrdn\fP.
+.SH OPTIONS
+.TP
+.B \-r
+Remove old RDN values from the entry.  Default is to keep old values.
+.TP
+.B \-n
+Show what would be done, but don't actually change entries.  Useful for
+debugging in conjunction with -v.
+.TP
+.B \-v
+Use verbose mode, with many diagnostics written to standard output.
+.TP
+.B \-k
+Use Kerberos authentication instead of simple authentication.  It is
+assumed that you already have a valid ticket granting ticket.
+.B ldapmodrdn
+must be compiled with KERBEROS defined for this option to have effect.
+.TP
+.B \-K
+Same as \-k, but only does step 1 of the kerberos bind.  This is useful
+when connecting to a slapd and there is no x500dsa.hostname principal
+registered with your kerberos servers.
+.TP
+.B \-c
+Continuous operation mode.  Errors  are  reported,  but ldapmodify
+will  continue  with  modifications.   The default is to exit after
+reporting an error.
+.TP
+.B \-d debuglevel
+Set the LDAP debugging level to \fIdebuglevel\fP.
+.B ldapmodrdn
+must be
+compiled with LDAP_DEBUG defined for this option to have any effect.
+.TP
+.B \-f file
+Read the entry modification information from \fIfile\fP instead of from
+standard input or the command-line.
+.TP
+.B \-D binddn
+Use \fIbinddn\fP to bind to the X.500 directory. \fIbinddn\fP should be
+a string-represented DN as defined in RFC 1779.
+.TP
+.B \-w passwd
+Use \fIpasswd\fP as the password for simple authentication.
+.TP
+.B \-h ldaphost
+Specify an alternate host on which the ldap server is running.
+.TP
+.B \-p ldapport
+Specify an alternate TCP port where the ldap server is listening.
+.SH INPUT FORMAT
+If the command-line arguments \fIdn\fP and \fIrdn\fP are given, \fIrdn\fP
+will replace the RDN of the entry specified by the DN, \fIdn\fP.
+.LP
+Otherwise, the contents of \fIfile\fP (or standard input if
+no
+.RI \- f
+flag is given) should consist of one or more entries.
+.LP
+.nf
+    Distinguished Name (DN)
+    Relative Distinguished Name (RDN)
+.fi
+.LP
+One or more blank lines may be used to separate each DN/RDN pair.
+.SH EXAMPLE
+Assuming that the file
+.B /tmp/entrymods
+exists and has the contents:
+.LP
+.nf
+    cn=Modify Me, o=University of Michigan, c=US
+    cn=The New Me
+.fi
+.LP
+the command:
+.LP
+.nf
+    ldapmodify -r -f /tmp/entrymods
+.fi
+.LP
+will change the RDN of the "Modify Me" entry from "Modify Me" to
+"The New Me" and the old cn, "Modify Me" will be removed.
+.LP
+.SH DIAGNOSTICS
+Exit status is 0 if no errors occur.  Errors result in a non-zero exit
+status and a diagnostic message being written to standard error.
+.SH "SEE ALSO"
+.BR ldapadd (1),
+.BR ldapdelete (1),
+.BR ldapmodify (1),
+.BR ldapsearch (1),
+.BR ldap (3),
+.BR ldap_modrdn2 (3)
+.LP
+Kille, S.,
+.IR "A String Representation of Distinguished Names",
+.SM RFC
+1779,
+ISODE Consortium, March 1995.
+.SH BUGS
+There is no interactive mode, but there probably should be.
diff --git a/doc/man/man1/ldapsearch.1 b/doc/man/man1/ldapsearch.1
new file mode 100644 (file)
index 0000000..2d66334
--- /dev/null
@@ -0,0 +1,291 @@
+.TH LDAPSEARCH 1 "29 March 1996" "U-M LDAP LDVERSION"
+.SH NAME
+ldapsearch \- ldap search tool
+.SH SYNOPSIS
+.B ldapsearch
+.B [\-n]
+.B [\-u]
+.B [\-v]
+.B [\-k]
+.B [\-K]
+.B [\-t]
+.B [\-A]
+.B [\-B]
+.B [\-L]
+.B [\-R]
+.B [\-d debuglevel]
+.B [\-F sep]
+.B [\-f file]
+.B [\-D binddn]
+.B [\-w bindpasswd]
+.B [\-h ldaphost]
+.B [\-p ldapport]
+.B [\-b searchbase]
+.B [\-s scope ]
+.B [\-a deref]
+.B [\-l time limit]
+.B [\-z size limit]
+.B filter
+.B [attrs....]
+.SH DESCRIPTION
+.I ldapsearch
+is a shell-accessible interface to the
+.BR ldap_search (3)
+library call.
+.LP
+.B ldapsearch
+opens a connection to an LDAP server, binds, and performs a search
+using the filter \fIfilter\fP.  The \fIfilter\fP should conform to
+the string representation for LDAP filters as defined in RFC 1558.
+.LP
+If
+.B ldapsearch
+finds one or more entries, the attributes specified by
+\fIattrs\fP are retrieved and the entries and values are printed to
+standard output.  If no \fIattrs\fP are listed, all attributes are
+returned.
+.SH OPTIONS
+.TP
+.B \-n
+Show what would be done, but don't actually perform the search.  Useful for
+debugging in conjunction with -v.
+.TP
+.B \-u
+Include the User Friendly form of the Distinguished Name (DN) in the output
+.TP
+.B \-v
+Run in verbose mode, with many diagnostics written to standard output
+.TP
+.B \-k
+Use Kerberos authentication instead of simple authentication.  It is
+assumed that you already have a valid ticket granting ticket.
+.B ldapsearch
+must be compiled with KERBEROS defined for this option to have any effect.
+.TP
+.B \-K
+Same as \-k, but only does step 1 of the kerberos bind.  This is useful
+when connecting to a slapd and there is no x500dsa.hostname principal
+registered with your kerberos servers.
+.TP
+.B \-t
+Write retrieved values to a set of temporary files.  This is useful for
+dealing with non-ASCII values such as jpegPhoto or audio.
+.TP
+.B \-A
+Retrieve attributes only (no values).  This is useful when you just want to
+see if an attribute is present in an entry and are not interested in the
+specific values.
+.TP
+.B \-B
+Do not suppress display of non-ascii values.  This is useful when
+dealing with values that appear in alternate characters sets such as
+ISO-8859.1.  This option is implied by -L (see below).
+.TP
+.B \-L
+Display search results in
+.BR ldif (5)
+format.  This option also turns on the -B option, and causes the -F option
+to be ignored.
+.TP
+.B \-R
+Do not automatically follow referrals returned while searching.
+.B ldapsearch
+must be compiled with LDAP_REFERRALS defined for referrals to be
+automatically followed by default, and for this option to have any effect.
+.TP
+.B \-F sep
+Use \fIsep\fP as the field separator between attribute names and values.
+The default separator is `=', unless the -L flag has been specified, in
+which case this option is ignored.
+.TP
+.B \-S attribute
+Sort the entries returned based on \fIattribute\fP. The default is not
+to sort entries returned.  If \fIattribute\fP is a zero-length string (""),
+the entries are sorted by the components of their Distingished Name.  See
+.BR ldap_sort (3)
+for more details. Note that
+.B ldapsearch
+normally prints out entries as it receives them. The use of the
+.B \-S
+option defeats this behavior, causing all entries to be retrieved,
+then sorted, then printed.
+.TP
+.B \-d debuglevel
+Set the LDAP debugging level to \fIdebuglevel\fP.
+.B ldapsearch
+must be compiled with LDAP_DEBUG defined for this option to have any effect.
+.TP
+.B \-f file
+Read a series of lines from \fIfile\fP, performing one LDAP search for
+each line.  In this case, the \fIfilter\fP given on the command line
+is treated as a pattern where the first occurrence of \fB%s\fP is
+replaced with a line from \fIfile\fP.  If \fIfile\fP is a single \fI-\fP
+character, then the lines are read from standard input.
+.TP
+.B \-D binddn
+Use \fIbinddn\fP to bind to the X.500 directory. \fIbinddn\fP should be
+a string-represented DN as defined in RFC 1779.
+.TP
+.B \-w bindpasswd
+Use \fIbindpasswd\fP as the password for simple authentication.
+.TP
+.B \-h ldaphost
+Specify an alternate host on which the ldap server is running.
+.TP
+.B \-p ldapport
+Specify an alternate TCP port where the ldap server is listening.
+.TP
+.B \-b searchbase
+Use \fIsearchbase\fP as the starting point for the search instead of
+the default.
+.TP
+.B \-s scope
+Specify the scope of the search.  \fIscope\fP should be one of
+.B base,
+.B one,
+or
+.B sub
+to specify a base object, one-level, or subtree search.  The default
+is
+.BR sub .
+.TP
+.B \-a deref
+Specify how aliases dereferencing is done.  \fIderef\fP should be one of
+.B never,
+.B always,
+.B search,
+or
+.B find
+to specify that aliases are never dereferenced, always dereferenced,
+dereferenced when searching, or dereferenced only when locating the
+base object for the search.  The default is to never dereference aliases.
+.TP
+.B \-l timelimit
+wait at most \fItimelimit\fP seconds for a search to complete.
+.TP
+.B \-z sizelimit
+retrieve at most \fIsizelimit\fP seconds for a search to complete.
+.SH OUTPUT FORMAT
+If one or more entries are found, each entry is written to standard output
+in the form:
+.LP
+.nf
+    Distinguished Name (DN)
+    User Friendly Name (this line present only if the -u option is used)
+    attributename=value
+    attributename=value
+    attributename=value
+    ...
+.fi
+.LP
+Multiple entries are separated with a single blank line.  If the -F option
+is used to specify a separator character, it will be used instead of the
+`=' character.  If the -t option is used, the name of a temporary file
+is used in place of the actual value.  If the -A option
+is given, only the "attributename" part is written.
+.SH EXAMPLE
+The following command:
+.LP
+.nf
+    ldapsearch "cn=mark smith" cn telephoneNumber
+.fi
+.LP
+will perform a subtree search (using the default search base) for entries
+with a commonName of "mark smith".  The commonName and telephoneNumber
+values will be retrieved and printed to standard output.
+The output might look something like this if two entries are found:
+.LP
+.nf
+cn=Mark D Smith, ou="College of Literature, Science, and the Arts", ou=Students, ou=People, o=University of Michigan, c=US
+cn=Mark Smith
+cn=Mark David Smith
+cn=Mark D Smith 1
+cn=Mark D Smith
+telephoneNumber=+1 313 930-9489
+
+cn=Mark C Smith, ou=Information Technology Division, ou=Faculty and Staff, ou=People, o=University of Michigan, c=US
+cn=Mark Smith
+cn=Mark C Smith 1
+cn=Mark C Smith
+telephoneNumber=+1 313 764-2277
+.fi
+.LP
+The command:
+.LP
+.nf
+    ldapsearch -u -t "uid=mcs" jpegPhoto audio
+.fi
+.LP
+will perform a subtree search using the default search base for entries
+with user id of "mcs".  The user friendly form of the entry's DN will be
+output after the line that contains the DN itself, and the jpegPhoto
+and audio values will be retrieved and written to temporary files.  The
+output might look like this if one entry with one value for each of the
+requested attributes is found:
+.LP
+.nf
+cn=Mark C Smith, ou=Information Technology Division, ou=Faculty and Staff, ou=People, o=University of Michigan, c=US
+Mark C Smith, Information Technology Division, Faculty and Staff, People, University of Michigan, US
+audio=/tmp/ldapsearch-audio-a19924
+jpegPhoto=/tmp/ldapsearch-jpegPhoto-a19924
+.fi
+.LP
+This command:
+.LP
+.nf
+    ldapsearch -L -s one -b "c=US" "o=university*" o description
+.fi
+.LP
+will perform a one-level search at the c=US level for all organizations
+whose organizationName begins with \fBuniversity\fP.  Search results
+will be displayed in the LDIF format.
+The organizationName and description attribute values will be retrieved
+and printed to standard output, resulting in output similar to this:
+.LP
+.nf
+dn: o=University of Alaska Fairbanks, c=US
+o: University of Alaska Fairbanks
+description: Preparing Alaska for a brave new yesterday
+description: leaf node only
+
+dn: o=University of Colorado at Boulder, c=US
+o: University of Colorado at Boulder
+description: No personnel information
+description: Institution of education and research
+
+dn: o=University of Colorado at Denver, c=US
+o: University of Colorado at Denver
+o: UCD
+o: CU/Denver
+o: CU-Denver
+description: Institute for Higher Learning and Research
+
+dn: o=University of Florida, c=US
+o: University of Florida
+o: UFl
+description: Warper of young minds
+
+etc....
+.fi
+.SH DIAGNOSTICS
+Exit status is 0 if no errors occur.  Errors result in a non-zero exit
+status and a diagnostic message being written to standard error.
+.SH "SEE ALSO"
+.BR ldapadd (1),
+.BR ldapdelete (1),
+.BR ldapmodify (1),
+.BR ldapmodrdn (1),
+.BR ldap (3),
+.BR ldap_search (3)
+.LP
+Kille, S.,
+.IR "A String Representation of Distinguished Names",
+.SM RFC
+1779,
+ISODE Consortium, March 1995.
+.LP
+Howes, T.,
+.IR "A String Representation of LDAP Search Filters",
+.SM RFC
+1558,
+University of Michigan, December 1993.
diff --git a/doc/man/man1/ud.1 b/doc/man/man1/ud.1
new file mode 100644 (file)
index 0000000..43284a7
--- /dev/null
@@ -0,0 +1,73 @@
+.TH UD 1 "18 March 1993" "U-M LDAP LDVERSION"
+.UC 6
+.SH NAME
+ud \- interactive X.500 Directory Server query program
+.SH SYNOPSIS
+.B ud
+[-Dv] [-s 
+.IR server ]
+[-d
+.IR debug-mask ]
+[-l
+.IR ldap-debug-mask ]
+[-f
+.IR file ]
+.SH DESCRIPTION
+.IR ud
+is used to interogate a directory server via the Lightweight Directory
+Access Protocol (LDAP).
+.SH OPTIONS
+.TP 1i
+.B \-s
+Used to specify the name of an LDAP server to which
+.B ud
+should connect.  If this
+flag is omitted, the value specified in the
+.B ud
+configuration file is used.  If
+no value is specified in the configuration file, or the configuration
+file does not exist, the name
+.IR ldap
+is used.  Of course, it is up to the system administrator to make sure that
+the name
+.IR ldap
+can be resolved (presumably through the use of a CNAME or A record in the DNS
+and the appropriate search path specified in the resolver config file).
+.TP 1i
+.B \-d
+Sets the
+.B ud
+debug mask to the value specified.  
+Values for the mask can be dumped by using the
+.IR \-D
+flag.
+.TP 1i
+.B \-f
+Sets the configuration file to the name specified.
+.TP 1i
+.B \-l
+Sets the LDAP debug mask to the value specified.  
+.TP 1i
+.B \-v
+Turns on verbose output.  Also toggable via the ud 
+.IR verbose 
+command.
+.TP 1i
+.B \-D
+Prints out a list of valid ud debug masks.
+.SH FILES
+ETCDIR/ud.conf         The ud configuration file.
+.SH "SEE ALSO"
+.BR ud.conf (5),
+.BR ldap (3)
+.SH DIAGNOSTICS
+.B ud
+will try to be nice about error conditions, and in most cases prints a warm
+and fuzzy error message when it encounters a problem.  Sometimes the error
+will be unexpected, and in these cases, 
+.B ud
+uses the ldap_perror() routine to print an informative diagnostic.
+.SH BUGS
+Too numerous to mention.
+.SH AUTHOR
+Bryan Beecher, University of Michigan
diff --git a/doc/man/man3/Make-template b/doc/man/man3/Make-template
new file mode 100644 (file)
index 0000000..6e153f6
--- /dev/null
@@ -0,0 +1,52 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1994 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP man3 makefile
+#
+#-----------------------------------------------------------------------------
+
+LDAPSRC= ../../..
+SECT=3
+INSTDIR=$(MANDIR)/man$(SECT)
+VERSIONFILE = $(LDAPSRC)/build/version
+
+all:   FORCE
+
+install:       FORCE
+       -$(MKDIR) -p $(INSTDIR)
+       @TMPMAN=/tmp/ldapman.$$$$; \
+       VERSION=`$(CAT) $(VERSIONFILE)`; \
+       for page in *.$(SECT); do \
+           $(SED) -e 's%ETCDIR%$(RUNTIMEETCDIR)%' -e "s%LDVERSION%$$VERSION%" \
+                   $$page > $$TMPMAN; \
+           echo "installing $(INSTDIR)/$$page"; \
+           $(INSTALL) $(INSTALLFLAGS) -m 644 $$TMPMAN $(INSTDIR)/$$page; \
+           if [ -f "$$page.links" ]; then \
+               for link in `$(CAT) $$page.links`; do \
+                   echo ".so man$(SECT)/$$page" > $$TMPMAN; \
+                   echo "installing $(INSTDIR)/$$link as link to $$page"; \
+                   $(INSTALL) $(INSTALLFLAGS) -m 644 $$TMPMAN \
+                           $(INSTDIR)/$$link; \
+               done; \
+           fi; \
+       done; \
+       $(RM) $$TMPMAN
+
+clean: FORCE
+
+depend:        FORCE
+
+lint:  FORCE
+
+5lint: FORCE
+
+links:
+       @$(LN) .src/*.$(SECT) .src/*links .
diff --git a/doc/man/man3/cldap_close.3 b/doc/man/man3/cldap_close.3
new file mode 100644 (file)
index 0000000..7896ba0
--- /dev/null
@@ -0,0 +1,30 @@
+.TH CLDAP_CLOSE 3  "18 November 1994" "U-M LDAP LDVERSION"
+.SH NAME
+cldap_close \- Dispose of Connectionless LDAP Pointer
+.SH SYNOPSIS
+.nf
+.ft B
+#include <lber.h>
+#include <ldap.h>
+.LP
+.ft B
+void cldap_close( ld )
+.ft
+LDAP *ld;
+.SH DESCRIPTION
+.LP
+The
+.B cldap_close()
+routine disposes of memory allocated by
+.BR cldap_open (3).
+It should be called when all CLDAP communication is complete.
+.LP
+.B cldap_close()
+takes a single parameter \fIld\fP, the LDAP pointer
+returned by a previous call to
+.BR cldap_open (3).
+.SH SEE ALSO
+.BR ldap (3),
+.BR cldap_open (3),
+.BR cldap_search_s (3),
+.BR cldap_setretryinfo (3)
diff --git a/doc/man/man3/cldap_open.3 b/doc/man/man3/cldap_open.3
new file mode 100644 (file)
index 0000000..738bda2
--- /dev/null
@@ -0,0 +1,53 @@
+.TH CLDAP_OPEN 3  "18 November 1994" "U-M LDAP LDVERSION"
+.SH NAME
+cldap_open \- Prepare for Connectionless LDAP Communication
+.SH SYNOPSIS
+.nf
+.ft B
+#include <lber.h>
+#include <ldap.h>
+.LP
+.ft B
+LDAP *cldap_open(host, port)
+.ft
+char *host;
+int port;
+.SH DESCRIPTION
+.LP
+The
+.B cldap_open()
+routine is called to prepare for connectionless LDAP
+communication (over
+.BR udp (4p)).
+It allocates an LDAP structure which
+is passed to future search requests.
+.LP
+.B cldap_open()
+takes
+\fIhost\fP, the nane of the host on which the LDAP server is running, and
+\fIport\fP, the port number to which to connect.  If the default
+IANA-assigned port of 389 is desired, LDAP_PORT should be specified for
+\fIport\fP.  \fIhost\fP can contain a space-separated list of hosts or
+addresses to try.
+.B cldap_open()
+returns a pointer to an LDAP structure, which should be
+passed to subsequent calls to
+.BR cldap_search_s (3),
+.BR cldap_setretryinfo (3),
+and
+.BR cldap_close (3).
+Certain fields in the LDAP structure can be set to
+indicate size limit, time limit, and how aliases are handled during
+operations.  See
+.BR ldap_open (3)
+and <ldap.h> for more details.
+.SH ERRORS
+If an error occurs,
+.B cldap_open()
+will return NULL and errno will be set appropriately.
+.SH SEE ALSO
+.BR ldap (3)
+.BR cldap_search_s (3),
+.BR cldap_setretryinfo (3),
+.BR cldap_close (3),
+.BR udp (4p)
diff --git a/doc/man/man3/cldap_search_s.3 b/doc/man/man3/cldap_search_s.3
new file mode 100644 (file)
index 0000000..1c4da54
--- /dev/null
@@ -0,0 +1,105 @@
+.TH CLDAP_SEARCH_S 3  "18 November 1994" "U-M LDAP LDVERSION"
+.SH NAME
+cldap_search_s \- Connectionless LDAP Search
+.SH SYNOPSIS
+.nf
+.ft B
+#include <lber.h>
+#include <ldap.h>
+.LP
+.ft B
+int cldap_search_s( ld, base, scope, filter, attrs, attrsonly,
+       res, logdn )
+.ft
+LDAP *ld;
+char *base;
+int scope;
+char *filter;
+char **attrs;
+int attrsonly;
+LDAPMessage **res;
+char *logdn;
+.SH DESCRIPTION
+.LP
+The
+.B cldap_search_s()
+routine performs an LDAP search using the
+Connectionless LDAP (CLDAP) protocol.
+.LP
+.B cldap_search_s()
+has parameters and behavior identical to that of
+.BR ldap_search_s (3),
+except for the addition of the \fIlogdn\fP
+parameter.  logdn should contain a distinguished name to be used only
+for logging purposed by the LDAP server.  It should be in the text
+format described by RFC 1779 "A String Representation of Distinguished Names".
+.SH RETRANSMISSION ALGORITHM
+.B cldap_search_s()
+operates using the CLDAP protocol over
+.BR udp (4p).
+Since UDP is a non-reliable protocol, a retry mechanism is used to increase
+reliability.  The
+.BR cldap_setretryinfo (3)
+routine can be used to set two
+retry parameters:  \fItries\fP, a count of the number of times to send
+a search request and \fItimeout\fP, an initial timeout that determines
+how long to wait for a response before re-trying.  \fItimeout\fP is
+specified seconds.  These values are stored in the \fBld_cldaptries\fP and
+\fBld_cldaptimeout\fP members of the \fIld\fP LDAP structure, and the
+default values set in
+.BR ldap_open (3)
+are 4 and 3 respectively.  The retransmission algorithm used is:
+.LP
+Step 1.  Set the current timeout to \fBld_cldaptimeout\fP seconds, and
+the current LDAP server address to the first LDAP server found during
+the
+.BR ldap_open (3)
+call.
+.LP
+Step 2:  Send the search request to the current LDAP server address.
+.LP
+Step 3:  Set the wait timeout to the current timeout divided by the
+number of server addresses found during
+.BR ldap_open (3)
+or to one
+second, whichever is larger.  Wait at most that long for a response; if
+a response is received, STOP.  Note that the wait timeout is always rounded
+down to the next lowest second.
+.LP
+Step 5:  Repeat steps 2 and 3 for each LDAP server address.
+.LP
+Step 6:  Set the current timeout to twice its previous value and repeat
+Steps 2 through 6 a maximum of \fItries\fP times.
+.SH RETRANSMISSION EXAMPLE
+Assume that the default values for \fItries\fP and \fItimeout\fP of
+4 tries and 3 seconds are used.  Further, assume that a space-separated
+list of two hosts, each with one address, was passed to
+.BR cldap_open (3).
+The pattern of requests sent will be (stopping as soon as a response is
+received):
+.nf
+  Time         Search Request Sent To:
+   +0                  Host A try 1
+   +1  (0+3/2)         Host B try 1
+   +2  (1+3/2)         Host A try 2
+   +5  (2+6/2)         Host B try 2
+   +8  (5+6/2)         Host A try 3
+   +14 (8+12/2)                Host B try 3
+   +20 (14+12/2)       Host A try 4
+   +32 (20+24/2)       Host B try 4
+   +44 (20+24/2)       (give up - no response)
+.ft
+.SH ERRORS
+.B cldap_search_s()
+returns LDAP_SUCCESS if a search was successful and the
+appropriate LDAP error code otherwise.  See
+.BR ldap_error (3)
+for more information.
+.SH SEE ALSO
+.BR ldap (3),
+.BR ldap_error (3),
+.BR ldap_search_s (3),
+.BR cldap_open (3),
+.BR cldap_setretryinfo (3),
+.BR cldap_close (3),
+.BR udp (4p)
diff --git a/doc/man/man3/cldap_setretryinfo.3 b/doc/man/man3/cldap_setretryinfo.3
new file mode 100644 (file)
index 0000000..55ef671
--- /dev/null
@@ -0,0 +1,42 @@
+.TH CLDAP_SETRETRYINFO 3  "18 November 1994" "U-M LDAP LDVERSION"
+.SH NAME
+cldap_setretryinfo \- Set Connectionless LDAP Request Retransmission Parameters
+.SH SYNOPSIS
+.nf
+.ft B
+#include <lber.h>
+#include <ldap.h>
+.LP
+.ft B
+void cldap_setretryinfo(ld, tries, timeout)
+.ft
+LDAP *ld;
+int tries;
+int timeout;
+.SH DESCRIPTION
+.LP
+The
+.B cldap_setretryinfo()
+routine is used to set the CLDAP
+request retransmission behavior for future
+.BR cldap_search_s (3)
+calls.
+.LP
+.B cldap_setretryinfo()
+takes \fIld\fP, the LDAP pointer returned from a
+previous call to
+.BR cldap_open (3),
+\fItries\fP, the maximum number of
+times to send a request, and \fItimeout\fP, the initial time, in
+seconds, to wait before re-sending a request.  The default values (set by
+.BR cldap_open (3))
+are 4 tries and 3 seconds between tries.  See
+.BR cldap_search_s (3)
+for a complete description of the retransmission
+algorithm used.
+.LP
+.SH SEE ALSO
+.BR ldap (3),
+.BR cldap_open (3),
+.BR cldap_search_s (3),
+.BR cldap_close (3)
diff --git a/doc/man/man3/lber-decode.3 b/doc/man/man3/lber-decode.3
new file mode 100644 (file)
index 0000000..e05fb33
--- /dev/null
@@ -0,0 +1,358 @@
+.TH LBER-DECODE 3  "18 November 1994"
+.SH NAME
+ber_get_next, ber_skiptag, ber_peek_tag, ber_scanf, ber_get_int, ber_get_stringb, ber_get_stringa, ber_get_null, ber_get_boolean, ber_get_bitstring, ber_first_element, ber_next_element \- LBER simplified Basic Encoding Rules library routines for decoding
+.SH SYNOPSIS
+.nf
+.ft B
+#include <lber.h>
+.ft
+.fi
+.LP
+.nf
+.ft B
+typedef struct berelement {
+    char *ber_buf;
+    char *ber_ptr;
+    char *ber_end;
+    struct seqorset *ber_sos;
+    int ber_tag;
+    int ber_usertag;
+} BerElement;
+.ft
+.fi
+.LP
+.nf
+.ft B
+typedef struct sockbuf {
+    int sb_sd;
+    BerElement sb_ber;
+} Sockbuf;
+.ft
+.fi
+.LP
+.nf
+.ft B
+typedef struct berval {
+    unsigned long bv_len;
+    char *bv_val;
+};
+.ft
+.fi
+.LP
+.nf
+.ft B
+ber_get_next(sb, len, ber)
+Sockbuf *sb;
+unsigned long \(**len;
+BerElement \(**ber;
+.ft
+.fi
+.LP
+.nf
+.ft B
+ber_skip_tag(ber, len)
+BerElement \(**ber;
+unsigned long \(**len;
+.ft
+.fi
+.LP
+.nf
+.ft B
+ber_peek_tag(ber, len)
+BerElement \(**ber;
+unsigned long \(**len;
+.ft
+.fi
+.LP
+.nf
+.ft B
+ber_get_int(ber, num)
+BerElement \(**ber;
+long \(**num;
+.ft
+.fi
+.LP
+.nf
+.ft B
+ber_get_stringb(ber, buf, len)
+BerElement \(**ber;
+char \(**buf;
+unsigned long \(**len;
+.ft
+.fi
+.LP
+.nf
+.ft B
+ber_get_stringa(ber, buf)
+BerElement \(**ber;
+char \(***buf;
+.ft
+.fi
+.LP
+.nf
+.ft B
+ber_get_stringal(ber, bv)
+BerElement \(**ber;
+struct berval \(***bv;
+.ft
+.fi
+.LP
+.nf
+.ft B
+ber_get_null(ber)
+BerElement \(**ber;
+.ft
+.fi
+.LP
+.nf
+.ft B
+ber_get_boolean(ber, bool)
+BerElement \(**ber;
+int \(**bool;
+.ft
+.fi
+.LP
+.nf
+.ft B
+ber_get_bitstringa(ber, buf, blen)
+BerElement \(**ber;
+char \(***buf;
+unsigned long \(**blen;
+.ft
+.fi
+.LP
+.nf
+.ft B
+ber_first_element(ber, len, cookie)
+BerElement \(**ber;
+unsigned long \(**len;
+char \(***cookie;
+.ft
+.fi
+.LP
+.nf
+.ft B
+ber_next_element(ber, len, cookie)
+BerElement \(**ber;
+unsigned long \(**len;
+char \(**cookie;
+.ft
+.fi
+.LP
+.nf
+.ft B
+ber_scanf(ber, fmt [, arg...] )
+BerElement \(**ber;
+char \(**fmt;
+.ft
+.fi
+.LP
+.nf
+.ft B
+ber_bvfree(bv)
+struct berval \(**bv;
+.ft
+.fi
+.LP
+.nf
+.ft B
+ber_bvecfree(bvec)
+struct berval \(***bvec;
+.SH DESCRIPTION
+.LP
+These routines provide a subroutine interface to a simplified
+implementation of the Basic Encoding Rules of ASN.1.  The version
+of BER these routines support is the one defined for the LDAP
+protocol.  The encoding rules are the same as BER, except that 
+only definite form lengths are used, and bitstrings and octet strings
+are always encoded in primitive form.  In addition, these lightweight
+BER routines restrict tags and class to fit in a single octet (this
+means the actual tag must be less than 31).  When a "tag" is specified
+in the descriptions below, it refers to the tag, class, and primitive
+or constructed bit in the first octet of the encoding.  This man page
+describes the decoding routines in the lber library.  See lber-encode(3)
+for details on the corresponding encoding routines.
+.LP
+Normally, the only routines that need be called by an application
+are ber_get_next() to get the next BER element and ber_scanf()
+to do the actual decoding.  In some cases, ber_peek_tag() may also
+need to be called in normal usage.  The other routines are provided for those
+applications that need more control than ber_scanf() provides.  In
+general, these routines return the tag of the element decoded, or
+-1 if an error occurred.
+.LP
+The ber_get_next() routine is used to read the next BER element from
+the given Sockbuf, \fIsb\fP.  A Sockbuf consists of the descriptor
+(usually socket, but a file descriptor works just as well) from which
+to read, and a BerElement structure used
+to maintain a buffer.  On the first call, the \fIsb_ber\fP struct should
+be zeroed.  It strips off and returns the
+leading tag byte, strips off and returns the length of the
+entire element in \fIlen\fP,
+and sets up \fIber\fP for subsequent calls to ber_scanf() et al to decode
+the element.
+.LP
+The ber_scanf() routine is used to decode a BER element in much the
+same way that scanf(3) works.  It reads from \fIber\fP, a pointer to a
+BerElement such as returned by ber_get_next(), interprets the
+bytes according to the format string \fIfmt\fP, and stores the
+results in its additional arguments.  The format string contains
+conversion specifications which are used to direct the interpretation
+of the BER element.  The format string can contain the following
+characters.
+.RS
+.LP
+.TP 3
+.SM a
+Octet string.  A char ** should be supplied.  Memory is allocated,
+filled with the contents of the octet string, null-terminated, and
+returned in the parameter.
+.TP
+.SM s
+Octet string.  A char * buffer should be supplied, followed by a pointer
+to an integer initialized to the size of the buffer.  Upon return, the
+null-terminated octet string is put into the buffer, and the integer is
+set to the actual size of the octet string.
+.TP
+.SM O
+Octet string.  A struct ber_val ** should be supplied, which upon return
+points to a malloced struct berval containing the octet string and its
+length.  ber_bvfree() can be called to free the malloced memory.
+.TP
+.SM b
+Boolean.  A pointer to an integer should be supplied.
+.TP
+.SM i
+Integer.  A pointer to an integer should be supplied.
+.TP
+.SM B
+Bitstring.  A char ** should be supplied which will point to the malloced
+bits, followed by an unsigned long *, which will point to the length
+(in bits) of the bitstring returned.
+.TP
+.SM n
+Null.  No parameter is required.  The element is simply skipped if
+it is recognized.
+.TP
+.SM v
+Sequence of octet strings.  A char *** should be supplied, which upon
+return points to a malloced null-terminated array of char *'s
+containing the octet strings.  NULL is returned if the sequence is empty.
+.TP
+.SM V
+Sequence of octet strings with lengths.
+A struct berval *** should be supplied, which upon
+return points to a malloced null-terminated array of struct berval *'s
+containing the octet strings and their lengths.
+NULL is returned if the sequence is empty.  ber_bvecfree() can be called
+to free the malloced memory.
+.TP
+.SM x
+Skip element.  The next element is skipped.
+.TP
+.SM {
+Begin sequence.  No parameter is required.  The initial sequence tag
+and length are skipped.
+.TP
+.SM }
+End sequence.  No parameter is required and no action is taken.
+.TP
+.SM [
+Begin set.  No parameter is required.  The initial set tag
+and length are skipped.
+.TP
+.SM ]
+End set.  No parameter is required and no action is taken.
+.RE
+.LP
+The ber_get_int() routine tries to interpret the next element as an integer,
+returning the result in \fInum\fP.  The tag of whatever it finds is returned
+on success, -1 on failure.
+.LP
+The ber_get_stringb() routine is used to read an octet string into a
+preallocated buffer.  The \fIlen\fP parameter should be initialized to
+the size of the buffer, and will contain the length of the octet string
+read upon return.  The buffer should be big enough to take the octet
+string value plus a terminating NULL byte.
+.LP
+The ber_get_stringa() routine is used to malloc space into which an octet
+string is read.
+.LP
+The ber_get_stringal() routine is used to malloc space into which an octet
+string and its length are read.  It takes a struct berval **, and returns
+the result in this parameter.
+.LP
+The ber_get_null() routine is used to read a NULL element.  It returns
+the tag of the element it skips over.
+.LP
+The ber_get_boolean() routine is used to read a boolean value.  It is called
+the same way that ber_get_int() is called.
+.LP
+The ber_get_bitstringa() routine is used to read a bitstring value.  It
+takes a char ** which will hold the malloced bits, followed by an
+unsigned long *, which will point to the length (in bits) of the
+bitstring returned.
+.LP
+The ber_first_element() routine is used to return the tag and length
+of the first element in a set or sequence.  It also returns in \fIcookie\fP
+a magic cookie parameter that should be passed to subsequent calls to
+ber_next_element(), which returns similar information.
+.SH EXAMPLES
+Assume the variable \fIber\fP contains a lightweight BER encoding of
+the following ASN.1 object:
+.LP
+.nf
+      AlmostASearchRequest := SEQUENCE {
+          baseObject      DistinguishedName,
+          scope           ENUMERATED {
+              baseObject    (0),
+              singleLevel   (1),
+              wholeSubtree  (2)
+          },
+          derefAliases    ENUMERATED {
+              neverDerefaliases   (0),
+              derefInSearching    (1),
+              derefFindingBaseObj (2),
+              alwaysDerefAliases  (3)
+          },
+          sizelimit       INTEGER (0 .. 65535),
+          timelimit       INTEGER (0 .. 65535),
+          attrsOnly       BOOLEAN,
+          attributes      SEQUENCE OF AttributeType
+      }
+.fi
+.LP
+The element can be decoded using ber_scanf() as follows.
+.LP
+.nf
+      int    scope, ali, size, time, attrsonly;
+      char   *dn, **attrs;
+
+      if ( ber_scanf( ber, "{aiiiib{v}}", &dn, &scope, &ali,
+          &size, &time, &attrsonly, &attrs ) == -1 )
+              /* error */
+      else
+              /* success */
+.fi
+.SH ERRORS
+If an error occurs during decoding, generally these routines return -1.
+.LP
+.SH NOTES
+.LP
+The return values for all of these functions are declared in the
+<lber.h> header file.  Some routines may malloc memory.
+.SH SEE ALSO
+.BR lber-encode (3)
+.BR ldap-parse (3)
+.BR ldap-sync (3)
+.BR ldap-async (3)
+.LP
+Yeong, W., Howes, T., and Hardcastle-Kille, S., "Lightweight Directory Access
+Protocol", OSI-DS-26, April 1992.
+.LP
+Information Processing - Open Systems Interconnection - Model and Notation -
+Service Definition - Specification of Basic Encoding Rules for Abstract
+Syntax Notation One, International Organization for Standardization,
+International Standard 8825.
+.SH AUTHOR
+Tim Howes, University of Michigan
diff --git a/doc/man/man3/lber-encode.3 b/doc/man/man3/lber-encode.3
new file mode 100644 (file)
index 0000000..0130481
--- /dev/null
@@ -0,0 +1,315 @@
+.TH LBER-ENCODE 3  "15 June 1992"
+.SH NAME
+ber_alloc, ber_flush, ber_printf, ber_put_int, ber_put_ostring, ber_put_string, ber_put_null, ber_put_boolean, ber_put_bitstring, ber_start_seq, ber_start_set, ber_put_seq, ber_put_set \- LBER simplified Basic Encoding Rules library routines for encoding
+.SH SYNOPSIS
+.nf
+.ft B
+#include <lber.h>
+.ft
+.fi
+.LP
+.nf
+.ft B
+typedef struct berelement {
+    char *ber_buf;
+    char *ber_ptr;
+    char *ber_end;
+    struct seqorset *ber_sos;
+    int ber_tag;
+    int ber_usertag;
+} BerElement;
+.ft
+.fi
+.LP
+.nf
+.ft B
+typedef struct sockbuf {
+    int sb_sd;
+    BerElement sb_ber;
+} Sockbuf;
+.ft
+.fi
+.LP
+.nf
+.ft B
+BerElement *ber_alloc()
+.ft
+.fi
+.LP
+.nf
+.ft B
+ber_flush(sb, ber, freeit)
+Sockbuf *sb;
+BerElement *ber;
+int freeit;
+.ft
+.fi
+.LP
+.nf
+.ft B
+ber_printf(ber, fmt [, arg... ] )
+BerElement *ber;
+char \(**fmt;
+.ft
+.fi
+.LP
+.nf
+.ft B
+ber_put_int(ber, num, tag)
+BerElement *ber;
+long num;
+char tag;
+.ft
+.fi
+.LP
+.nf
+.ft B
+ber_put_ostring(ber, str, len, tag)
+BerElement *ber;
+char \(**str;
+unsigned long len;
+char tag;
+.ft
+.fi
+.LP
+.nf
+.ft B
+ber_put_string(ber, str, tag)
+BerElement *ber;
+char \(**str;
+char tag;
+.ft
+.fi
+.LP
+.nf
+.ft B
+ber_put_null(ber, tag)
+BerElement *ber;
+char tag;
+.ft
+.fi
+.LP
+.nf
+.ft B
+ber_put_boolean(ber, bool, tag)
+BerElement *ber;
+int bool;
+char tag;
+.ft
+.fi
+.LP
+.nf
+.ft B
+ber_put_bitstring(ber, str, blen, tag)
+BerElement *ber;
+char *str;
+int blen;
+char tag;
+.ft
+.fi
+.LP
+.nf
+.ft B
+ber_start_seq(ber, tag)
+BerElement *ber;
+char tag;
+.ft
+.fi
+.LP
+.nf
+.ft B
+ber_start_set(ber, tag)
+BerElement *ber;
+char tag;
+.ft
+.fi
+.LP
+.nf
+.ft B
+ber_put_seq(ber)
+BerElement *ber;
+.ft
+.fi
+.LP
+.nf
+.ft B
+ber_put_set(ber)
+BerElement *ber;
+.SH DESCRIPTION
+.LP
+These routines provide a subroutine interface to a simplified
+implementation of the Basic Encoding Rules of ASN.1.  The version
+of BER these routines support is the one defined for the LDAP
+protocol.  The encoding rules are the same as BER, except that 
+only definite form lengths are used, and bitstrings and octet strings
+are always encoded in primitive form.  In addition, these lightweight
+BER routines restrict tags and class to fit in a single octet (this
+means the actual tag must be less than 31).  When a "tag" is specified
+in the descriptions below, it refers to the tag, class, and primitive
+or constructed bit in the first octet of the encoding.  This
+man page describes the encoding routines in the lber library.  See
+lber-decode(3) for details on the corresponding decoding routines.
+.LP
+Normally, the only routines that need be called by an application
+are ber_alloc() to allocate a BER element for encoding, ber_printf()
+to do the actual encoding, and ber_flush() to actually write the
+element.  The other routines are provided for those
+applications that need more control than ber_printf() provides.  In
+general, these routines return the length of the element encoded, or
+-1 if an error occurred.
+.LP
+The ber_alloc() routine is used to allocate a new BER element.  The
+ber_flush() routine is used to actually write the element to a socket
+(or file) descriptor, once it has been fully encoded (using ber_printf()
+and friends).  The \fIsb\fP structure contains the descriptor and a
+BerElement used for input buffering.  Only the \fIsb_sd\fP field is relevant
+to the ber_flush() routine.
+.LP
+The ber_printf() routine is used to encode a BER element in much the
+same way that sprintf(3) works.  One important difference, though, is
+that some state information is kept with the \fIber\fP parameter so
+that multiple calls can be made to ber_printf() to append things to
+the end of the BER element.  Ber_printf() writes to \fIber\fP, a pointer to a
+BerElement such as returned by ber_alloc().  It interprets and
+formats its arguments according to the format string \fIfmt\fP.
+The format string can contain the following characters:
+.RS
+.LP
+.TP 3
+.SM b
+Boolean.  An integer parameter should be supplied.  A boolean element
+is output.
+.TP
+.SM i
+Integer.  An integer parameter should be supplied.  An integer element
+is output.
+.TP
+.SM B
+Bitstring.  A char * pointer to the start of the bitstring is supplied,
+followed by the number of bits in the bitstring.  A bitstring element
+is output.
+.TP
+.SM n
+Null.  No parameter is required.  A null element is output.
+.TP
+.SM o
+Octet string.  A char * is supplied, followed by the length of the
+string pointed to.  An octet string element is output.
+.TP
+.SM s
+Octet string.  A null-terminated string is supplied.  An octet string
+element is output, not including the trailing NULL octet.
+.TP
+.SM t
+Tag.  An int specifying the tag to give the next element is provided.
+This works across calls.
+.TP
+.SM v
+Several octet strings.  A null-terminated array of char *'s is
+supplied.  Note that a construct like '{v}' is required to get
+an actual SEQUENCE OF octet strings.
+.TP
+.SM {
+Begin sequence.  No parameter is required.
+.TP
+.SM }
+End sequence.  No parameter is required.
+.TP
+.SM [
+Begin set.  No parameter is required.
+.TP
+.SM ]
+End set.  No parameter is required.
+.RE
+.LP
+The ber_put_int() routine writes the integer element \fInum\fP to
+the BER element \fIber\fP.
+.LP
+The ber_put_boolean() routine writes the boolean value given by
+\fIbool\fP to the BER element.
+.LP
+The ber_put_bitstring() routine writes \fIblen\fP bits starting
+at \fIstr\fP as a bitstring value to the given BER element.  Note
+that \fIblen\fP is the length \fIin bits\fP of the bitstring.
+.LP
+The ber_put_ostring() routine writes \fIlen\fP bytes starting at
+\fIstr\fP to the BER element as an octet string.
+.LP
+The ber_put_string() routine writes the null-terminated string (minus
+the terminating '\0') to the BER element as an octet string.
+.LP
+The ber_put_null() routine writes a NULL element to the BER element.
+.LP
+The ber_start_seq() routine is used to start a sequence in the BER
+element.  The ber_start_set() routine works similarly.
+The end of the sequence or set is marked by the nearest matching
+call to ber_put_seq() or ber_put_set(), respectively.
+.LP
+The ber_first_element() routine is used to return the tag and length
+of the first element in a set or sequence.  It also returns in \fIcookie\fP
+a magic cookie parameter that should be passed to subsequent calls to
+ber_next_element(), which returns similar information.
+.SH EXAMPLES
+Assuming the following variable declarations, and that the variables
+have been assigned appropriately, an lber encoding of
+the following ASN.1 object:
+.LP
+.nf
+      AlmostASearchRequest := SEQUENCE {
+          baseObject      DistinguishedName,
+          scope           ENUMERATED {
+              baseObject    (0),
+              singleLevel   (1),
+              wholeSubtree  (2)
+          },
+          derefAliases    ENUMERATED {
+              neverDerefaliases   (0),
+              derefInSearching    (1),
+              derefFindingBaseObj (2),
+              alwaysDerefAliases  (3)
+          },
+          sizelimit       INTEGER (0 .. 65535),
+          timelimit       INTEGER (0 .. 65535),
+          attrsOnly       BOOLEAN,
+          attributes      SEQUENCE OF AttributeType
+      }
+.fi
+.LP
+can be achieved like so:
+.LP
+.nf
+      int    scope, ali, size, time, attrsonly;
+      char   *dn, **attrs;
+
+      /* ... fill in values ... */
+      if ( (ber = ber_alloc()) == NULLBER )
+               /* error */
+
+      if ( ber_printf( ber, "{siiiib{v}}", dn, scope, ali,
+          size, time, attrsonly, attrs ) == -1 )
+              /* error */
+      else
+              /* success */
+.fi
+.SH ERRORS
+If an error occurs during encoding, generally these routines return -1.
+.LP
+.SH NOTES
+.LP
+The return values for all of these functions are declared in the
+<lber.h> header file.
+.SH SEE ALSO
+.BR ldap-async (3)
+.BR ldap-sync (3)
+.BR ldap-parse (3)
+.BR lber-decode (3)
+.LP
+Yeong, W., Howes, T., and Hardcastle-Kille, S., "Lightweight Directory Access
+Protocol", OSI-DS-26, April 1992.
+.LP
+Information Processing - Open Systems Interconnection - Model and Notation -
+Service Definition - Specification of Basic Encoding Rules for Abstract
+Syntax Notation One, International Organization for Standardization,
+International Standard 8825.
+.SH AUTHOR
+Tim Howes, University of Michigan
diff --git a/doc/man/man3/ldap.3 b/doc/man/man3/ldap.3
new file mode 100644 (file)
index 0000000..8f2c20e
--- /dev/null
@@ -0,0 +1,501 @@
+.TH LDAP 3  "13 November 1995" "U-M LDAP LDVERSION"
+.SH NAME
+ldap - Lightweight Directory Access Protocol package
+.SH SYNOPSIS
+.nf
+.ft B
+#include <lber.h>
+#include <ldap.h>
+.ft
+.fi
+.SH DESCRIPTION
+.LP
+The Lightweight Directory Access Protocol provides TCP/IP access to
+the X.500 Directory or to a stand-alone LDAP server.
+The University of Michigan LDAP package includes a stand-alone server in
+.BR slapd (8),
+an LDAP to X.500 gateway in
+.BR ldapd (8),
+various LDAP clients, and an LDAP client library used to provide
+programmatic access to the LDAP protocol. This man page gives an
+overview of the LDAP library routines.
+.LP
+Both synchronous and asynchronous APIs are provided.  Also included are
+various routines to parse the results returned from these routines.
+These routines are found in the libldap.a library.
+.LP
+The basic interaction is as follows.  A connection is made to an LDAP
+server by calling
+.BR ldap_open (3).
+An LDAP bind operation is performed by calling
+one of
+.BR ldap_bind (3)
+and friends.  Next, other operations are performed
+by calling one of the synchronous or asynchronous routines (e.g.,
+.BR ldap_search_s (3)
+or
+.BR ldap_search (3)
+followed by
+.BR ldap_result (3)).
+Results returned from these routines are interpreted by calling the
+LDAP parsing routines.  The LDAP association is terminated by calling
+.BR ldap_unbind (3).
+Errors can be interpreted by calling
+.BR ldap_perror (3).
+The
+.BR ldap_set_rebind_proc (3)
+routine can be used to set a routine to be called back when an LDAP bind
+operation needs to occur when handling a client referral.
+.SH SEARCH FILTERS
+Search filters to be passed to the ldap search routines can be
+constructed by hand, or by calling the
+.BR ldap_getfilter (3)
+routines, which use the
+.BR ldapgetfilter.conf (5)
+file to turn a string (presumably that a user has typed) into a series
+of search filters.
+.SH DISPLAYING RESULTS
+Results obtained from the ldap search routines can be output by hand,
+by calling
+.BR ldap_first_entry (3)
+and
+.BR ldap_next_entry (3)
+to step through
+the entries returned,
+.BR ldap_first_attribute (3)
+and
+.BR ldap_next_attribute (3)
+to step through an entry's attributes, and
+.BR ldap_get_values (3)
+to retrieve a given attribute's value, and then calling
+.BR printf (3)
+or whatever to display the values.
+.LP
+Alternatively, the entry can be output automatically by calling
+the
+.BR ldap_entry2text (3),
+.BR ldap_entry2text_search (3),
+.BR ldap_entry2html (3),
+or
+.BR ldap_entry2html_search (3)
+routines.  These routines look up the object
+class of the entry they are passed in the
+.BR ldaptemplates.conf (5)
+file to decide which attributes to display and how to display them.
+Output is handled via a routine passed in as a parameter.
+.SH UNIFORM RESOURCE LOCATORS (URLS)
+The
+.BR ldap_url (3)
+routines can be used test a URL to see if it is an LDAP URL, to parse LDAP
+URLs into their component pieces, and to initiate searches directly using
+an LDAP URL.
+.SH USER FRIENDLY NAMING
+The
+.BR ldap_ufn (3)
+routines implement a user friendly naming
+scheme via LDAP.  This scheme allows you to look up entries
+using fuzzy, untyped names like "mark smith, umich, us".
+.SH CACHING
+The
+.BR ldap_cache (3)
+routines implement a local client caching scheme,
+providing a substantial performance increase for repeated queries.
+.SH UTILITY ROUTINES
+Also provided are various utility routines.  The
+.BR ldap_sort (3)
+routines are used to sort the entries and values returned via
+the ldap search routines.  The
+.BR ldap_friendly (3)
+routines are
+used to map from short two letter country codes (or other strings)
+to longer "friendlier" names.  The
+.BR ldap_charset (3)
+routines can be used to translate to and from the T.61 character
+set used for many character strings in the LDAP protocol.
+.SH CONNECTIONLESS ACCESS
+The
+.BR cldap_search_s (3)
+routine allows you to access the directory
+via Connectionless LDAP (CLDAP), which is similar to LDAP but
+operates over UDP, obviating the need to set up and tear down
+a connection by calling
+.BR ldap_open (3),
+.BR ldap_bind (3),
+and
+.BR ldap_unbind (3).
+.BR cldap_open (3)
+should be called before using
+.BR cldap_search_s (3).
+All the same getfilter, parsing, and display that can be used
+with regular LDAP routines can be used with the CLDAP routines.
+.SH BER LIBRARY
+Also included in the distribution is a set of lightweight Basic
+Encoding Rules routines.  These routines are used by the LDAP library
+routines to encode and decode LDAP protocol elements using the
+(slightly simplified) Basic Encoding Rules defined by LDAP.  They are
+not normally used directly by an LDAP application program.  The
+routines provide a printf and scanf-like interface, as well as
+lower-level access.  These routines are found in the liblber.a
+library.
+.SH INDEX
+.TP 20
+.SM ldap_open(3)
+open a connection to an LDAP server
+.TP
+.SM ldap_init(3)
+initialize the LDAP library without opening a connection to a server
+.TP
+.SM ldap_result(3)
+wait for the result from an asynchronous operation
+.TP
+.SM ldap_abandon(3)
+abandon (abort) an asynchronous operation
+.TP
+.SM ldap_add(3)
+asynchronously add an entry
+.TP
+.SM ldap_add_s(3)
+synchronously add an entry
+.TP
+.SM ldap_bind(3)
+asynchronously bind to the directory
+.TP
+.SM ldap_bind_s(3)
+synchronously bind to the directory
+.TP
+.SM ldap_simple_bind(3)
+asynchronously bind to the directory using simple authentication
+.TP
+.SM ldap_simple_bind_s(3)
+synchronously bind to the directory using simple authentication
+.TP
+.SM ldap_kerberos_bind_s(3)
+synchronously bind to the directory using kerberos authentication
+.TP
+.SM ldap_kerberos_bind1(3)
+asynchronously bind to the LDAP server using kerberos authentication
+.TP
+.SM ldap_kerberos_bind1_s(3)
+synchronously bind to the LDAP server using kerberos authentication
+.TP
+.SM ldap_kerberos_bind2(3)
+asynchronously bind to the DSA using kerberos authentication
+.TP
+.SM ldap_kerberos_bind2_s(3)
+synchronously bind to the DSA using kerberos authentication
+.TP
+.SM ldap_unbind(3)
+synchronously unbind from the LDAP server and close the connection
+.TP
+.SM ldap_unbind_s(3)
+equivalent to
+.BR ldap_unbind (3)
+.TP
+.SM ldap_memfree (3)
+dispose of memory allocated by LDAP routines (this is only used on the
+Microsoft Windows platforms; use
+.BR free (3)
+on all other platforms).
+.TP
+.SM ldap_enable_cache(3)
+enable LDAP client caching
+.TP
+.SM ldap_disable_cache(3)
+disable LDAP client caching
+.TP
+.SM ldap_destroy_cache(3)
+disable LDAP client caching and destroy cache contents
+.TP
+.SM ldap_flush_cache(3)
+flush LDAP client cache
+.TP
+.SM ldap_uncache_entry(3)
+uncache requests pertaining to an entry
+.TP
+.SM ldap_uncache_request(3)
+uncache a request
+.TP
+.SM ldap_set_cache_options(3)
+set cache options
+.TP
+.SM ldap_compare(3)
+asynchronous compare to a directory entry
+.TP
+.SM ldap_compare_s(3)
+synchronous compare to a directory entry
+.TP
+.SM ldap_delete(3)
+asynchronously delete an entry
+.TP
+.SM ldap_delete_s(3)
+synchronously delete an entry
+.TP
+.SM ldap_init_templates(3)
+initialize display template routines from a file
+.TP
+.SM ldap_init_templates_buf(3)
+initialize display template routines from a buffer
+.TP
+.SM ldap_free_templates(3)
+free display template routine memory
+.TP
+.SM ldap_first_disptmpl(3)
+get first display template
+.TP
+.SM ldap_next_disptmpl(3)
+get next display template
+.TP
+.SM ldap_oc2template(3)
+return template appropriate for objectclass
+.TP
+.SM ldap_name2template(3)
+return named template
+.TP
+.SM ldap_tmplattrs(3)
+return attributes needed by template
+.TP
+.SM ldap_first_tmplrow(3)
+return first row of displayable items in a template
+.TP
+.SM ldap_next_tmplrow(3)
+return next row of displayable items in a template
+.TP
+.SM ldap_first_tmplcol(3)
+return first column of displayable items in a template
+.TP
+.SM ldap_next_tmplcol(3)
+return next column of displayable items in a template
+.TP
+.SM ldap_entry2text(3)
+display an entry as text using a display template
+.TP
+.SM ldap_entry2text_search(3)
+search for and display an entry as text using a display template
+.TP
+.SM ldap_vals2text(3)
+display values as text
+.TP
+.SM ldap_entry2html(3)
+display an entry as HTML (HyperText Markup Language) using a display template
+.TP
+.SM ldap_entry2html_search(3)
+search for and display an entry as HTML using a display template
+.TP
+.SM ldap_vals2html(3)
+display values as HTML
+.TP
+.SM ldap_perror(3)
+print an LDAP error indication to standard error
+.TP
+.SM ld_errno(3)
+LDAP error indication
+.TP
+.SM ldap_result2error(3)
+extract LDAP error indication from LDAP result
+.TP
+.SM ldap_errlist(3)
+list of ldap errors and their meanings
+.TP
+.SM ldap_err2string(3)
+convert LDAP error indication to a string
+.TP
+.SM ldap_first_attribute(3)
+return first attribute name in an entry
+.TP
+.SM ldap_next_attribute(3)
+return next attribute name in an entry
+.TP
+.SM ldap_first_entry(3)
+return first entry in a chain of search results
+.TP
+.SM ldap_next_entry(3)
+return next entry in a chain of search results
+.TP
+.SM ldap_count_entries(3)
+return number of entries in a search result
+.TP
+.SM ldap_friendly_name(3)
+map from unfriendly to friendly names
+.TP
+.SM ldap_free_friendlymap(3)
+free resources used by ldap_friendly(3)
+.TP
+.SM ldap_get_dn(3)
+extract the DN from an entry
+.TP
+.SM ldap_explode_dn(3)
+convert a DN into its component parts
+.TP
+.SM ldap_explode_dns(3)
+convert a DNS-style DN into its component parts (experimental)
+.TP
+.SM ldap_is_dns_dn(3)
+check to see if a DN is a DNS-style DN (experimental)
+.TP
+.SM ldap_dn2ufn(3)
+convert a DN into user friendly form
+.TP
+.SM ldap_get_values(3)
+return an attribute's values
+.TP
+.SM ldap_get_values_len(3)
+return an attribute values with lengths
+.TP
+.SM ldap_value_free(3)
+free memory allocated by ldap_get_values(3)
+.TP
+.SM ldap_value_free_len(3)
+free memory allocated by ldap_get_values_len(3)
+.TP
+.SM ldap_count_values(3)
+return number of values
+.TP
+.SM ldap_count_values_len(3)
+return number of values
+.TP
+.SM ldap_init_getfilter(3)
+initialize getfilter routines from a file
+.TP
+.SM ldap_init_getfilter_buf(3)
+initialize getfilter routines from a buffer
+.TP
+.SM ldap_getfilter_free(3)
+free resources allocated by ldap_init_getfilter(3)
+.TP
+.SM ldap_getfirstfilter(3)
+return first search filter
+.TP
+.SM ldap_getnextfilter(3)
+return next search filter
+.TP
+.SM ldap_build_filter(3)
+construct an LDAP search filter from a pattern
+.TP
+.SM ldap_setfilteraffixes(3)
+set prefix and suffix for search filters
+.TP
+.SM ldap_modify(3)
+asynchronously modify an entry
+.TP
+.SM ldap_modify_s(3)
+synchronously modify an entry
+.TP
+.SM ldap_mods_free(3)
+free array of pointers to mod structures used by ldap_modify(3)
+.TP
+.SM ldap_modrdn2(3)
+asynchronously modify the RDN of an entry
+.TP
+.SM ldap_modrdn2_s(3)
+synchronously modify the RDN of an entry
+.TP
+.SM ldap_modrdn(3)
+depreciated - use ldap_modrdn2(3)
+.TP
+.SM ldap_modrdn_s(3)
+depreciated - use ldap_modrdn2_s(3)
+.TP
+.SM ldap_msgfree(3)
+free results allocated by ldap_result(3)
+.TP
+.SM ldap_search(3)
+asynchronously search the directory
+.TP
+.SM ldap_search_s(3)
+synchronously search the directory
+.TP
+.SM ldap_search_st(3)
+synchronously search the directory with timeout
+.TP
+.SM ldap_ufn_search_s(3)
+user friendly search the directory
+.TP
+.SM ldap_ufn_search_c(3)
+user friendly search the directory with cancel
+.TP
+.SM ldap_ufn_search_ct(3)
+user friendly search the directory with cancel and timeout
+.TP
+.SM ldap_ufn_setfilter(3)
+set filter file used by ldap_ufn(3) routines
+.TP
+.SM ldap_ufn_setprefix(3)
+set prefix used by ldap_ufn(3) routines
+.TP
+.SM ldap_ufn_timeout(3)
+set timeout used by ldap_ufn(3) routines
+.TP
+.SM ldap_is_ldap_url(3)
+check a URL string to see if it is an LDAP URL
+.TP
+.SM ldap_url_parse(3)
+break up an LDAP URL string into its components
+.TP
+.SM ldap_url_search(3)
+asynchronously search using an LDAP URL
+.TP
+.SM ldap_url_search_s(3)
+synchronously search using an LDAP URL
+.TP
+.SM ldap_url_search_st(3)
+synchronously search using an LDAP URL and a timeout
+.TP
+.SM ldap_init_searchprefs(3)
+initialize searchprefs routines from a file
+.TP
+.SM ldap_init_searchprefs_buf(3)
+initialize searchprefs routines from a buffer
+.TP
+.SM ldap_free_searchprefs(3)
+free memory allocated by searchprefs routines
+.TP
+.SM ldap_first_searchobj(3)
+return first searchpref object
+.TP
+.SM ldap_next_searchobj(3)
+return next searchpref object
+.TP
+.SM ldap_sort_entries(3)
+sort a list of search results
+.TP
+.SM ldap_sort_values(3)
+sort a list of attribute values
+.TP
+.SM ldap_sort_strcasecmp(3)
+case insensitive string comparison
+.TP
+.SM ldap_set_string_translators(3)
+set character set translation routines used by LDAP library
+.TP
+.SM ldap_t61_to_8859(3)
+translate from ISO-8859 characters to the T.61 characters
+.TP
+.SM ldap_8859_to_t61(3)
+translate from T.61 characters to the ISO-8859 characters
+.TP
+.SM ldap_translate_from_t61(3)
+translate from the T.61 character set to another character set
+.TP
+.SM ldap_translate_to_t61(3)
+translate to the T.61 character set from another character set
+.TP
+.SM ldap_enable_translation(3)
+enable or disable character translation for an LDAP entry result
+.TP
+.SM cldap_open(3)
+open a connectionless LDAP (CLDAP) session
+.TP
+.SM cldap_search_s(3)
+perform a search using connectionless LDAP
+.TP
+.SM cldap_setretryinfo(3)
+set retry and timeout information using connectionless LDAP
+.TP
+.SM cldap_close(3)
+terminate a connectionless LDAP session
+.SH SEE ALSO
+.BR ldapd (8),
+.BR slapd (8)
+.SH AUTHORS
+Tim Howes, Mark Smith, Gordon Good, Lance Sloan, and Steve Rothwell from
+the University of Michigan, along with help from lots of others.
diff --git a/doc/man/man3/ldap.3.links b/doc/man/man3/ldap.3.links
new file mode 100644 (file)
index 0000000..02a3482
--- /dev/null
@@ -0,0 +1 @@
+cldap.3
diff --git a/doc/man/man3/ldap_abandon.3 b/doc/man/man3/ldap_abandon.3
new file mode 100644 (file)
index 0000000..770513c
--- /dev/null
@@ -0,0 +1,42 @@
+.TH LDAP_ABANDON 3  "1 December 1994" "U-M LDAP LDVERSION"
+.SH NAME
+ldap_abandon \- Abandon an LDAP operation in progress
+.SH SYNOPSIS
+.nf
+.ft B
+#include <lber.h>
+#include <ldap.h>
+.LP
+.ft B
+int ldap_abandon(ld, msgid)
+.ft
+LDAP *ld;
+int msgid;
+.SH DESCRIPTION
+The
+.B ldap_abandon()
+routine is used to abandon or cancel an LDAP
+operation in progress.  The \fImsgid\fP passed should be the
+message id of an outstanding LDAP operation, as returned by
+.BR ldap_search (3),
+.BR ldap_modify (3),
+etc.
+.LP
+.BR ldap_abandon ()
+checks to see if the result of the operation has already come in.  If it
+has, it deletes it from the queue of pending messages.  If not,
+it sends an LDAP abandon operation to the the LDAP server.
+.LP
+The caller can expect that the result of an abandoned operation
+will not be returned from a future call to
+.BR ldap_result (3).
+.SH ERRORS
+.B ldap_abandon()
+returns 0 if everything goes ok, -1 otherwise,
+setting \fIld_errno\fP appropriately. See
+.BR ldap_error (3)
+for details.
+.SH SEE ALSO
+.BR ldap(3),
+.BR ldap_result(3),
+.B ldap_error(3)
diff --git a/doc/man/man3/ldap_add.3 b/doc/man/man3/ldap_add.3
new file mode 100644 (file)
index 0000000..85290ad
--- /dev/null
@@ -0,0 +1,60 @@
+.TH LDAP_ADD 3  "15 November 1994" "U-M LDAP LDVERSION"
+.SH NAME
+ldap_add, ldap_add_s \- Perform an LDAP add operation
+.SH SYNOPSIS
+.nf
+.ft B
+#include <lber.h>
+#include <ldap.h>
+.LP
+.ft B
+int ldap_add(ld, dn, attrs)
+.ft
+LDAP *ld;
+char *dn;
+LDAPMod *attrs[];
+.LP
+.ft B
+int ldap_add_s(ld, dn, attrs)
+.ft
+LDAP *ld;
+char *dn;
+LDAPMod *attrs[];
+.SH DESCRIPTION
+The
+.B ldap_add_s()
+routine is used to perform an LDAP add operation.
+It takes \fIdn\fP, the DN of the entry to add, and \fIattrs\fP, a
+null-terminated array of the entry's attributes.  The LDAPMod structure
+is used to represent attributes, with the \fImod_type\fP and
+\fImod_values\fP fields being used as described under
+.BR ldap_modify (3),
+and the \fIldap_op\fP field being used only if you need to specify
+the LDAP_MOD_BVALUES option. Otherwise, it should be set to zero.
+.LP
+Note that all entries except that
+specified by the last component in the given DN must already exist.
+.B ldap_add_s()
+returns an LDAP error code indicating success or failure
+of the operation.  See
+.BR ldap_error (3)
+for more details.
+.LP
+The
+.B ldap_add()
+routine works just like
+.BR ldap_add_s() ,
+but it is asynchronous.  It returns the message id of the request it
+initiated.  The result of this operation can be obtained by calling
+.BR ldap_result (3).
+.SH ERRORS
+.B ldap_add()
+returns -1 in case of error initiating the request, and
+will set the \fIld_errno\fP field in the \fIld\fP parameter
+to indicate the error.
+.B ldap_add_s()
+will return an LDAP error code
+directly (LDAP_SUCCESS if everything went ok, some error otherwise).
+.SH SEE ALSO
+.BR ldap(3),
+.B ldap_modify(3)
diff --git a/doc/man/man3/ldap_add.3.links b/doc/man/man3/ldap_add.3.links
new file mode 100644 (file)
index 0000000..5a06555
--- /dev/null
@@ -0,0 +1 @@
+ldap_add_s.3
diff --git a/doc/man/man3/ldap_bind.3 b/doc/man/man3/ldap_bind.3
new file mode 100644 (file)
index 0000000..c172b28
--- /dev/null
@@ -0,0 +1,196 @@
+.TH LDAP_BIND 3  "28 March 1996" "U-M LDAP LDVERSION"
+.SH NAME
+ldap_bind, ldap_bind_s, ldap_simple_bind, ldap_simple_bind_s, ldap_kerberos_bind_s, ldap_kerberos_bind1, ldap_kerberos_bind1_s, ldap_kerberos_bind2, ldap_kerberos_bind2_s, ldap_unbind, ldap_unbind_s, ldap_set_rebind_proc \- LDAP bind routines
+.SH SYNOPSIS
+.nf
+.ft B
+#include <lber.h>
+#include <ldap.h>
+.LP
+.ft B
+int ldap_bind(ld, who, cred, method)
+.ft
+LDAP *ld;
+char *who, *cred;
+int method;
+.LP
+.ft B
+int ldap_bind_s(ld, who, cred, method)
+.ft
+LDAP *ld;
+char *who, *cred;
+int method;
+.LP
+.ft B
+int ldap_simple_bind(ld, who, passwd)
+.ft
+LDAP *ld;
+char *who, *passwd;
+.LP
+.ft B
+int ldap_simple_bind_s(ld, who, passwd)
+.ft
+LDAP *ld;
+char *who, *passwd;
+.LP
+.ft B
+int ldap_kerberos_bind_s(ld, who)
+.ft
+LDAP *ld;
+char *who;
+.LP
+.ft B
+int ldap_kerberos_bind1(ld, who)
+.ft
+LDAP *ld;
+char *who;
+.LP
+.ft B
+int ldap_kerberos_bind1_s(ld, who)
+.ft
+LDAP *ld;
+char *who;
+.LP
+.ft B
+int ldap_kerberos_bind2(ld, who)
+.ft
+LDAP *ld;
+char *who;
+.LP
+.ft B
+int ldap_kerberos_bind2_s(ld, who)
+.ft
+LDAP *ld;
+char *who;
+.LP
+.ft B
+int ldap_unbind(ld)
+.ft
+LDAP *ld;
+.LP
+.ft B
+int ldap_unbind_s(ld)
+.ft
+LDAP *ld;
+.LP
+.ft B
+void ldap_set_rebind_proc( ld, rebindproc )
+.ft
+LDAP *ld;
+int (*rebindproc)();
+.SH DESCRIPTION
+.LP
+These routines provide various interfaces to the LDAP bind operation.
+After a connection is made to an LDAP server using
+.BR ldap_open (3),
+an LDAP bind operation must be performed before other operations can
+be attempted over the conection.  Both synchronous and asynchronous
+versions of each variant of the bind call are provided.  There are
+three types of calls, providing simple authentication, kerberos
+authentication, and general routines to do either one.  All routines
+take \fIld\fP as their first parameter, as returned from
+.BR ldap_open (3).
+.SH SIMPLE AUTHENTICATION
+The simplest form of the bind call is
+.BR ldap_simple_bind_s() .
+It takes the DN to bind as in \fIwho\fP, and the userPassword associated
+with the entry in \fIpasswd\fP.  It returns an LDAP error indication
+(see
+.BR ldap_error (3)).
+The
+.B ldap_simple_bind()
+call is asynchronous,
+taking the same parameters but only initiating the bind operation and
+returning the message id of the request it sent.  The result of the
+operation can be obtained by a subsequent call to
+.BR ldap_result (3).
+.SH KERBEROS AUTHENTICATION
+If the LDAP library and LDAP server being contacted have been
+compiled with the KERBEROS option defined,
+Kerberos version 4 authentication can be accomplished by calling
+the
+.BR ldap_kerberos_bind_s()
+routine.  It assumes the user already
+has obtained a ticket granting ticket.  It takes \fIwho\fP, the DN
+of the entry to bind as.  This routine does both steps of the
+kerberos binding process synchronously.  The
+.B ldap_kerberos_bind1_s()
+and
+.B ldap_kerberos_bind2_s()
+routines allow synchronous access to the
+individual steps, authenticating to the LDAP server and DSA, respectively.
+The
+.B ldap_kerberos_bind1()
+and
+.B ldap_kerberos_bind2()
+routines provide equivalent asynchronous access.
+.SH GENERAL AUTHENTICATION
+The
+.B ldap_bind()
+and
+.B ldap_bind_s()
+routines can be used when the
+authentication method to use needs to be selected at runtime.  They
+both take an extra \fImethod\fP parameter selecting the authentication
+method to use.  It should be set to one of LDAP_AUTH_SIMPLE,
+LDAP_AUTH_KRBV41, or LDAP_AUTH_KRBV42, to select simple authentication,
+kerberos authentication to the LDAP server, or kerberos authentication
+to the DSA, respectively.
+.B ldap_bind()
+returns the message id of the request it initiates.
+.B ldap_bind_s()
+returns an LDAP error indication.
+.SH UNBINDING
+The
+.B ldap_unbind()
+call is used to unbind from the directory,
+terminate the current association, and free the resources contained
+in the \fIld\fP structure.  Once it is called, the connection to
+the LDAP server is closed, and the \fIld\fP structure is invalid.
+The
+.B ldap_unbind_s()
+call is just another name for
+.BR ldap_unbind() ;
+both of these calls are synchronous in nature.
+.SH RE-BINDING WHILE FOLLOWING REFERRALS
+The
+.B ldap_set_rebind_proc()
+call is used to set a routine that will be called back to obtain bind
+credentials used when a new server is contacted during the following of
+an LDAP referral.  Note that this function is only available when the
+LDAP libraries are compiled with LDAP_REFERRALS defined and is only
+used when the ld_options field in the LDAP structure has
+LDAP_OPT_REFERRALS set (this is the default).  If
+.B ldap_set_rebind_proc()
+is never called, or if it is called with a NULL \fIrebindproc\fP
+parameter, an unauthenticated simple LDAP bind will always be done
+when chasing referrals.
+.LP
+\fIrebindproc\fP should be a function that is declared like this:
+.LP
+.nf
+int rebindproc( LDAP *ld, char **whop, char **credp,
+    int *methodp, int freeit );
+.fi
+.LP
+The LDAP library will first call the rebindproc to obtain the
+referral bind credentials, and the \fIfreeit\fP parameter will be
+zero.  The \fIwhop\fP, \fIcredp\fP, and \fImethodp\fP should be
+set as appropriate.  If the rebindproc returns LDAP_SUCCESS, referral
+processing continues, and the rebindproc will be called a second
+time with \fIfreeit\fP non-zero to give your application a chance to
+free any memory allocated in the previous call.
+.LP
+If anything but LDAP_SUCCESS is returned by the first call to
+the rebindproc, then referral processing is stopped and that error code
+is returned for the original LDAP operation.
+.SH ERRORS
+Asynchronous routines will return -1 in case of error, setting the
+\fIld_errno\fP parameter of the \fIld\fP structure.  Synchronous
+routines return whatever \fIld_errno\fP is set to.  See
+.BR ldap_error (3)
+for more information.
+.SH SEE ALSO
+.BR ldap(3),
+.BR ldap_error(3),
+.BR ldap_open(3)
diff --git a/doc/man/man3/ldap_bind.3.links b/doc/man/man3/ldap_bind.3.links
new file mode 100644 (file)
index 0000000..b03f592
--- /dev/null
@@ -0,0 +1,11 @@
+ldap_bind_s.3
+ldap_simple_bind.3
+ldap_simple_bind_s.3
+ldap_kerberos_bind_s.3
+ldap_kerberos_bind1.3
+ldap_kerberos_bind1_s.3
+ldap_kerberos_bind2.3
+ldap_kerberos_bind2_s.3
+ldap_unbind.3
+ldap_unbind_s.3
+ldap_set_rebind_proc.3
diff --git a/doc/man/man3/ldap_cache.3 b/doc/man/man3/ldap_cache.3
new file mode 100644 (file)
index 0000000..fbc8b0f
--- /dev/null
@@ -0,0 +1,117 @@
+.TH LDAP_CACHE 3  "14 November 1994" "U-M LDAP LDVERSION"
+.SH NAME
+ldap_enable_cache, ldap_disable_cache, ldap_destroy_cache, ldap_flush_cache, ldap_uncache_entry, ldap_uncache_request, ldap_set_cache_options \- LDAP client caching routines
+.SH SYNOPSIS
+.nf
+.ft B
+#include <lber.h>
+#include <ldap.h>
+.ft
+.LP
+.ft B
+ldap_enable_cache( ld, timeout, maxmem )
+.ft
+LDAP   *ld;
+long   timeout;
+long   maxmem;
+.LP
+.ft B
+void ldap_disable_cache( ld )
+.ft
+LDAP   *ld;
+.LP
+.ft B
+void ldap_destroy_cache( ld )
+.ft
+LDAP   *ld;
+.LP
+.ft B
+void ldap_flush_cache( ld )
+.ft
+LDAP   *ld;
+.LP
+.ft B
+void ldap_uncache_entry( ld, dn )
+.ft
+LDAP   *ld;
+char   *dn;
+.LP
+.ft B
+void ldap_uncache_request( ld, msgid )
+.ft
+LDAP   *ld;
+int    msgid;
+.LP
+.ft B
+void ldap_set_cache_options( ld, opts )
+.ft
+LDAP           *ld;
+unsigned long  opts;
+.fi
+.SH DESCRIPTION
+.LP
+These routines are used to control the behavior of client caching of
+.BR ldap_search (3),
+.BR cldap_search_s (3),
+and
+.BR ldap_compare (3)
+operations.  By
+default, the cache is disabled and no caching is done.  Enabling the
+cache can greatly improve performance and reduce network bandwidth when
+a client DUA makes repeated requests.
+.LP
+.B ldap_enable_cache()
+should be called to turn on local caching or to
+change cache parameters (lifetime of cached requests and memory used).
+The \fIld\fP parameter should be the result of a successful call to
+.BR ldap_open (3).
+The \fItimeout\fP is specified in seconds, and is used to
+decide how long to keep cached requests.  The \fImaxmem\fP value is in
+bytes, and is used to set an upper bound on how memory the cache will
+use.  You can specify 0 for \fImaxmem\fP to restrict the cache size by
+the \fItimeout\fP only.  The first call to ldap_enable_cache creates
+the cache; subsequent calls re-enable the cache and set the timeout and
+memory values.
+.LP
+.B ldap_disable_cache()
+temporarily disables use of the cache (new
+requests are not cached and the cache is not checked when returning
+results).  It does not delete the cache contents.
+.LP
+.B ldap_destroy_cache()
+turns off caching and completely removes the cache from memory.
+.LP
+.B ldap_flush_cache()
+deletes the cache contents, but does not effect it in any other way.
+.LP
+.B ldap_uncache_entry()
+removes all requests that make reference to the
+distinguished name \fIdn\fP from the cache.  It should be used, for
+example, after doing an
+.BR ldap_modify (3)
+call involving \fIdn\fP.
+.LP
+.B ldap_uncache_request()
+removes the request indicated by the LDAP request
+id \fImsgid\fP from the cache.
+.LP
+.B ldap_set_cache_options()
+is used to change caching behavior.  The current supported options are
+.B LDAP_CACHE_OPT_CACHENOERRS
+to suppress caching of any requests that result in an error, and
+.B LDAP_CACHE_OPT_CACHEALLERRS
+to enable caching of all requests.  The default behavior is to not
+cache requests that result in errors, except that request that result
+in the error
+.B LDAP_SIZELIMIT_EXCEEDED
+are cached.
+.SH ERRORS
+.B ldap_enable_cache()
+returns 0 upon success, and -1 if it is unable to
+allocate space for the cache.  All the other calls are declared as
+void and return nothing.
+.SH SEE ALSO
+.BR ldap (3),
+.BR ldap_search (3),
+.BR ldap_compare (3),
+.BR cldap_search_s (3)
diff --git a/doc/man/man3/ldap_cache.3.links b/doc/man/man3/ldap_cache.3.links
new file mode 100644 (file)
index 0000000..960d731
--- /dev/null
@@ -0,0 +1,7 @@
+ldap_enable_cache.3
+ldap_disable_cache.3
+ldap_destroy_cache.3
+ldap_flush_cache.3
+ldap_uncache_entry.3
+ldap_uncache_request.3
+ldap_set_cache_options.3
diff --git a/doc/man/man3/ldap_charset.3 b/doc/man/man3/ldap_charset.3
new file mode 100644 (file)
index 0000000..c926b07
--- /dev/null
@@ -0,0 +1,127 @@
+.TH LDAP_CHARSET 3  "28 March 1996" "U-M LDAP LDVERSION"
+.SH NAME
+ldap_set_string_translators,
+ldap_t61_to_8859,
+ldap_8859_to_t61,
+ldap_translate_from_t61,
+ldap_translate_to_t61,
+ldap_enable_translation \- LDAP character set translation routines
+.SH SYNOPSIS
+.nf
+.ft B
+#include <lber.h>
+#include <ldap.h>
+.ft
+.LP
+.ft B
+void ldap_set_string_translators( ld, encode_proc, decode_proc )
+.ft
+LDAP                   *ld;
+BERTranslateProc       encode_proc;
+BERTranslateProc       decode_proc;
+.LP
+.ft B
+typedef int (*BERTranslateProc)( char **bufp, unsigned long *buflenp,
+       int free_input );
+.ft
+.LP
+.ft B
+int ldap_t61_to_8859( bufp, buflenp, free_input )
+.ft
+char           **bufp;
+unsigned long  *buflenp;
+int            free_input;
+.LP
+.ft B
+int ldap_8859_to_t61( bufp, buflenp, free_input )
+.ft
+char           **bufp;
+unsigned long  *buflenp;
+int            free_input;
+.LP
+.ft B
+int ldap_translate_from_t61( ld, bufp, lenp, free_input )
+.ft
+LDAP           *ld;
+char           **bufp;
+unsigned long  *lenp;
+int             free_input;
+.LP
+.ft B
+int ldap_translate_to_t61( ld, bufp, lenp, free_input )
+.ft
+LDAP           *ld;
+char           **bufp;
+unsigned long  *lenp;
+int             free_input;
+.LP
+.ft B
+void ldap_enable_translation( ld, entry, enable )
+.ft
+LDAP           *ld;
+LDAPMessage    *entry;
+int            enable;
+.fi
+.SH DESCRIPTION
+.LP
+These routines are used to used to enable translation of character strings
+used in the LDAP library to and from the T.61 character set used in the
+LDAP protocol.  These functions are only available if the LDAP and LBER
+libraries are compiled with STR_TRANSLATION defined.
+It is also possible to turn on character translation by default so that
+all LDAP library callers will experience translation; see the LDAP
+Make-common source file for details.
+.LP
+.B ldap_set_string_translators()
+sets the translation routines that will
+be used by the LDAP library.  They are not actually used until the
+\fIld_lberoptions\fP field of the LDAP structure is set to include the
+LBER_TRANSLATE_STRINGS option.
+.LP
+.B ldap_t61_to_8859()
+and
+.B ldap_8859_to_t61()
+are translation routines for
+converting between T.61 characters and ISO-8859 characters.  The specific
+8859 character set used is determined at compile time.
+.LP
+.B ldap_translate_from_t61()
+is used to translate a string of characters from the T.61 character set to a
+different character set.  The actual translation is done using the
+\fIdecode_proc\fP that was passed to a previous call to
+.B ldap_set_string_translators().
+On entry, \fI*bufp\fP should point to the start of the T.61 characters
+to be translated and \fI*lenp\fP should contain the number of bytes to
+translate.  If \fIfree_input\fP is non-zero, the input buffer will be
+freed if translation is a success.  If the translation is a success,
+LDAP_SUCCESS will be returned, \fI*bufp\fP will point to a newly
+malloc'd buffer that contains the translated characters, and
+\fI*lenp\fP will contain the length of the result.  If translation
+fails, an LDAP error code will be returned.
+
+.LP
+.B ldap_translate_to_t61()
+is used to translate a string of characters to the T.61 character set from a
+different character set.  The actual translation is done using the
+\fIencode_proc\fP that was passed to a previous call to
+.B ldap_set_string_translators().
+This function is called just like
+.B ldap_translate_from_t61().
+.LP
+.B ldap_enable_translation()
+is used to turn on or off string translation for the LDAP entry \fIentry\fP
+(typically obtained by calling
+.B ldap_first_entry()
+or
+.B ldap_next_entry()
+after a successful LDAP search operation).  If \fIenable\fP is zero,
+translation is disabled; if non-zero, translation is enabled.  This routine
+is useful if you need to ensure that a particular attribute is not
+translated when it is extracted using
+.B ldap_get_values()
+or
+.B ldap_get_values_len().
+For example, you would not want to translate a binary attributes such as
+jpegPhoto.
+.SH SEE ALSO
+.BR ldap (3)
diff --git a/doc/man/man3/ldap_charset.3.links b/doc/man/man3/ldap_charset.3.links
new file mode 100644 (file)
index 0000000..c7525af
--- /dev/null
@@ -0,0 +1,6 @@
+ldap_set_string_translators.3
+ldap_enable_translation.3
+ldap_translate_from_t61.3
+ldap_translate_to_t61.3
+ldap_t61_to_8859.3
+ldap_8859_to_t61.3
diff --git a/doc/man/man3/ldap_compare.3 b/doc/man/man3/ldap_compare.3
new file mode 100644 (file)
index 0000000..3df8ca9
--- /dev/null
@@ -0,0 +1,51 @@
+.TH LDAP_COMPARE 3  "15 November 1994" "U-M LDAP LDVERSION"
+.SH NAME
+ldap_compare, ldap_compare_s \- Perform an LDAP compare operation
+.SH SYNOPSIS
+.nf
+.ft B
+#include <lber.h>
+#include <ldap.h>
+.LP
+.ft B
+int ldap_compare_s(ld, dn, attr, value)
+.ft
+LDAP *ld;
+char *dn, *attr, *value;
+.LP
+.ft B
+int ldap_compare(ld, dn, attr, value)
+.ft
+LDAP *ld;
+char *dn, *attr, *value;
+.SH DESCRIPTION
+The
+.B ldap_compare_s()
+routine is used to perform an LDAP compare operation
+synchronously.  It takes \fIdn\fP, the DN of the entry upon which to perform
+the compare, and \fIattr\fP and \fIvalue\fP, the attribute type and value to
+compare to those found in the entry.  It returns an LDAP error code, which
+will be LDAP_COMPARE_TRUE if the entry contains the attribute value and
+LDAP_COMPARE_FALSE if it does not.  Otherwise, some error code is returned.
+.LP
+The
+.B ldap_compare()
+routine is used to perform an LDAP compare operation
+asynchronously.  It takes the same parameters as
+.BR ldap_compare_s() ,
+but returns the message id of the request it initiated.  The result of
+the compare can be obtained by a subsequent call to
+.BR ldap_result (3).
+.SH ERRORS
+.B ldap_compare_s()
+returns an LDAP error code which can be interpreted
+by calling one of
+.BR ldap_perror (3)
+and friends.  ldap_compare() returns
+-1 if something went wrong initiating the request.  It returns the
+non-negative message id of the request if things went ok.
+.SH BUGS
+There is no way to compare binary values, but there should be.
+.SH SEE ALSO
+.BR ldap(3),
+.BR ldap_error(3)
diff --git a/doc/man/man3/ldap_compare.3.links b/doc/man/man3/ldap_compare.3.links
new file mode 100644 (file)
index 0000000..ed16b8e
--- /dev/null
@@ -0,0 +1 @@
+ldap_compare_s.3
diff --git a/doc/man/man3/ldap_delete.3 b/doc/man/man3/ldap_delete.3
new file mode 100644 (file)
index 0000000..3149890
--- /dev/null
@@ -0,0 +1,48 @@
+.TH LDAP_DELETE 3  "15 November 1994" "U-M LDAP LDVERSION"
+.SH NAME
+ldap_delete, ldap_delete_s \- Perform an LDAP delete operation
+.SH SYNOPSIS
+.nf
+.ft B
+#include <lber.h>
+#include <ldap.h>
+.LP
+.ft B
+int ldap_delete_s(ld, dn)
+.ft
+LDAP *ld;
+char *dn;
+.LP
+.ft B
+int ldap_delete(ld, dn)
+.ft
+LDAP *ld;
+char *dn;
+.SH DESCRIPTION
+The
+.B ldap_delete_s()
+routine is used to perform an LDAP delete operation
+synchronously.  It takes \fIdn\fP, the DN of the entry to be deleted.
+It returns an LDAP error code, indicating the success or failure of the
+operation.
+.LP
+The
+.B ldap_delete()
+routine is used to perform an LDAP delete operation
+asynchronously.  It takes the same parameters as
+.BR ldap_delete_s() ,
+but returns the message id of the request it initiated.  The result of
+the delete can be obtained by a subsequent call to
+.BR ldap_result (3).
+.SH ERRORS
+.B ldap_delete_s()
+returns an LDAP error code which can be interpreted
+by calling one of
+.BR ldap_perror (3)
+and friends.
+.B ldap_delete()
+returns -1 if something went wrong initiating the request.  It returns the
+non-negative message id of the request if things went ok.
+.SH SEE ALSO
+.BR ldap(3),
+.BR ldap_error(3)
diff --git a/doc/man/man3/ldap_delete.3.links b/doc/man/man3/ldap_delete.3.links
new file mode 100644 (file)
index 0000000..7bf980f
--- /dev/null
@@ -0,0 +1 @@
+ldap_delete_s.3
diff --git a/doc/man/man3/ldap_disptmpl.3 b/doc/man/man3/ldap_disptmpl.3
new file mode 100644 (file)
index 0000000..03c1e65
--- /dev/null
@@ -0,0 +1,450 @@
+.TH LDAP_DISPTMPL 3  "13 December 1994" "U-M LDAP LDVERSION"
+.SH NAME
+ldap_init_templates, ldap_init_templates_buf, ldap_free_templates, ldap_first_disptmpl, ldap_next_disptmpl, ldap_oc2template, ldap_tmplattrs, ldap_first_tmplrow, ldap_next_tmplrow, ldap_first_tmplcol, ldap_next_tmplcol, \- LDAP display template routines
+.SH SYNOPSIS
+.nf
+.ft B
+#include <disptmpl.h>
+.ft
+.LP
+.ft B
+int ldap_init_templates( file, tmpllistp )
+.ft
+char                   *file;
+struct ldap_disptmpl   **tmpllistp;
+.LP
+.ft B
+int ldap_init_templates_buf( buf, buflen, tmpllistp )
+.ft
+char                   *buf;
+unsigned long          len;
+struct ldap_disptmpl   **tmpllistp;
+.LP
+.ft B
+void ldap_free_templates( tmpllist )
+.ft
+struct ldap_disptmpl   *tmpllist;
+.LP
+.ft B
+struct ldap_disptmpl *ldap_first_disptmpl( tmpllist )
+.ft
+struct ldap_disptmpl   *tmpllist;
+.LP
+.ft B
+struct ldap_disptmpl *ldap_next_disptmpl( tmpllist, tmpl )
+.ft
+struct ldap_disptmpl   *tmpllist;
+struct ldap_disptmpl   *tmpl;
+.LP
+.ft B
+struct ldap_disptmpl *ldap_oc2template( oclist, tmpllist )
+.ft
+char                   **oclist;
+struct ldap_disptmpl   *tmpllist;
+.LP
+.ft B
+struct ldap_disptmpl *ldap_name2template( name, tmpllist )
+.ft
+char                   *name;
+struct ldap_disptmpl   *tmpllist;
+.LP
+.ft B
+char **ldap_tmplattrs( tmpl, includeattrs, exclude, syntaxmask )
+.ft
+struct ldap_disptmpl   *tmpl;
+char                   **includeattrs;
+int                    exclude;
+unsigned long          syntaxmask;
+.LP
+.ft B
+struct ldap_tmplitem *ldap_first_tmplrow( tmpl )
+.ft
+struct ldap_disptmpl   *tmpl;
+.LP
+.ft B
+struct ldap_tmplitem *ldap_next_tmplrow( tmpl, row )
+.ft
+struct ldap_disptmpl   *tmpl;
+struct ldap_tmplitem   *row;
+.LP
+.ft B
+struct ldap_tmplitem *ldap_first_tmplcol( tmpl, row )
+.ft
+struct ldap_disptmpl   *tmpl;
+struct ldap_tmplitem   *row;
+.LP
+.ft B
+struct ldap_tmplitem *ldap_next_tmplcol( tmpl, row, col )
+.ft
+struct ldap_disptmpl   *tmpl;
+struct ldap_tmplitem   *row;
+struct ldap_tmplitem   *col;
+.fi
+.SH DESCRIPTION
+These functions provide a standard way to access LDAP entry display
+templates.  Entry display templates provide a standard way for LDAP
+applications to display directory entries.  The general idea is that it
+is possible to map the list of object class values present in an entry
+to an appropriate display template.  Display templates are defined in a
+configuration file (see ldaptemplates.conf(5)).  Each display template
+contains a pre-determined list of items, where each item generally
+corresponds to an attribute to be displayed.  The items contain
+information and flags that the caller can use to display the attribute and
+values in a reasonable fashion.  Each item has a syntaxid, which are
+described in the SYNTAX IDS section below.  The ldap_entry2text(3)
+routines use the display template functions and produce text output.
+.LP
+ldap_init_templates() reads a sequence of templates from a valid LDAP
+template configuration file (see ldaptemplates.conf(5))
+.I Zero
+is returned upon success, and
+.I tmpllistp
+is set to point to a list of templates.  Each member of the list is an
+ldap_disptmpl structure (defined below in the DISPTMPL STRUCTURE ELEMENTS
+section).
+.LP
+.LP
+ldap_init_templates_buf() reads a sequence of templates from
+.I buf
+(whose size is
+.I buflen).
+.I buf
+should point to the data in the format defined for an LDAP template
+configuration file (see ldaptemplates.conf(5))
+.I Zero
+is returned upon success, and
+.I tmpllistp
+is set to point to a list of templates.
+.LP
+The
+.B LDAP_SET_DISPTMPL_APPDATA()
+macro is used to set the value of the dt_appdata field in an ldap_disptmpl
+structure.  This field is reserved for the calling application to use; it
+is not used internally.
+.LP
+The
+.B LDAP_GET_DISPTMPL_APPDATA()
+macro is used to retrieve the value in the dt_appdata field.
+.LP
+The
+.B LDAP_IS_DISPTMPL_OPTION_SET()
+macro is used to test a ldap_disptmpl structure for the existence of a
+template option.  The options currently defined are:
+.B LDAP_DTMPL_OPT_ADDABLE
+(it is appropriate to allow entries of this type to be added),
+.B LDAP_DTMPL_OPT_ALLOWMODRDN
+(it is appropriate to offer the "modify rdn" operation),
+.B LDAP_DTMPL_OPT_ALTVIEW
+(this template is merely an alternate view of another template, typically
+used for templates pointed to be an LDAP_SYN_LINKACTION item).
+.LP
+ldap_free_templates() disposes of the templates allocated by
+ldap_init_templates().
+.LP
+ldap_first_disptmpl() returns the first template in the list
+.I tmpllist.
+The
+.I tmpllist
+is typically obtained by calling ldap_init_templates().
+.LP
+ldap_next_disptmpl() returns the template after
+.I tmpl
+in the template list
+.I tmpllist.  A
+.SM NULL
+pointer is returned if
+.I tmpl
+is the last template in the list.
+.LP
+ldap_oc2template() searches
+.I tmpllist
+for the best template to use to display an entry that has a specific
+set of objectClass values.
+.I oclist
+should be a null-terminated array of strings that contains the values
+of the objectClass attribute of the entry.  A pointer to the first
+template where all of the object classes listed in one of the
+template's dt_oclist elements are contained in
+.I oclist
+is returned.  A
+.B NULL
+pointer is returned if no appropriate template is found.
+.LP
+ldap_tmplattrs() returns a null-terminated array that contains the
+names of attributes that need to be retrieved if the template
+.I tmpl
+is to be used to display an entry.  The attribute list should be freed
+using ldap_value_free().  The
+.I includeattrs
+parameter contains a null-terminated array of attributes that should
+always be included (it may be
+.B NULL
+if no extra attributes are required).  If
+.I syntaxmask
+is non-zero, it is used to restrict the attribute set returned.  If
+.I exclude
+is zero, only attributes where the logical AND of the template item
+syntax id and the
+.I syntaxmask
+is non-zero are included.  If
+.I exclude
+is non-zero, attributes where the logical AND of the template item
+syntax id and the
+.I  syntaxmask
+is non-zero are excluded.
+.LP
+ldap_first_tmplrow() returns a pointer to the first row of items in
+template
+.I tmpl.
+.LP
+ldap_next_tmplrow() returns a pointer to the row that follows
+.I row
+in template
+.I tmpl.
+.LP
+ldap_first_tmplcol() returns a pointer to the first item (in the first
+column) of row
+.I row
+within template
+.I tmpl.  A pointer to an ldap_tmplitem structure (defined below
+in the TMPLITEM STRUCTURE ELEMENTS section) is returned.
+.LP
+The
+.B LDAP_SET_TMPLITEM_APPDATA()
+macro is used to set the value of the ti_appdata field in a ldap_tmplitem
+structure.  This field is reserved for the calling application to use; it
+is not used internally.
+.LP
+The
+.B LDAP_GET_TMPLITEM_APPDATA()
+macro is used to retrieve the value of the ti_appdata field.
+.LP
+The
+.B LDAP_IS_TMPLITEM_OPTION_SET()
+macro is used to test a ldap_tmplitem structure for the existence of an
+item option.  The options currently defined are:
+.B LDAP_DITEM_OPT_READONLY
+(this attribute should not be modified),
+.B LDAP_DITEM_OPT_SORTVALUES
+(it makes sense to sort the values),
+.B LDAP_DITEM_OPT_SINGLEVALUED
+(this attribute can only hold a single value),
+.B LDAP_DITEM_OPT_VALUEREQUIRED
+(this attribute must contain at least one value),
+.B LDAP_DITEM_OPT_HIDEIFEMPTY
+(do not show this item if there are no values), and
+.B LDAP_DITEM_OPT_HIDEIFFALSE
+(for boolean attributes only:  hide this item if the value is FALSE).
+.LP
+ldap_next_tmplcol() returns a pointer to the item (column) that follows column
+.I col
+within row
+.I row
+of template
+.I tmpl.
+.SH DISPTMPL STRUCTURE ELEMENTS
+The ldap_disptmpl structure is defined as:
+.nf
+.ft B
+struct ldap_disptmpl {
+       char                    *dt_name;
+       char                    *dt_pluralname;
+       char                    *dt_iconname;
+       unsigned long           dt_options;
+       char                    *dt_authattrname;
+       char                    *dt_defrdnattrname;
+       char                    *dt_defaddlocation;
+       struct ldap_oclist      *dt_oclist;
+       struct ldap_adddeflist  *dt_adddeflist;
+       struct ldap_tmplitem    *dt_items;
+       void                    *dt_appdata;
+       struct ldap_disptmpl    *dt_next;
+};
+.ft
+.fi
+The dt_name member is the singular name of the template.  The dt_pluralname
+is the plural name.  The dt_iconname member will contain the name of an
+icon or other graphical element that can be used to depict entries that
+correspond to this display template.  The dt_options contains options which
+may be tested using the LDAP_IS_TMPLITEM_OPTION_SET() macro.
+.LP
+The dt_authattrname contains the name of the DN-syntax attribute whose
+value(s) should be used to authenticate to make changes to an entry.  If
+dt_authattrname is NULL, then authenticating as the entry itself is
+appropriate.  The dt_defrdnattrname is the name of the attribute that
+is normally used to name entries of this type, e.g., "cn" for person
+entries.  The dt_defaddlocation is the distinguished name of an entry
+below which new entries of this type are typically created (its value is
+site-dependent).
+.LP
+dt_oclist is a pointer to a linked list of object class arrays, defined as:
+.nf
+.ft B
+struct ldap_oclist {
+       char                    **oc_objclasses;
+       struct ldap_oclist      *oc_next;
+};
+.ft
+.fi
+These are used by the ldap_oc2template() routine.
+.LP
+dt_adddeflist is a pointer to a linked list of rules for defaulting the
+values of attributes when new entries are created.  The ldap_adddeflist
+structure is defined as:
+.nf
+.ft B
+struct ldap_adddeflist {
+       int                     ad_source;
+       char                    *ad_attrname;
+       char                    *ad_value;
+       struct ldap_adddeflist  *ad_next;
+};
+.ft
+.fi
+The ad_attrname member contains the name of the attribute whose value this
+rule sets.  If ad_source is 
+.B LDAP_ADSRC_CONSTANTVALUE
+then the ad_value member contains the (constant) value to use.
+If  ad_source is
+.B LDAP_ADSRC_ADDERSDN
+then ad_value is ignored and the distinguished name of the person who
+is adding the new entry is used as the default value for ad_attrname. 
+.SH TMPLITEM STRUCTURE ELEMENTS
+The ldap_tmplitem structure is defined as:
+.nf
+.ft B
+struct ldap_tmplitem {
+       unsigned long           ti_syntaxid;
+       unsigned long           ti_options;
+       char                    *ti_attrname;
+       char                    *ti_label;
+       char                    **ti_args;
+       struct ldap_tmplitem    *ti_next_in_row;
+       struct ldap_tmplitem    *ti_next_in_col;
+       void                    *ti_appdata;
+};
+.ft
+.fi
+.SH SYNTAX IDS
+Syntax ids are found in the ldap_tmplitem structure element ti_syntaxid,
+and they can be used to determine how to display the values for the
+attribute associated with an item.  The LDAP_GET_SYN_TYPE() macro can
+be used to return a general type from a syntax id.  The five general types
+currently defined are:
+.B LDAP_SYN_TYPE_TEXT
+(for attributes that are most appropriately shown as text),
+.B LDAP_SYN_TYPE_IMAGE
+(for JPEG or FAX format images),
+.B LDAP_SYN_TYPE_BOOLEAN
+(for boolean attributes),
+.B LDAP_SYN_TYPE_BUTTON
+(for attributes whose values are to be retrieved and display only upon 
+request, e.g., in response to the press of a button, a JPEG image is
+retrieved, decoded, and displayed), and
+.B LDAP_SYN_TYPE_ACTION
+(for special purpose actions such as "search for the entries where this
+entry is listed in the seeAlso attribute").
+.LP
+The
+.B LDAP_GET_SYN_OPTIONS
+macro can be used to retrieve an unsigned long bitmap that defines
+options.  The only currently defined option is
+.B LDAP_SYN_OPT_DEFER,
+which (if set) implies that the values for the attribute should not
+be retrieved until requested.
+.LP
+There are sixteen distinct syntax ids currently defined.  These generally
+correspond to one or more X.500 syntaxes.
+.LP
+.B LDAP_SYN_CASEIGNORESTR
+is used for text attributes which are simple strings whose case is ignored
+for comparison purposes.
+.LP
+.B LDAP_SYN_MULTILINESTR
+is used for text attributes which consist of multiple lines,
+e.g., postalAddress, homePostalAddress, multilineDescription, or any
+attributes of syntax caseIgnoreList.
+.LP
+.B LDAP_SYN_RFC822ADDR
+is used for case ignore string attributes that are RFC-822 conformant
+mail addresses, e.g., mail.
+.LP
+.B LDAP_SYN_DN
+is used for attributes with a Distinguished Name syntax, e.g., seeAlso.
+.LP
+.B LDAP_SYN_BOOLEAN
+is used for attributes with a boolean syntax.
+.LP
+.B LDAP_SYN_JPEGIMAGE
+is used for attributes with a jpeg syntax, e.g., jpegPhoto.
+.LP
+.B LDAP_SYN_JPEGBUTTON
+is used to provide a button (or equivalent interface element) that can be
+used to retrieve, decode, and display an attribute of jpeg syntax.
+.LP
+.B LDAP_SYN_FAXIMAGE
+is used for attributes with a photo syntax, e.g., Photo.  These are
+actually Group 3 Fax (T.4) format images.
+.LP
+.B LDAP_SYN_FAXBUTTON
+is used to provide a button (or equivalent interface element) that can be
+used to retrieve, decode, and display an attribute of photo syntax.
+.LP
+.B LDAP_SYN_AUDIOBUTTON
+is used to provide a button (or equivalent interface element) that can be
+used to retrieve and play an attribute of audio syntax.  Audio values are
+in the "mu law" format, also known as "au" format.
+.LP
+.B LDAP_SYN_TIME
+is used for attributes with the UTCTime syntax, e.g., lastModifiedTime.
+The value(s) should be displayed in complete date and time fashion.
+.LP
+.B LDAP_SYN_DATE
+is used for attributes with the UTCTime syntax, e.g., lastModifiedTime.
+Only the date portion of the value(s) should be displayed.
+.LP
+.B LDAP_SYN_LABELEDURL
+is used for labeledURL attributes.
+.LP
+.B LDAP_SYN_SEARCHACTION
+is used to define a search that is used to retrieve related information.
+If ti_attrname is not NULL, it is assumed to be a boolean attribute which
+will cause no search to be performed if its value is FALSE.  The ti_args
+structure member will have four strings in it:  ti_args[ 0 ] should be
+the name of an attribute whose values are used to help construct a search
+filter or "-dn" is the distinguished name of the entry being displayed
+should be used, ti_args[ 1 ] should be a filter pattern where any occurrences
+of "%v" are replaced with the value derived from ti_args[ 0 ], ti_args[ 2 ]
+should be the name of an additional attribute to retrieve when performing
+the search, and ti_args[ 3 ] should be a human-consumable name for that
+attribute.  The ti_args[ 2 ] attribute is typically displayed along with
+a list of distinguished names when multiple entries are returned by the
+search.
+.LP
+.B LDAP_SYN_LINKACTION
+is used to define a link to another template by name.  ti_args[ 0 ] will
+contain the name of the display template to use.  The ldap_name2template()
+routine can be used to obtain a pointer to the correct ldap_disptmpl structure.
+.LP
+.B LDAP_SYN_ADDDNACTION
+and
+.B LDAP_SYN_VERIFYDNACTION
+are reserved as actions but currently undefined.
+.SH ERRORS
+The init template functions return
+.B LDAP_TMPL_ERR_VERSION
+if buf points to data that is newer than can be handled,
+.B LDAP_TMPL_ERR_MEM
+if there is a memory allocation problem,
+.B LDAP_TMPL_ERR_SYNTAX
+if there is a problem with the format of the templates buffer or file.
+.B LDAP_TMPL_ERR_FILE
+is returned by
+.B ldap_init_templates
+if the file cannot be read.   Other routines generally return
+.B NULL
+upon error.
+.SH SEE ALSO
+.BR ldap (3),
+.BR ldap_entry2text (3),
+.BR ldaptemplates.conf (5)
diff --git a/doc/man/man3/ldap_disptmpl.3.links b/doc/man/man3/ldap_disptmpl.3.links
new file mode 100644 (file)
index 0000000..8f8a377
--- /dev/null
@@ -0,0 +1,11 @@
+ldap_init_templates.3
+ldap_init_templates_buf.3
+ldap_free_templates.3
+ldap_first_disptmpl.3
+ldap_next_disptmpl.3
+ldap_oc2template.3
+ldap_tmplattrs.3
+ldap_first_tmplrow.3
+ldap_next_tmplrow.3
+ldap_first_tmplcol.3
+ldap_next_tmplcol.3
diff --git a/doc/man/man3/ldap_entry2text.3 b/doc/man/man3/ldap_entry2text.3
new file mode 100644 (file)
index 0000000..5445425
--- /dev/null
@@ -0,0 +1,326 @@
+.TH LDAP_ENTRY2TEXT 3  "13 November 1994" "U-M LDAP %LDVERSION%"
+.SH NAME
+ldap_entry2text, ldap_entry2text_search, ldap_vals2text \- LDAP entry display routines
+.SH SYNOPSIS
+.nf
+.ft B
+#include <lber.h>
+#include <ldap.h>
+#include <disptmpl.h>
+.ft
+.LP
+.ft B
+int ldap_entry2text( ld, buf, entry, tmpl, defattrs, defvals, writeproc,
+    writeparm, eol, rdncount, opts )
+.ft
+       LDAP                    *ld;
+       char                    *buf;
+       LDAPMessage             *entry;
+       struct ldap_disptmpl    *tmpl;
+       char                    **defattrs;
+       char                    ***defvals;
+       int                     (*writeproc)();
+       void                    *writeparm;
+       char                    *eol;
+       int                     rdncount;
+       unsigned long           opts;
+.LP
+.ft B
+int ldap_entry2text_search( ld, entry, tmpllist, defattrs, defvals,
+    writeproc, writeparm, eol, rdncount, opts )
+.ft
+       LDAP                    *ld;
+       char                    *dn;
+       char                    *base;
+       LDAPMessage             *entry;
+       struct ldap_disptmpl    *tmpllist;
+       char                    **defattrs;
+       char                    ***defvals;
+       int                     (*writeproc)();
+       void                    *writeparm;
+       char                    *eol;
+       int                     rdncount;
+       unsigned long           opts;
+.LP
+.ft B
+int ldap_vals2text( ld, buf, vals, label, labelwidth, syntaxid, writeproc,
+    writeparm, eol, rdncount )
+.ft
+       LDAP                    *ld;
+       char                    *buf;
+       char                    **vals;
+       char                    *label;
+       int                     labelwidth;
+       unsigned long           syntaxid;
+       int                     (*writeproc)();
+       void                    *writeparm;
+       char                    *eol;
+       int                     rdncount;
+.LP
+.ft B
+int ldap_entry2html( ld, buf, entry, tmpl, defattrs, defvals, writeproc,
+    writeparm, eol, rdncount, opts )
+.ft
+       LDAP                    *ld;
+       char                    *buf;
+       LDAPMessage             *entry;
+       struct ldap_disptmpl    *tmpl;
+       char                    **defattrs;
+       char                    ***defvals;
+       int                     (*writeproc)();
+       void                    *writeparm;
+       char                    *eol;
+       int                     rdncount;
+       unsigned long           opts;
+       char                    *urlprefix;
+       char                    *base;
+.LP
+.ft B
+int ldap_entry2html_search( ld, entry, tmpllist, defattrs, defvals,
+    writeproc, writeparm, eol, rdncount, opts )
+.ft
+       LDAP                    *ld;
+       char                    *dn;
+       LDAPMessage             *entry;
+       struct ldap_disptmpl    *tmpllist;
+       char                    **defattrs;
+       char                    ***defvals;
+       int                     (*writeproc)();
+       void                    *writeparm;
+       char                    *eol;
+       int                     rdncount;
+       unsigned long           opts;
+       char                    *urlprefix;
+.LP
+.ft B
+int ldap_vals2html( ld, buf, vals, label, labelwidth, syntaxid, writeproc,
+    writeparm, eol, rdncount )
+.ft
+       LDAP                    *ld;
+       char                    *buf;
+       char                    **vals;
+       char                    *label;
+       int                     labelwidth;
+       unsigned long           syntaxid;
+       int                     (*writeproc)();
+       void                    *writeparm;
+       char                    *eol;
+       int                     rdncount;
+       char                    *urlprefix;
+.LP
+.ft B
+
+
+#define LDAP_DISP_OPT_AUTOLABELWIDTH   0x00000001
+#define LDAP_DISP_OPT_HTMLBODYONLY      0x00000002
+
+#define LDAP_DTMPL_BUFSIZ              2048
+.ft
+.fi
+.SH DESCRIPTION
+These functions use the LDAP display template routines (see
+ldap_disptmpl(3) and ldap_templates.conf(5)) to produce a plain text
+or an HyperText Markup Language (HTML) display of an entry or a set of
+values.  Typical plain text output produced for an entry might look like:
+.nf
+
+    "Barbara J Jensen, Information Technology Division"
+     Also Known As:
+                  Babs Jensen
+                  Barbara Jensen
+                  Barbara J Jensen
+     E-Mail Address:
+                  bjensen@terminator.rs.itd.umich.edu
+     Work Address: 
+                  535 W. William 
+                  Ann Arbor, MI 48103
+     Title:        
+                  Mythical Manager, Research Systems
+     ...
+.fi
+The exact output produced will depend on the display template configuration.
+HTML output is similar to the plain text output, but more richly formatted.
+.LP
+.B ldap_entry2text(\|)
+produces a text representation of
+.I entry
+and writes the text by calling the
+.I writeproc
+function.  All of the attributes values to be displayed must be present
+in
+.I entry;
+no interaction with the LDAP server will be performed within
+.B ldap_entry2text.
+.I ld 
+is the LDAP pointer obtained by a previous call to
+.B ldap_open.
+.I writeproc
+should be declared as:
+.LP
+.ft B
+.nf
+int writeproc( writeparm, p, len )
+.ft
+       void            *writeparm;
+       char            *p;
+       int             len;
+.fi
+.LP
+where
+.I p
+is a pointer to text to be written and
+.I len
+is the length of the text.
+.I p
+is guaranteed to be zero-terminated.  Lines of text are terminated
+with the string
+.I eol.
+.I buf
+is a pointer to a buffer of size
+.B LDAP_DTMPL_BUFSIZ
+or larger.  If
+.I buf is
+.B NULL
+then a buffer is allocated and freed internally.
+.I tmpl
+is a pointer to the display template to be used (usually obtained by calling
+.B ldap_oc2template).
+If
+.I tmpl
+is NULL,
+no template is used and a generic display is produced.
+.I defattrs
+is a NULL-terminated array of LDAP attribute names which you wish to
+provide default values for (only used if
+.I entry
+contains no values for the attribute).  An array of NULL-terminated arrays of
+default values corresponding to the attributes should be passed in
+.I defvals.  The
+.I rdncount
+parameter is used to limit the number of Distinguished Name (DN) components
+that are actually displayed for DN attributes.  If
+.I rdncount
+is zero, all components are shown.
+.I opts
+is used to specify output options.  The only values currently allowed
+are zero (default output),
+.B LDAP_DISP_OPT_AUTOLABELWIDTH
+which causes the width for labels to be determined based on the longest
+label in
+.I tmpl, and
+.B LDAP_DISP_OPT_HTMLBODYONLY.
+The 
+.B LDAP_DISP_OPT_HTMLBODYONLY
+option instructs the library not to include <HTML>, <HEAD>, <TITLE>, and
+<BODY> tags.  In other words, an HTML fragment is generated, and the
+caller is responsible for prepending and appending the appropriate HTML
+tags to construct a correct HTML document.
+.LP
+.B ldap_entry2text_search(\|)
+is similar to
+.B ldap_entry2text,
+and all of the like-named parameters have the same meaning except as noted
+below.  
+If
+.I base
+is not NULL, it is the search base to use when executing search actions.  If
+it is NULL, search action template items are ignored.  If
+.I entry
+is not NULL, it should contain the
+.I objectClass
+attribute values for the entry to be displayed.  If
+.I entry
+is NULL,
+.I dn
+must not be NULL, and 
+.B ldap_entry2text_search
+will retrieve the objectClass values itself by calling
+.B ldap_search_s.
+.B ldap_entry2text_search
+will determine the appropriate display template to use by calling
+.B ldap_oc2template,
+and will call
+.B ldap_search_s
+to retrieve any attribute values to be displayed.  The
+.I tmpllist
+parameter is a pointer to the entire list of templates available (usually
+obtained by calling
+.B ldap_init_templates
+or
+.B ldap_init_templates_buf).
+If
+.I tmpllist
+is NULL,
+.B ldap_entry2text_search
+will attempt to read a load templates from the default template configuration
+file ETCDIR/ldaptemplates.conf.
+.LP
+.B ldap_vals2text
+produces a text representation of a single set of LDAP attribute values.  The
+.I ld,
+.I buf,
+.I writeproc,
+.I writeparm,
+.I eol,
+and
+.I rdncount
+parameters are the same as the like-named parameters for
+.B ldap_entry2text.
+.I vals
+is a NULL-terminated list of values, usually obtained by a call to
+.B ldap_get_values.
+.I label
+is a string shown next to the values (usually a friendly form of an
+LDAP attribute name).
+.I labelwidth
+specifies the label margin, which is the number of blank spaces displayed
+to the left of the values.  If zero is passed, a default label width is
+used.
+.I syntaxid
+is a display template attribute syntax identifier (see ldap_disptmpl(3)
+for a list of the pre-defined 
+.B LDAP_SYN_...
+values).
+.LP
+.B ldap_entry2html
+produces an HTML representation of 
+.I entry.
+It behaves exactly like ldap_entry2text(3), except for the formatted output
+and the addition of two parameters.
+.I urlprefix
+is the starting text to use when constructing an LDAP URL.  The default is
+the string
+.I ldap:///
+The second additional parameter,
+.I base,
+the search base to use when executing search actions.  If it is NULL, search
+action template items are ignored.
+.LP
+.B ldap_entry2html_search
+behaves exactly like ldap_entry2text_search(3), except HTML output is produced
+and one additional parameter is required.
+.I urlprefix
+is the starting text to use when constructing an LDAP URL.  The default is
+the string
+.I ldap:///
+.LP
+.B ldap_vals2html
+behaves exactly like ldap_vals2text, except HTML output is produced
+and one additional parameter is required.
+.I urlprefix
+is the starting text to use when constructing an LDAP URL.  The default is
+the string
+.I ldap:///
+.SH ERRORS
+These routines all return an LDAP error code (LDAP_SUCCESS is returned
+if no error occurs).  See ldap_error(3) for details. The
+.I ld_errno
+field of the
+.I ld
+parameter is also set to indicate the error.
+.SH FILES
+ETCDIR/ldaptemplates.conf
+.SH SEE ALSO
+.BR ldap (3),
+.BR ldap_disptmpl (3),
+.BR ldaptemplates.conf (5)
diff --git a/doc/man/man3/ldap_entry2text.3.links b/doc/man/man3/ldap_entry2text.3.links
new file mode 100644 (file)
index 0000000..572a8f1
--- /dev/null
@@ -0,0 +1,5 @@
+ldap_entry2text_search.3
+ldap_vals2text.3
+ldap_entry2html.3
+ldap_entry2html_search.3
+ldap_vals2html.3
diff --git a/doc/man/man3/ldap_error.3 b/doc/man/man3/ldap_error.3
new file mode 100644 (file)
index 0000000..c517b7e
--- /dev/null
@@ -0,0 +1,219 @@
+.TH LDAP_ERROR 3  "15 November 1994" "U-M LDAP LDVERSION"
+.SH NAME
+ldap_perror, ld_errno, ldap_result2error, ldap_errlist, ldap_err2string \- LDAP protocol error handling routines
+.SH SYNOPSIS
+.nf
+.ft B
+#include <lber.h>
+#include <ldap.h>
+.LP
+.ft B
+struct ldaperror {
+    int e_code;
+    char *e_reason;
+};
+.LP
+.ft B
+struct ldaperror ldap_errlist[];
+.LP
+.ft B
+char *ldap_err2string(err)
+.ft
+int err;
+.LP
+.ft B
+void ldap_perror(ld, s)
+.ft
+LDAP *ld;
+char *s;
+.LP
+.ft B
+int ldap_result2error(ld, res, freeit)
+.ft
+LDAP *ld;
+LDAPMessage *res;
+int freeit;
+.SH DESCRIPTION
+These routines provide interpretation of the various error codes
+returned by the LDAP protocol and LDAP library routines, and assigned
+to the
+.I ld_errno
+field in the \fIld\fP structure.
+.LP
+The
+.B ldap_result2error()
+routine takes \fIres\fP, a result as produced by
+.BR ldap_result (3)
+or
+.BR ldap_search_s (3),
+and returns
+the corresponding error code.  Possible error codes are listed
+below.  If the \fIfreeit\fP parameter is non zero it indicates that the
+\fIres\fP parameter should be freed by a call to
+.BR ldap_msgfree (3)
+after the error code has been extracted.  The
+.B ld_errno
+field in \fIld\fP is set and returned.
+.LP
+The returned value can be passed to
+.B ldap_err2string()
+or looked up in
+.B ldap_errlist[]
+to get a text description of the message.  The string
+returned from
+.B ldap_err2string()
+is a pointer to a static area that
+should not be modified.  The last element in the
+.B ldap_errlist[]
+array is signaled by an error code of -1.
+.LP
+The
+.B ldap_perror()
+routine can be called to print an indication of
+the error on standard error, similar to the way
+.BR perror (3)
+works.
+.SH ERRORS
+The possible values for an ldap error code are:
+.LP
+.TP 20
+.SM LDAP_SUCCESS
+The request was successful.
+.TP
+.SM LDAP_OPERATIONS_ERROR
+An operations error occurred.
+.TP
+.SM LDAP_PROTOCOL_ERROR
+A protocol violation was detected.
+.TP
+.SM LDAP_TIMELIMIT_EXCEEDED
+An LDAP time limit was exceeded.
+.TP
+.SM LDAP_SIZELIMIT_EXCEEDED
+An LDAP size limit was exceeded.
+.TP
+.SM LDAP_COMPARE_FALSE
+A compare operation returned false.
+.TP
+.SM LDAP_COMPARE_TRUE
+A compare operation returned true.
+.TP
+.SM LDAP_STRONG_AUTH_NOT_SUPPORTED
+The LDAP server does not support strong authentication.
+.TP
+.SM LDAP_STRONG_AUTH_REQUIRED
+Strong authentication is required for the operation.
+.TP
+.SM LDAP_PARTIAL_RESULTS
+Partial results only returned.
+.TP
+.SM LDAP_NO_SUCH_ATTRIBUTE
+The attribute type specified does not exist in the entry.
+.TP
+.SM LDAP_UNDEFINED_TYPE
+The attribute type specified is invalid.
+.TP
+.SM LDAP_INAPPROPRIATE_MATCHING
+Filter type not supported for the specified attribute.
+.TP
+.SM LDAP_CONSTRAINT_VIOLATION
+An attribute value specified violates some constraint (e.g., a postalAddress
+has too many lines, or a line that is too long).
+.TP
+.SM LDAP_TYPE_OR_VALUE_EXISTS
+An attribute type or attribute value specified already exists in the entry.
+.TP
+.SM LDAP_INVALID_SYNTAX
+An invalid attribute value was specified.
+.TP
+.SM LDAP_NO_SUCH_OBJECT
+The specified object does not exist in The Directory.
+.TP
+.SM LDAP_ALIAS_PROBLEM
+An alias in The Directory points to a nonexistent entry.
+.TP
+.SM LDAP_INVALID_DN_SYNTAX
+A syntactically invalid DN was specified.
+.TP
+.SM LDAP_IS_LEAF
+The object specified is a leaf.
+.TP
+.SM LDAP_ALIAS_DEREF_PROBLEM
+A problem was encountered when dereferencing an alias.
+.TP
+.SM LDAP_INAPPROPRIATE_AUTH
+Inappropriate authentication was specified (e.g., LDAP_AUTH_SIMPLE was
+specified and the entry does not have a userPassword attribute).
+.TP
+.SM LDAP_INVALID_CREDENTIALS
+Invalid credentials were presented (e.g., the wrong password).
+.TP
+.SM LDAP_INSUFFICIENT_ACCESS
+The user has insufficient access to perform the operation.
+.TP
+.SM LDAP_BUSY
+The DSA is busy.
+.TP
+.SM LDAP_UNAVAILABLE
+The DSA is unavailable.
+.TP
+.SM LDAP_UNWILLING_TO_PERFORM
+The DSA is unwilling to perform the operation.
+.TP
+.SM LDAP_LOOP_DETECT
+A loop was detected.
+.TP
+.SM LDAP_NAMING_VIOLATION
+A naming violation occurred.
+.TP
+.SM LDAP_OBJECT_CLASS_VIOLATION
+An object class violation occurred (e.g., a "must" attribute was missing
+from the entry).
+.TP
+.SM LDAP_NOT_ALLOWED_ON_NONLEAF
+The operation is not allowed on a nonleaf object.
+.TP
+.SM LDAP_NOT_ALLOWED_ON_RDN
+The operation is not allowed on an RDN.
+.TP
+.SM LDAP_ALREADY_EXISTS
+The entry already exists.
+.TP
+.SM LDAP_NO_OBJECT_CLASS_MODS
+Object class modifications are not allowed.
+.TP
+.SM LDAP_OTHER
+An unknown error occurred.
+.TP
+.SM LDAP_SERVER_DOWN
+The LDAP library can't contact the LDAP server.
+.TP
+.SM LDAP_LOCAL_ERROR
+Some local error occurred.  This is usually a failed malloc.
+.TP
+.SM LDAP_ENCODING_ERROR
+An error was encountered encoding parameters to send to the LDAP server.
+.TP
+.SM LDAP_DECODING_ERROR
+An error was encountered decoding a result from the LDAP server.
+.TP
+.SM LDAP_TIMEOUT
+A timelimit was exceeded while waiting for a result.
+.TP
+.SM LDAP_AUTH_UNKNOWN
+The authentication method specified to ldap_bind() is not known.
+.TP
+.SM LDAP_FILTER_ERROR
+An invalid filter was supplied to ldap_search() (e.g., unbalanced
+parentheses).
+.TP
+.SM LDAP_PARAM_ERROR
+An ldap routine was called with a bad parameter (e.g., a NULL ld
+pointer, etc.).
+.TP
+.SM LDAP_NO_MEMORY
+An memory allocation (e.g., malloc(3)) call failed in an ldap
+library routine.
+.SH SEE ALSO
+.BR ldap(3),
+.BR perror(3)
diff --git a/doc/man/man3/ldap_error.3.links b/doc/man/man3/ldap_error.3.links
new file mode 100644 (file)
index 0000000..841370d
--- /dev/null
@@ -0,0 +1,5 @@
+ldap_perror.3
+ld_errno.3
+ldap_result2error.3
+ldap_errlist.3
+ldap_err2string.3
diff --git a/doc/man/man3/ldap_first_attribute.3 b/doc/man/man3/ldap_first_attribute.3
new file mode 100644 (file)
index 0000000..452a928
--- /dev/null
@@ -0,0 +1,79 @@
+.TH LDAP_FIRST_ATTRIBUTE 3  "25 November 1994" "U-M LDAP LDVERSION"
+.SH NAME
+ldap_first_attribute, ldap_next_attribute \- step through LDAP entry attributes
+.SH SYNOPSIS
+.nf
+.ft B
+#include <lber.h>
+#include <ldap.h>
+.LP
+.ft B
+char *ldap_first_attribute(ld, entry, berptr)
+.ft
+LDAP *ld;
+LDAPMessage *entry;
+BerElement **berptr;
+.LP
+.ft B
+char *ldap_next_attribute(ld, entry, ber)
+.ft
+LDAP *ld;
+LDAPMessage *entry;
+BerElement *ber;
+.SH DESCRIPTION
+The
+.B ldap_first_attribute()
+and
+.B ldap_next_attribute()
+routines are used
+to step through the attributes in an LDAP entry.
+.B ldap_first_attribute()
+takes an \fIentry\fP as returned by
+.BR ldap_first_entry (3)
+or
+.BR ldap_next_entry (3)
+and returns a pointer to a per-connection buffer
+containing the first attribute type in the entry.  The return value
+should be treated as if it is a pointer to a static area (i.e.,
+.BR strdup (3)
+it if you want to save it).
+.LP
+It also returns, in \fIberptr\fP, a pointer to a BerElement it has
+allocated to keep track of its current position.  This pointer should
+be passed to subsequent calls to
+.B ldap_next_attribute()
+and is used used
+to effectively step through the entry's attributes.  This pointer
+is freed by
+.B ldap_next_attribute()
+when there are no more attributes (that
+is, when
+.B ldap_next_attribute()
+returns NULL).  Otherwise, the caller is
+responsible for freeing the BerElement pointed to by \fIberptr\fP when
+it is no longer needed by calling
+.BR ber_free (3).
+When calling
+.BR ber_free (3)
+in this instance, be sure the second argument is 0.
+.LP
+The attribute names returned are suitable for inclusion in a call
+to
+.BR ldap_get_values (3)
+to retrieve the attribute's values.
+.SH ERRORS
+If an error occurs, NULL is returned and the ld_errno field in the
+\fIld\fP parameter is set to indicate the error.  See
+.BR ldap_error (3)
+for a description of possible error codes.
+.SH NOTES
+The
+.B ldap_first_attribute()
+routine mallocs memory that may need to
+be freed by the caller via
+.BR ber_free (3).
+.SH SEE ALSO
+.BR ldap(3),
+.BR ldap_first_entry(3),
+.BR ldap_get_values(3),
+.BR ldap_error(3)
diff --git a/doc/man/man3/ldap_first_attribute.3.links b/doc/man/man3/ldap_first_attribute.3.links
new file mode 100644 (file)
index 0000000..739fe3a
--- /dev/null
@@ -0,0 +1 @@
+ldap_next_attribute.3
diff --git a/doc/man/man3/ldap_first_entry.3 b/doc/man/man3/ldap_first_entry.3
new file mode 100644 (file)
index 0000000..368ad0f
--- /dev/null
@@ -0,0 +1,83 @@
+.TH LDAP_FIRST_ENTRY 3  "25 November 1994" "U-M LDAP LDVERSION"
+.SH NAME
+ldap_first_entry, ldap_next_entry, ldap_count_entries \- LDAP result entry parsing and counting routines
+.SH SYNOPSIS
+.nf
+.ft B
+#include <lber.h>
+#include <ldap.h>
+.LP
+.ft B
+ldap_count_entries(ld, result)
+.ft
+LDAP *ld;
+LDAPMessage *result;
+.LP
+.ft B
+LDAPMessage *ldap_first_entry(ld, result)
+.ft
+LDAP *ld;
+LDAPMessage *result;
+.LP
+.ft B
+LDAPMessage *ldap_next_entry(ld, entry)
+.ft
+LDAP *ld;
+LDAPMessage *entry;
+.SH DESCRIPTION
+.LP
+These routines are used to parse results received from
+.BR ldap_result (3)
+or the synchronous LDAP search operation routines
+.BR ldap_search_s (3)
+and
+.BR ldap_search_st (3).
+.LP
+The
+.B ldap_first_entry()
+routine is used to retrieve the first entry in a chain
+of search results.  It takes the \fIresult\fP as returned by a call to
+.BR ldap_result (3)
+or
+.BR ldap_search_s (3)
+or
+.BR ldap_search_st (3)
+and returns a pointer to the first entry in the result.
+.LP
+This pointer should be supplied on a subsequent call to
+.B ldap_next_entry()
+to get the next entry, the result of which should be
+supplied to the next call to
+.BR ldap_next_entry() ,
+etc.
+.B ldap_next_entry()
+will return NULL when there are no more entries.  The entries returned
+from these calls are used in calls to the routines described in
+.BR ldap_get_dn (3),
+.BR ldap_first_attribute (3),
+.BR ldap_get_values (3),
+etc.
+.LP
+A count of the number of entries in the search result can be obtained
+by calling
+.BR ldap_count_entries() .
+.SH ERRORS
+If an error occurs in
+.B ldap_first_entry()
+or
+.BR ldap_next_entry() ,
+NULL is returned and the ld_errno field in the \fIld\fP parameter
+is set to indicate the error.  If an error occurs in
+.BR ldap_count_entries() ,
+-1 is returned, and
+.B ld_errno
+is set appropriately.  See
+.BR ldap_error (3)
+for a description of possible error codes.
+.SH SEE ALSO
+.BR ldap(3),
+.BR ldap_result(3),
+.BR ldap_search(3),
+.BR ldap_first_attribute(3),
+.BR ldap_get_values(3),
+.BR ldap_get_dn(3)
diff --git a/doc/man/man3/ldap_first_entry.3.links b/doc/man/man3/ldap_first_entry.3.links
new file mode 100644 (file)
index 0000000..781590b
--- /dev/null
@@ -0,0 +1,2 @@
+ldap_next_entry.3
+ldap_count_entries.3
diff --git a/doc/man/man3/ldap_friendly.3 b/doc/man/man3/ldap_friendly.3
new file mode 100644 (file)
index 0000000..1cf254b
--- /dev/null
@@ -0,0 +1,68 @@
+.TH LDAP_FRIENDLY 3  "11 October 1993" "U-M LDAP LDVERSION"
+.SH NAME
+ldap_friendly_name, ldap_free_friendlymap \- LDAP unfriendly to friendly name mapping routine
+.SH SYNOPSIS
+.nf
+.ft B
+#include <lber.h>
+#include <ldap.h>
+.LP
+.ft B
+typedef struct friendly {
+        char *f_unfriendly;
+        char *f_friendly;
+} FriendlyMap;
+.LP
+.ft B
+char *ldap_friendly_name(filename, name, map)
+.ft
+char *filename;
+char *name;
+FriendlyMap **map;
+.LP
+.ft B
+void ldap_free_friendlymap(map)
+.ft
+FriendlyMap **map;
+.SH DESCRIPTION
+This routine is used to map one set of strings to another.  Typically,
+this is done for country names, to map from the two-letter country
+codes to longer more readable names.  The mechanism is general enough
+to be used with other things, though.
+.LP
+\fIfilename\fP is the name of a file containing the unfriendly to
+friendly mapping, \fIname\fP is the unfriendly name to map to a friendly
+name, and \fImap\fP is a result-parameter that should be set to NULL
+on the first call.  It is then used to hold the mapping in core so that
+the file need not be read on subsequent calls.
+.LP
+For example:
+.LP
+.nf
+.ft tt
+        FriendlyMap *map = NULL;
+
+        printf( "unfriendly %s => friendly %s\\n", name,
+            ldap_friendly_name( "ETCDIR/ldapfriendly", name, &map ) );
+.ft
+.fi
+.LP
+The mapping file should contain lines like this: unfriendlyname\\tfriendlyname.
+Lines that begin with a '#' character are comments and are ignored.
+.LP
+The
+.B ldap_free_friendlymap()
+call is used to free structures allocated by
+.B ldap_friendly_name()
+when no more calls to
+.B ldap_friendly_name()
+are to be made.
+.SH ERRORS
+NULL is returned by
+.B ldap_friendly_name()
+if there is an error opening \fIfilename\fP, or if the file has a bad
+format, or if the \fImap\fP parameter is NULL.
+.SH FILES
+ETCDIR/ldapfriendly.conf
+.SH SEE ALSO
+.BR ldap (3)
diff --git a/doc/man/man3/ldap_friendly.3.links b/doc/man/man3/ldap_friendly.3.links
new file mode 100644 (file)
index 0000000..5b17231
--- /dev/null
@@ -0,0 +1,2 @@
+ldap_friendly_name.3
+ldap_free_friendlymap.3
diff --git a/doc/man/man3/ldap_get_dn.3 b/doc/man/man3/ldap_get_dn.3
new file mode 100644 (file)
index 0000000..55530fc
--- /dev/null
@@ -0,0 +1,116 @@
+.TH LDAP_GET_DN 3  "16 June 1995" "U-M LDAP LDVERSION"
+.SH NAME
+ldap_get_dn, ldap_explode_dn, ldap_dn2ufn, ldap_is_dns_dn, ldap_explode_dns \- LDAP DN handling routines
+.SH SYNOPSIS
+.nf
+.ft B
+#include <lber.h>
+#include <ldap.h>
+.LP
+.ft B
+char *ldap_get_dn(ld, entry)
+.ft
+LDAP *ld;
+LDAPMessage *entry;
+.LP
+.ft B
+char **ldap_explode_dn(dn, notypes)
+.ft
+char *dn;
+int notypes;
+.LP
+.ft B
+char *ldap_dn2ufn(dn)
+.ft
+char *dn;
+.LP
+.ft B
+int ldap_is_dns_dn(dn)
+.ft
+char *dn;
+.LP
+.ft B
+char **ldap_explode_dns(dn)
+.ft
+char *dn;
+.SH DESCRIPTION
+These routines allow LDAP entry names (Distinguished Names, or DNs)
+to be obtained, parsed, converted to a user-friendly form, and tested.
+A DN has the form described in RFC 1779 "A String Representation of
+Distinguished Names", unless it is an experimental DNS-style DN
+which takes the form of an RFC 822 mail address.
+.LP
+The
+.B ldap_get_dn()
+routine takes an \fIentry\fP as returned by
+.BR ldap_first_entry (3)
+or
+.BR ldap_next_entry (3)
+and returns a copy of
+the entry's DN.  Space for the DN will have been obtained via
+.BR malloc (3),
+and should be freed by the caller by a call to
+.BR free (3).
+.LP
+The
+.B ldap_explode_dn()
+routine takes a DN as returned by
+.B ldap_get_dn()
+and breaks it up into its component parts.  Each part is known as a
+Relative Distinguished Name, or RDN.
+.B ldap_explode_dn()
+returns a
+NULL-terminated array, each component of which contains an RDN from the
+DN.  The \fInotypes\fP parameter is used to request that only the RDN
+values be returned, not their types.  For example, the DN "cn=Bob,
+c=US" would return as either { "cn=Bob", "c=US", NULL } or { "Bob",
+"US", NULL }, depending on whether notypes was 0 or 1, respectively.
+The result can be freed by calling
+.BR ldap_value_free (3).
+.LP
+.B ldap_dn2ufn()
+is used to turn a DN as returned by
+.B ldap_get_dn()
+into a more user-friendly form, stripping off type names.  See
+RFC 1781 "Using the Directory to Achieve User Friendly Naming"
+for more details on the UFN format.  The space for the UFN returned
+is obtained by a call to
+.BR malloc (3),
+and the user is responsible for freeing it via a call to
+.BR free (3).
+.LP
+.B ldap_is_dns_dn()
+returns non-zero if the dn string is an experimental
+DNS-style DN (generally in the form of an RFC 822 e-mail address).  It
+returns zero if the dn appears to be an RFC 1779 format DN.
+.LP
+.B ldap_explode_dns()
+takes a DNS-style DN and breaks it up into its
+component parts.
+.B ldap_explode_dns()
+returns a NULL-terminated array.
+For example, the DN "mcs.umich.edu" will return { "mcs", "umich", "edu",
+NULL }.  The result can be freed by calling
+.BR ldap_value_free (3).
+.SH ERRORS
+If an error occurs in
+.BR ldap_get_dn() ,
+NULL is returned and the
+.B ld_errno
+field in the \fIld\fP parameter is set to indicate the error.  See
+.BR ldap_error (3)
+for a description of possible error codes.
+.BR ldap_explode_dn() ,
+.B ldap_explode_dns()
+and
+.B ldap_dn2ufn()
+will return NULL with
+.BR errno (3)
+set appropriately in case of trouble.
+.SH NOTES
+These routines malloc memory that the caller must free.
+.SH SEE ALSO
+.BR ldap(3),
+.BR ldap_first_entry(3),
+.BR ldap_error(3),
+.BR ldap_value_free(3)
diff --git a/doc/man/man3/ldap_get_dn.3.links b/doc/man/man3/ldap_get_dn.3.links
new file mode 100644 (file)
index 0000000..f713c4b
--- /dev/null
@@ -0,0 +1,4 @@
+ldap_explode_dn.3
+ldap_explode_dns.3
+ldap_dn2ufn.3
+ldap_is_dns_dn.3
diff --git a/doc/man/man3/ldap_get_values.3 b/doc/man/man3/ldap_get_values.3
new file mode 100644 (file)
index 0000000..ac0dcdb
--- /dev/null
@@ -0,0 +1,99 @@
+.TH LDAP_GET_VALUES 3  "25 November 1994" "U-M LDAP LDVERSION"
+.SH NAME
+ldap_get_values, ldap_get_values_len, ldap_count_values \- LDAP attribute value handling routines
+.SH SYNOPSIS
+.nf
+.ft B
+#include <lber.h>
+#include <ldap.h>
+
+typedef struct berval {
+    unsigned long bv_len;
+    char *bv_val;
+};
+.LP
+.ft B
+char **ldap_get_values(ld, entry, attr)
+.ft
+LDAP *ld;
+LDAPMessage *entry;
+char *attr
+.LP
+.ft B
+struct berval **ldap_get_values_len(ld, entry, attr)
+.ft
+LDAP *ld;
+LDAPMessage *entry;
+char *attr
+.LP
+.ft B
+ldap_count_values(vals)
+.ft
+char **vals;
+.LP
+.ft B
+ldap_count_values_len(vals)
+.ft
+struct berval **vals;
+.LP
+.ft B
+ldap_value_free(vals)
+.ft
+char **vals;
+.LP
+.ft B
+ldap_value_free_len(vals)
+.ft
+struct berval **vals;
+.SH DESCRIPTION
+These routines are used to retrieve and manipulate attribute values
+from an LDAP entry as returned by
+.BR ldap_first_entry (3)
+or
+.BR ldap_next_entry (3).
+.B ldap_get_values()
+takes the \fIentry\fP and the attribute \fIattr\fP
+whose values are desired and returns a NULL-terminated array of the
+attribute's values.  \fIattr\fP may be an attribute type as returned
+from
+.BR ldap_first_attribute (3)
+or
+.BR ldap_next_attribute (3),
+or if the attribute type is known it can simply be given.
+.LP
+The number of values in the array can be counted by calling
+.BR ldap_count_values() .
+The array of values returned can be freed by calling
+.BR ldap_value_free() .
+.LP
+If the attribute values are binary in nature, and thus not suitable
+to be returned as an array of char *'s, the
+.B ldap_get_values_len()
+routine can be used instead.  It takes the same parameters as
+.BR ldap_get_values() ,
+but returns a NULL-terminated array of pointers
+to berval structures, each containing the length of and a pointer
+to a value.
+.LP
+The number of values in the array can be counted by calling
+.BR ldap_count_values_len() .
+The array of values returned can be freed by calling
+.BR ldap_value_free_len() .
+.SH ERRORS
+If an error occurs in
+.B ldap_get_values()
+or
+.BR ldap_get_values_len() ,
+NULL is returned and the
+.B ld_errno
+field in the \fIld\fP parameter is set to
+indicate the error.  See
+.BR ldap_error (3)
+for a description of possible error codes.
+.SH NOTES
+These routines malloc memory that the caller must free.
+.SH SEE ALSO
+.BR ldap(3),
+.BR ldap_first_entry(3),
+.BR ldap_first_attribute(3),
+.BR ldap_error(3)
diff --git a/doc/man/man3/ldap_get_values.3.links b/doc/man/man3/ldap_get_values.3.links
new file mode 100644 (file)
index 0000000..ac2b454
--- /dev/null
@@ -0,0 +1,5 @@
+ldap_get_values_len.3
+ldap_value_free.3
+ldap_value_free_len.3
+ldap_count_values.3
+ldap_count_values_len.3
diff --git a/doc/man/man3/ldap_getfilter.3 b/doc/man/man3/ldap_getfilter.3
new file mode 100644 (file)
index 0000000..67a8df3
--- /dev/null
@@ -0,0 +1,193 @@
+.TH LDAP_GETFILTER 3  "28 November 1994" "U-M LDAP LDVERSION"
+.SH NAME
+ldap_init_getfilter, ldap_init_getfilter_buf, ldap_getfilter_free,
+ldap_getfirstfilter, ldap_getnextfilter, ldap_build_filter \- LDAP filter generating routines
+.SH SYNOPSIS
+.nf
+.ft B
+#include <lber.h>
+#include <ldap.h>
+.ft
+.fi
+.LP
+.nf
+.ft B
+#define LDAP_FILT_MAXSIZ       1024
+
+typedef struct ldap_filt_info {
+        char                    *lfi_filter;
+        char                    *lfi_desc;
+        int                     lfi_scope;
+        int                     lfi_isexact;
+        struct ldap_filt_info   *lfi_next;
+} LDAPFiltInfo;
+
+typedef struct ldap_filt_list {
+    char                        *lfl_tag;
+    char                        *lfl_pattern;
+    char                        *lfl_delims;
+    LDAPFiltInfo                *lfl_ilist;
+    struct ldap_filt_list       *lfl_next;
+} LDAPFiltList;
+
+typedef struct ldap_filt_desc {
+        LDAPFiltList            *lfd_filtlist;
+        LDAPFiltInfo            *lfd_curfip;
+        LDAPFiltInfo            lfd_retfi;
+        char                    lfd_filter[ LDAP_FILT_MAXSIZ ];
+        char                    *lfd_curval;
+        char                    *lfd_curvalcopy;
+        char                    **lfd_curvalwords;
+        char                    *lfd_filtprefix;
+        char                    *lfd_filtsuffix;
+} LDAPFiltDesc;
+.ft
+.fi
+.LP
+.ft B
+LDAPFiltDesc *ldap_init_getfilter( file )
+.ft
+char *file;
+.LP
+.nf
+.ft B
+LDAPFiltDesc *ldap_init_getfilter_buf( buf, buflen )
+.ft
+char *buf;
+long buflen;
+.LP
+.ft B
+ldap_getfilter_free( lfdp )
+.ft
+LDAPFiltDesc *lfdp;
+.LP
+.nf
+.ft B
+LDAPFiltInfo *ldap_getfirstfilter(lfdp, tagpat, value)
+.ft
+LDAPFiltDesc *lfdp;
+char *tagpat;
+char *value;
+.LP
+.nf
+.ft B
+LDAPFiltInfo *ldap_getnextfilter(lfdp)
+.ft
+LDAPFiltDesc *lfdp;
+.LP
+.ft B
+void ldap_setfilteraffixes(lfdp, prefix, suffix)
+.ft
+LDAPFiltDesc *lfdp;
+char *prefix;
+char *suffix;
+.LP
+.ft B
+void ldap_build_filter( buf, buflen, pattern, prefix, suffix,
+       attr, value, valwords )
+.ft
+char *buf;
+unsigned long buflen;
+char *pattern;
+char *prefix;
+char *suffix;
+char *attr;
+char *value;
+char **valwords;
+.SH DESCRIPTION
+.LP
+These routines are used to generate filters to be used in
+ldap_search(3) or ldap_search_s(3).  Either ldap_init_getfilter or
+ldap_init_getfilter_buf must be called prior to calling any of
+the other routines except ldap_build_filter.
+.LP
+ldap_init_getfilter()
+takes a file name as its only argument.  The contents of the file must
+be a valid LDAP filter configuration file (see ldapfilter.conf(5)).  If
+the file is successfully read, a pointer to an LDAPFiltDesc is
+returned.  This is an opaque object that is passed in subsequent get
+filter calls.
+.LP
+ldap_init_getfilter_buf()
+reads from
+.I buf
+(whose length is
+.I buflen)
+the LDAP filter configuration information.
+.I buf
+must point to the contents of a valid LDAP filter configuration file
+(see ldapfilter.conf(5)).  If the filter configuration information is
+successfully read, a pointer to an LDAPFiltDesc is returned.  This is
+an opaque object that is passed in subsequent get filter calls.
+.LP
+ldap_getfilter_free()
+deallocates the memory consumed by ldap_init_getfilter.  Once it is
+called, the LDAPFiltDesc is no longer valid and cannot be used again.
+.LP
+ldap_getfirstfilter()
+retrieves the first filter that is appropriate for
+.I value.
+Only filter sets that have tags that match the regular expession
+.I tagpat
+are considered.  ldap_getfirstfilter returns a pointer to an
+LDAPFiltInfo structure, which contains a filter with
+.I value
+inserted as appropriate in lfi_filter, a text match description in
+lfi_desc, lfi_scope set to indicate the search scope, and lfi_isexact
+set to indicate the type of filter.  NULL is returned
+if no matching filters are found.  lfi_scope will be one of
+.B LDAP_SCOPE_BASE,
+.B LDAP_SCOPE_ONELEVEL,
+or
+.B LDAP_SCOPE_SUBTREE.
+lfi_isexact
+will be zero if the filter has any '~' or '*' characters in it and
+non-zero otherwise.
+.LP
+ldap_getnextfilter()
+retrieves the next appropriate filter in the filter set that was
+determined when ldap_getfirstfilter was called.  It returns NULL when
+the list has been exhausted.
+.LP
+ldap_setfilteraffixes()
+sets a
+.I prefix
+to be prepended and a
+.I suffix
+to be appended to all filters returned in the future.
+.LP
+ldap_build_filter()
+constructs an LDAP search filter in
+.I buf.
+.I buflen
+is the size, in bytes, of the largest filter
+.I buf
+can hold.  A pattern for the desired filter is passed in
+.I pattern.
+Where the string %a appears in the pattern it is replaced with
+.I attr.
+.I prefix
+is pre-pended to the resulting filter, and
+.I suffix
+is appended.  Either can be NULL (in which case they are not used).
+.I value
+and
+.I valwords
+are used when the string %v appears in
+.I pattern.
+See ldapfilter.conf(5) for a description of how %v is handled.
+.LP
+.SH ERRORS
+NULL is returned by ldap_init_getfilter if there is an error reading
+.I file.
+NULL is returned by ldap_getfirstfilter and ldap_getnextfilter when there
+are no more appropriate filters to return.
+.SH NOTES
+.LP
+The return values for all of these functions are declared in the
+<ldap.h> header file.  Some routines may malloc memory.
+.SH FILES
+ETCDIR/ldapfilter.conf
+.SH SEE ALSO
+.BR ldap (3),
+.BR ldapfilter.conf (5)
diff --git a/doc/man/man3/ldap_getfilter.3.links b/doc/man/man3/ldap_getfilter.3.links
new file mode 100644 (file)
index 0000000..c90ca62
--- /dev/null
@@ -0,0 +1,7 @@
+ldap_init_getfilter.3
+ldap_init_getfilter_buf.3
+ldap_getfilter_free.3
+ldap_getfirstfilter.3
+ldap_getnextfilter.3
+ldap_setfilteraffixes.3
+ldap_build_filter.3
diff --git a/doc/man/man3/ldap_modify.3 b/doc/man/man3/ldap_modify.3
new file mode 100644 (file)
index 0000000..baf71a3
--- /dev/null
@@ -0,0 +1,113 @@
+.TH LDAP_MODIFY 3  "15 November 1994" "U-M LDAP LDVERSION"
+.SH NAME
+ldap_modify, ldap_modify_s \- Perform an LDAP modify operation
+.SH SYNOPSIS
+.nf
+.ft B
+#include <lber.h>
+#include <ldap.h>
+.LP
+.ft B
+.nf
+int ldap_modify(ld, dn, mods)
+.ft
+LDAP *ld;
+char *dn;
+LDAPMod *mods[];
+.LP
+.ft B
+.nf
+int ldap_modify_s(ld, dn, mods)
+.ft
+LDAP *ld;
+char *dn;
+LDAPMod *mods[];
+.LP
+.ft B
+.nf
+void ldap_mods_free( mods, freemods )
+.ft
+LDAPMod **mods;
+int freemods;
+.SH DESCRIPTION
+The routine
+.B ldap_modify_s()
+is used to perform an LDAP modify operation.
+\fIdn\fP is the DN of the entry to modify, and \fImods\fP is a
+null-terminated array of modifications to make to the entry.  Each element
+of the \fImods\fP array is a pointer to an LDAPMod structure, which is
+defined below.
+.LP
+.nf
+.ft B
+       typedef struct ldapmod {
+           int mod_op;
+           char *mod_type;
+           union {
+               char **modv_strvals;
+               struct berval **modv_bvals;
+           } mod_vals;
+           struct ldapmod *mod_next;
+       } LDAPMod;
+       #define mod_values mod_vals.modv_strvals
+       #define mod_bvalues mod_vals.modv_bvals
+.ft
+.fi
+.LP
+The \fImod_op\fP field is used to specify the type of modification to
+perform and should be one of LDAP_MOD_ADD, LDAP_MOD_DELETE, or
+LDAP_MOD_REPLACE.  The \fImod_type\fP and \fImod_values\fP fields
+specify the attribute type to modify and a null-terminated array of
+values to add, delete, or replace respectively.  The \fImod_next\fP
+field is used only by the LDAP server and may be ignored by the
+client.
+.LP
+If you need to specify a non-string value (e.g., to add a
+photo or audio attribute value), you should set \fImod_op\fP to the
+logical OR of the operation as above (e.g., LDAP_MOD_REPLACE)
+and the constant LDAP_MOD_BVALUES.  In this case, \fImod_bvalues\fP
+should be used instead of \fImod_values\fP, and it should point to
+a null-terminated array of struct bervals, as defined in <lber.h>.
+.LP
+For LDAP_MOD_ADD modifications, the given values are added to the
+entry, creating the attribute if necessary.  For LDAP_MOD_DELETE
+modifications, the given values are deleted from the entry, removing
+the attribute if no values remain.  If the entire attribute is to be deleted,
+the \fImod_values\fP field should be set to NULL.  For LDAP_MOD_REPLACE
+modifications, the attribute will have the listed values after the
+modification, having been created if necessary.  All modifications are
+performed in the order in which they are listed.
+.LP
+.B
+ldap_modify_s()
+returns the LDAP error code resulting from the
+modify operation.  This code can be interpreted by
+.BR ldap_perror (3)
+and friends.
+.LP
+The
+.B ldap_modify()
+operation works the same way as
+.BR ldap_modify_s() ,
+except that it is asynchronous, returning the message id of the
+request it initiates, or -1 on error.  The result of the operation
+can be obtained by calling
+.BR ldap_result (3).
+.LP
+.B ldap_mods_free()
+can be used to free each element of a NULL-terminated
+array of mod structures.  If \fIfreemods\fP is non-zero, the
+\fImods\fP pointer itself is freed as well.
+.SH ERRORS
+.B ldap_modify_s()
+returns an ldap error code, either LDAP_SUCCESS or
+an error if there was trouble.
+.B ldap_modify()
+returns -1 in case
+of trouble, setting the
+.B ld_errno
+field of \fIld\fP.
+.SH SEE ALSO
+.BR ldap (3),
+.BR ldap_error (3),
+.BR ldap_add (3)
diff --git a/doc/man/man3/ldap_modify.3.links b/doc/man/man3/ldap_modify.3.links
new file mode 100644 (file)
index 0000000..8eebf41
--- /dev/null
@@ -0,0 +1,2 @@
+ldap_modify_s.3
+ldap_mods_free.3
diff --git a/doc/man/man3/ldap_modrdn.3 b/doc/man/man3/ldap_modrdn.3
new file mode 100644 (file)
index 0000000..1b38275
--- /dev/null
@@ -0,0 +1,75 @@
+.TH LDAP_MODRDN 3  "1 December 1994" "U-M LDAP LDVERSION"
+.SH NAME
+ldap_modrdn, ldap_modrdn_s, ldap_modrdn2, ldap_modrdn2_s \- Perform an LDAP modify RDN operation
+.SH SYNOPSIS
+.nf
+.ft B
+#include <lber.h>
+#include <ldap.h>
+.LP
+.ft B
+int ldap_modrdn(ld, dn, newrdn)
+.ft
+LDAP \(**ld;
+char \(**dn, \(**newrdn;
+.LP
+.ft B
+.LP
+.ft B
+int ldap_modrdn_s(ld, dn, newrdn)
+.ft
+LDAP \(**ld;
+char \(**dn, \(**newrdn;
+.LP
+.ft B
+int ldap_modrdn2(ld, dn, newrdn, deleteoldrdn)
+.ft
+LDAP \(**ld;
+char \(**dn, \(**newrdn;
+int deleteoldrdn;
+.LP
+.ft B
+int ldap_modrdn2_s(ld, dn, newrdn, deleteoldrdn)
+.ft
+LDAP \(**ld;
+char \(**dn, \(**newrdn;
+int deleteoldrdn;
+.SH DESCRIPTION
+The
+.B ldap_modrdn()
+and
+.B ldap_modrdn_s()
+routines perform an LDAP modify
+RDN operation.  They both take \fIdn\fP, the DN of the entry whose
+RDN is to be changed, and \fInewrdn\fP, the new RDN to give the entry.
+The old RDN of the entry is never kept as an attribute of the entry.
+.B ldap_modrdn()
+is asynchronous, returning the message id of the operation
+it initiates.
+.B ldap_modrdn_s()
+is synchronous, returning the LDAP error
+code indicating the success or failure of the operation.  Use of
+these routines is deprecated.  Use the versions described below
+instead.
+.LP
+The
+.B ldap_modrdn2()
+and
+.B ldap_modrdn2_s()
+routines also perform an LDAP
+modify RDN operation, taking the same parameters as above.  In addition,
+they both take the \fIdeleteoldrdn\fP parameter which is used as a boolean
+value to indicate whether the old RDN values should be deleted from
+the entry or not.
+.SH ERRORS
+The synchronous (_s) versions of these routines return an LDAP error
+code, either LDAP_SUCCESS or an error if there was trouble.
+The asynchronous versions return -1 in case
+of trouble, setting the
+.B ld_errno
+field of \fIld\fP.  See
+.BR ldap_error (3)
+for more details.
+.SH SEE ALSO
+.BR ldap (3),
+.BR ldap_error (3)
diff --git a/doc/man/man3/ldap_modrdn.3.links b/doc/man/man3/ldap_modrdn.3.links
new file mode 100644 (file)
index 0000000..6760787
--- /dev/null
@@ -0,0 +1,3 @@
+ldap_modrdn_s
+ldap_modrdn2
+ldap_modrdn2_s
diff --git a/doc/man/man3/ldap_open.3 b/doc/man/man3/ldap_open.3
new file mode 100644 (file)
index 0000000..746e665
--- /dev/null
@@ -0,0 +1,113 @@
+.TH LDAP_OPEN 3  "28 March 1996" "U-M LDAP LDVERSION"
+.SH NAME
+ldap_init, ldap_open \- Initialize the LDAP library and open a connection to an LDAP server
+.SH SYNOPSIS
+.nf
+.ft B
+#include <lber.h>
+#include <ldap.h>
+.LP
+.ft B
+LDAP *ldap_open(host, port)
+.ft
+char *host;
+int port;
+.LP
+.ft B
+LDAP *ldap_init(host, port)
+.ft
+char *host;
+int port;
+.SH DESCRIPTION
+.LP
+.B ldap_open()
+opens a connection to an LDAP server and allocates an LDAP
+structure which is used to identify
+the connection and to maintain per-connection information.
+.B ldap_init()
+allocates an LDAP structure but does not open an initial connection.  One
+of these two routines must be called before any operations are attempted.
+.LP
+.B ldap_open()
+takes \fIhost\fP, the hostname on which the LDAP server is
+running, and \fIport\fP, the port number to which to connect.  If the default
+IANA-assigned port of 389 is desired, LDAP_PORT should be specified for
+\fIport\fP.  The \fIhost\fP parameter may contain a blank-separated list
+of hosts to try to connect to, and each host may optionally by of the form
+\fIhost:port\fP.  If present, the \fI:port\fP overrides the \fIport\fP
+parameter to
+.BR ldap_open() .
+Upon successfully making a connection to an
+LDAP server,
+.B ldap_open()
+returns a pointer to an LDAP structure (defined below), which
+should be passed to subsequent calls to
+.BR ldap_bind() ,
+.BR ldap_search() ,
+etc. Certain fields in the LDAP structure can be set to indicate size limit,
+time limit, and how aliases are handled during operations.  See <ldap.h>
+for more details.
+.LP
+.nf
+.ft tt
+       typedef struct ldap {
+               /* ... other stuff you should not mess with ... */
+               char            ld_lberoptions;
+               int             ld_deref;
+       #define LDAP_DEREF_NEVER        0
+       #define LDAP_DEREF_SEARCHING    1
+       #define LDAP_DEREF_FINDING      2
+       #define LDAP_DEREF_ALWAYS       3
+               int             ld_timelimit;
+               int             ld_sizelimit;
+       #define LDAP_NO_LIMIT           0
+               int             ld_errno;
+               char            *ld_error;
+               char            *ld_matched;
+               int             ld_refhoplimit;
+               unsigned long   ld_options;
+       #define LDAP_OPT_REFERRALS      0x00000002      /* set by default */
+       #define LDAP_OPT_RESTART        0x00000004
+               /* ... other stuff you should not mess with ... */
+       } LDAP;
+.ft
+.fi
+.LP
+.B
+ldap_init()
+acts just like
+.BR ldap_open() ,
+but does not open a connection
+to the LDAP server.  The actual connection open will occur when the
+first operation is attempted.  At this time,
+.B ldap_init()
+should only
+be used if the LDAP library is compiled with LDAP_REFERRALS defined.
+.SH ERRORS
+If an error occurs, these routines will return NULL and errno should be
+set appropriately.
+.SH OPTIONS
+Options that affect a particular LDAP instance may be set by modifying
+the \fIld_options\fP field in the LDAP structure.  This field is set
+to \fILDAP_OPT_REFERRALS\fP in
+.B ldap_open() and
+.B ldap_init(),
+which causes the library to automatically follow referrals
+to other servers that may be returned in response to an LDAP operation.
+.LP
+The other supported option is \fILDAP_OPT_RESTART\fP, which if set will
+cause the LDAP library to restart the
+.BR select (2)
+system call when it is interrupted by the system (i.e., errno is set to
+EINTR).  This option is not supported on the Macintosh and under MS-DOS.
+.LP
+An option can be turned off by clearing the appropriate bit in the
+\fIld_options\fP field.
+.SH NOTES
+There are other elements in the LDAP structure that you should not
+change. You should not make any assumptions about the order of elements
+in the LDAP structure.
+.SH SEE ALSO
+.BR ldap (3),
+.BR ldap_bind (3),
+.BR errno (3)
diff --git a/doc/man/man3/ldap_open.3.links b/doc/man/man3/ldap_open.3.links
new file mode 100644 (file)
index 0000000..163bb14
--- /dev/null
@@ -0,0 +1 @@
+ldap_init.3
diff --git a/doc/man/man3/ldap_result.3 b/doc/man/man3/ldap_result.3
new file mode 100644 (file)
index 0000000..306e8be
--- /dev/null
@@ -0,0 +1,106 @@
+.TH LDAP_RESULT 3  "26 November 1994" "U-M LDAP LDVERSION"
+.SH NAME
+ldap_result \- Wait for the result of an LDAP operation
+.SH SYNOPSIS
+.nf
+.ft B
+#include <lber.h>
+#include <ldap.h>
+.LP
+.ft B
+int ldap_result(ld, msgid, all, timeout, result)
+.ft
+LDAP *ld;
+int msgid, all;
+struct timeval *timeout;
+LDAPMessage **result;
+.LP
+.ft B
+int ldap_msgfree(msg)
+.ft
+LDAPMessage *msg;
+.SH DESCRIPTION
+The
+.B ldap_result()
+routine is used to wait for and return the result of
+an operation previously initiated by one of the LDAP asynchronous
+operation routines (e.g.,
+.BR ldap_search (3),
+.BR ldap_modify (3),
+etc.).  Those routines all return -1 in case of error, and an
+invocation identifier upon successful initiation of the operation. The
+invocation identifier is picked by the library and is guaranteed to be
+unique across the LDAP session.  It can be used to request the result
+of a specific operation from
+.B ldap_result()
+through the \fImsgid\fP parameter.
+.LP
+The
+.B ldap_result()
+routine will block or not, depending upon the setting
+of the \fItimeout\fP parameter.
+If timeout is not a NULL pointer,  it  specifies  a  maximum
+interval  to wait for the selection to complete.  If timeout
+is a NULL  pointer,  the  select  blocks  indefinitely.   To
+effect  a  poll,  the  timeout argument should be a non-NULL
+pointer, pointing to a zero-valued timeval structure.  See
+.BR select (2)
+for further details.
+.LP
+If the result of a specific operation is required, \fImsgid\fP should
+be set to the invocation identifier returned when the operation was
+initiated, otherwise LDAP_RES_ANY should be supplied.  The \fIall\fP
+parameter only has meaning for search responses and is used to select
+whether a single entry of the search response should be returned, or
+all results of the search should be returned.
+.LP
+A search response is made up of zero or
+more search entries followed by a search result.  If \fIall\fP is set
+to 0, search entries will be returned one at a time as they come in,
+via separate calls to
+.BR ldap_result() .
+If it's set to 1, the search
+response will only be returned in its entirety, i.e., after all entries
+and the final search result have been received.
+.LP
+Upon success, the type of the result received is returned and the
+\fIresult\fP parameter will contain the result of the operation.  This
+result should be passed to the LDAP parsing routines,
+.BR ldap_first_entry (3)
+and friends, for interpretation.
+.LP
+The possible result types returned are:
+.LP
+.nf
+       #define LDAP_RES_BIND                   0x61L
+       #define LDAP_RES_SEARCH_ENTRY           0x64L
+       #define LDAP_RES_SEARCH_RESULT          0x65L
+       #define LDAP_RES_MODIFY                 0x67L
+       #define LDAP_RES_ADD                    0x69L
+       #define LDAP_RES_DELETE                 0x6bL
+       #define LDAP_RES_MODRDN                 0x6dL
+       #define LDAP_RES_COMPARE                0x6fL
+.fi
+.LP
+The
+.B ldap_msgfree()
+routine is used to free the memory allocated for
+a result by
+.B ldap_result()
+or
+.BR ldap_search_s (3)
+and friends.  It takes
+a pointer to the result to be freed and returns the type of the
+message it freed.
+.SH ERRORS
+.B ldap_result()
+returns -1 if something bad happens, and zero if the
+timeout specified was exceeded.
+.SH NOTES
+This routine mallocs memory for results that it receives.  The memory
+can be freed by calling
+.BR ldap_msgfree .
+.SH SEE ALSO
+.BR ldap (3),
+.BR ldap_search (3),
+.BR select (2)
diff --git a/doc/man/man3/ldap_result.3.links b/doc/man/man3/ldap_result.3.links
new file mode 100644 (file)
index 0000000..ca9f245
--- /dev/null
@@ -0,0 +1 @@
+ldap_msgfree.3
diff --git a/doc/man/man3/ldap_search.3 b/doc/man/man3/ldap_search.3
new file mode 100644 (file)
index 0000000..e1a7022
--- /dev/null
@@ -0,0 +1,116 @@
+.TH LDAP_SEARCH 3  "23 November 1994" "U-M LDAP LDVERSION"
+.SH NAME
+ldap_search, ldap_search_s, ldap_search_st \- Perform an LDAP search operation
+.SH SYNOPSIS
+.nf
+.ft B
+#include <sys/time.h> /* for struct timeval definition */
+#include <lber.h>
+#include <ldap.h>
+.LP
+.ft B
+int ldap_search(ld, base, scope, filter, attrs, attrsonly)
+.ft
+LDAP *ld;
+char *base;
+int scope;
+char *filter, *attrs[];
+int attrsonly;
+.LP
+.ft B
+int ldap_search_s(ld, base, scope, filter, attrs, attrsonly, res)
+.ft
+LDAP *ld;
+char *base;
+int scope;
+char *filter, *attrs[]
+int attrsonly;
+LDAPMessage **res;
+.LP
+.ft B
+int ldap_search_st(ld, base, scope, filter, attrs, attrsonly, timeout, res)
+.ft
+LDAP *ld;
+char *base;
+int scope;
+char *filter, *attrs[]
+int attrsonly;
+struct timeval *timeout;
+LDAPMessage **res;
+.SH DESCRIPTION
+These routines are used to perform LDAP search operations.
+.B ldap_search_s()
+does the search synchronously (i.e., not
+returning until the operation completes).
+.B ldap_search_st()
+does
+the same, but allows a \fItimeout\fP to be specified.
+.B ldap_search()
+is the asynchronous version, initiating the search and returning
+the message id of the operation it initiated.
+\fIBase\fP is the DN of the entry at which to start the search.
+\fIScope\fP is the scope of the search and should be one of LDAP_SCOPE_BASE,
+to search the object itself,
+LDAP_SCOPE_ONELEVEL, to search the object's immediate children,
+or LDAP_SCOPE_SUBTREE, to search the object and all its descendents.
+.LP
+\fIFilter\fP is a string
+representation of the filter to apply in the search.  Simple filters
+can be specified as \fIattributetype=attributevalue\fP.  More complex
+filters are specified using a prefix notation according to the following
+BNF:
+.LP
+.nf
+        <filter> ::= '(' <filtercomp> ')'
+        <filtercomp> ::= <and> | <or> | <not> | <simple>
+        <and> ::= '&' <filterlist>
+        <or> ::= '|' <filterlist>
+        <not> ::= '!' <filter>
+        <filterlist> ::= <filter> | <filter> <filterlist>
+        <simple> ::= <attributetype> <filtertype> <attributevalue>
+        <filtertype> ::= '=' | '~=' | '<=' | '>='
+.fi
+.LP
+The '~=' construct is used to specify approximate matching.  The
+representation for <attributetype> and <attributevalue> are as
+described in RFC 1778.  In addition, <attributevalue> can be a single *
+to achieve an attribute existence test, or can contain text and *'s
+interspersed to achieve substring matching.
+.LP
+For example, the filter "mail=*" will find any entries that have a mail
+attribute.  The filter "mail=*@terminator.rs.itd.umich.edu" will find
+any entries that have a mail attribute ending in the specified string.
+To put parentheses in a filter, escape them with a backslash '\\'
+character.  See RFC 1588 for a more complete description of allowable
+filters.  See
+.BR ldap_getfilter (3)
+for routines to help in constructing search filters automatically.
+.LP
+\fIAttrs\fP is a null-terminated array of attribute types to return
+from entries that match \fIfilter\fP.  If NULL is specified, all
+attributes will be returned.  \fIAttrsonly\fP should be set to 1 if
+only attribute types are wanted.  It should be set to 0 if both
+attributes types and attribute values are wanted.
+.SH ERRORS
+.B ldap_search_s()
+and
+.B ldap_search_st()
+will return the LDAP error code resulting from the search operation.
+See
+.BR ldap_error (3)
+for details.
+.B ldap_search()
+returns -1 in case of trouble.
+.SH NOTES
+Note that both read
+and list functionality are subsumed by these routines,
+by using a filter like "objectclass=*" and a scope of LDAP_SCOPE_BASE (to
+emulate read) or LDAP_SCOPE_ONELEVEL (to emulate list).
+.LP
+These routines may malloc memory.  Return values are contained
+in <ldap.h>.
+.SH SEE ALSO
+.BR ldap (3),
+.BR ldap_result (3),
+.BR ldap_getfilter (3),
+.BR ldap_error (3)
diff --git a/doc/man/man3/ldap_search.3.links b/doc/man/man3/ldap_search.3.links
new file mode 100644 (file)
index 0000000..ff54c0d
--- /dev/null
@@ -0,0 +1,2 @@
+ldap_search_s.3
+ldap_search_st.3
diff --git a/doc/man/man3/ldap_searchprefs.3 b/doc/man/man3/ldap_searchprefs.3
new file mode 100644 (file)
index 0000000..98b6e78
--- /dev/null
@@ -0,0 +1,158 @@
+.TH SEARCHPREFS 3  "13 June 1994" "U-M LDAP LDVERSION"
+.SH NAME
+ldap_init_searchprefs, ldap_init_searchprefs_buf, ldap_free_searchprefs, ldap_first_searchobj, ldap_next_searchobj \- LDAP search preference configuration routeines
+.SH SYNOPSIS
+.nf
+.ft B
+#include <srchpref.h>
+.ft
+.fi
+.LP
+.nf
+.ft B
+struct ldap_searchattr {
+       char                            *sa_attrlabel;
+       char                            *sa_attr;
+                                       /* max 32 matchtypes for now */
+       u_long                          sa_matchtypebitmap;
+       char                            *sa_selectattr;
+       char                            *sa_selecttext;
+       struct ldap_searchattr          *sa_next;
+};
+
+struct ldap_searchmatch {
+       char                            *sm_matchprompt;
+       char                            *sm_filter;
+       struct ldap_searchmatch         *sm_next;
+};
+
+struct ldap_searchobj {
+       char                            *so_objtypeprompt;
+       unsigned long                   so_options;
+       char                            *so_prompt;
+       short                           so_defaultscope;
+       char                            *so_filterprefix;
+       char                            *so_filtertag;
+       char                            *so_defaultselectattr;
+       char                            *so_defaultselecttext;
+       struct ldap_searchattr          *so_salist;
+       struct ldap_searchmatch         *so_smlist;
+       struct ldap_searchobj           *so_next;
+};
+.ft
+.fi
+.LP
+.nf
+.ft B
+int ldap_init_searchprefs( file, solistp )
+       char            \(**file;
+       struct ldap_searchobj   \(***solistp;
+.ft
+.fi
+.LP
+.nf
+.ft B
+int ldap_init_searchprefs_buf( buf, buflen, solistp )
+       char            \(**buf;
+       unsigned long   len;
+       struct ldap_searchobj   \(***solistp;
+.ft
+.fi
+.LP
+.nf
+.ft B
+struct ldap_searchobj \(**ldap_free_searchprefs( solist )
+       struct ldap_searchobj   \(**solist;
+.ft
+.fi
+.LP
+.nf
+.ft B
+struct ldap_searchobj \(**ldap_first_searchobj( solist )
+       struct ldap_seachobj    \(**solist;
+.ft
+.fi
+.LP
+.nf
+.ft B
+struct ldap_searchobj \(**ldap_next_searchobj( solist, so )
+       struct ldap_searchobj   \(**solist;
+       struct ldap_searchobj   \(**so;
+
+.SH DESCRIPTION
+These functions provide a standard way to access LDAP search preference
+configuration data.  LDAP search preference configurations are typically
+used by LDAP client programs to specify which attributes a user may
+search by, labels for the attributes, and LDAP filters and scopes
+associated with those searches.  Client software presents these choices
+to a user, who can then specify the type of search to be performed.
+.LP
+.B ldap_init_searchprefs(\|)
+reads a sequence of search preference configurations from a valid LDAP 
+searchpref configuration file
+(see ldapsearchprefs.conf(5))
+.I Zero
+is returned upon success, and 
+.I solistp
+is set to point to a list of search preference data structures.
+.LP
+.B ldap_init_searchprefs_buf(\|)
+reads a sequence of search preference configurations from
+.I buf
+(whose size is
+.I buflen).
+.I buf
+should point to the data in the format defined for an LDAP search preference 
+configuration file (see ldapsearchprefs.conf(5))
+.I Zero
+is returned upon success, and 
+.I solistp
+is set to point to a list of search preference data structures.
+
+.LP
+.B ldap_free_searchprefs(\|)
+disposes of the data structures allocated by
+.B ldap_init_searchprefs(\|).
+.LP
+.B ldap_first_searchpref(\|)
+returns the first search preference data structure in the list
+.I solist.
+The
+.I solist
+is typically obtained by calling
+.B ldap_init_searchprefs(\|).
+.LP
+.B ldap_next_searchpref(\|)
+returns the search preference after
+.I so
+in the template list
+.I solist.  A
+.SM NULL
+pointer is returned if
+.I so
+is the last entry in the list.
+.LP
+.SH ERRORS
+The init preferences functions return
+.B LDAP_SEARCHPREF_ERR_VERSION
+if buf points to data that is newer than can be handled, and
+.B LDAP_SEARCHPREF_ERR_MEM
+if there is a memory allocation problem.
+.SH NOTES
+.SH SEE ALSO
+.BR ldap (3),
+.BR ldapsearchprefs.conf (5),
+.BR ldapd (8)
+.LP
+Yeong, W., Howes, T., and Hardcastle-Kille, S., "Lightweight Directory Access
+Protocol", OSI-DS-26, April 1992.
+.LP
+Howes, T., Hardcastle-Kille, S., Yeong, W., and Robbins, C., "Lightweight
+Directory Access Protocol", OSI-DS-26, April 1992.
+.LP
+Hardcastle-Kille, S., "A String Representation of Distinguished Names",
+OSI-DS-23, April 1992.
+.LP
+Information Processing - Open Systems Interconnection - The Directory,
+International Organization for Standardization.  International Standard
+9594, (1988).
diff --git a/doc/man/man3/ldap_searchprefs.3.links b/doc/man/man3/ldap_searchprefs.3.links
new file mode 100644 (file)
index 0000000..95e2629
--- /dev/null
@@ -0,0 +1,5 @@
+ldap_init_searchprefs.3
+ldap_init_searchprefs_buf.3
+ldap_free_searchprefs.3
+ldap_first_searchobj.3
+ldap_next_searchobj.3
diff --git a/doc/man/man3/ldap_sort.3 b/doc/man/man3/ldap_sort.3
new file mode 100644 (file)
index 0000000..f56122a
--- /dev/null
@@ -0,0 +1,101 @@
+.TH LDAP_SORT 3  "14 November 1994" "U-M LDAP LDVERSION"
+.SH NAME
+ldap_sort_entries, ldap_sort_values, ldap_sort_strcasecmp \- LDAP sorting routines
+.SH SYNOPSIS
+.nf
+.ft B
+#include <lber.h>
+#include <ldap.h>
+.LP
+.ft B
+ldap_sort_entries(ld, chain, attr, cmp)
+.ft
+LDAP *ld;
+LDAPMessage **chain;
+char *attr;
+int (*cmp)();
+.LP
+.ft B
+ldap_sort_values(ld, vals, cmp)
+.ft
+LDAP *ld;
+char **vals;
+int (*cmp)();
+.LP
+.ft B
+ldap_sort_strcasecmp(a, b)
+.ft
+char *a;
+char *b;
+.SH DESCRIPTION
+These routines are used to sort lists of entries and values retrieved
+from an LDAP server.
+.B ldap_sort_entries()
+is used to sort a chain
+of entries retrieved from an LDAP search call either by DN or by some
+arbitrary attribute in the entries.  It takes \fIld\fP, the LDAP
+structure, which is only used for error reporting, \fIchain\fP, the
+list of entries as returned by
+.BR ldap_search_s (3)
+or
+.BR ldap_result (3).
+\fIattr\fP is the attribute to use as a key in the sort
+or NULL to sort by DN, and \fIcmp\fP is the comparison function to use
+when comparing values (or individual DN components if sorting by DN).
+In this case, \fIcmp\fP should be a function taking two single values
+of the \fIattr\fP to sort by, and returning a value less than zero,
+equal to zero, or greater than zero, depending on whether the first
+argument is less than, equal to, or greater than the second argument.
+The convention is the same as used by
+.BR qsort (3),
+which is called to do the actual sorting.
+.LP
+.B ldap_sort_values()
+is used to sort an array of values from an entry,
+as returned by
+.BR ldap_get_values (3).
+It takes the LDAP connection
+structure \fIld\fP, the array of values
+to sort \fIvals\fP, and \fIcmp\fP, the comparison
+function to use during the sort.
+Note that \fIcmp\fP will be passed a pointer to each element in the
+\fIvals\fP array, so if you pass the normal char ** for this parameter,
+\fIcmp\fP should take two char **'s as arguments (i.e., you cannot
+pass \fIstrcasecmp\fP or its friends for \fIcmp\fP).  You can, however,
+pass the function
+.B ldap_sort_strcasecmp()
+for this purpose.
+.LP
+For example:
+.LP
+.nf
+.ft tt
+       LDAP *ld;
+       LDAPMessage *res;
+
+       /* ... call to ldap_search_s(), fill in res, retrieve sn attr ... */
+
+       /* now sort the entries on surname attribute */
+       if ( ldap_sort_entries( ld, &res, "sn", ldap_sort_strcasecmp ) != 0 )
+               ldap_perror( ld, "ldap_sort_entries" );
+.ft
+.fi
+.SH NOTES
+.LP
+The
+.B ldap_sort_entries()
+routine applies the comparison function to
+each value of the attribute in the array as returned by a call to
+.BR ldap_get_values (3),
+until a mismatch is found.
+This works fine for single-valued attributes, but
+may produce unexpected results for multi-valued attributes.
+When sorting by DN, the comparison function is
+applied to an exploded version of the DN, without types.
+The return values for all of these functions are declared in the
+<ldap.h> header file.  Some routines may malloc memory.
+.SH SEE ALSO
+.BR ldap (3),
+.BR ldap_search (3),
+.BR ldap_result (3),
+.BR qsort (3)
diff --git a/doc/man/man3/ldap_sort.3.links b/doc/man/man3/ldap_sort.3.links
new file mode 100644 (file)
index 0000000..7a4be53
--- /dev/null
@@ -0,0 +1,3 @@
+ldap_sort_entries.3
+ldap_sort_values.3
+ldap_sort_strcasecmp.3
diff --git a/doc/man/man3/ldap_ufn.3 b/doc/man/man3/ldap_ufn.3
new file mode 100644 (file)
index 0000000..6fe1a51
--- /dev/null
@@ -0,0 +1,130 @@
+.TH LDAP_UFN 3  "23 November 1994" "U-M LDAP LDVERSION"
+.SH NAME
+ldap_ufn_search_s, ldap_ufn_search_c, ldap_ufn_search_ct, ldap_ufn_setfilter, ldap_ufn_setfilter, ldap_ufn_setprefix, ldap_ufn_timeout \- Perform an LDAP user friendly search operation
+.SH SYNOPSIS
+.nf
+.ft B
+#include <lber.h>
+#include <ldap.h>
+.LP
+.ft B
+int ldap_ufn_search_c(ld, ufn, attrs, attrsonly, res, cancelproc,
+                       cancelparm)
+.ft
+LDAP *ld;
+char *ufn;
+char **attrs;
+int attrsonly;
+LDAPMessage **res;
+int (*cancelproc)();
+void *cancelparm;
+.LP
+.ft B
+int ldap_ufn_search_ct(ld, ufn, attrs, attrsonly, res, cancelproc,
+                       cancelparm, tag1, tag2, tag3)
+.ft
+LDAP *ld;
+char *ufn;
+char **attrs;
+int attrsonly;
+LDAPMessage **res;
+int (*cancelproc)();
+void *cancelparm;
+char *tag1, *tag2, *tag3;
+.LP
+.ft B
+int ldap_ufn_search_s(ld, ufn, attrs, attrsonly, res)
+.ft
+LDAP *ld;
+char *ufn;
+char **attrs;
+int attrsonly;
+LDAPMessage **res;
+.LP
+.ft B
+LDAPFiltDesc *ldap_ufn_setfilter(ld, fname)
+.ft
+LDAP *ld;
+char *fname;
+.LP
+.ft B
+void ldap_ufn_setprefix(ld, prefix)
+.ft
+LDAP *ld;
+char *prefix;
+.LP
+.ft B
+int ldap_ufn_timeout(tvparam)
+.ft
+void *tvparam;
+.SH DESCRIPTION
+These routines are used to perform LDAP user friendly search operations.
+.B ldap_ufn_search_s()
+is the simplest form.  It does the search
+synchronously.  It takes \fIld\fP to identify the the LDAP connection.
+The \fIufn\fP parameter is the user friendly name for which to search.
+The \fIattrs\fP, \fIattrsonly\fP and \fIres\fP parameters are the
+same as for
+.BR ldap_search (3).
+.LP
+The
+.B ldap_ufn_search_c()
+routine functions the same as
+.BR ldap_ufn_search_s() ,
+except that it takes \fIcancelproc\fP, a function to call periodicly
+during the search.  It should be a function taking a single void *
+argument, given by \fIcalcelparm\fP.  If \fIcancelproc\fP returns a
+non-zero result, the search will be abandoned and no results returned.
+The purpose of this routine is to provide a way for the search to be
+cancelled, for example, by a user or because some other condition
+occurs.
+.LP
+The
+.B ldap_ufn_search_ct()
+routine is like
+.BR ldap_ufn_search_c() ,
+except that it takes three extra parameters.  \fItag1\fP is passed to the
+.BR ldap_init_getfilter (3)
+routine when resolving the first component of
+the UFN.  \fItag2\fP is used when resolving intermediate components.
+\fItag3\fP is used when resolving the last component.  By default,
+the tags used by the other UFN search routines during these three
+phases of the search are "ufn first", "ufn intermediate", and "ufn last".
+.LP
+The
+.B ldap_ufn_setfilter()
+routine is used to set the
+.BR ldapfilter.conf (5)
+file for use with the
+.BR ldap_init_getfilter (3)
+routine to \fIfname\fP.
+.LP
+The
+.B ldap_ufn_setprefix()
+routine is used to set the default prefix
+(actually, it's a suffix) appended to UFNs before searhing.  UFNs
+with fewer than three components have the prefix appended first,
+before searching.  If that fails, the UFN is tried with progressively
+shorter versions of the prefix, stripping off components.  If the UFN
+has three or more components, it is tried by itself first.  If that
+fails, a similar process is applied with the prefix appended.
+.LP
+The
+.B ldap_ufn_timeout()
+routine is used to set the timeout associated
+with
+.B ldap_ufn_search_s()
+searches.  The \fItimeout\fP parameter
+should actually be a pointer to a struct timeval (this is so
+.B ldap_ufn_timeout()
+can be used as a cancelproc in the above routines).
+.SH NOTES
+These routines may malloc memory.  Return values are contained
+in <ldap.h>.
+.SH SEE ALSO
+.BR gettimeofday (2),
+.BR ldap (3),
+.BR ldap_search (3),
+.BR ldap_getfilter (3),
+.BR ldapfilter.conf (5),
+.BR ldap_error (3)
diff --git a/doc/man/man3/ldap_ufn.3.links b/doc/man/man3/ldap_ufn.3.links
new file mode 100644 (file)
index 0000000..9cdab32
--- /dev/null
@@ -0,0 +1,6 @@
+ldap_ufn_search_s.3
+ldap_ufn_search_c.3
+ldap_ufn_search_ct.3
+ldap_ufn_setprefix.3
+ldap_ufn_setfilter.3
+ldap_ufn_timeout.3
diff --git a/doc/man/man3/ldap_url.3 b/doc/man/man3/ldap_url.3
new file mode 100644 (file)
index 0000000..7e04bcc
--- /dev/null
@@ -0,0 +1,136 @@
+.TH LDAP_URL 3  "28 March 1996" "U-M LDAP LDVERSION"
+.SH NAME
+ldap_is_ldap_url,
+ldap_url_parse,
+ldap_free_urldesc,
+ldap_url_search,
+ldap_url_search_s,
+ldap_url_search_st \- LDAP Uniform Resource Locator routines
+.SH SYNOPSIS
+.nf
+.ft B
+#include <lber.h>
+#include <ldap.h>
+.ft
+.LP
+.ft B
+int ldap_is_ldap_url( url )
+.ft
+char           *url;
+.LP
+.ft B
+int ldap_url_parse( url, ludpp )
+.ft
+char           *url;
+LDAPURLDesc    **ludpp;
+.LP
+typedef struct ldap_url_desc {
+    char       *lud_host;      /* LDAP host to contact */
+    int        lud_port;               /* port on host */
+    char       *lud_dn;                /* base for search */
+    char       **lud_attrs;    /* NULL-terminate list of attributes */
+    int        lud_scope;      /* a valid LDAP_SCOPE_... value */
+    char       *lud_filter;    /* LDAP search filter */
+    char       *lud_string;    /* for internal use only */
+} LDAPURLDesc;
+.LP
+.ft B
+ldap_free_urldesc( ludp )
+.ft
+LDAPURLDesc    *ludp;
+.LP
+.ft B
+int ldap_url_search( ld, url, attrsonly )
+.ft
+LDAP           *ld;
+char           *url;
+int            attrsonly;
+.LP
+.ft B
+int ldap_url_search_s( ld, url, attrsonly, res )
+.ft
+LDAP           *ld;
+char           *url;
+int            attrsonly;
+LDAPMessage    **res;
+.LP
+.ft B
+int ldap_url_search_st( ld, url, attrsonly, timeout, res )
+.ft
+LDAP           *ld;
+char           *url;
+int            attrsonly;
+struct timeval *timeout;
+LDAPMessage    **res;
+.SH DESCRIPTION
+These routines support the use of LDAP URLs (Uniform Resource Locators).
+LDAP URLs look like this:
+.nf
+
+  \fBldap://\fP\fIhostport\fP\fB/\fP\fIdn\fP[\fB?\fP\fIattributes\fP[\fB?\fP\fIscope\fP[\fB?\fP\fIfilter\fP]]]
+
+where:
+  \fIhostport\fP is a host name with an optional ":portnumber"
+  \fIdn\f is the base DN to be used for an LDAP search operation
+  \fIattributes\fP is a comma separated list of attributes to be retrieved
+  \fIscope\fP is one of these three strings:  base one sub (default=base)
+  \fIfilter\f is LDAP search filter as used in a call to ldap_search(3)
+
+e.g.,  ldap://ldap.itd.umich.edu/c=US?o,description?one?o=umich
+.fi
+.LP
+URLs that are wrapped in angle-brackets and/or preceded by "URL:" are also
+tolerated.
+.LP
+.B ldap_is_ldap_url()
+returns a non-zero value if \fIurl\fP looks like an LDAP URL (as
+opposed to some other kind of URL).  It can be used as a quick check
+for an LDAP URL; the
+.B ldap_url_parse()
+routine should be used if a more thorough check is needed.
+.LP
+.B ldap_url_parse()
+breaks down an LDAP URL passed in \fIurl\fP into its component pieces.
+If successful, zero is returned, an LDAP URL description is
+allocated, filled in, and \fIludpp\fP is set to point to it.  If an
+error occurs, one of these values is returned:
+.nf
+
+    LDAP_URL_ERR_NOTLDAP       - URL doesn't begin with "ldap://"
+    LDAP_URL_ERR_NODN  - URL has no DN (required)
+    LDAP_URL_ERR_BADSCOPE      - URL scope string is invalid
+    LDAP_URL_ERR_MEM   - can't allocate memory space
+.fi
+.LP
+.B ldap_free_urldesc()
+should be called to free an LDAP URL description that was obtained from
+a call to
+.B ldap_url_parse().
+.LP
+.B ldap_url_search()
+initiates an asynchronous LDAP search based on the contents of the
+\fIurl\fP string.  This routine acts just like
+.BR ldap_search (3)
+except that many search parameters are pulled out of the URL.
+.LP
+.B ldap_url_search_s()
+performs a synchronous LDAP search based on the contents of the
+\fIurl\fP string.  This routine acts just like
+.BR ldap_search_s (3)
+except that many search parameters are pulled out of the URL.
+.LP
+.B ldap_url_search_st()
+performs a synchronous LDAP URL search with a specified \fItimeout\fP.
+This routine acts just like
+.BR ldap_search_st (3)
+except that many search parameters are pulled out of the URL.
+.SH SEE ALSO
+.BR ldap (3),
+.BR ldap_search (3)
+.LP
+.B An LDAP URL Format,
+Tim Howes and Mark Smith, December 1995.  Internet Draft (work in progress).
+Currently available at this URL:
+.nf
+ftp://ds.internic.net/internet-drafts/draft-ietf-asid-ldap-format-03.txt
+.fi
diff --git a/doc/man/man3/ldap_url.3.links b/doc/man/man3/ldap_url.3.links
new file mode 100644 (file)
index 0000000..7ea85a4
--- /dev/null
@@ -0,0 +1,6 @@
+ldap_is_ldap_url.3
+ldap_url_parse.3
+ldap_free_urldesc.3
+ldap_url_search.3
+ldap_url_search_s.3
+ldap_url_search_st.3
diff --git a/doc/man/man3/regex.3 b/doc/man/man3/regex.3
new file mode 100644 (file)
index 0000000..ba9cc38
--- /dev/null
@@ -0,0 +1,326 @@
+.TH regex 3 local
+.DA Jun 19 1986
+.SH NAME
+re_comp, re_exec, re_subs, re_modw, re_fail  \- regular expression handling
+.SH ORIGIN
+Dept. of Computer Science
+.br
+York University
+.SH SYNOPSIS
+.B char *re_comp(pat)
+.br
+.B char *pat;
+.PP
+.B re_exec(str)
+.br
+.B char *str;
+.PP
+.B re_subs(src, dst)
+.br
+.B char *src;
+.br
+.B char *dst;
+.PP
+.B void re_fail(msg, op)
+.br
+.B char *msg;
+.br
+.B char op;
+.PP
+.B void re_modw(str)
+.br
+.B char *str;
+
+.SH DESCRIPTION
+.PP
+These functions implement
+.IR ed (1)-style
+partial regular expressions and supporting facilities.
+.PP
+.I Re_comp
+compiles a pattern string into an internal form (a deterministic finite-state
+automaton) to be executed by
+.I re_exec
+for pattern matching.
+.I Re_comp
+returns 0 if the pattern is compiled successfully, otherwise it returns an
+error message string. If
+.I re_comp
+is called with a 0 or a \fInull\fR string, it returns without changing the
+currently compiled regular expression.
+.sp
+.I Re_comp
+supports the same limited set of
+.I regular expressions
+found in
+.I ed
+and Berkeley
+.IR regex (3)
+routines:
+.sp
+.if n .in +1.6i
+.if t .in +1i
+.de Ti
+.if n .ti -1.6i
+.if t .ti -1i
+.. 
+.if n .ta 0.8i +0.8i +0.8i
+.if t .ta 0.5i +0.5i +0.5i
+.Ti 
+[1]    \fIchar\fR      Matches itself, unless it is a special
+character (meta-character): \fB. \\ [ ] * + ^ $\fR
+
+.Ti 
+[2]    \fB.\fR Matches \fIany\fR character.
+
+.Ti 
+[3]    \fB\\\fR        Matches the character following it, except
+when followed by a digit 1 to 9, \fB(\fR, fB)\fR, \fB<\fR or \fB>\fR.
+(see [7], [8] and [9]) It is used as an escape character for all 
+other meta-characters, and itself. When used
+in a set ([4]), it is treated as an ordinary
+character.
+
+.Ti
+[4]    \fB[\fIset\fB]\fR       Matches one of the characters in the set.
+If the first character in the set is \fB^\fR,
+it matches a character NOT in the set. A
+shorthand 
+.IR S - E
+is used to specify a set of
+characters 
+.I S 
+up to 
+.IR E , 
+inclusive. The special
+characters \fB]\fR and \fB-\fR have no special
+meaning if they appear as the first chars
+in the set.
+.nf
+       examples:       match:
+       [a-z]           any lowercase alpha
+       [^]-]           any char except ] and -
+       [^A-Z]          any char except 
+                       uppercase alpha
+       [a-zA-Z0-9]     any alphanumeric
+.fi
+
+.Ti 
+[5]    \fB*\fR Any regular expression form [1] to [4], followed by
+closure char (*) matches zero or more matches of
+that form.
+
+.Ti 
+[6]    \fB+\fR Same as [5], except it matches one or more.
+
+.Ti 
+[7]            A regular expression in the form [1] to [10], enclosed
+as \\(\fIform\fR\\) matches what form matches. The enclosure
+creates a set of tags, used for [8] and for
+pattern substitution in
+.I re_subs. 
+The tagged forms are numbered
+starting from 1.
+
+.Ti 
+[8]            A \\ followed by a digit 1 to 9 matches whatever a
+previously tagged regular expression ([7]) matched.
+
+.Ti
+[9]    \fB\\<\fR       Matches the beginning of a \fIword\fR,
+that is, an empty string followed by a
+letter, digit, or _ and not preceded by
+a letter, digit, or _ .
+.Ti
+       \fB\\>\fR       Matches the end of a \fIword\fR,
+that is, an empty string preceded
+by a letter, digit, or _ , and not
+followed by a letter, digit, or _ .
+
+.Ti 
+[10]           A composite regular expression 
+\fIxy\fR where \fIx\fR and \fIy\fR
+are in the form of [1] to [10] matches the longest
+match of \fIx\fR followed by a match for \fIy\fR.
+
+.Ti 
+[11]   \fB^ $\fR       a regular expression starting with a \fB^\fR character
+and/or ending with a \fB$\fR character, restricts the
+pattern matching to the beginning of the line,
+and/or the end of line [anchors]. Elsewhere in the
+pattern, \fB^\fR and \fB$\fR are treated as ordinary characters.
+.if n .in -1.6i
+.if t .in -1i
+
+.PP
+.I Re_exec
+executes the internal form produced by
+.I re_comp
+and searches the argument string for the regular expression described
+by the internal
+form. 
+.I Re_exec
+returns 1 if the last regular expression pattern is matched within the string,
+0 if no match is found. In case of an internal error (corrupted internal
+form), 
+.I re_exec 
+calls the user-supplied
+.I re_fail
+and returns 0.
+.PP
+The strings passed to both
+.I re_comp
+and
+.I re_exec
+may have trailing or embedded newline characters. The strings 
+must be terminated by nulls.
+.PP
+.I Re_subs
+does
+.IR ed -style
+pattern substitution, after a successful match is found by
+.I re_exec.
+The source string parameter to
+.I re_subs
+is copied to the destination string with the following interpretation;
+.sp
+.if n .in +1.6i
+.if t .in +1i
+.Ti
+[1]    &       Substitute the entire matched string in the destination.
+
+.Ti
+[2]    \\\fIn\fR       Substitute the substring matched by a tagged subpattern
+numbered \fIn\fR, where \fIn\fR is between 1 to 9, inclusive.
+
+.Ti
+[3]    \\\fIchar\fR    Treat the next character literally,
+unless the character is a digit ([2]).
+.if n .in -1.6i
+.if t .in -1i
+
+.PP
+If the copy operation with the substitutions is successful,
+.I re_subs
+returns 1.
+If the source string is corrupted, or the last call to
+.I re_exec
+fails, it returns 0.
+
+.I Re_modw
+is used to 
+add new characters into an internal table to
+change the re_exec's understanding of what
+a \fIword\fR should look like, when matching with \fB\\<\fR and \fB\\>\fR
+constructs. If the string parameter is 0 or null string,
+the table is reset back to the default, which contains \fBA-Z a-z 0-9 _\fR .
+
+.I Re_fail
+is a user-supplied routine to handle internal errors.
+.I re_exec
+calls
+.I re_fail
+with an error message string, and the opcode character that caused the error.
+The default
+.I re_fail
+routine simply prints the message and the opcode character to
+.I stderr
+and invokes
+.IR exit (2).
+.SH EXAMPLES
+In the examples below, the
+.I nfaform
+describes the internal form after the pattern is compiled. For additional
+details, refer to the sources.
+.PP
+.ta 0.5i +0.5i +0.5i
+.nf
+foo*.*
+       nfaform:        CHR f CHR o CLO CHR o END CLO ANY END END
+       matches:        \fIfo foo fooo foobar fobar foxx ...\fR
+
+fo[ob]a[rz]
+       nfaform:        CHR f CHR o CCL 2 o b CHR a CCL 2 r z END
+       matches:        \fIfobar fooar fobaz fooaz\fR
+
+foo\\\\+
+       nfaform:        CHR f CHR o CHR o CHR \\ CLO CHR \\ END END
+       matches:        \fIfoo\\ foo\\\\ foo\\\\\\  ...\fR
+
+\\(foo\\)[1-3]\\1      (same as foo[1-3]foo, but takes less internal space)
+       nfaform:        BOT 1 CHR f CHR o CHR o EOT 1 CCL 3 1 2 3 REF 1 END
+       matches:        \fIfoo1foo foo2foo foo3foo\fR
+
+\\(fo.*\\)-\\1
+       nfaform:        BOT 1 CHR f CHR o CLO ANY END EOT 1 CHR - REF 1 END
+       matches:        \fIfoo-foo fo-fo fob-fob foobar-foobar ...\fR
+.SH DIAGNOSTICS
+.I Re_comp
+returns one of the following strings if an error occurs:
+.PP
+.nf
+.in +0.5i
+\fINo previous regular expression,
+Empty closure,
+Illegal closure,
+Cyclical reference,
+Undetermined reference,
+Unmatched \e(,
+Missing ],
+Null pattern inside \e(\e),
+Null pattern inside \e<\e>,
+Too many \e(\e) pairs,
+Unmatched \e)\fP.
+.in -0.5i
+.fi
+.SH REFERENCES
+.if n .ta 3i
+.if t .ta 1.8i
+.nf
+\fISoftware tools\fR   Kernighan & Plauger
+\fISoftware tools in Pascal\fR Kernighan & Plauger
+\fIGrep sources\fR [rsx-11 C dist]     David Conroy
+\fIEd - text editor\fR Unix Programmer's Manual
+\fIAdvanced editing on Unix\fR B. W. Kernighan
+\fIRegExp sources\fR   Henry Spencer
+.fi
+.SH "HISTORY AND NOTES"
+These routines are derived from various implementations
+found in 
+.I "Software Tools"
+books, and David Conroy's 
+.I grep. 
+They are NOT derived from licensed/restricted software.
+For more interesting/academic/complicated implementations,
+see Henry Spencer's 
+.I regexp 
+routines (V8), or 
+.I "GNU Emacs"
+pattern
+matching module.
+.PP
+The
+.I re_comp
+and
+.I re_exec
+routines perform
+.I almost
+as well as their licensed counterparts, sometimes better. 
+In very few instances, they
+are about 10% to 15% slower.
+.SH AUTHOR
+Ozan S. Yigit (oz)
+.br
+usenet: utzoo!yetti!oz
+.br
+bitnet: oz@yusol || oz@yuyetti
+.SH "SEE ALSO"
+ed(1), ex(1), egrep(1), fgrep(1), grep(1), regex(3)
+.SH BUGS
+These routines are \fIPublic Domain\fR. You can get them
+in source.
+.br
+The internal storage for the \fInfa form\fR is not checked for
+overflows. Currently, it is 1024 bytes.
+.br
+Others, no doubt.
diff --git a/doc/man/man5/Make-template b/doc/man/man5/Make-template
new file mode 100644 (file)
index 0000000..3d2d554
--- /dev/null
@@ -0,0 +1,52 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1994 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP man5 makefile
+#
+#-----------------------------------------------------------------------------
+
+LDAPSRC= ../../..
+SECT=5
+INSTDIR=$(MANDIR)/man$(SECT)
+VERSIONFILE = $(LDAPSRC)/build/version
+
+all:   FORCE
+
+install:       FORCE
+       -$(MKDIR) -p $(INSTDIR)
+       @TMPMAN=/tmp/ldapman.$$$$; \
+       VERSION=`$(CAT) $(VERSIONFILE)`; \
+       for page in *.$(SECT); do \
+           $(SED) -e 's%ETCDIR%$(RUNTIMEETCDIR)%' -e "s%LDVERSION%$$VERSION%" \
+                   $$page > $$TMPMAN; \
+           echo "installing $(INSTDIR)/$$page"; \
+           $(INSTALL) $(INSTALLFLAGS) -m 644 $$TMPMAN $(INSTDIR)/$$page; \
+           if [ -f "$$page.links" ]; then \
+               for link in `$(CAT) $$page.links`; do \
+                   echo ".so man$(SECT)/$$page" > $$TMPMAN; \
+                   echo "installing $(INSTDIR)/$$link as link to $$page"; \
+                   $(INSTALL) $(INSTALLFLAGS) -m 644 $$TMPMAN \
+                           $(INSTDIR)/$$link; \
+               done; \
+           fi; \
+       done; \
+       $(RM) $$TMPMAN
+
+clean: FORCE
+
+depend:        FORCE
+
+lint:  FORCE
+
+5lint: FORCE
+
+links:
+       @$(LN) .src/*.$(SECT) .src/*links .
diff --git a/doc/man/man5/ldapfilter.conf.5 b/doc/man/man5/ldapfilter.conf.5
new file mode 100644 (file)
index 0000000..954bc2f
--- /dev/null
@@ -0,0 +1,198 @@
+.TH LDAPFILTER.CONF 5  "21 September 1994" "U-M LDAP LDVERSION"
+.SH NAME
+ldapfilter.conf \- configuration file for LDAP get filter routines
+.SH SYNOPSIS
+ETCDIR/ldapfilter.conf
+.SH DESCRIPTION
+.LP
+The file
+.B ETCDIR/ldapfilter.conf
+contains information used by
+the LDAP get filter routines (see
+.BR ldap-getfilter (3)).
+Blank lines and
+lines that have a first character of `#' are treated as comments and
+ignored.  The configuration information consists of lines that contain
+one, two, three, four, or five tokens.  Tokens are separated
+by white space, and double quotes `"' can be used to include white space
+inside a token.
+.LP
+The file consists of a sequence of one or more filter sets.  A filter
+set begins with a line containing a single token called a
+.I tag.
+The
+.I tag
+is used in the
+.BR ldap_getfirstfilter (3)
+call to select the filter set.
+.LP
+The filter set consists of a sequence of one or more filter lists.  The
+first line in a filter list must contain four or five tokens: the
+.I value pattern,
+the
+.I delimiter list,
+a
+.I filter template,
+a
+.I match description,
+and an optional
+.I search scope.
+The
+.I value pattern
+is a regular expression that is matched against the
+.B value
+passed to the
+.BR ldap_getfirstfilter (3)
+call to select the filter list.
+.LP
+The
+.I delimiter list
+is a list of characters (in the form of a single string) that are used to
+break the
+.B value
+into distinct words. 
+.LP
+The
+.I filter template
+is used to construct an LDAP filter (it is described further below)
+.LP
+The
+.I match description
+is returned to the called along with a filter as a piece of text that can
+be used to describe the sort of LDAP search that took place.  It should
+correctly compete both of the following phrases:
+"One
+.I match description
+match was found for..."
+and
+"Three
+.I match description
+matches were found for...."
+.LP
+The
+.I search scope
+is optional, and should be one of "base", "onelevel", or "subtree".  If
+.I search scope
+is not provided, the default is "subtree".
+.LP
+The remaining lines of the filter list should contain two or three tokens,
+a
+.I filter template,
+a
+.I match description
+and an optional
+.I search scope
+(as described above).
+.LP
+The
+.I filter template
+is similar in concept to a printf(3) style format
+string.  Everything is taken literally except for the character
+sequences:
+.nf
+.ft I
+    %v
+    %v$
+    %vN
+    %vM-N
+    %vN-
+.ft
+.fi
+A plain
+.I %v
+means to substitute the entire
+.B value
+string in place of the
+.I %v.
+.I %v$
+means substitute the last word in this spot.
+A
+.I %vN,
+where N is a single digit 1-9, means substitute word N in this spot.
+Words are number from left to right within the value starting at 1.
+A
+.I %vM-N,
+where M and N are both single digits 1-9, means substitute the indicated
+sequence of words.
+A
+.I %vN-,
+where N is again a single digit 1-9, means substitute word N through the
+last word in
+.B value.
+.SH EXAMPLE
+The following ldap filter configuration file contains two filter sets
+.RB ( finger
+and
+.B go500gw
+.BR onelevel ),
+each of which contains four filter lists.
+.LP
+.nf
+  # ldap filter file
+  #
+  finger
+    "="                " "     "%v"                    "arbitrary filter"
+
+    "[0-9][0-9\-]*"    " "     "(telephoneNumber=*%v)" "phone number"
+
+    "@"                " "     "(mail=%v)"             "email address"
+
+    "^.[. _].*"       ". _"   "(cn=%v1* %v2-)"        "first initial"
+
+    ".*[. _].$"        ". _"   "(cn=%v1-*)"            "last initial"
+
+    "[. _]"            ". _"   "(|(sn=%v1-)(cn=%v1-))"        "exact"
+                               "(|(sn~=%v1-)(cn~=%v1-))"      "approximate"
+
+    ".*"               ". "    "(|(cn=%v1)(sn=%v1)(uid=%v1))" "exact"
+                               "(|(cn~=%v1)(sn~=%v1))"        "approximate"
+
+  "go500gw onelevel"
+    "^..$"  " "   "(|(o=%v)(c=%v)(l=%v)(co=%v))"       "exact" "onelevel"
+                  "(|(o~=%v)(c~=%v)(l~=%v)(co~=%v))"   "approximate" "onelevel"
+
+    " "     " "   "(|(o=%v)(l=%v)(co=%v)"       "exact"        "onelevel"
+                  "(|(o~=%v)(l~=%v)(co~=%v)"    "approximate"  "onelevel"
+
+    "\."    " "   "(associatedDomain=%v)"       "exact"        "onelevel"
+
+    ".*"    " "   "(|(o=%v)(l=%v)(co=%v)"       "exact"        "onelevel"
+                  "(|(o~=%v)(l~=%v)(co~=%v)"    "approximate"  "onelevel"
+.fi
+.LP
+The call
+.ft B
+ldap_getfirstfilter( lfdp, "finger", "m.smith" );
+.ft
+will return an LDAPFiltInfo structure with the
+.B lfi_filter
+member containing the string
+.I (cn=m* smith)
+with the
+.B lfi_desc
+member containing the string
+.I first initial,
+and
+.B lfi_scope
+containing the value LDAP_SCOPE_SUBTREE.
+.LP
+The call
+.ft B
+ldap_getfirstfilter( lfdp, "go500gw onelevel", "umich" );
+.ft
+will return an LDAPFiltInfo structure with the
+.B lfi_filter
+member containing the string
+.I (|(o=umich)(l=umich)(co=umich)
+with the
+.B lfi_desc
+member containing the string
+.I exact,
+and
+.B lfi_scope
+containing the value LDAP_SCOPE_ONELEVEL.
+.SH FILES
+ETCDIR/ldapfilter.conf
+.SH SEE ALSO
+.BR ldap (3),
+.BR ldap_getfilter (3)
diff --git a/doc/man/man5/ldapfriendly.5 b/doc/man/man5/ldapfriendly.5
new file mode 100644 (file)
index 0000000..088fd13
--- /dev/null
@@ -0,0 +1,26 @@
+.TH LDAPFRIENDLY 5  "24 November 1994" "U-M LDAP LDVERSION"
+.SH NAME
+ldapfriendly \- configuration file for LDAP friendly routines
+.SH SYNOPSIS
+ETCDIR/ldapfriendly
+.SH DESCRIPTION
+.LP
+The file ETCDIR/ldapfriendly contains simple mapping information
+used by the
+.BR ldap_friendly_name (3)
+routine.  Blank lines and
+lines that have a first character of `#' are treated as comments and
+ignored.  The configuration information consists of lines that contain
+an "unfriendly" name, a tab, and a "friendly" name.
+.LP
+Other friendly mapping files can be created and used by
+.BR ldap_friendly_name (3).
+Just use the same format as that described
+above and include the file name in the
+.B ldap_friendly_name()
+call.
+.SH FILES
+ETCDIR/ldapfriendly
+.SH SEE ALSO
+.BR ldap (3),
+.BR ldap_friendly_name (3)
diff --git a/doc/man/man5/ldapsearchprefs.conf.5 b/doc/man/man5/ldapsearchprefs.conf.5
new file mode 100644 (file)
index 0000000..7f58505
--- /dev/null
@@ -0,0 +1,246 @@
+.TH LDAPSEARCHPREFS.CONF 5  "1 December 1994" "U-M LDAP LDVERSION"
+.SH NAME
+ldapsearchprefs.conf \- configuration file for LDAP search preference routines
+.SH SYNOPSIS
+ETCDIR/ldapsearchprefs.conf
+.SH DESCRIPTION
+.LP
+The file ETCDIR/ldapsearchprefs.conf contains information used by
+the LDAP search preference routines (see ldap-searchpref(3)).  Blank lines
+and lines that have a first character of `#' are treated as comments and
+ignored.  Non-comment lines contain one or more tokens.  Tokens are
+separated by white space, and double quotes `"' can be used to include
+white space inside a token.
+.LP
+Search preferences are typically used by LDAP-based client programs to
+specify what a user may search for, which attributes are searched, and
+which options are available to the user.
+.LP
+The first non-commment line specifies the version of the template
+information and must contain the token
+.I Version
+followed by an integer version number.  E.g.,
+.nf
+.ft B
+    Version 1
+.ft
+.fi
+The current version is
+.I 1,
+so the above example is always the correct opening line.
+.LP
+The remainder of the file consists of one or more search preference
+configurations.
+The first line of a search preference is a human-readable name for the
+type of object being searched for, e.g. "People" or "Organizations".
+This name is stored in the
+.I so_objtypeprompt
+member of the
+.I ldap_searchobj
+structure.
+E.g.,
+.nf
+.ft B
+    "People"
+.ft
+.fi
+specifies a label for a search preference designed to find X.500 
+entries for People.
+.LP
+The next line specifies a list of options for this search object.  The
+only option currently allowed is "internal" which means that this search
+object should not be presented directly to a user.  Options are placed in the
+.I so_options
+member of the
+.I ldap_searchobj
+structure and can be tested using the LDAP_IS_SEARCHOBJ_OPTION_SET() macro.
+Use "" if no special options are desired.
+.LP
+The next line specifes a label
+to use for "Fewer Choices" (for lack of a better term) searches.  "Fewer
+Choices" searches are those where the user's input is fed to the
+ldap_filter routines to determine an appropriate filter to use.  This
+contrasts with explicitly-constructed LDAP filters, or "More Choices"
+searches, where the user can explicitly construct an LDAP filter.  The
+"Fewer" and "More Choices" terms derive from the maX.500, waX.500 and
+xax500 directory user agents, which offer two configurations of their
+"Find Entry" dialogs - one where the user types a search string, and the
+client code attempts to find reasonable filter(s) to use in searching
+("Fewer Choices"), and one where the user can select from several pop-up
+menus which allow complete specification of the search to be performed
+("More Choices").
+.LP
+For example:
+.nf
+.ft B
+    "Search For:"
+.ft
+.fi
+can be used by LDAP client programs to label the field into which the
+user can type a "Fewer Choices" search.  This information is stored in
+the
+.I so_prompt
+member of the
+.I ldap_searchobj
+structure.
+
+.LP
+The next line specifies an LDAP filter prefix to append to all "More Choices"
+searched.  This is typically used to limit the types of entries returned
+to those containing a specific object class.  For example:
+.nf
+.ft B
+    "(&(objectClass=person)"
+.ft
+.fi
+would cause only entries containing the object class "person" to be
+returned by a search.  Note that parentheses may be unbalanced here, since
+this is a filter prefix, not an entire filter.  This information is
+stored in the
+.I so_filterprefix
+member of the 
+.I ldap_searchobj
+structure.
+
+.LP
+The next line is an LDAP filter tag (see ldap-filter(3)) which specifies
+the set of LDAP filters to be applied for "Fewer Choices" searching.
+The line
+.nf
+.ft B
+    "xax500-People"
+.ft
+.fi
+would tell the client program to use the set of LDAP filters from the
+ldap filter configuration file tagged "xax500-People".  This information is
+stored in the
+.I so_filtertag
+member of the
+.I ldap_searchobj
+structure.
+
+.LP
+The next line specifies an LDAP attribute to retrieve to help the user
+choose when several entries match the search terms specified.  For example:
+.nf
+.ft B
+    "title"
+.ft
+.fi
+specifies that if more than one entry matches the search criteria, the
+client program should retrieve the "title" attribute that and present
+that to the user to allow them to select the appropriate entry.
+The next line specifies a label for the above attribute, e.g.
+.nf
+.ft B
+    "Title:"
+.ft
+.fi
+The above information is stored in the
+.I so_defaultselectattr
+and
+.I so_defaultselecttext
+members of the
+.I ldap_searchobj
+structure.  Note that these are defaults, and are intended to be overridden
+by the sa_selectattr and sa_selecttext fields of the ldap_searchattr
+data structure (see below).
+
+.LP
+The next line specifies the scope of the LDAP search to be performed.
+Acceptable values are subtree, onelevel, and base.  See ldap(3) for
+more information.
+
+.LP
+The next section is a list of "More Choices" search options, terminated by
+a line containing only the string "END".  Example:
+.nf
+.ft B
+  "Common Name"        cn      11111   ""      ""
+  "Surname"    sn      11111   ""      ""
+  "Business Phone"     "telephoneNumber"       11101   ""      ""
+  END
+.ft
+.fi
+
+Each line represents one method of searching.  In this example, there
+are three ways of searching - by Common Name, by Surname, and by
+Business Phone number.  The first field is the text which should be
+displayed to user.  The second field is the attribute which will be
+searched.  The third field is a bitmap which specifies which of the
+match types (discussed below) are permitted for this search type.  A
+"1" value in a given bit position indicates that a particular
+match type is valid, and a "0" indicates that is it not valid.  The
+fourth and fifth fields are, respectively, the select attribute name
+(corresponding to the sa_selectattr field of the ldap_searchattr data
+structure) and on-screen name for the select attribute (corresponding
+to the sa_selecttext field).  These values are intended to override
+the so_defaultselectattr and so_defaultselecttext values, described
+above.  If blank, the client software should use the default values above.
+
+.LP
+The next section is a list of search match options, terminated by a
+a line containing only the string "END".  Example:
+.nf
+.ft B
+  "exactly matches"    "(%a=%v))"
+  "approximately matches"      "(%a~=%v))"
+  "starts with"        "(%a=%v*))"
+  "ends with"  "(%a=*%v))"
+  "contains"   "(%a=*%v*))"
+  END
+.ft
+.fi
+In this example, there are five ways of refining the search.  For each method,
+there is an LDAP filter suffix which is appended to the ldap filter thus
+far constructed.  The routine ldap_build_filter() may be used to construct
+the whole filter.  It substitutes the appropriate attribute for "%a" in the
+filter, and a value (generally, something the user types) for "%v".
+
+.SH EXAMPLE
+The following example illustrates one possible configuration of search
+preferences for "people".
+.LP
+.nf
+# Version number
+Version 1
+# Name for this search object
+People
+# Label to place before text box user types in
+"Search For:"
+# Filter prefix to append to all "More Choices" searches
+"(&(objectClass=person)"
+# Tag to use for "Fewer Choices" searches - from ldapfilter.conf file
+"xax500-People"
+# If a search results in > 1 match, retrieve this attribute to help
+# user disambiguate the entries...
+multilineDescription
+# ...and label it with this string:
+"Description"
+# Search scope to use when searching
+subtree
+# Follows a list of "More Choices" search options.  Format is:
+# Label, attribute, select-bitmap, extra attr display name, extra attr ldap name
+# If last two are null, "Fewer Choices" name/attributes used
+"Common Name"                   cn                 11111  ""  ""
+"Surname"                       sn                 11111  ""  ""
+"Business Phone"                "telephoneNumber"  11101  ""  ""
+"E-Mail Address"                "mail"             11111  ""  ""
+"Uniqname"                      "uid"              11111  ""  ""
+END
+# Match types
+"exactly matches"               "(%a=%v))"
+"approximately matches"         "(%a~=%v))"
+"starts with"                   "(%a=%v*))"
+"ends with"                     "(%a=*%v))"
+"contains"                      "(%a=*%v*))"
+END
+.fi
+.LP
+In this example, the user may search for People.  For "fewer choices" searching,
+the tag for the ldap filter config file is "xax500-People".
+.SH FILES
+ETCDIR/ldapsearchprefs.conf
+.SH SEE ALSO
+.BR ldap (3).
+.BR ldap-searchprefs (3)
diff --git a/doc/man/man5/ldaptemplates.conf.5 b/doc/man/man5/ldaptemplates.conf.5
new file mode 100644 (file)
index 0000000..5b6579e
--- /dev/null
@@ -0,0 +1,275 @@
+.TH LDAPTEMPLATES.CONF 5  "13 December 1994" "U-M LDAP LDVERSION"
+.SH NAME
+ldaptemplates.conf \- configuration file for LDAP display template routines
+.SH SYNOPSIS
+ETCDIR/ldaptemplates.conf
+.SH DESCRIPTION
+.LP
+The file ETCDIR/ldaptemplates.conf contains information used by
+the LDAP display templates routines (see ldap-disptmpl(3)).  Blank lines
+and lines that have a first character of `#' are treated as comments and
+ignored.  Non-comment lines contain one or more tokens.  Tokens are
+separated by white space, and double quotes `"' can be used to include
+white space inside a token.
+.LP
+The first non-commment line specifies the version of the template
+information and must contain the token
+.I Version
+followed by an integer version number.  E.g.,
+.nf
+.ft B
+    Version 1
+.ft
+.fi
+The current version is
+.I 1,
+so the above example is always the correct opening line.
+.LP
+The remainder of the file consists of one or more display templates.
+The first two lines of the display template should each contain a single
+token that specifies singular and plural names for the template that are
+suitable for human consumption.  These names are stored in the
+.I dt_name
+and
+.I dt_pluralname
+members of the
+.I ldap_disptmpl
+structure.
+E.g.,
+.nf
+.ft B
+    "Person"
+    "People"
+.ft
+.fi
+specifies appropriate names for a template designed to display X.500
+person information.
+.LP
+The next line specifies the name of the icon or similar element that is
+associated with this template.  E.g.,
+.nf
+.ft B
+    "person icon"
+.ft
+.fi
+.LP
+The next line is a blank-separated list of template options.  "" can be
+used if no options are desired.  Available options are:  "addable" (it
+is appropriate to allow entries of this type to be added), "modrdn" (it
+is appropriate to offer the "modify rdn" operation), "altview" (this
+template is merely an alternate view of another template, typically
+used for templates pointed to be a linkaction item).  E.g.,
+.nf
+.ft B
+    "addable" "modrdn"
+.ft
+.fi
+.LP
+The next portion of the template is a list of X.500 object classes that
+is used to determine whether the template should be used to display a
+given entry.  The object class information consists of one or more lines,
+followed by a terminating line that contains the single token
+.I END.
+Each line contains one or more object class names, all of which must be
+present in an X.500 entry for the
+.I ldap_oc2template(3)
+routine to return a pointer to this template.
+The object class information is stored in the
+.I dt_oclist
+member of the
+.I ldap_disptmpl
+structure.  Multiple lines can be used to associate more than one set
+of object classes with a given template.  E.g.,
+.nf
+.ft B
+    umichPerson
+    lblPerson
+    END
+.ft
+.fi
+means that the template is appropriate for display of umichPerson entries or
+lblPerson entries.
+.LP
+Next next line after the object class list is the name of the attribute
+to authenticate as to make changes (use "" if it is appropriate to
+authenticate as the entry itself).  E.g.,
+.nf
+.ft B
+    "owner"
+.ft
+.fi
+.LP
+The next line is the default attribute to use when naming a new entry.
+E.g.,
+.nf
+.ft B
+    "cn"
+.ft
+.fi
+.LP
+The next line is the default location under which new entries are created.
+It should be a string-represented Distringuished Name. E.g.,
+.nf
+.ft B
+    "o=University of Michigan, c=US"
+.ft
+.fi
+.LP
+The next section is a list of rules used to assign default values to new
+entries.  The list should be terminated with a line that contains the
+single token
+.I END.
+Each line in this section should either begin with the token
+.I constant
+and be followed by the name of the attribute and a constant value to
+assign, or the line should begin with
+.I addersdn
+followed by the name of an attribute whose value will be the DN of the
+person who has authenticated to add the entry.
+E.g.,
+.nf
+.ft B
+    constant   associatedDomain        umich.edu
+    addersdn   seeAlso
+    END
+.ft
+.fi
+.LP
+The last portion of the template is a list of items to display.  It
+consists of one or more lines, followed by a terminating line that
+contains the single token
+.I END.
+Each line is must begin with the token
+.I samerow
+or the token
+.I item
+.LP
+It is assumed that each item appears on a row by itself unless it was
+preceded by a
+.I samerow
+line (in which case it should be displayed on the same line as the
+previous item, if possible).  Lines that begin with
+.I samerow
+should not have any other tokens on them.
+.LP
+Lines that begin with
+.I item
+must have at least three more tokens on them:  an item type, a label,
+and an attribute name.  Any extra tokens are taken as extra arguments
+and are stored in the
+.I ti_args
+member of the
+.I ldap_tmplitem
+structure.
+.LP
+The item type token must be one of the following strings:
+.I cis
+(for case ignore string attributes),
+.I mls
+(for multiline string attributes),
+.I mail
+(for RFC-822 conformant mail address attributes),
+.I dn
+(for distinguished name pointer attributes),
+.I bool
+(for Boolean attributes),
+.I jpeg
+(for JPEG photo attributes),
+.I jpegbtn
+(for a button that will retrieve and show a JPEG photo attribute),
+.I fax
+(for FAX T.4 format image attributes),
+.I faxbtn
+(for a button that will retrieve and show a FAX photo attribute),
+.I audiobtn
+(for audio attributes),
+.I time
+(for UTC time attributes),
+.I date
+(for UTC time attributes where only the date portion should be shown),
+.I url
+(for labeled Uniform Resource Locator attributes),
+.I searchact
+(to define an action that will do a directory search for other entries),
+.I linkact
+(to define an action which is a link to another display template).  See
+the ACTIONS section below for more information on search and link actions.
+.LP
+An example of an item line for the drink attribute (displayed with
+label "Favorite Beverage"):
+.nf
+.ft B
+    item cis   "Favorite Beverage"     drink
+.ft
+.fi
+.SH ACTIONS
+This section has not been written yet.  Sorry!
+.SH EXAMPLE
+The following template configuration file contains two templates, one
+for display of people entries and one for display of contries.
+.nf
+.ft B
+    #
+    # LDAP display templates
+    #
+    # Version must be 1 for now
+    #
+    Version 1
+
+    #
+    # Person template
+    "Person"
+    "People"
+
+    # name of the icon that is associated with this template
+    "person icon"
+
+    # blank-separated list of template options ("" for none)
+    "addable"
+
+    #
+    # objectclass list
+    person
+    END
+
+    #
+    # name of attribute to authenticate as ("" means auth as this entry)
+    ""
+
+    #
+    # default attribute name to use when forming RDN of a new entry
+    #
+    cn
+
+    #
+    # default location when adding new entries (DN; "" means no default)
+    "o=University of Michigan, c=US"
+
+    #
+    # rules used to define default values for new entries
+    END
+
+    #
+    # list of items for display
+    item jpegbtn       "View Photo"            jpegPhoto       "Next Photo"
+    item audiobtn      "Play Sound"            audio
+    item cis   "Also Known As"         cn
+    item cis   "Title"                 title
+    item mls   "Work Address"          postalAddress
+    item cis   "Work Phone"            telephoneNumber
+    item cis   "Fax Number"            facsimileTelephoneNumber
+    item mls   "Home Address"          homePostalAddress
+    item cis   "Home Phone"            homePhone
+    item cis   "User ID"               uid
+    item mail  "E-Mail Address"        mail
+    item cis   "Description"           description
+    item cis   "Favorite Beverage"     drink
+    item dn            "See Also"              seeAlso
+    END
+.ft
+.fi
+.SH FILES
+ETCDIR/ldaptemplates.conf
+.SH SEE ALSO
+.BR ldap (3),
+.BR ldap_disptmpl (3)
diff --git a/doc/man/man5/ldif.5 b/doc/man/man5/ldif.5
new file mode 100644 (file)
index 0000000..3eaba3b
--- /dev/null
@@ -0,0 +1,107 @@
+.TH LDIF 5  "13 November 1995" "U-M LDAP LDVERSION"
+.SH NAME
+ldif \- LDAP Data Interchange Format
+.SH DESCRIPTION
+The LDAP Data Interchange Format (LDIF) is used to represent LDAP
+entries in text form. The
+.BR ldif2ldbm (8)
+tools can be used to convert from LDIF format to the LDBM format
+used by
+.BR slapd (8).
+The
+.BR ldbmcat (8)
+tool can be used to do the reverse conversion. See "The SLAPD and
+SLURPD Administrator's Guide" for more information on this format and
+the conversion tools.
+.LP
+The basic form of an LDIF entry is:
+.LP
+.nf
+.ft tt
+       [<id>]
+       dn: <distinguished name>
+       <attrtype>: <attrvalue>
+       <attrtype>: <attrvalue>
+       ...
+.ft
+.fi
+.LP
+where <id> is the optional entry ID (a positive decimal number).
+Normally, you would not supply the <id>, allowing the database creation
+tools to do that for you. The
+.BR ldbmcat (8)
+program, however, produces an LDIF format that includes <id> so that
+new indexes created will be consistent with the existing database.  A
+line may be continued by starting the next line with a single space or
+tab character, e.g.,
+.LP
+.nf
+.ft tt
+       dn: cn=Barbara J Jensen, o=University of Michi
+        gan, c=US
+.ft
+.fi
+.LP
+Multiple attribute values are specified on separate lines, e.g.,
+.LP
+.nf
+.ft tt
+       cn: Barbara J Jensen
+       cn: Babs Jensen
+.ft
+.fi
+.LP
+If an <attrvalue> contains a non-printing character, or begins with a
+space or a colon ':', the <attrtype> is followed by a double colon and
+the value is encoded in base 64 notation. e.g., the value " begins with
+a space" would be encoded like this:
+.LP
+.nf
+.ft tt
+       cn:: IGJlZ2lucyB3aXRoIGEgc3BhY2U=
+.ft
+.fi
+.LP
+Multiple entries within the same LDIF file are separated by blank
+lines.
+.SH EXAMPLE
+Here is an example of an LDIF file containing three entries.
+.LP
+.nf
+.ft tt
+       dn: cn=Barbara J Jensen, o=University of Michi
+        gan, c=US
+       cn: Barbara J Jensen
+       cn: Babs Jensen
+       objectclass: person
+       sn: Jensen
+
+       dn: cn=Bjorn J Jensen, o=University of Michi
+        gan, c=US
+       cn: Bjorn J Jensen
+       cn: Bjorn Jensen
+       objectclass: person
+       sn: Jensen
+
+       dn: cn=Jennifer J Jensen, o=University of Michi
+        gan, c=US
+       cn: Jennifer J Jensen
+       cn: Jennifer Jensen
+       objectclass: person
+       sn: Jensen
+       jpegPhoto:: /9j/4AAQSkZJRgABAAAAAQABAAD/2wBDABALD
+        A4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQ
+        ERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVG
+       ...
+.ft
+.fi
+.LP
+Notice that the jpegPhoto in Jennifer Jensen's entry is encoded using
+base 64.
+.SH SEE ALSO
+.BR ldap (3),
+.BR slapd (8),
+.BR ldif2ldbm (8),
+.BR ldbmcat (8)
+.LP
+"The SLAPD and SLURPD Administrator's Guide"
diff --git a/doc/man/man5/slapd.conf.5 b/doc/man/man5/slapd.conf.5
new file mode 100644 (file)
index 0000000..e0e6249
--- /dev/null
@@ -0,0 +1,340 @@
+.TH SLAPD.CONF 5  "13 November 1995" "U-M LDAP LDVERSION"
+.SH NAME
+slapd.conf \- configuration file for slapd, the stand-alone LDAP daemon
+.SH SYNOPSIS
+ETCDIR/slapd.conf
+.SH DESCRIPTION
+The file
+.B ETCDIR/slapd.conf
+contains configuration information for the
+.BR slapd (8)
+daemon.  This configuration file is also used by the
+.BR slurpd (8)
+replication daemon and by the LDBM indexing utilities
+.BR ldif2ldbm (8),
+.BR ldif2index (8),
+.BR ldif2id2entry (8),
+and
+.BR ldif2id2children (8).
+.LP
+The
+.B slapd.conf
+file consists of a series of global configuration options that apply to
+.B slapd
+as a whole (including all backends), followed by zero or more database
+backend definitions that contain information specific to a backend
+instance.
+.LP
+The general format of
+.B slapd.conf
+is as follows:
+.LP
+.nf
+    # comment - these options apply to every database
+    <global configuration options>
+    # first database definition & configuration options
+    database   <backend 1 type>
+    <configuration options specific to backend 1>
+    # subsequent database definitions & configuration options
+    ...
+.fi
+.LP
+As many backend-specific sections as desired may be included.  Global
+options can be overridden in a backend (for options that appear more
+than once, the last appearance in the
+.B slapd.conf
+file is used).  Blank lines and comment lines beginning with a `#'
+character are ignored. If a line begins with white space, it is
+considered a continuation of the previous line.
+.LP
+Arguments on configuration lines are separated by white space. If an
+argument contains white space, the argument should be enclosed in
+double quotes.  If an argument contains a double quote (`"') or a
+backslash character (`\\'), the character should be preceded by a
+backslash character.
+.LP
+The specific configuration options available are discussed below in the
+Global Configuration Options, General Backend Options, LDBM
+Backend-Specific Options, Shell Backend-Specific Options, and Password
+Backend-Specific Options sections.  Refer to "The SLAPD and SLURPD
+Administrator's Guide" for more details on the slapd configuration
+file.
+.SH GLOBAL CONFIGURATION OPTIONS
+Options described in this section apply to all backends, unless specifically 
+overridden in a backend definition. Arguments that should be replaced by 
+actual text are shown in brackets <>.
+.TP
+.B
+access to <what> [ by <who> <accesslevel> ]+
+Grant access (specified by <accesslevel>) to a set of entries and/or
+attributes (specified by <what>) by one or more requestors (specified
+by <who>).  Refer to "The SLAPD and SLURPD Administrator's Guide" for
+information on using the
+.B slapd
+access-control mechanisms.
+.TP
+.B
+attribute <name> [<name2>] { bin | ces | cis | tel | dn }
+Associate a syntax with an attribute name. By default, an 
+attribute is assumed to have syntax
+.BR cis .
+An optional alternate name can be 
+given for an attribute. The possible syntaxes and their meanings are:
+.RS
+.RS
+.PD 0
+.TP
+.B bin
+binary
+.TP
+.B ces
+case exact string
+.TP
+.B cis
+case ignore string
+.TP
+.B tel
+telephone number string
+.TP
+.B dn
+distinguished name
+.PD
+.RE
+.RE
+.TP
+.B
+defaultaccess { none | compare | search | read | write | delete }
+Specify the default access to grant requestors not matched by 
+any other access line.  The default behavior is to grant read access.
+.TP
+.B include <filename>
+Read additional configuration information from the given file before
+continuing with the next line of the current file.
+.TP
+.B loglevel <integer>
+Specify the level at which debugging statements and operation 
+statistics should be syslogged (currently logged to the
+.BR syslogd (8) 
+LOG_LOCAL4 facility).  Log levels are additive, and available levels
+are:
+.RS
+.RS
+.PD 0
+.TP
+.B 1
+trace function calls
+.TP
+.B 2
+debug packet handling
+.TP
+.B 4
+heavy trace debugging
+.TP
+.B 8
+connection management
+.TP
+.B 16
+print out packets sent and received
+.TP
+.B 32
+search filter processing
+.TP
+.B 64
+configuration file processing
+.TP
+.B 128
+access control list processing
+.TP
+.B 256
+stats log connections/operations/results
+.TP
+.B 512
+stats log entries sent
+.TP
+.B 1024
+print communication with shell backends
+.TP
+.B 2048
+entry parsing
+.PD
+.RE
+.RE
+.TP
+.B
+objectclass <name> requires <attrs> allows <attrs>
+Define the schema rules for the object class named <name>.  These are
+used in conjunction with the schemacheck option.
+.TP
+.B referral <url>
+Specify the referral to pass back when
+.BR slapd (8)
+cannot find a local database to handle a request.
+.TP
+.B schemacheck { on | off }
+Turn schema checking on or off. The default is off.
+.TP
+.B sizelimit <integer>
+Specify the maximum number of entries to return from a search operation.
+The default size limit is 500.
+.TP
+.B srvtab <filename>
+Specify the srvtab file in which the kerberos keys necessary for
+authenticating clients using kerberos can be found. This option is only
+meaningful if you are using Kerberos authentication.
+.TP
+.B timelimit <integer>
+Specify the maximum number of seconds (in real time)
+.B slapd
+will spend answering a search request.  The default time limit is 3600.
+.SH GENERAL BACKEND OPTIONS
+Options in this section only apply to the configuration file section
+for the backend in which they are defined.  They are supported by every
+type of backend.
+.TP
+.B database <databasetype>
+Mark the beginning of a new database instance definition. <databasetype>
+should be one of
+.B ldbm,
+.B shell,
+or
+.B passwd
+depending on which backend will serve the database.
+.TP
+.B lastmod on | off
+Controls whether
+.B slapd
+will automatically maintain the 
+modifiersName, modifyTimestamp, creatorsName, and 
+createTimestamp attributes for entries.  By default, lastmod is off.
+.TP
+.B readonly on | off
+This option puts the database into "read-only" mode.  Any attempts to 
+modify the database will return an "unwilling to perform" error.  By
+default, readonly is off.
+.TP
+.B
+replica host=<hostname>[:port] "binddn=<DN>" bindmethod=simple |
+.B
+kerberos [credentials=<password>] [srvtab=<filename>]
+.br
+Specify a replication site for this database.  Refer to "The SLAPD and
+SLURPD Administrator's Guide" for detailed information on setting up
+a replicated
+.B slapd
+directory service.
+.TP
+.B replogfile <filename>
+Specify the name of the replication log file to log changes to.  
+The replication log is typically written by
+.BR slapd (8)
+and read by
+.BR slurpd (8).
+See
+.BR slapd.replog (5)
+for more information.
+.TP
+.B rootdn <dn>
+Specify the DN of an entry that is not subject to access control 
+or administrative limit restrictions for operations on this database.
+.TP
+.B rootpw <password>
+Specify a password for the rootdn.
+.TP
+.B suffix <dn suffix>
+Specify the DN suffix of queries that will be passed to this 
+backend database.  Multiple suffix lines can be given and at least one is 
+required for each database definition.
+.TP
+.B updatedn <dn>
+This option is only applicable in a slave
+.B slapd.
+It specifies the DN allowed to make changes to the replica (typically,
+this is the DN
+.BR slurpd (8)
+binds as when making changes to the replica).
+.SH LDBM BACKEND-SPECIFIC OPTIONS
+Options in this category only apply to the LDBM backend database. That is,
+they must follow a "database ldbm" line and come before any subsequent
+"database" lines.  The LDBM backend is a high-performance database that
+makes extensive use of indexing and caching to speed data access. 
+.TP
+.B cachesize <integer>
+Specify the size in entries of the in-memory cache maintained 
+by the LDBM backend database instance.  The default is 1000 entries.
+.TP
+.B dbcachesize <integer>
+Specify the size in bytes of the in-memory cache associated 
+with each open index file. If not supported by the underlying database 
+method, this option is ignored without comment.  The default is 100000 bytes.
+.TP
+.B directory <directory>
+Specify the directory where the LDBM files containing the database and
+associated indexes live.  The default is
+.B /usr/tmp.
+.TP
+.B
+index { <attrlist> | default } [ pres,eq,approx,sub,none ]
+Specify the indexes to maintain for the given attribute. If only 
+an <attr> is given, all possible indexes are maintained.
+.TP
+.B mode <integer>
+Specify the file protection mode that newly created database 
+index files should have.  The default is 0600.
+.SH SHELL BACKEND-SPECIFIC OPTIONS
+Options in this category only apply to the SHELL backend database. That is,
+they must follow a "database shell" line and come before any subsequent
+"database" lines.  The Shell backend executes external programs to
+implement operations, and is designed to make it easy to tie an existing
+database to the
+.B slapd
+front-end.
+.TP
+.B bind <pathname>
+.TP
+.B unbind <pathname>
+.TP
+.B search <pathname>
+.TP
+.B compare <pathname>
+.TP
+.B modify <pathname>
+.TP
+.B modrdn <pathname>
+.TP
+.B add <pathname>
+.TP
+.B delete <pathname>
+.TP
+.B abandon <pathname>
+These options specify the pathname of the command to execute in response 
+to the given LDAP operation. The command given should understand and 
+follow the input/output conventions described in Appendix B of "The SLAPD
+and SLURPD Administrator's Guide."
+.LP
+Note that you need only supply configuration lines for those commands you
+want the backend to handle. Operations for which a command is not
+supplied will be refused with an "unwilling to perform" error.
+.SH PASSWORD BACKEND-SPECIFIC OPTIONS
+Options in this category only apply to the PASSWD backend database.
+That is, they must follow a "database passwd" line and come before any
+subsequent "database" lines.  The PASSWD database serves up the user
+account information listed in the system
+.BR passwd (5)
+file.
+.TP
+.B file <filename>
+Specifies an alternate passwd file to use.  The default is
+.B /etc/passwd.
+.SH EXAMPLE
+"The SLAPD and SLURPD Administrator's Guide" contains an annotated
+example of a configuration file.
+.SH FILES
+ETCDIR/slapd.conf
+.SH SEE ALSO
+.BR ldap (3),
+.BR slapd.replog (5),
+.BR passwd (5),
+.BR slapd (8),
+.BR slurpd (8),
+.LP
+"The SLAPD and SLURPD Administrator's Guide"
diff --git a/doc/man/man5/slapd.replog.5 b/doc/man/man5/slapd.replog.5
new file mode 100644 (file)
index 0000000..83d0cc6
--- /dev/null
@@ -0,0 +1,158 @@
+.TH SLAPD.REPLOG 5  "11 April 1995" "U-M LDAP LDVERSION"
+.SH NAME
+slapd.replog \- slapd replication log format
+.SH SYNOPSIS
+slapd.replog
+slapd.replog.lock
+.SH DESCRIPTION
+.LP
+The file slapd.replog is produced by the stand-alone LDAP daemon,
+.IR slapd ,
+when changes are made to its local database that are to be
+propagated to one or more replica
+.IR slapd s.
+The file consists of
+zero or more records, each one corresponding to a change, addition,
+or deletion from the
+.I slapd
+database.  The file is meant to be read
+and processed by
+.IR slurpd ,
+the stand-alone LDAP update replication daemon.  The records are
+separated by a blank line.  Each record has the following format.
+.LP
+The record begins with one or more lines indicating the replicas
+to which the change is to be propagated:
+.LP
+.nf
+       replica: <hostname[:portnumber]>
+.fi
+.LP
+Next, the time the change took place given, as the number of seconds since
+00:00:00 GMT, Jan. 1, 1970, with an optional decimal extension, in order
+to make times unique.  Note that slapd does not make times unique, but
+slurpd makes all times unique in its copies of the replog files.
+.LP
+.nf
+       time: <integer[.integer]>
+.fi
+.LP
+Next, the distinguished name of the entry being changed is given:
+.LP
+.nf
+       dn: <distinguishedname>
+.fi
+.LP
+Next, the type of change being made is given:
+.LP
+.nf
+       changetype: <[modify|add|delete|modrdn]>
+.fi
+.LP
+Finally, the change information itself is given, the format of which
+depends on what kind of change was specified above.  For a \fIchangetype\fP
+of \fImodify\fP, the format is one or more of the following:
+.LP
+.nf
+       add: <attributetype>
+       <attributetype>: <value1>
+       <attributetype>: <value2>
+       ...
+       -
+.fi
+.LP
+Or, for a replace modification:
+.LP
+.nf
+       replace: <attributetype>
+       <attributetype>: <value1>
+       <attributetype>: <value2>
+       ...
+       -
+.fi
+.LP
+Or, for a delete modification:
+.LP
+.nf
+       delete: <attributetype>
+       <attributetype>: <value1>
+       <attributetype>: <value2>
+       ...
+       -
+.fi
+.LP
+If no \fIattributetype\fP lines are given, the entire attribute is to be
+deleted.
+.LP
+For a \fIchangetype\fP of \fIadd\fP, the format is:
+.LP
+.nf
+       <attributetype1>: <value1>
+       <attributetype1>: <value2>
+       ...
+       <attributetypeN>: <value1>
+       <attributetypeN>: <value2>
+.fi
+.LP
+For a \fIchangetype\fP of \fImodrdn\fP, the format is:
+.LP
+.nf
+       newrdn: <newrdn>
+       deleteoldrdn: 0 | 1
+.fi
+.LP
+where a value of 1 for deleteoldrdn means to delete the values
+forming the old rdn from the entry, and a value of 0 means to
+leave the values as non-distinguished attributes in the entry.
+.LP
+For a \fIchangetype\fP of \fIdelete\fP, no additional information
+is needed in the record.
+.LP
+The format of the values is the LDAP Directory Interchange Format
+described in
+.BR ldif (5).
+.LP
+Access to the \fIslapd.replog\fP file is synchronized through the
+use of
+.BR flock (3)
+on the file \fIslapd.replog.lock\fP.  Any process
+reading or writing this file should obey this locking convention.
+.SH EXAMPLE
+The following sample \fIslapd.replog\fP file contains information
+on one of each type of change.
+.LP
+.nf
+       replica: truelies.rs.itd.umich.edu
+       replica: judgmentday.rs.itd.umich.edu
+       time: 797612941
+       dn: cn=Babs Jensen, o=U of M, c=US
+       changetype: add
+       objectclass: person
+       cn: babs
+       cn: babs jensen
+       sn: jensen
+        
+       replica: truelies.rs.itd.umich.edu
+       replica: judgmentday.rs.itd.umich.edu
+       time: 797612973
+       dn: cn=Babs Jensen, o=U of M, c=US
+       changetype: modify
+       add: description
+       description: the fabulous babs
+        
+       replica: truelies.rs.itd.umich.edu
+       replica: judgmentday.rs.itd.umich.edu
+       time: 797613020
+       dn: cn=Babs Jensen, o=U of M, c=US
+       changetype: modrdn
+       newrdn: cn=Barbara J Jensen
+       deleteoldrdn: 0
+.fi
+.SH FILES
+slapd.replog
+slapd.replog.lock
+.SH SEE ALSO
+.BR ldap (3),
+.BR ldif (5),
+.BR slapd (8),
+.BR slurpd (8)
diff --git a/doc/man/man5/ud.conf.5 b/doc/man/man5/ud.conf.5
new file mode 100644 (file)
index 0000000..13575bf
--- /dev/null
@@ -0,0 +1,96 @@
+.TH UD.CONF 5 "18 March 1993" "U-M LDAP LDVERSION"
+.UC 6
+.SH NAME
+ud.conf \- ud configuration file
+.SH SYNOPSIS
+/etc/ud.conf
+.SH DESCRIPTION
+The
+.I ud
+configuration file is used to set system-wide defaults to be applied when
+running
+.IR ud .
+Note that each user may specify an optional configuration file,
+.IR .udrc ,
+in his/her home directory which will be used instead of the system-wide
+configuration file.
+.SH OPTIONS
+The different configuration options are:
+.TP 1i
+\fBserver <name>\fP
+Used to specify the name of an LDAP server to which 
+.I ud 
+should connect.  There may be only one entry per config file.
+The server's name can be specified as a domain-style name or an IP address.
+.TP 1i
+\fBbase <base>\fP
+Used to specify the search base to use when performing search operations.
+The base may be changed by those using
+.I ud
+by using the
+.I cb
+command.
+There may be only one entry per config file.
+The base must be specified as a Distinguished Name in LDAP format.
+.TP 1i
+\fBgroupbase <base>\fP
+Used to specify the base used when creating groups.
+The base may be changed by those using
+.I ud
+by using the 
+.I changegroup
+command.
+There may be only one entry per config file.
+The base must be specified as a Distinguished Name in LDAP format.
+.TP 1i
+\fBsearch <algorithm>\fP
+Used to specify a search algorithm to use when performing searches.  More than
+one algorithm may be specified, and each is tried in turn until a suitable
+response is found.
+
+Each algorithm specifies a filter that should be used when performing a find
+operation.  Filters contain LDAP-style attribute types (e.g., uid, cn,
+postalAddress)
+and operators to test for equality or approximate equality.  Prefix operators
+may also be used to specify AND, OR and NOT operations (see ldap(3) for
+more details on the filter format).  Algorithms use a
+compile-time constant as a separator to use when parsing the input the user
+has provided.  This parsed input can then be referenced similarly to an
+.I awk
+program using symbols like $1, $2, and $0 for the entire batch of input.
+
+For example, the algoritm
+.I cn=$0
+causes
+.I ud
+to perform a lookup on the entire string the user has typed, searching for 
+anything where the commonName exactly matches the whole thing.
+
+Another example,
+.I sn~=$NF
+causes
+.I ud
+to do a search where the last element the user has typed (NF = number of fields
+and is a special "number" that can be used in
+.I awk
+as well as
+.IR ud )
+searching for any matches that approximately match Surname.
+
+Search algorithms also support a special feature which allows one to specify
+the 
+.I exact
+number of fields that must be present in order for the algorithm to be
+applied.  This number must be specified between square brackets.
+
+For example,
+.I [1] uid=$1
+causes this algorithm to be applied when the number of fields is exactly equal
+to one.  If there is exactly one field, the token is looked up as a UID.
+.SH FILES
+.I  /etc/ud.conf
+.SH "SEE ALSO"
+ud(1),
+ldap(3)
+.SH AUTHOR
+Bryan Beecher, University of Michigan
diff --git a/doc/man/man8/Make-template b/doc/man/man8/Make-template
new file mode 100644 (file)
index 0000000..55899f5
--- /dev/null
@@ -0,0 +1,52 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1994 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP man8 makefile
+#
+#-----------------------------------------------------------------------------
+
+LDAPSRC= ../../..
+SECT=8
+INSTDIR=$(MANDIR)/man$(SECT)
+VERSIONFILE = $(LDAPSRC)/build/version
+
+all:   FORCE
+
+install:       FORCE
+       -$(MKDIR) -p $(INSTDIR)
+       @TMPMAN=/tmp/ldapman.$$$$; \
+       VERSION=`$(CAT) $(VERSIONFILE)`; \
+       for page in *.$(SECT); do \
+           $(SED) -e 's%ETCDIR%$(RUNTIMEETCDIR)%' -e "s%LDVERSION%$$VERSION%" \
+                   $$page > $$TMPMAN; \
+           echo "installing $(INSTDIR)/$$page"; \
+           $(INSTALL) $(INSTALLFLAGS) -m 644 $$TMPMAN $(INSTDIR)/$$page; \
+           if [ -f "$$page.links" ]; then \
+               for link in `$(CAT) $$page.links`; do \
+                   echo ".so man$(SECT)/$$page" > $$TMPMAN; \
+                   echo "installing $(INSTDIR)/$$link as link to $$page"; \
+                   $(INSTALL) $(INSTALLFLAGS) -m 644 $$TMPMAN \
+                           $(INSTDIR)/$$link; \
+               done; \
+           fi; \
+       done; \
+       $(RM) $$TMPMAN
+
+clean: FORCE
+
+depend:        FORCE
+
+lint:  FORCE
+
+5lint: FORCE
+
+links:
+       @$(LN) .src/*.$(SECT) .src/*links .
diff --git a/doc/man/man8/centipede.8 b/doc/man/man8/centipede.8
new file mode 100644 (file)
index 0000000..680e9b9
--- /dev/null
@@ -0,0 +1,154 @@
+.TH CENTIPEDE 8C "2 December 1995" "U-M LDAP LDVERSION"
+.SH NAME
+centipede \- LDAP centroid index generation and maintenance program
+.SH SYNOPSIS
+.B ETCDIR/centipede
+.B [\-f filter]
+.B [\-F] [\-R]
+.B [\-f filter] [\-t directory]
+.B [\-m authmethod] [\-b binddn] 
+.B [\-p passwd] [\-c cachesize]
+.B \-s sourceurl \-d desturl attributes
+.SH DESCRIPTION
+.LP
+The centipede program is used to extract centroid or other index
+information from one LDAP server and install it in another. Although
+index information can be extracted from any LDAP server, only a
+.BR slapd (8)
+LDAP server will understand the information and thus be capable of
+making use of it as indexing information (i.e., you should only
+install index information in a
+.BR slapd (8)
+LDAP server).
+.LP
+The basic form of the command is as follows
+.LP
+.nf
+.ft tt
+       ETCDIR/centipede [options]
+               -s "ldap://[host/]subtree-to-index-dn"
+               -d "ldap://[host/]parent-of-index-entry-dn"
+               attributes
+.ft
+.fi
+.LP
+where the
+.B \-s
+option specifies the subtree for which index information is to
+be generated, and the
+.B \-d
+option specifies the parent under which the index information is to
+be installed.
+.LP
+For example, suppose you are running an
+LDAP server on the host
+.I babs.com
+for an organization called "BabsCo" based in the US, and you want to
+generate index information for the cn, sn and objectclass attributes of
+all the people entries in your subtree. You want to install the index
+informatioin in the indexing
+.BR slapd (8)
+running on the host
+.I vertigo.rs.itd.umich.edu
+under the c=US entry.
+This way, when an LDAP client connects to the
+.BR slapd (8)
+on vertigo and does a subtree search of c=US,
+.BR slapd (8)
+can consult the index information to tell whether it should refer the
+client to your server or not. You could accomplish this with a command
+like this:
+.LP
+.nf
+.ft tt
+       ETCDIR/centipede -f '(objectclass=person)'
+               -m simple -b your-rootdn -p your-rootdnpw
+               -s "ldap://babs.com/o=BabsCo, c=US"
+               -d "ldap://vertigo.rs.itd.umich.edu/c=US"
+               cn sn objectclass
+.ft
+.fi
+.LP
+Note the
+.B \-b
+and
+.B \-p
+options can be used to authenticate as an entity able to read all
+the information you want.
+.LP
+See "The SLAPD and SLURPD Administrator's Guide" for more details on
+using this program.
+.SH OPTIONS
+.TP
+.B \-v
+Turn on verbose mode. This option can be given multiple times to increase
+the level of verbosity.
+.TP
+.B \-n
+Do not actually install index information. Useful in conjunction with
+.B -v
+for seeing what
+.B centipede
+is up to.
+.TP
+.BI \-f " ldapfilter"
+Specify a filter used to select the entries for which to generate indexing
+information.
+.I ldapfilter
+should be a string LDAP filter as described by RFC 1588.
+.TP
+.BI \-F
+Generate full, as opposed to relative, index information.
+.TP
+.BI \-R
+Generate relative, as opposed to full, index information. Full information
+is still generated if there is no previous information available from
+which to generate the relative information. This is the default.
+.TP
+.BI \-t " directory"
+Specify the directory in which to create temporary files, find existing
+index information, and put new index information. The default is
+whatever is used by tempnam.
+.TP
+.BI \-b " binddn"
+Specify the DN to authenticate with when extracting index information.
+.TP
+.BI \-p " passwd"
+Specify the password to use for simple authentication when extracting
+index information.
+.TP
+.BI \-m " authmethod"
+Specify the authentication method to use when extracting index information.
+.I authmethod
+should be either "simple" or "kerberos".
+.TP
+.BI \-B " binddn"
+Specify the DN to authenticate with when installing index information.
+.TP
+.BI \-P " passwd"
+Specify the password to use for simple authentication when installing
+index information.
+.TP
+.BI \-M " authmethod"
+Specify the authentication method to use when installing index information.
+.I authmethod
+should be either "simple" or "kerberos".
+.TP
+.BI \-c " cachesize"
+Specify the size in bytes of the cache used when building the new
+index information. Upping this number can cause a big performance boost,
+if you've got the memory for it.
+.SH NOTES
+This is all very experimental at the moment, and is subject to change.
+.LP
+Currently,
+.B centipede
+only handles value-based index information. A future version of centipede
+will allow other types of index information to be manipulated (e.g.,
+word-based indexes, substring indexes, phonetic indexes, hash indexes,
+etc.). A future version may also allow weights to be generated.
+.SH "SEE ALSO"
+.BR ldap (3),
+.BR slapd (8)
+.LP
+"The SLAPD and SLURPD Administrator's Guide"
diff --git a/doc/man/man8/chlog2replog.8 b/doc/man/man8/chlog2replog.8
new file mode 100644 (file)
index 0000000..e99dfd8
--- /dev/null
@@ -0,0 +1,102 @@
+.TH CHLOG2REPLOG 8C "26 April 1996" "U-M LDAP LDVERSION"
+.SH NAME
+chlog2replog \- convert an X.500 DSA-style changelog to an LDAP-style
+replication log
+.SH SYNOPSIS
+.B ETCDIR/chlog2replog
+.B \-r hostname:port [\-r hostname:port ...]
+.B \-d dn\-suffix [\-o output\-file] < input\-file
+.LP
+.SH DESCRIPTION
+.LP
+chlog2replog is used to convert an X.500\-style changelog to an
+LDAP\-style replication log.  It reads its standard input and
+writes standard output if no \-o flag is given.  If the \-o flag
+is given,
+.B chlog2replog
+writes its output to the given file, following
+the same advisory locking mechanisms respected by the
+.B slurpd
+program.  This makes it possible to use chlog2replog in a pipeline
+to produce input for
+.B slurpd.
+
+.SH OPTIONS
+.TP
+.BI \-r " hostname:port"
+This option specifies the hostname and port number to which updates
+should be propagated. 
+.B chlog2replog
+will include one "replica: hostname:port" directive in each replication
+log entry it writes out for each
+.B \-r
+option given.  You may supply as many replica hostname:port options as
+you wish.
+.TP
+.BI \-d " dn\-suffix"
+This option specifies an additional string to append to converted
+DNs (Distinguished Names) converted from the changelog file.  The
+DNs in the changelog file will typically be partial DNs which omit
+the portion of the directory tree "above" the organizational root.
+For example, if your directory tree is rooted at o=University of
+Michigan, c=US, you will need to include the argument
+"\-d ", o=University of Michigan, c=US".
+.TP
+.BI \-o " output\-file"
+If given, this option specifies an output file to which converted
+replication log entries will be written.
+.B chlog2replog
+obeys the same file locking conventions used by
+.B slurpd,
+so that it is possible to use
+.B chlog2replog
+to "feed" changes from an X.500 DSA to
+.B slurpd.  See the
+.B examples
+section, below, for more information.
+.SH EXAMPLES
+To read the DSA-style changelog file
+.BR changlelog
+and write on the standard output an LDAP-style replication log,
+appending ", o=University of Michigan, c=US" to all entry
+DNs, and including a replica: entry for host "ldapserver," port
+389, give the command:
+.LP
+.nf
+.ft tt
+       ETCDIR/chlog2replog -d ", o=University of Michigan, c=US"
+       -r ldapserver:389 < changelog
+.ft
+.fi
+.LP
+To do the same, but routing the output to the file "replog," using
+slurpd\-compatible file\-locking,
+give this command:
+.LP
+.nf
+.ft tt
+       ETCDIR/chlog2replog -d ", o=University of Michigan, c=US"
+       -r ldapserver:389 -o replog < changelog
+.ft
+.fi
+.LP
+To continually read new changes from the file "changelog" and write
+them to the file "replog",
+give this command:
+.LP
+.nf
+.ft tt
+       tail +0f changelog  | ETCDIR/chlog2replog
+       -d ", o=University of Michigan, c=US"
+       -r ldapserver:389 -o replog < changelog
+.ft
+.fi
+
+.LP
+.SH "SEE ALSO"
+.BR ldap (3),
+.BR ldif (5),
+.BR slurpd (8),
+.BR slapd (8),
+.LP
+"The SLAPD and SLURPD Administrator's Guide"
diff --git a/doc/man/man8/edb2ldif.8 b/doc/man/man8/edb2ldif.8
new file mode 100644 (file)
index 0000000..15c066f
--- /dev/null
@@ -0,0 +1,99 @@
+.TH EDB2LDIF 8C "12 November 1995" "U-M LDAP LDVERSION"
+.SH NAME
+edb2ldif \- QUIPU EDB file to LDIF conversion tool
+.SH SYNOPSIS
+.B ETCDIR/edb2ldif
+.B [\-d] [\-v] [\-r] [\-o] [\-b basedn]
+.B [\-a addvalsfile] [\-f fileattrdir]
+.B [\-i ignoreattr...] [edbfile...]
+.B 
+.SH DESCRIPTION
+.LP
+Data that is held in a QUIPU DSA (available as part of the ISODE package)
+is stored in or can be easily converted to the EDB file format.  The
+.I edb2ldif
+tool is used to convert directory data from EDB file format to the
+LDAP Directory Interchange Format (LDIF) used by
+.BR slapd (8)
+and associated utilities.  The
+.BR ldif2ldbm (8)
+program can be used to convert the resulting LDIF data into a database
+that is compatible with
+.BR slapd (8).
+.LP
+.I edb2ldif
+writes LDIF formatted data to standard output.  If you specify a particular
+.I edbfile
+(or files) to read data from, they are converted.  If no
+.I edbfile
+is specified, the files named
+.BR EDB.root
+(if it exists) and
+.BR EDB
+in the current directory are converted. An entire EDB hierarchy
+can be converted using the
+.B \-r
+option.
+.LP
+When
+.I edb2ldif
+is invoked, it will also look for files named
+.BR .add
+in the directories
+where EDB files are found and append the contents of the
+.BR .add
+file to each entry in the corresponding EDB file. 
+Typically, this feature is used to include inherited
+attribute values (e.g., objectClass) that do not appear in the EDB files.
+.LP
+See "The SLAPD and SLURPD Administrator's Guide" for more details on
+using
+.I edb2ldif,
+including step-by-step conversion instructions.
+.SH OPTIONS
+.TP
+.B \-d
+Turn on some extra debugging which is written to standard error.
+.TP
+.B \-v
+Enable verbose mode that writes status information to standard error, such
+as which EDB file is being processed, how many entries have been
+converted so far, etc.
+.TP
+.B \-r
+Recurse through child directories, processing all EDB files found.
+.TP
+.B \-o
+Cause local
+.B .add
+file definitions to override the global addfile (see the
+.B \-a
+option below)
+.TP
+.BI \-b " basedn"
+Specify the Distinguished Name that all EDB file entries appear below.
+.TP
+.B \-a " addvalsfile"
+The LDIF information contained in this file will be appended to each entry.
+(See the
+.B \-o
+option above.)
+.TP
+.BI \-f " fileattrdir"
+Specify a single directory where all file-based attributes (typically sounds
+and images) can be found.  If this option is not given, file attributes are
+assumed to be located in the same directory as the EDB file that refers to
+them.
+.TP
+.BI \-i " ignoreattr"
+Specify an attribute that should not be converted.  You can include as many
+\- i flags as necessary.
+.SH "SEE ALSO"
+.BR ldap (3),
+.BR ldif (5),
+.BR slapd (8),
+.BR ldif2ldbm (8)
+.LP
+"The SLAPD and SLURPD Administrator's Guide"
+.LP
+Volume 5 of The ISODE Manual
diff --git a/doc/man/man8/go500.8 b/doc/man/man8/go500.8
new file mode 100644 (file)
index 0000000..6fbbf8f
--- /dev/null
@@ -0,0 +1,170 @@
+.TH GO500 8C "27 November 1994" "U-M LDAP LDVERSION"
+.SH NAME
+go500 \- Local Gopher index search to X.500 search gateway
+.SH SYNOPSIS
+.B ETCDIR/go500 [\-b searchbase] [\-d level] [\-l]
+.B [\-x hostname] [\-c rdncount] [\-f filterfile]
+.B [\-t templatefile]
+.B [\-p port] [\-I]
+.SH DESCRIPTION
+.I go500
+is the local gopher index search to X.500 search daemon.
+It looks like a gopher index server to a gopher
+client, translating the search criteria it is given into a
+search of a pre-configured portion of the X.500 directory.
+It uses LDAP to talk to X.500.  By default, it listens on
+port 5555 for connections from gopher clients.
+.LP
+The
+.B go500
+server can be run either from
+.BR inetd (8)
+or as stand-alone server.
+.SH STAND-ALONE OPERATION
+To start
+.B go500
+as a stand-alone server, simply start it with no arguments
+.LP
+.nf
+.ft tt
+       ETCDIR/go500
+.ft
+.fi
+.LP
+If you would like to start it at boot time add some lines like this to
+the
+.B etc/rc.local
+or equivalent file:
+.LP
+.nf
+.ft tt
+       if [ -f ETCDIR/go500 ]; then
+               ETCDIR/go500; echo ' go500'
+       fi
+.ft
+.fi
+.SH OPERATION WITH INETD
+To arrange to have
+.B go500
+started from
+.BR inetd (8),
+the Internet protocol
+daemon, add a line like the following to your
+.B /etc/services
+file, or the equivalent:
+.LP
+.nf
+.ft tt
+    go500           5555/tcp        go500
+.ft
+.fi
+.LP
+Next, add a line like this to your
+.B /etc/inetd.conf
+file, or the equivalent:
+.LP
+.nf
+.ft tt
+    go500   stream  tcp     nowait  nobody  ETCDIR/go500    go500 -I
+.ft
+.fi
+.LP
+For these changes to take effect with inetd, you will probably have
+to send it it a HUP signal.  See
+.BR inetd (8)
+for more details.
+.SH GOPHER CONFIGURATION
+The next step is to configure your local gopher server to have an
+entry for
+.BR go500 .
+With the standard unix gopher server, this
+can be done with a
+.B .link
+file.
+A sample
+.B .link
+file is given below, with the things you should
+change given in <>'s:
+.LP
+.nf
+.ft tt
+       Name=<Label of your choice>
+       Type=7
+       Port=5555
+       Path=
+       Host=<host.running.go500.here>
+.ft
+.fi
+.LP
+You may also have to restart your gopher daemon, or remove the
+.B .cache
+file.
+See
+.BR gopherd (8)
+for more details.
+.SH OPTIONS
+.TP
+.BI \-b " searchbase"
+Specify an alternate starting point for searches.  The argument should
+be a Distinguished Name in the form defined by RFC 1485.  For example,
+the DN "o=University of Michigan, c=US" could be given to search the
+University of Michigan portion of the X.500 tree.
+.TP
+.BI \-d " level"
+Turn on debugging as defined by
+.I level.
+If this option is specified,
+.B go500
+will not fork or disassociate from the invoking terminal.  Some general
+operation and status messages are printed for any value of \fIlevel\fP.
+\fIlevel\fP is taken as a bit string, with each bit corresponding to a
+different kind of debugging information.
+.TP
+.BI \-f " filterfile"
+Specify an alternate filter configuration file for use with the
+.BR ldap_getfilter (3)
+facility, used by
+.BR go500 .
+.TP
+.B \-l
+Enable logging of various status and errors to the LOG_LOCAL3 facility via
+syslog(8).
+.TP
+.BI \-p " port"
+Specify an alternate port on which to listen for connections.
+.TP
+.BI \-t " templatefile"
+Specify an alternate template  configuration  file  for
+use  with  the
+.BR ldap_init_templates (3)
+facility, used by
+.BR go500 .
+.TP
+.BI \-c " rdncount"
+Specify the number of DN components to show for the names and DN attributes
+within entries matching the search.
+.TP
+.BI \-x " hostname"
+Specify an alternate host on which the ldap server is running.
+.TP
+.B \-I
+Run from
+.BR inetd (8).
+.SH NOTES
+Some implementations of inetd have a small limit on the number of arguments
+that can be specified in the
+.BR /etc/inetd.conf (5)
+file.  This can cause
+problems if you are using
+.B go500
+with a lot of arguments.
+.LP
+The default values for most of the things you can specify with
+options are configured at compile time in the
+.B include/ldapconfig.h.edit
+include file.
+.SH "SEE ALSO"
+.BR ldap (3),
+.BR inetd (8),
+.BR gopherd (8),
+.BR go500gw (8)
diff --git a/doc/man/man8/go500gw.8 b/doc/man/man8/go500gw.8
new file mode 100644 (file)
index 0000000..4464a88
--- /dev/null
@@ -0,0 +1,170 @@
+.TH GO500GW 8C "27 November 1994" "U-M LDAP LDVERSION"
+.SH NAME
+go500gw \- General Gopher to X.500 gateway for browsing and searching
+.SH SYNOPSIS
+.B ETCDIR/go500gw [\-a] [\-d level] [\-f filterfile]
+.B [\-t templatefile] [\-c rdncount]
+.B [\-h helpfile] [\-l] [\-p listenport]
+.B [\-P ldapport] [\-x ldaphost] [\-I]
+.SH DESCRIPTION
+.B go500gw
+is the general gopher to X.500 browsing and search gateway daemon.
+It speaks gopher on one side and X.500 (via LDAP)
+on the other.  It presents the X.500 DIT as a tree of menus,
+search items, and documents in gopher space, supporting both
+browsing and searching of X.500 via a gopher client.  By default,
+it listens on port 7777 for connections from gopher clients.
+.LP
+The
+.B go500gw
+server can be run either from
+.BR inetd (8)
+or as stand-alone server.
+.SH STAND-ALONE OPERATION
+To start
+.B go500gw
+as a stand-alone server, simply start it with no arguments
+.LP
+.nf
+.ft tt
+       ETCDIR/go500gw
+.ft
+.fi
+.LP
+If you would like to start it at boot time add some lines like this to
+the
+.BR /etc/rc.local (5)
+or equivalent file:
+.LP
+.nf
+.ft tt
+       if [ -f ETCDIR/go500gw ]; then
+               ETCDIR/go500gw; echo ' go500gw'
+       fi
+.ft
+.fi
+.SH OPERATION WITH INETD
+To arrange to have
+.B go500gw
+started from
+.BR inetd (8), the Internet protocol
+daemon, add a line like the following to your
+.BR /etc/services (5)
+file, or the equivalent:
+.LP
+.nf
+.ft tt
+    go500gw           7777/tcp        go500gw
+.ft
+.fi
+.LP
+Next, add a line like this to your
+.BR /etc/inetd.conf (5)
+file, or the equivalent:
+.LP
+.nf
+.ft tt
+    go500gw  stream  tcp  nowait  nobody  ETCDIR/go500gw    go500gw -I
+.ft
+.fi
+.LP
+For these changes to take effect with inetd, you will probably have
+to send it it a HUP signal.  See
+.BR inetd (8)
+for more details.
+.SH GOPHER CONFIGURATION
+The next step is to configure your local gopher server to have an
+entry for
+.BR go500gw .
+With the standard unix gopher server, this
+can be done with a
+.B .link
+file.  A sample
+.B .link
+file is given below, with the things you should change given in <>'s:
+.LP
+.nf
+.ft tt
+       Name=<Label of your choice>
+       Type=1
+       Port=7777
+       Path=1<optional RFC 1779-format DN at which to start browsing>
+       Host=<host.running.go500gw.here>
+.ft
+.fi
+.LP
+You may also have to restart your gopher daemon, or remove the
+.B .cache
+file.
+.SH OPTIONS
+.TP
+.B \-a
+Search aliases when doing LDAP searches.  The default is not to
+search aliases.
+.TP
+.BI \-d " level"
+Turn on debugging as defined by
+.I level.
+If this option is specified,
+.B go500gw
+will not fork or disassociate from the invoking terminal.  Some general
+operation and status messages are printed for any value of \fIlevel\fP.
+\fIlevel\fP is taken as a bit string, with each bit corresponding to a
+different kind of debugging information.
+.TP
+.BI \-f " filterfile"
+Specify an alternate filter configuration file for use with the
+.BR ldap_getfilter (3)
+facility, used by
+.BR go500gw .
+.TP
+.BI \-h " helpfile"
+Specify an alternate help file.  The help file is what is displayed
+in the "About the Gopher to X.500 Gateway" menu item.
+.TP
+.B \-l
+Enable logging of various status and errors to the LOG_LOCAL3 facility via
+.BR syslog (8).
+.TP
+.BI \-p " listenport"
+Specify an alternate port on which to listen for connections.
+.TP
+.BI \-P " ldapport"
+Specify an alternate port on which to contact the LDAP server.
+.TP
+.BI \-t " templatefile"
+Specify an alternate template  configuration  file  for
+use  with  the
+.BI ldap_init_templates (3)
+facility, used by
+.B go500gw .
+.TP
+.BI \-c " rdncount"
+Specify the number of DN components to show for the names and DN attributes
+within entries matching the search.
+.TP
+.BI \-x " hostname"
+Specify an alternate host on which the ldap server is running.
+.TP
+.B \-I
+Run from
+.BR inetd (8).
+.SH NOTES
+Some implementations of inetd have a small limit on the number of arguments
+that can be specified in the
+.BR /etc/inetd.conf (5)
+file.  This can cause
+problems if you are using
+.B go500gw
+with a lot of arguments.
+.LP
+The default values for most of the things you can specify with
+options are configured at compile time in the
+.B include/ldapconfig.h.edit
+include file.
+.SH "SEE ALSO"
+.BR ldap (3),
+.BR ldap_getfilter (3),
+.BR inetd (8),
+.BR gopherd (8),
+.BR go500 (8)
diff --git a/doc/man/man8/in.xfingerd.8 b/doc/man/man8/in.xfingerd.8
new file mode 100644 (file)
index 0000000..a2cf788
--- /dev/null
@@ -0,0 +1,79 @@
+.TH IN.XFINGERD 8C "27 November 1994" "U-M LDAP LDVERSION"
+.SH NAME
+in.xfingerd \- Finger to LDAP/X.500 gateway daemon
+.SH SYNOPSIS
+.B ETCDIR/in.xfingerd [\-f filterfile] [\-i]
+.B [\-l] [\-t templatefile] [\-c rdncount] [\-x hostname]
+.B [\-p port]
+.SH DESCRIPTION
+.B in.xfingerd
+is the LDAP/X.500 finger daemon.  It runs from
+.BR inetd (8)
+and translates
+finger queries into LDAP queries or X.500 queries via LDAP.
+It also understands
+UFN-style names, so fingering something like "tim howes,umich,us@hostname"
+will do a UFN search.
+.LP
+To arrange to have in.xfingerd started from inetd
+add a line like this to your
+.BR /etc/inetd.conf (5)
+file, or the equivalent:
+.LP
+.nf
+.ft tt
+    finger stream tcp nowait nobody ETCDIR/in.xfingerd in.xfingerd
+.ft
+.fi
+.LP
+For these changes to take effect with inetd, you will probably have
+to send it it a HUP signal.  See
+.BR inetd (8)
+for more details.
+.SH OPTIONS
+.TP
+.BI \-f " filterfile"
+Specify an alternate filter configuration file for use with the
+.BR ldap_getfilter (3)
+facility, used by
+.BR in.xfingerd .
+.TP
+.B \-i
+Run in interactive mode.  With this flag in.xfingerd can be
+run from a terminal in "one shot" mode, reading the finger
+request from standard input.  This is useful for debugging.
+.TP
+.B \-l
+Disable logging of various status and errors to the LOG_LOCAL4 facility via
+.BR syslog (8).
+Note that this flag turns OFF logging.  The default is on.
+.TP
+.BI \-t " templatefile"
+Specify an alternate template configuration file for use with the
+.BR ldap_init_templates (3)
+facility, used by
+BR in.xfingerd .
+.TP
+.BI \-c " rdncount"
+Specify the number of DN components to show for the names and DN attributes
+within entries matching the search.
+.TP
+.BI \-x " hostname"
+Specify an alternate host on which the ldap server is running.
+.TP
+.BI \-p " port"
+Specify an alternate port on which the ldap server is listening.
+.SH NOTES
+The default values for most of the things you can specify with
+options are configured at compile time in the
+.B include/ldapconfig.h.edit
+include file.  Also included there are various messages displayed
+by the finger daemon when finding no matches, encountering errors, etc.
+You should configure
+.B ldapconfig.h.edit
+for your site.
+.SH "SEE ALSO"
+.BR finger (1)
+.BR ldap (3),
+.BR ldap_getfilter (3),
+.BR inetd (8),
diff --git a/doc/man/man8/ldapd.8 b/doc/man/man8/ldapd.8
new file mode 100644 (file)
index 0000000..d771093
--- /dev/null
@@ -0,0 +1,127 @@
+.TH LDAPD 8C "15 June 1992" "U-M LDAP LDVERSION"
+.SH NAME
+ldapd \- LDAP X.500 Protocol Daemon
+.SH SYNOPSIS
+.B ETCDIR/ldapd [\-d level] [\-l] [\-c dsaname]
+.B [\-p port] [\-t timeout] [\-r referraltimeout]
+.B [\-I] [\-U]
+.SH DESCRIPTION
+.LP
+.B Ldapd
+is the LDAP to X.500 gateway daemon.  The LDAP protocol is used to
+provide lightweight TCP/IP access to the X.500 Directory. The
+.B ldapd
+server is typically invoked at boot time, usually out of
+.BR  /etc/rc.local .
+Upon startup,
+.B ldapd
+normally forks and disassociates itself from the invoking tty, and then
+listens on port 389 for TCP connections from LDAP clients.
+The server performs the following basic operations for the client:
+.TP 14
+.B Bind
+Bind to the X.500 directory.  Currently only simple (clear-text password)
+and kerberos version 4 authentication are supported.
+.TP
+.B Search
+Search the X.500 directory for entries that match a given filter.
+The scope of the search can be base object, one level, or whole subtree.
+Note that the X.500 read and list can be emulated using search.
+.TP
+.B Modify
+Change the attributes and values of an existing X.500 entry.
+.TP
+.B Modify RDN
+Change the Relative Distinguished Name of an X.500 entry.
+.TP
+.B Add
+Add an entry to the X.500 directory.
+.TP
+.B Remove
+Remove an entry from the X.500 directory.
+.TP
+.B Abandon
+Abort an operation in progress.
+.LP
+See
+.BR ldap (3)
+for details on client-side access to the ldap server.  See
+.I RFC 1777: Lightweight Directory Access Protocol
+and
+.I RFC 1778: The String Representation of
+.I Standard Attribute Syntaxes
+for details of the protocol supporting the above operations.
+.SH OPTIONS
+.TP
+.BI \-d " level"
+Turn on debugging as defined by
+.I level.
+If this option is specified,
+.I ldapd
+will not fork or disassociate from the invoking terminal.  Some general
+operation and status messages are printed for any value of \fIlevel\fP.
+\fIlevel\fP is taken as a bit string, with each bit corresponding to a
+different kind of debugging information.  See <ldap.h> for details.
+.TP
+.B \-l
+Enable logging of various status and errors to the LOG_LOCAL4 facility via
+.BR syslog (8).
+.TP
+.RB \-c " dsaname"
+Connect to the named DSA initially.  The
+.I dsaname
+given should be a name found in the local dsaptailor file or an
+actual presentation address.
+.TP
+.BI \-p " port"
+Listen on port
+.I port
+instead of the default port.  This is useful for debugging purposes.
+.TP
+.BI \-t " timeout"
+Specify the timeout value after which idle connections from
+clients are closed.
+.TP
+.BI \-r " referraltimeout"
+Specify the timeout value after which idle connections to DSAs
+are closed.
+.TP
+.B \-I
+Run from
+.BR inetd (8)
+instead of as a stand-alone daemon.
+.TP
+.B \-U
+Support Connectionless LDAP (CLDAP).  In this mode, ldapd listens for
+CLDAP search requests only on a UDP port, performs the search, and
+returns the result.  See
+.BR udp (4)
+for more information on UDP.
+.SH EXAMPLES
+To start ldapd and have it fork and detach from the terminal and connect
+to the first DSA listed in the dsaptailor file, just type:
+.LP
+.nf
+.ft tt
+       ETCDIR/ldapd
+.ft
+.fi
+.LP
+To connect to an alternate DSA and turn on voluminous debugging which
+will be printed on standard error, type:
+.LP
+.nf
+.ft tt
+       ETCDIR/ldapd -c dsanameoraddr -d 31
+.ft
+.fi
+.LP
+where dsanameoraddr is a presentation address or a name that appears
+in the local dsaptailor file.
+.SH "SEE ALSO"
+.BR ldap (3),
+.BR udp (4),
+.BR slapd (8)
+.BR inetd (8)
+.LP
+Volume 5 of The ISODE Manual
diff --git a/doc/man/man8/ldbmcat.8 b/doc/man/man8/ldbmcat.8
new file mode 100644 (file)
index 0000000..f7fefef
--- /dev/null
@@ -0,0 +1,61 @@
+.TH LDBMCAT 8C "13 November 1995" "U-M LDAP LDVERSION"
+.SH NAME
+ldbmcat \- LDBM to LDIF database format conversion utility
+.SH SYNOPSIS
+.B ETCDIR/ldbmcat [\-n] id2entry\-file
+.LP
+.SH DESCRIPTION
+.LP
+This program is used to convert a
+.BR slapd (8)
+LDBM database to the text LDAP Directory Interchange Format (LDIF).
+It opens the given
+.I id2entry\-file
+and writes the corresponding LDIF output to standard output.
+.LP
+See "The SLAPD and SLURPD Administrator's Guide" for more details on
+using this program.
+.SH OPTIONS
+.TP
+.B \-n
+This option specifies that
+.B ldbmcat
+should not print entry IDs when it dumps out the database. Note
+that the printing of entry IDs is essential if you are going to
+use the LDIF format produced as input to
+.B ldif2index,
+for example, to create a new index file for use with an existing
+database.
+.SH EXAMPLES
+To make a text backup of your LDBM database and put it in a file called
+.BR ldif ,
+give the command:
+.LP
+.nf
+.ft tt
+       ETCDIR/ldbmcat -n id2entry.dbb > ldif
+.ft
+.fi
+.LP
+To create a new index for the
+.B mail
+attribute, give these commands:
+.LP
+.nf
+.ft tt
+       ETCDIR/ldbmcat id2entry.dbb > ldif
+       ETCDIR/ldif2index -i ldif -f slapd-config-file mail
+.ft
+.fi
+.LP
+Note that your
+.B slapd (8)
+should not be running (at least, not in read-write
+mode) when you do this to ensure consistency of the database.
+.SH "SEE ALSO"
+.BR ldap (3),
+.BR ldif (5),
+.BR ldif2ldbm (8),
+.BR slapd (8)
+.LP
+"The SLAPD and SLURPD Administrator's Guide"
diff --git a/doc/man/man8/ldif.8 b/doc/man/man8/ldif.8
new file mode 100644 (file)
index 0000000..2482de3
--- /dev/null
@@ -0,0 +1,48 @@
+.TH LDIF 8C "15 November 1995" "U-M LDAP LDVERSION"
+.SH NAME
+ldif \- convert arbitrary data to LDIF format
+.SH SYNOPSIS
+.B ETCDIR/ldif [\-b] attr\-name
+.LP
+.SH DESCRIPTION
+.LP
+This program is used to convert arbitrary data to the
+LDAP Directory Interchange Format (LDIF) described in
+.BR ldif (5).
+.B ldif
+reads data from standard input, converts it,
+and writes the corresponding LDIF output to standard output.
+The output is suitable for use as a line in an
+.BR ldif (5)
+file.
+.LP
+Without the
+.B \-b
+flag,
+.B ldif
+considers its input a sequence of values to be
+converted, one per line. With the
+.B \-b
+flag, 
+.B ldif
+considers its input as a single raw binary value to be
+converted. This can be useful when converting binary data
+such as a photo or audio attribute.
+.LP
+See "The SLAPD and SLURPD Administrator's Guide" for more details on
+using this program.
+.SH OPTIONS
+.TP
+.B \-b
+This option specifies that
+.B ldif
+should interpret its input as a single binary value for conversion.
+Otherwise, it interprets it as a sequence of lines, with each line
+containing a single value.
+.SH "SEE ALSO"
+.BR ldap (3),
+.BR ldif (5),
+.BR ldif2ldbm (8),
+.BR slapd (8)
+.LP
+"The SLAPD and SLURPD Administrator's Guide"
diff --git a/doc/man/man8/ldif2ldbm.8 b/doc/man/man8/ldif2ldbm.8
new file mode 100644 (file)
index 0000000..f6edfc6
--- /dev/null
@@ -0,0 +1,113 @@
+.TH LDIF2LDBM 8C "13 November 1995" "U-M LDAP LDVERSION"
+.SH NAME
+ldif2ldbm, ldif2index, ldif2id2entry, ldif2id2children \- LDIF to LDBM database format conversion utilities
+.SH SYNOPSIS
+.B ETCDIR/ldif2ldbm
+.B \-i ldif\-input\-file
+.B [\-d debug\-level] [\-f slapd\-config\-file]
+.B [\-j number\-of\-jobs]
+.LP
+.B ETCDIR/ldif2index
+.B \-i ldif\-input\-file
+.B [\-d debug\-level] [\-f slapd\-config\-file]
+.B attribute\-name
+.LP
+.B ETCDIR/ldif2id2entry
+.B \-i ldif\-input\-file
+.B [\-d debug\-level] [\-f slapd\-config\-file]
+.LP
+.B ETCDIR/ldif2id2children
+.B \-i ldif\-input\-file
+.B [\-d debug\-level] [\-f slapd\-config\-file]
+.LP
+.SH DESCRIPTION
+.LP
+These programs are used to convert a database in text LDIF LDAP
+Directory Interchange Format (LDIF) to an LDBM database suitable
+for use by
+.BR slapd (8).
+Normally, only
+.B ldif2ldbm
+is invoked by you. It will invoke the other programs as necessary.
+Occasionally, it may be necessary to invoke them by hand. For
+example, to create a new index file for an existing database, the
+.B ldif2index
+program can be invoked. The
+.BR ldbmcat (8)
+program is used to do the reverse conversion.
+.LP
+See "The SLAPD and SLURPD Administrator's Guide" for more details on
+using these programs.
+.SH OPTIONS
+The first three options apply to all four programs. The -j option is
+only for the 
+.B ldif2ldbm
+program.
+.TP
+.BI \-i " ldif\-input\-file"
+This option specifies the location of the LDIF input file containing
+the database to convert. It is required.
+.TP
+.BI \-d " debug\-level"
+Turn on debugging as defined by
+.B debug\-level.
+Some general operation and status messages are printed for any value of
+\fIdebug\-level\fP.  \fIdebug\-level\fP is taken as a bit string, with
+each bit corresponding to a different kind of debugging information. 
+See <ldap.h> for details.
+.TP
+.BI \-f " slapd\-config\-file"
+This option
+Specifies the
+.B slapd
+configuration file. The default is
+.BR ETCDIR/slapd.conf .
+.TP
+.BI \-j " number\-of\-jobs"
+This option only applies to the
+.B ldif2ldbm
+program. It specifies the level of parallelism to use when doing the
+conversion.
+.B ldif2ldbm
+invokes several other programs during the conversion process,
+most notably one invocation of
+.B ldif2index
+for each indexed attribute that appears in the LDIF input file. The -j
+option tells
+.B ldif2ldbm
+how many of these other programs it should run in parallel. This can
+speed up the conversion, but beware of starting too many processes
+in parallel, all competing for disk, memory, and cpu resources. The
+default is one.
+.SH EXAMPLES
+To convert the file
+.BR ldif.input
+into an LDBM database with indexes as described in the
+.I slapd
+config file
+.BR /usr/local/etc/slapd.conf ,
+give the command:
+.LP
+.nf
+.ft tt
+       ETCDIR/ldif2index -i ldif.input -f /usr/local/etc/slapd.conf
+.ft
+.fi
+.LP
+To do the same, but running two conversion sub-processes at a time,
+give this command:
+.LP
+.nf
+.ft tt
+       ETCDIR/ldif2index -i ldif.input -f /usr/local/etc/slapd.conf -j 2
+.ft
+.fi
+.LP
+.SH "SEE ALSO"
+.BR ldap (3),
+.BR ldif (5),
+.BR slapd.conf (5),
+.BR ldbmcat (8),
+.BR edb2ldif (8)
+.LP
+"The SLAPD and SLURPD Administrator's Guide"
diff --git a/doc/man/man8/ldif2ldbm.8.links b/doc/man/man8/ldif2ldbm.8.links
new file mode 100644 (file)
index 0000000..0906b6d
--- /dev/null
@@ -0,0 +1,3 @@
+ldif2index.8
+ldif2id2entry.8
+ldif2id2children.8
diff --git a/doc/man/man8/mail500.8 b/doc/man/man8/mail500.8
new file mode 100644 (file)
index 0000000..fd9bffb
--- /dev/null
@@ -0,0 +1,287 @@
+.TH MAIL500 8C "30 November 1994" "U-M LDAP LDVERSION"
+.SH NAME
+mail500 \- X.500 capable mailer
+.LP
+fax500 \- X.500 capable fax delivery agent
+.SH SYNOPSIS
+.B ETCDIR/mail500 [\-d level] [\-f mailfrom]
+.B [\-h hostname] [\-l ldaphost]
+.B [\-m address] [\-v vacationhost]
+.LP
+.B ETCDIR/fax500 [\-d level] [\-f mailfrom]
+.B [\-h hostname] [\-l ldaphost]
+.B [\-m address]
+.SH DESCRIPTION
+.B mail500
+is an LDAP/X.500-capable mailer, suitable to be invoked from a
+mail delivery agent such as
+.BR sendmail (8).
+It supports mail to both individuals and groups.
+.B fax500
+is an LDAP/X.500-capable facsimile delivery agent.  It utilizes the
+Internet remote-printing experiment (tpc.int).  For more
+information on tpc.int, look in
+.B /mrose/tpc
+on
+.BR ftp.ics.uci.edu ,
+or send mail to
+.BR tpc-faq@town.hall.org .
+.SH OPTIONS
+.RB \- d level
+Turn on debugging as defined by
+.I level.
+This option directs
+.B mail500/fax500
+to produce various debugging output via the
+.BR syslog (8)
+facility at the LOG_ALERT level.
+.TP
+.BI \-f " mailfrom"
+This option tells
+.B mail500/fax500
+what to set the envelop from address to when (re)invoking sendmail
+to deliver mail.
+.I mailfrom
+should be a valid email address.  Normally, this option is passed
+to
+.B mail500/fax500
+via the sendmail.cf(5) mailer definition, and is set
+to something like the $f macro.
+.TP
+.BI \-l " ldaphost"
+Specify an alternate host on which the LDAP server is running.
+.TP
+.BI \-m " address"
+If
+.I mail500/fax500
+produces a rejection message, this is the
+.I address
+from which it will com.  Normally, this option is passed to
+.I mail500/fax500
+via the sendmail.cf(5) mailer definition, and is set to something
+like $n@$w (typically, mailer-daemon@hostname).
+.TP
+.BI \-v " vacationhost"
+If the vacation facility is operative, this option specifies the
+host to which the mail of users who are on vacation should be sent.
+.SH HOW MAIL500 AND FAX500 WORK
+When mail500/fax500 gets invoked with one or more names to which to
+deliver mail, it searches for each name in X.500.  Where it searches,
+and what kind(s) of search(es) it does are compile-time configurable
+by changing the
+.B base
+array in
+.BR main.c .
+For example, the configuration we use at U-M is like this:
+.LP
+.nf
+Base    base[] =
+       { "ou=People, o=University of Michigan, c=US", 0
+               "uid=%s", "cn=%s", NULL,
+         "ou=System Groups, ou=Groups, o=University of Michigan, c=US", 1
+               "(&(cn=%s)(associatedDomain=%h))", NULL, NULL,
+         "ou=User Groups, ou=Groups, o=University of Michigan, c=US", 1
+               "(&(cn=%s)(associatedDomain=%h))", NULL, NULL,
+         NULL
+       };
+.fi
+.LP
+which means that in delivering mail to "name@umich.edu"
+.B mail500/fax500would do the
+the following searches, stopping if it finds a match at any step:
+.LP
+.nf
+subtree search of "ou=People, o=University of Michigan, c=US"
+       for (uid=name)
+subtree search of "ou=People, o=University of Michigan, c=US"
+       for (cn=name)
+subtree search of "ou=System Groups, ou=Groups, o=University of Michigan, c=US"
+       for (&(cn=name)(associatedDomain=umich.edu))
+subtree search of "ou=User Groups, ou=Groups, o=University of Michigan, c=US"
+       for (&(cn=name)(associatedDomain=umich.edu))
+.fi
+.LP
+Notice that when specifying a filter %s is replaced by the name,
+or user portion of the address while %h is replaced by whatever is
+passed in to
+.B mail500/fax500
+via the
+.RB \- h
+option (typically the host portion of the address).
+.LP
+You can also specify whether you want search results that matched
+because the entry's RDN matched the search to be given preference
+or not.  At U-M, we only give such preference in the mail group
+portion of the searches.  Beware with this option:  the algorithm
+used to decide whether an entry's RDN matched the search is very
+simple-minded, and may not always be correct.
+.LP
+There is currently no limit on the number of areas searched (the base
+array can be as large as you want), and an arbitrary limit of 2 filters
+for each base.  If you want more than that, simply changing the 3 in
+the typedef for Base should do the trick.
+.SH X.500 SUPPORT
+In X.500, there are several new attribute types and one new object
+class defined that
+.B mail500/fax500
+uses.  At its most basic, for normal
+entries
+.B mail500
+will deliver to the value(s) listed in the
+.B mail
+attribute of the entry, and
+.B fax500
+will attempt to deliver a fax to the telephone number listed in the
+.B facsimileTelephoneNumber
+attribute.  For example, at U-M my entry has the attribute
+.LP
+.nf
+       mail= tim@terminator.rs.itd.umich.edu
+.fi
+.LP
+So mail sent to tim@umich.edu will be delivered via
+.B mail500
+to that
+address (assuming the
+.BR sendmail.cf (5)
+file is set up to call
+.B mail500
+for mail to somebody@umich.edu - see below).  If there were multiple
+values for the mail attribute, multiple copies of the mail would be sent.
+.LP
+In the case of
+.BR fax500 , if my entry has the attribute
+.LP
+.nf
+       facsimileTelephoneNumber= +1 313 764 5140
+.fi
+.LP
+A message sent to tim@fax.umich.edu (assuming the sendmail.cf file
+is set up to pass mail @fax.umich.edu to
+.BR fax500 \-
+see below)
+will generate a message to
+remote-printer.Timothy_A_Howes@0.4.1.5.4.6.7.3.1.3.1.tpc.int.
+.LP
+A new object class, rfc822MailGroup, and several new attributes have
+been defined to handle email groups/mailing lists.  To use this, you
+will need to add this to your local
+.BR oidtable.oc :
+.LP
+.nf
+       # object class for representing rfc 822 mailgroups
+       rfc822MailGroup:        umichObjectClass.2 : \\
+               top : \\
+               cn : \\
+               rfc822Mailbox, member, memberOfGroup, owner, \\
+               errorsTo, rfc822ErrorsTo, requestsTo, rfc822RequestsTo, \\
+               joinable, associatedDomain, \\
+               description, multiLineDescription, \\
+               userPassword, krbName, \\
+               telecommunicationAttributeSet, postalAttributeSet
+.fi
+.LP
+And you will need to add these to your local oidtable.at:
+.LP
+.nf
+       # attrs for rfc822mailgroups
+       multiLineDescription:   umichAttributeType.2    : CaseIgnoreList
+       rfc822ErrorsTo:         umichAttributeType.26   : CaseIgnoreIA5String
+       rfc822RequestsTo:       umichAttributeType.27   : CaseIgnoreIA5String
+       joinable:               umichAttributeType.28   : Boolean
+       memberOfGroup:          umichAttributeType.29   : DN
+       errorsTo:               umichAttributeType.30   : DN
+       requestsTo:             umichAttributeType.31   : DN
+.fi
+.LP
+The idea was to define a kind of hybrid mail group that could handle
+people who were in X.500 or not.  So, for example, members of a group
+can be specified via the member attribute (for X.500 members) or the
+rfc822MailBox attribute (for non-X.500 members).  Similarly for the
+errorsTo and rfc822ErrorsTo, and the requestsTo and rfc822RequestsTo
+attributes.
+.LP
+To create a real mailing list, with a list maintainer, all you have to
+do is create an rfc822MailGroup and fill in the errorsTo or
+rfc822ErrorsTo attributes (or both).  That will cause any errors
+encountered when delivering mail to the group to go to the addresses
+listed (or X.500 entry via it's mail attribute).
+.LP
+If you fill in the requestsTo or rfc822RequestsTo (or both) attributes,
+mail sent to groupname-request will be sent to the addresses listed
+there.  If you fill in the owner attribute, mail sent to
+groupname-owner will be sent to the addresses listed there.  mail500
+does this automatically, so you don't have to explicitly add the
+groupname-request or groupname-owner aliases to your group.
+.LP
+To allow users to join a group, there is the joinable flag.  If TRUE,
+mail500 will search for entries that have a memberOfGroup attribute
+equal to the DN of the group, using the same algorithm it used to find
+the group in the first place (i.e. the DNs and filters listed in the
+base array).  This allows people to join (or subscribe to) a group
+without having to modify the group entry directly.  If joinable is
+FALSE, the search is not done.
+.SH SENDMAIL CONFIGURATION
+The idea is that you might have a rule like this in your sendmail.cf
+file somewhere in rule set 0:
+.LP
+.nf
+        R$*<@umich.edu>$*       $#mail500$@umich.edu$:<$1>
+        R$*<@fax.umich.edu>$*  $#fax500$@fax.umich.edu$:<$1>
+.fi
+.LP
+These rules say that any address that ends in @umich.edu will cause
+the mail500 mailer to be called to deliver the mail, and any address
+that ends in @fax.umich.edu will cause the fax500 mailer to
+be called.  You probably
+also want to do something to prevent addresses like terminator!tim@umich.edu
+or tim%terminator.rs.itd.umich.edu@umich.edu from being passed to mail500.
+At U-M, we do this by adding rules like this to rule set 9 where we
+strip off our local names:
+.LP
+.nf
+       R<@umich.edu>$*:$*                 $>10<@>$1:$2
+       R$+%$+<@umich.edu>                 $>10$1%$2<@>
+       R$+!$+<@umich.edu>                 $>10$1!$2<@>
+.fi
+.LP
+Of course, you would substitute your domain name for umich.edu in the
+above examples.  See the sample sendmail.cf file in the ldap source
+directory clients/mail500/ for more details.
+.LP
+The mail500 and fax500 mailers should be defined similar to this in the
+sendmail.cf file:
+.LP
+.nf
+Mmail500, P=ETCDIR/mail500, F=DFMSmnXuh, A=mail500 -f $f -h $h -m $n@$w $u
+Mfax500, P=ETCDIR/fax500, F=DFMSmnXuh, A=fax500 -f $f -h $h -m $n@$w $u
+.fi
+.LP
+This defines how mail500/fax500 will be treated by sendmail and what
+arguments it will have when it's called.  The various flags specified
+by the F=... parameter are explained in your local sendmail book (with
+any luck).  The arguments to mail500/fax500 are as defined under OPTIONS
+above.  The final argument $u is used to stand for the addresses to which
+to deliver the mail.
+.SH NOTES
+The default values for several #defines that control how mail500 
+and fax500 works are configured at compile time in the 
+include/ldapconfig.h.edit include file.  You should edit this 
+file to suit your site.
+.SH BUGS
+mail500/fax500 should use the ldap_getfilter(3) facility, instead of 
+compiling in the search filters to use.  This is shameful.
+.LP
+The support for joinable groups (searching to find members who have
+set something in their own entry) is really a hack because we did not
+have good enough access control to allow people to add and delete
+themselves from the group itself.
+.LP
+At one point, mail500 and fax500 were exactly the same binary, and
+would behave appropriately based on how they were invoked.  Unfortunately,
+several new features (e.g. vacation support) were added to mail500
+but not to fax500.
+.SH "SEE ALSO"
+.BR ldap(3),
+.BR sendmail.cf(5),
+.BR sendmail(8),
diff --git a/doc/man/man8/mail500.8.links b/doc/man/man8/mail500.8.links
new file mode 100644 (file)
index 0000000..a94161b
--- /dev/null
@@ -0,0 +1 @@
+fax500.8
diff --git a/doc/man/man8/rcpt500.8 b/doc/man/man8/rcpt500.8
new file mode 100644 (file)
index 0000000..3131812
--- /dev/null
@@ -0,0 +1,86 @@
+.TH RCPT500 8C "16 December 1994" "U-M LDAP LDVERSION"
+.SH NAME
+rcpt500 \- mail to X.500 gateway program
+.SH SYNOPSIS
+.B ETCDIR/rcpt500 [\-l] [\-h ldaphost] [\-p ldapport]
+.B [\-b searchbase] [\-a] [\-U] [\-z sizelimit] [\-u dapuser]
+.B [\-f filterfile] [\-t templatefile] [\-c rdncount]
+.SH DESCRIPTION
+.B rcpt500
+is a mail-query server that answers X.500 white pages queries.  It is
+designed to be run out of your mail system alias file (or the equivalent).
+.B rcpt500
+accepts the entire contents (including headers) of an RFC 822
+message on standard input.  The message is parsed, and a search or help
+command found in the Subject: header of message body is recognized and
+a reply is sent to the sender.
+.LP
+If you are using
+.BR sendmail (8),
+you could add the following line to the
+.BR aliases (5)
+file
+.RB ( /etc/aliases )
+to have
+.B rcpt500
+invoked whenever mail is sent to the address \fInamelookup\fP on your host:
+.nf
+.fi
+.ft tt
+    namelookup:        "|ETCDIR/rcpt500 -l"
+.ft
+.fi
+.SH OPTIONS
+.TP
+.B \-l
+Enable logging of requests to the LOG_DAEMON facility.
+.TP
+.BI \-h " ldaphost"
+Specify an alternate host on which the ldap server is running.
+.TP
+.BI \-p " ldapport"
+Specify and alternate TCP port where the ldap server is running.
+.TP
+.BI \-b " searchbase"
+Specify an alternate base for searches.  \fIsearchbase\fP should be
+a string-represented LDAP Distinguished Name.
+.TP
+.B \-a
+Turn off dereferencing of aliases for the LDAP search.
+.TP
+.B \-U
+Use Connectionless LDAP (over UDP).  This option is only available when
+.B rcpt500
+is compiled with -DCLDAP.
+.TP
+.BI \-z " sizelimit"
+Limit the maximum number of entries returned to \fIsizelimit\fP
+entries.
+.TP
+.BI \-t " templatefile"
+Specify an alternate template configuration file for use with the
+.BR ldap_init_templates (3)
+facility, used by rcpt500.
+.TP
+.BI \-c " rdncount"
+Specify the number of DN components to show for the names and DN attributes
+within entries matching the search.
+.SH NOTES
+The default values for most of the things you can specify with options
+are configured at compile time in the
+.B include/ldapconfig.h.edit
+include
+file.  Also included there are the pathname of the help file, the name
+of the command used to send replies, etc.  You should configure
+.B ldapconfig.h.edit
+for your site.
+.SH FILES
+.PD 0
+.TP 20
+.B ETCDIR/rcpt500.help
+help file
+.PD
+.SH "SEE ALSO"
+.BR ldap (3),
+.BR aliases (5),
+.BR sendmail (8)
diff --git a/doc/man/man8/slapd.8 b/doc/man/man8/slapd.8
new file mode 100644 (file)
index 0000000..be0c97d
--- /dev/null
@@ -0,0 +1,104 @@
+.TH SLAPD 8C "6 November 1995" "U-M LDAP LDVERSION"
+.SH NAME
+slapd \- Stand-alone LDAP Daemon
+.SH SYNOPSIS
+.B ETCDIR/slapd [\-d debug\-level]
+.B [\-f slapd\-config\-file] [\-p port\-number]
+.B [\-s syslog\-level] [\-i]
+.B 
+.SH DESCRIPTION
+.LP
+.B Slapd
+is the stand-alone LDAP daemon. It listens for LDAP connections on
+port 389, responding
+to the LDAP operations it receives over these connections.
+.B slapd
+is typically invoked at boot time, usually out of
+.BR  /etc/rc.local .
+Upon startup,
+.B slapd
+normally forks and disassociates itself from the invoking tty.
+If the
+.B \-d
+flag is given and debugging is set to some non-zero
+value,
+.B slapd
+will not fork and disassociate from the invoking tty.
+.LP
+.B Slapd
+can be configured to provide replicated service for a database with
+the help of
+.BR slurpd ,
+the standalone LDAP update replication daemon.
+See
+.BR slurpd (8)
+for details.
+.LP
+See "The SLAPD and SLURPD Administrator's Guide" for more details on
+.BR slapd .
+.SH OPTIONS
+.TP
+.BI \-d " debug\-level"
+Turn on debugging as defined by
+.I debug\-level.
+If this option is specified,
+.B slapd
+will not fork or disassociate from the invoking terminal.  Some general
+operation and status messages are printed for any value of \fIdebug\-level\fP.
+\fIdebug\-level\fP is taken as a bit string, with each bit corresponding to a
+different kind of debugging information.  See <ldap.h> for details.
+.TP
+.BI \-s " syslog\-level"
+This option tells
+.B slapd
+at what level debugging statements should be logged to the
+.BR syslog (8)
+facility.
+.TP
+.BI \-f " slapd\-config\-file"
+Specifies the slapd configuration file. The default is
+.BR ETCDIR/slapd.conf .
+.TP
+.BI \-p " port\-number"
+.B slapd
+will listen on the default LDAP port (389) unless this option is given
+to override the default.
+.TP
+.B \-i
+This option tells
+.B slapd
+that it is being run from
+.BR inetd(8) ,
+the Internet protocol daemon.
+.SH EXAMPLES
+To start 
+.I slapd
+and have it fork and detach from the terminal and start serving
+the LDAP databases defined in the default config file, just type:
+.LP
+.nf
+.ft tt
+       ETCDIR/slapd
+.ft
+.fi
+.LP
+To start 
+.B slapd
+with an alternate configuration file, and turn
+on voluminous debugging which will be printed on standard error, type:
+.LP
+.nf
+.ft tt
+       ETCDIR/slapd -f /usr/local/slapd/slapd.conf -d 255
+.ft
+.fi
+.LP
+.SH "SEE ALSO"
+.BR ldap (3),
+.BR slapd.conf (5),
+.BR slurpd (8)
+.LP
+"The SLAPD and SLURPD Administrator's Guide"
+.SH BUGS
+When using the LDBM database backend, the Modify RDN operation does not
+update the attribute values in the entry that are affected by the change.
diff --git a/doc/man/man8/slurpd.8 b/doc/man/man8/slurpd.8
new file mode 100644 (file)
index 0000000..037584e
--- /dev/null
@@ -0,0 +1,151 @@
+.TH SLURPD 8C "6 November 1995" "U-M LDAP LDVERSION"
+.SH NAME
+slurpd \- Standalone LDAP Update Replication Daemon
+.SH SYNOPSIS
+.B ETCDIR/slurpd [\-d debug\-level]
+.B [\-f slapd\-config\-file] [\-r slapd\-replog\-file]
+.B [\-t temp\-dir] [\-o] [\-k srvtab\-file]
+.B 
+.SH DESCRIPTION
+.LP
+.B Slurpd
+is used to propagate changes from one slapd database to another.  If
+slapd is configured to produce a replication log, 
+.B slurpd
+reads that
+replication log and sends the changes to the slave 
+.B slapd
+instances
+via the LDAP protocol.
+.B slurpd
+is typically invoked at boot time, usually out of
+.BR  /etc/rc.local .
+.LP
+Upon startup,
+.B slurpd
+normally forks and disassociates itself from the invoking tty,
+then reads the replication log (given either by the
+.I replogfile
+directive in the 
+.B slapd
+config file, or by the
+.RB \- r
+command-line option).
+If the replication log file does not exist or is empty,
+.B slurpd
+goes to sleep.  It periodically wakes up and checks to see if there
+are any changes to be propoagated.
+.LP
+When
+.B slurpd
+notices that there are changes to propagate to slave 
+.B slapd
+instances, it locks the replication log, makes its own private copy,
+releases the lock, and forks one copy of itself for each replica
+.B slapd
+to be updated.  Each child process binds to the slave 
+.B slapd
+as the
+DN given by the
+.I binddn
+option to the
+.I replica
+directive in the
+.B slapd
+config file, and sends the changes.
+.LP
+See
+.BR slapd (8)
+for details on the standalone LDAP daemon.
+.SH OPTIONS
+.TP
+.BI \-d " debug\-level"
+Turn on debugging as defined by
+.I debug\-level.
+If this option is specified,
+.B slurpd
+will not fork or disassociate from the invoking terminal.  Some general
+operation and status messages are printed for any value of \fIdebug\-level\fP.
+\fIdebug\-level\fP is taken as a bit string, with each bit corresponding to a
+different kind of debugging information.  See <ldap.h> for details.
+.TP
+.BI \-f " slapd\-config\-file"
+Specifies the slapd configuration file.  The default is
+.BR ETCDIR/slapd.conf .
+.TP
+.BI \-r " slapd\-replog\-file"
+Specifies the name of the 
+.B slapd
+replication logfile.  Normally, the name
+of the replication log file is read from the 
+.B slapd
+configuration file.
+The
+.B \-r
+option allows you to override this.  In conjunction with the
+.B \-o
+option, you can process a replication log file in a "one\-shot" mode.  For
+example, if 
+.B slurpd
+has encountered errors in processing a replication log,
+you can run it in one\-shot mode and give the rejection file name as
+the argument to the \-r option, once you've resolved the problem which caused
+the replication to fail.
+.TP
+.B \-o
+Run in "one\-shot" mode.  Normally, 
+.B slurpd
+processes the replog file
+and then watches for more replication entries to be appended.  In
+one\-shot mode, 
+.B slurpd
+processes a replication log and exits.
+.TP
+.BI \-t " temp\-dir"
+.B slurpd
+copies the replication log to a working directory before processing it.
+This option allows you to specify the location of these temporary files. 
+The default is
+.BR /usr/tmp .
+.TP
+.BI \-k " srvtab\-file"
+Specify the location of the kerberos srvtab file which contains keys
+for the replica 
+.I slapd
+instances.  Overrides the srvtab argument to the
+replica directive in the 
+.I slapd
+configuration file.
+.SH EXAMPLES
+To start 
+.I slurpd
+and have it fork and detach from the terminal and process
+the replication logs generated by
+.I slapd,
+just type:
+.LP
+.nf
+.ft tt
+       ETCDIR/slurpd
+.ft
+.fi
+.LP
+To start 
+.I slurpd
+with an alternate 
+.I slapd
+configuration file, and turn
+on voluminous debugging which will be printed on standard error, type:
+.LP
+.nf
+.ft tt
+       ETCDIR/slurpd -f /usr/local/etc/slapd.conf -d 255
+.ft
+.fi
+.LP
+.SH "SEE ALSO"
+.BR ldap (3),
+.BR slapd.replog (5),
+.BR slapd (8)
+.LP
+"The SLAPD and SLURPD Administrator's Guide"
diff --git a/doc/rfc/Make-template b/doc/rfc/Make-template
new file mode 100644 (file)
index 0000000..62e794d
--- /dev/null
@@ -0,0 +1,29 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1994 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP doc/rfc makefile
+#
+#-----------------------------------------------------------------------------
+
+all:   FORCE
+
+install:       FORCE
+
+lint:  FORCE
+
+5lint: FORCE
+
+clean: FORCE
+
+depend:        FORCE
+
+links:
+       @$(LN) .src/*.txt .
diff --git a/doc/rfc/rfc1558.txt b/doc/rfc/rfc1558.txt
new file mode 100644 (file)
index 0000000..1bb5bd9
--- /dev/null
@@ -0,0 +1,171 @@
+
+
+
+
+
+
+Network Working Group                                           T. Howes
+Request for Comments: 1558                        University of Michigan
+Category: Informational                                    December 1993
+
+
+             A String Representation of LDAP Search Filters
+
+Status of this Memo
+
+   This memo provides information for the Internet community.  This memo
+   does not specify an Internet standard of any kind.  Distribution of
+   this memo is unlimited.
+
+Abstract
+
+   The Lightweight Directory Access Protocol (LDAP) [1] defines a
+   network representation of a search filter transmitted to an LDAP
+   server.  Some applications may find it useful to have a common way of
+   representing these search filters in a human-readable form.  This
+   document defines a human-readable string format for representing LDAP
+   search filters.
+
+1.  LDAP Search Filter Definition
+
+   An LDAP search filter is defined in [1] as follows:
+
+     Filter ::= CHOICE {
+             and                [0] SET OF Filter,
+             or                 [1] SET OF Filter,
+             not                [2] Filter,
+             equalityMatch      [3] AttributeValueAssertion,
+             substrings         [4] SubstringFilter,
+             greaterOrEqual     [5] AttributeValueAssertion,
+             lessOrEqual        [6] AttributeValueAssertion,
+             present            [7] AttributeType,
+             approxMatch        [8] AttributeValueAssertion
+     }
+
+     SubstringFilter ::= SEQUENCE {
+             type    AttributeType,
+             SEQUENCE OF CHOICE {
+                     initial        [0] LDAPString,
+                     any            [1] LDAPString,
+                     final          [2] LDAPString
+             }
+     }
+
+
+
+
+
+Howes                                                           [Page 1]
+\f
+RFC 1558             Representation of LDAP Filters        December 1993
+
+
+     AttributeValueAssertion ::= SEQUENCE
+             attributeType   AttributeType,
+             attributeValue  AttributeValue
+     }
+
+     AttributeType ::= LDAPString
+
+     AttributeValue ::= OCTET STRING
+
+     LDAPString ::= OCTET STRING
+
+   where the LDAPString above is limited to the IA5 character set.  The
+   AttributeType is a string representation of the attribute object
+   identifier in dotted OID format (e.g., "2.5.4.10"), or the shorter
+   string name of the attribute (e.g., "organizationName", or "o").  The
+   AttributeValue OCTET STRING has the form defined in [2].  The Filter
+   is encoded for transmission over a network using the Basic Encoding
+   Rules defined in [3], with simplifications described in [1].
+
+2.  String Search Filter Definition
+
+   The string representation of an LDAP search filter is defined by the
+   following BNF.  It uses a prefix format.
+
+     <filter> ::= '(' <filtercomp> ')'
+     <filtercomp> ::= <and> | <or> | <not> | <item>
+     <and> ::= '&' <filterlist>
+     <or> ::= '|' <filterlist>
+     <not> ::= '!' <filter>
+     <filterlist> ::= <filter> | <filter> <filterlist>
+     <item> ::= <simple> | <present> | <substring>
+     <simple> ::= <attr> <filtertype> <value>
+     <filtertype> ::= <equal> | <approx> | <greater> | <less>
+     <equal> ::= '='
+     <approx> ::= '~='
+     <greater> ::= '>='
+     <less> ::= '<='
+     <present> ::= <attr> '=*'
+     <substring> ::= <attr> '=' <initial> <any> <final>
+     <initial> ::= NULL | <value>
+     <any> ::= '*' <starval>
+     <starval> ::= NULL | <value> '*' <starval>
+     <final> ::= NULL | <value>
+
+   <attr> is a string representing an AttributeType, and has the format
+   defined in [1].  <value> is a string representing an AttributeValue,
+   or part of one, and has the form defined in [2].  If a <value> must
+   contain one of the characters '*' or '(' or ')', these characters
+
+
+
+Howes                                                           [Page 2]
+\f
+RFC 1558             Representation of LDAP Filters        December 1993
+
+
+   should be escaped by preceding them with the backslash '\' character.
+
+3.  Examples
+
+   This section gives a few examples of search filters written using
+   this notation.
+
+     (cn=Babs Jensen)
+     (!(cn=Tim Howes))
+     (&(objectClass=Person)(|(sn=Jensen)(cn=Babs J*)))
+     (o=univ*of*mich*)
+
+4.  Security Considerations
+
+   Security issues are not discussed in this memo.
+
+5.  References
+
+   [1] Yeong, W., Howes, T., and S. Kille, "Lightweight Directory Access
+       Protocol", RFC 1487, Performance Systems International,
+       University of Michigan, ISODE Consortium, July 1993.
+
+   [2] Howes, T., Kille, S., Yeong, W., and C. Robbins, "The String
+       Representation of Standard Attribute Syntaxes", RFC 1488,
+       University of Michigan, ISODE Consortium, Performance Systems
+       International, NeXor Ltd., July 1993.
+
+   [3] "Specification of Basic Encoding Rules for Abstract Syntax
+       Notation One (ASN.1)", CCITT Recommendation X.209, 1988.
+
+6.  Author's Address
+
+       Tim Howes
+       University of Michigan
+       ITD Research Systems
+       535 W William St.
+       Ann Arbor, MI 48103-4943
+       USA
+
+       Phone: +1 313 747-4454
+       EMail: tim@umich.edu
+
+
+
+
+
+
+
+
+
+
+Howes                                                           [Page 3]
+\f
\ No newline at end of file
diff --git a/doc/rfc/rfc1777.txt b/doc/rfc/rfc1777.txt
new file mode 100644 (file)
index 0000000..f5593e7
--- /dev/null
@@ -0,0 +1,1235 @@
+
+
+
+
+
+
+Network Working Group                                           W. Yeong
+Request for Comments: 1777             Performance Systems International
+Obsoletes: 1487                                                 T. Howes
+Category: Standards Track                         University of Michigan
+                                                                S. Kille
+                                                        ISODE Consortium
+                                                              March 1995
+
+
+                 Lightweight Directory Access Protocol
+
+Status of this Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Abstract
+
+   The protocol described in this document is designed to provide access
+   to the X.500 Directory while not incurring the resource requirements
+   of the Directory Access Protocol (DAP). This protocol is specifically
+   targeted at simple management applications and browser applications
+   that provide simple read/write interactive access to the X.500
+   Directory, and is intended to be a complement to the DAP itself.
+
+   Key aspects of LDAP are:
+
+   - Protocol elements are carried directly over TCP or other transport,
+     bypassing much of the session/presentation overhead.
+
+   - Many protocol data elements are encoding as ordinary strings (e.g.,
+     Distinguished Names).
+
+   - A lightweight BER encoding is used to encode all protocol elements.
+
+1.  History
+
+   The tremendous interest in X.500 [1,2] technology in the Internet has
+   lead to efforts to reduce the high "cost of entry" associated with
+   use of the technology, such as the Directory Assistance Service [3]
+   and DIXIE [4]. While efforts such as these have met with success,
+   they have been solutions based on particular implementations and as
+   such have limited applicability.  This document continues the efforts
+   to define Directory protocol alternatives but departs from previous
+   efforts in that it consciously avoids dependence on particular
+
+
+
+Yeong, Howes & Kille                                            [Page 1]
+\f
+RFC 1777                          LDAP                        March 1995
+
+
+   implementations.
+
+2.  Protocol Model
+
+   The general model adopted by this protocol is one of clients
+   performing protocol operations against servers. In this model, this
+   is accomplished by a client transmitting a protocol request
+   describing the operation to be performed to a server, which is then
+   responsible for performing the necessary operations on the Directory.
+   Upon completion of the necessary operations, the server returns a
+   response containing any results or errors to the requesting client.
+   In keeping with the goal of easing the costs associated with use of
+   the Directory, it is an objective of this protocol to minimize the
+   complexity of clients so as to facilitate widespread deployment of
+   applications capable of utilizing the Directory.
+
+   Note that, although servers are required to return responses whenever
+   such responses are defined in the protocol, there is no requirement
+   for synchronous behavior on the part of either client or server
+   implementations: requests and responses for multiple operations may
+   be exchanged by client and servers in any order, as long as clients
+   eventually receive a response for every request that requires one.
+
+   Consistent with the model of servers performing protocol operations
+   on behalf of clients, it is also to be noted that protocol servers
+   are expected to handle referrals without resorting to the return of
+   such referrals to the client. This protocol makes no provisions for
+   the return of referrals to clients, as the model is one of servers
+   ensuring the performance of all necessary operations in the
+   Directory, with only final results or errors being returned by
+   servers to clients.
+
+   Note that this protocol can be mapped to a strict subset of the
+   directory abstract service, so it can be cleanly provided by the DAP.
+
+3.  Mapping Onto Transport Services
+
+   This protocol is designed to run over connection-oriented, reliable
+   transports, with all 8 bits in an octet being significant in the data
+   stream.  Specifications for two underlying services are defined here,
+   though others are also possible.
+
+3.1.  Transmission Control Protocol (TCP)
+
+   The LDAPMessage PDUs are mapped directly onto the TCP bytestream.
+   Server implementations running over the TCP should provide a protocol
+   listener on port 389.
+
+
+
+
+Yeong, Howes & Kille                                            [Page 2]
+\f
+RFC 1777                          LDAP                        March 1995
+
+
+3.2.  Connection Oriented Transport Service (COTS)
+
+   The connection is established.  No special use of T-Connect is made.
+   Each LDAPMessage PDU is mapped directly onto T-Data.
+
+4.  Elements of Protocol
+
+   For the purposes of protocol exchanges, all protocol operations are
+   encapsulated in a common envelope, the LDAPMessage, which is defined
+   as follows:
+
+     LDAPMessage ::=
+         SEQUENCE {
+              messageID      MessageID,
+              protocolOp     CHOICE {
+                                  bindRequest         BindRequest,
+                                  bindResponse        BindResponse,
+                                  unbindRequest       UnbindRequest,
+                                  searchRequest       SearchRequest,
+                                  searchResponse      SearchResponse,
+                                  modifyRequest       ModifyRequest,
+                                  modifyResponse      ModifyResponse,
+                                  addRequest          AddRequest,
+                                  addResponse         AddResponse,
+                                  delRequest          DelRequest,
+                                  delResponse         DelResponse,
+                                  modifyRDNRequest    ModifyRDNRequest,
+                                  modifyRDNResponse   ModifyRDNResponse,
+                                  compareDNRequest    CompareRequest,
+                                  compareDNResponse   CompareResponse,
+                                  abandonRequest      AbandonRequest
+                             }
+         }
+
+     MessageID ::= INTEGER (0 .. maxInt)
+
+   The function of the LDAPMessage is to provide an envelope containing
+   common fields required in all protocol exchanges. At this time the
+   only common field is a message ID, which is required to have a value
+   different from the values of any other requests outstanding in the
+   LDAP session of which this message is a part.
+
+   The message ID value must be echoed in all LDAPMessage envelopes
+   encapsulting responses corresponding to the request contained in the
+   LDAPMessage in which the message ID value was originally used.
+
+   In addition to the LDAPMessage defined above, the following
+   definitions are also used in defining protocol operations:
+
+
+
+Yeong, Howes & Kille                                            [Page 3]
+\f
+RFC 1777                          LDAP                        March 1995
+
+
+     LDAPString ::= OCTET STRING
+
+   The LDAPString is a notational convenience to indicate that, although
+   strings of LDAPString type encode as OCTET STRING types, the legal
+   character set in such strings is limited to the IA5 character set.
+
+     LDAPDN ::= LDAPString
+
+     RelativeLDAPDN ::= LDAPString
+
+   An LDAPDN and a RelativeLDAPDN are respectively defined to be the
+   representation of a Distinguished Name and a Relative Distinguished
+   Name after encoding according to the specification in [5], such that
+
+     <distinguished-name> ::= <name>
+
+     <relative-distinguished-name> ::= <name-component>
+
+   where <name> and <name-component> are as defined in [5].
+
+     AttributeValueAssertion ::=
+         SEQUENCE {
+              attributeType       AttributeType,
+              attributeValue      AttributeValue
+         }
+
+   The AttributeValueAssertion type definition  is similar to the one in
+   the X.500 Directory standards.
+
+     AttributeType ::= LDAPString
+
+     AttributeValue ::= OCTET STRING
+
+   An AttributeType value takes on as its value the textual string
+   associated with that AttributeType in the X.500 Directory standards.
+   For example, the AttributeType 'organizationName' with object
+   identifier 2.5.4.10 is represented as an AttributeType in this
+   protocol by the string "organizationName".  In the event that a
+   protocol implementation encounters an Attribute Type with which it
+   cannot associate a textual string, an ASCII string encoding of the
+   object identifier associated with the Attribute Type may be
+   subsitituted.  For example, the organizationName AttributeType may be
+   represented by the ASCII string "2.5.4.10" if a protocol
+   implementation is unable to associate the string "organizationName"
+   with it.
+
+
+
+
+
+
+Yeong, Howes & Kille                                            [Page 4]
+\f
+RFC 1777                          LDAP                        March 1995
+
+
+   A field of type AttributeValue takes on as its value an octet string
+   encoding of a Directory AttributeValue type. The definition of these
+   string encodings for different Directory AttributeValue types may be
+   found in companions to this document that define the encodings of
+   various attribute syntaxes such as [6].
+
+     LDAPResult ::=
+         SEQUENCE {
+             resultCode    ENUMERATED {
+                             success                      (0),
+                             operationsError              (1),
+                             protocolError                (2),
+                             timeLimitExceeded            (3),
+                             sizeLimitExceeded            (4),
+                             compareFalse                 (5),
+                             compareTrue                  (6),
+                             authMethodNotSupported       (7),
+                             strongAuthRequired           (8),
+                             noSuchAttribute              (16),
+                             undefinedAttributeType       (17),
+                             inappropriateMatching        (18),
+                             constraintViolation          (19),
+                             attributeOrValueExists       (20),
+                             invalidAttributeSyntax       (21),
+                             noSuchObject                 (32),
+                             aliasProblem                 (33),
+                             invalidDNSyntax              (34),
+                             isLeaf                       (35),
+                             aliasDereferencingProblem    (36),
+                             inappropriateAuthentication  (48),
+                             invalidCredentials           (49),
+                             insufficientAccessRights     (50),
+                             busy                         (51),
+                             unavailable                  (52),
+                             unwillingToPerform           (53),
+                             loopDetect                   (54),
+                             namingViolation              (64),
+                             objectClassViolation         (65),
+                             notAllowedOnNonLeaf          (66),
+                             notAllowedOnRDN              (67),
+                             entryAlreadyExists           (68),
+                             objectClassModsProhibited    (69),
+                             other                        (80)
+                           },
+             matchedDN     LDAPDN,
+             errorMessage  LDAPString
+         }
+
+
+
+
+Yeong, Howes & Kille                                            [Page 5]
+\f
+RFC 1777                          LDAP                        March 1995
+
+
+   The LDAPResult is the construct used in this protocol to return
+   success or failure indications from servers to clients. In response
+   to various requests, servers will return responses containing fields
+   of type LDAPResult to indicate the final status of a protocol
+   operation request.  The errorMessage field of this construct may, at
+   the servers option, be used to return an ASCII string containing a
+   textual, human-readable error diagnostic. As this error diagnostic is
+   not standardized, implementations should not rely on the values
+   returned.  If the server chooses not to return a textual diagnostic,
+   the errorMessage field of the LDAPResult type should contain a zero
+   length string.
+
+   For resultCodes of noSuchObject, aliasProblem, invalidDNSyntax,
+   isLeaf, and aliasDereferencingProblem, the matchedDN field is set to
+   the name of the lowest entry (object or alias) in the DIT that was
+   matched and is a truncated form of the name provided or, if an alias
+   has been dereferenced, of the resulting name.  The matchedDN field
+   should be set to NULL DN (a zero length string) in all other cases.
+
+4.1.  Bind Operation
+
+   The function of the Bind Operation is to initiate a protocol session
+   between a client and a server, and to allow the authentication of the
+   client to the server. The Bind Operation must be the first operation
+   request received by a server from a client in a protocol session.
+   The Bind Request is defined as follows:
+
+     BindRequest ::=
+         [APPLICATION 0] SEQUENCE {
+                             version   INTEGER (1 .. 127),
+                             name      LDAPDN,
+                             authentication CHOICE {
+                                  simple        [0] OCTET STRING,
+                                  krbv42LDAP    [1] OCTET STRING,
+                                  krbv42DSA     [2] OCTET STRING
+                             }
+         }
+
+   Parameters of the Bind Request are:
+
+   - version: A version number indicating the version of the protocol to
+     be used in this protocol session.  This document describes version
+     2 of the LDAP protocol.  Note that there is no version negotiation,
+     and the client should just set this parameter to the version it
+     desires.
+
+
+
+
+
+
+Yeong, Howes & Kille                                            [Page 6]
+\f
+RFC 1777                          LDAP                        March 1995
+
+
+   - name: The name of the Directory object that the client wishes to
+     bind as.  This field may take on a null value (a zero length
+     string) for the purposes of anonymous binds.
+
+   - authentication: information used to authenticate the name, if any,
+     provided in the Bind Request. The "simple" authentication option
+     provides minimal authentication facilities, with the contents of
+     the authentication field consisting only of a cleartext password.
+     This option should also be used when unauthenticated or anonymous
+     binds are to be performed, with the field containing a zero length
+     string in such cases. Kerberos version 4 [7] authentication to the
+     LDAP server and the DSA is accomplished by using the "krbv42LDAP"
+     and "krbv42DSA" authentication options, respectively.  Note that
+     though they are referred to as separate entities here, there is no
+     requirement these two entities be distinct (i.e., a DSA could speak
+     LDAP directly).  Two separate authentication options are provided
+     to support all implementations.  Each octet string should contain
+     the kerberos ticket (e.g., as returned by krb_mk_req()) for the
+     appropriate service.  The suggested service name for authentication
+     to the LDAP server is "ldapserver".  The suggested service name for
+     authentication to the DSA is "x500dsa".  In both cases, the
+     suggested instance name for the service is the name of the host on
+     which the service is running.  Of course, the actual service names
+     and instances will depend on what is entered in the local kerberos
+     principle database.
+
+   The Bind Operation requires a response, the Bind Response, which is
+   defined as:
+
+     BindResponse ::= [APPLICATION 1] LDAPResult
+
+   A Bind Response consists simply of an indication from the server of
+   the status of the client's request for the initiation of a protocol
+   session.
+
+   Upon receipt of a Bind Request, a protocol server will authenticate
+   the requesting client if necessary, and attempt to set up a protocol
+   session with that client. The server will then return a Bind Response
+   to the client indicating the status of the session setup request.
+
+4.2.  Unbind Operation
+
+   The function of the Unbind Operation is to terminate a protocol
+   session.  The Unbind Operation is defined as follows:
+
+     UnbindRequest ::= [APPLICATION 2] NULL
+
+
+
+
+
+Yeong, Howes & Kille                                            [Page 7]
+\f
+RFC 1777                          LDAP                        March 1995
+
+
+   The Unbind Operation has no response defined. Upon transmission of an
+   UnbindRequest, a protocol client may assume that the protocol session
+   is terminated. Upon receipt of an UnbindRequest, a protocol server
+   may assume that the requesting client has terminated the session and
+   that all outstanding requests may be discarded.
+
+4.3.  Search Operation
+
+   The Search Operation allows a client to request that a search be
+   performed on its behalf by a server. The Search Request is defined as
+   follows:
+
+     SearchRequest ::=
+         [APPLICATION 3] SEQUENCE {
+             baseObject    LDAPDN,
+             scope         ENUMERATED {
+                                baseObject            (0),
+                                singleLevel           (1),
+                                wholeSubtree          (2)
+                           },
+             derefAliases  ENUMERATED {
+                                        neverDerefAliases     (0),
+                                        derefInSearching      (1),
+                                        derefFindingBaseObj   (2),
+                                        derefAlways           (3)
+                                   },
+             sizeLimit     INTEGER (0 .. maxInt),
+             timeLimit     INTEGER (0 .. maxInt),
+             attrsOnly     BOOLEAN,
+             filter        Filter,
+             attributes    SEQUENCE OF AttributeType
+     }
+
+     Filter ::=
+         CHOICE {
+             and                [0] SET OF Filter,
+             or                 [1] SET OF Filter,
+             not                [2] Filter,
+             equalityMatch      [3] AttributeValueAssertion,
+             substrings         [4] SubstringFilter,
+             greaterOrEqual     [5] AttributeValueAssertion,
+             lessOrEqual        [6] AttributeValueAssertion,
+             present            [7] AttributeType,
+             approxMatch        [8] AttributeValueAssertion
+         }
+
+     SubstringFilter
+         SEQUENCE {
+
+
+
+Yeong, Howes & Kille                                            [Page 8]
+\f
+RFC 1777                          LDAP                        March 1995
+
+
+             type               AttributeType,
+             SEQUENCE OF CHOICE {
+                 initial        [0] LDAPString,
+                 any            [1] LDAPString,
+                 final          [2] LDAPString
+             }
+         }
+
+   Parameters of the Search Request are:
+
+   - baseObject: An LDAPDN that is the base object entry relative to
+     which the search is to be performed.
+
+   - scope: An indicator of the scope of the search to be performed. The
+     semantics of the possible values of this field are identical to the
+     semantics of the scope field in the Directory Search Operation.
+
+   - derefAliases: An indicator as to how alias objects should be
+     handled in searching.  The semantics of the possible values of
+     this field are, in order of increasing value:
+
+             neverDerefAliases: do not dereference aliases in searching
+             or in locating the base object of the search;
+
+             derefInSearching: dereference aliases in subordinates of
+             the base object in searching, but not in locating the
+             base object of the search;
+
+             derefFindingBaseObject: dereference aliases in locating
+             the base object of the search, but not when searching
+             subordinates of the base object;
+
+             derefAlways: dereference aliases both in searching and in
+             locating the base object of the search.
+
+   - sizelimit: A sizelimit that restricts the maximum number of entries
+     to be returned as a result of the search. A value of 0 in this
+     field indicates that no sizelimit restrictions are in effect for
+     the search.
+
+   - timelimit: A timelimit that restricts the maximum time (in seconds)
+     allowed for a search. A value of 0 in this field indicates that no
+     timelimit restrictions are in effect for the search.
+
+   - attrsOnly: An indicator as to whether search results should contain
+     both attribute types and values, or just attribute types.  Setting
+     this field to TRUE causes only attribute types (no values) to be
+     returned.  Setting this field to FALSE causes both attribute types
+
+
+
+Yeong, Howes & Kille                                            [Page 9]
+\f
+RFC 1777                          LDAP                        March 1995
+
+
+     and values to be returned.
+
+   - filter: A filter that defines the conditions that must be fulfilled
+     in order for the search to match a given entry.
+
+   - attributes: A list of the attributes from each entry found as a
+     result of the search to be returned. An empty list signifies that
+     all attributes from each entry found in the search are to be
+     returned.
+
+   The results of the search attempted by the server upon receipt of a
+   Search Request are returned in Search Responses, defined as follows:
+
+  Search Response ::=
+      CHOICE {
+           entry          [APPLICATION 4] SEQUENCE {
+                               objectName     LDAPDN,
+                               attributes     SEQUENCE OF SEQUENCE {
+                                                   AttributeType,
+                                                   SET OF AttributeValue
+                                              }
+                          },
+           resultCode     [APPLICATION 5] LDAPResult
+       }
+
+   Upon receipt of a Search Request, a server will perform the necessary
+   search of the DIT.
+
+   The server will return to the client a sequence of responses
+   comprised of:
+
+   - Zero or more Search Responses each consisting of an entry found
+     during the search; with the response sequence terminated by
+
+   - A single Search Response containing an indication of success, or
+     detailing any errors that have occurred.
+
+   Each entry returned will contain all attributes, complete with
+   associated values if necessary, as specified in the 'attributes'
+   field of the Search Request.
+
+   Note that an X.500 "list" operation can be emulated by a one-level
+   LDAP search operation with a filter checking for the existence of the
+   objectClass attribute, and that an X.500 "read" operation can be
+   emulated by a base object LDAP search operation with the same filter.
+
+
+
+
+
+
+Yeong, Howes & Kille                                           [Page 10]
+\f
+RFC 1777                          LDAP                        March 1995
+
+
+4.4.  Modify Operation
+
+   The Modify Operation allows a client to request that a modification
+   of the DIB be performed on its behalf by a server.  The Modify
+   Request is defined as follows:
+
+ModifyRequest ::=
+    [APPLICATION 6] SEQUENCE {
+         object         LDAPDN,
+         modification   SEQUENCE OF SEQUENCE {
+                             operation      ENUMERATED {
+                                                 add       (0),
+                                                 delete    (1),
+                                                 replace   (2)
+                                            },
+                             modification   SEQUENCE {
+                                               type    AttributeType,
+                                               values  SET OF
+                                                         AttributeValue
+                                            }
+                        }
+    }
+
+   Parameters of the Modify Request are:
+
+   - object: The object to be modified. The value of this field should
+     name the object to be modified after all aliases have been
+     dereferenced. The server will not perform any alias dereferencing
+     in determining the object to be modified.
+
+   - A list of modifications to be performed on the entry to be modified.
+     The entire list of entry modifications should be performed
+     in the order they are listed, as a single atomic operation.  While
+     individual modifications may violate the Directory schema, the
+     resulting entry after the entire list of modifications is performed
+     must conform to the requirements of the Directory schema. The
+     values that may be taken on by the 'operation' field in each
+     modification construct have the following semantics respectively:
+
+             add: add values listed to the given attribute, creating
+             the attribute if necessary;
+
+             delete: delete values listed from the given attribute,
+
+     removing the entire attribute if no values are listed, or
+     if all current values of the attribute are listed for
+     deletion;
+
+
+
+
+Yeong, Howes & Kille                                           [Page 11]
+\f
+RFC 1777                          LDAP                        March 1995
+
+
+     replace: replace existing values of the given attribute
+     with the new values listed, creating the attribute if
+     necessary.
+
+   The result of the modify attempted by the server upon receipt of a
+   Modify Request is returned in a Modify Response, defined as follows:
+
+     ModifyResponse ::= [APPLICATION 7] LDAPResult
+
+   Upon receipt of a Modify Request, a server will perform the necessary
+   modifications to the DIB.
+
+   The server will return to the client a single Modify Response
+   indicating either the successful completion of the DIB modification,
+   or the reason that the modification failed. Note that due to the
+   requirement for atomicity in applying the list of modifications in
+   the Modify Request, the client may expect that no modifications of
+   the DIB have been performed if the Modify Response received indicates
+   any sort of error, and that all requested modifications have been
+   performed if the Modify Response indicates successful completion of
+   the Modify Operation.
+
+4.5.  Add Operation
+
+   The Add Operation allows a client to request the addition of an entry
+   into the Directory. The Add Request is defined as follows:
+
+     AddRequest ::=
+         [APPLICATION 8] SEQUENCE {
+              entry          LDAPDN,
+              attrs          SEQUENCE OF SEQUENCE {
+                                  type          AttributeType,
+                                  values        SET OF AttributeValue
+                             }
+         }
+
+   Parameters of the Add Request are:
+
+   - entry: the Distinguished Name of the entry to be added. Note that
+     all components of the name except for the last RDN component must
+     exist for the add to succeed.
+
+   - attrs: the list of attributes that make up the content of the entry
+     being added.
+
+   The result of the add attempted by the server upon receipt of a Add
+   Request is returned in the Add Response, defined as follows:
+
+
+
+
+Yeong, Howes & Kille                                           [Page 12]
+\f
+RFC 1777                          LDAP                        March 1995
+
+
+     AddResponse ::= [APPLICATION 9] LDAPResult
+
+   Upon receipt of an Add Request, a server will attempt to perform the
+   add requested. The result of the add attempt will be returned to the
+   client in the Add Response.
+
+4.6.  Delete Operation
+
+   The Delete Operation allows a client to request the removal of an
+   entry from the Directory. The Delete Request is defined as follows:
+
+     DelRequest ::= [APPLICATION 10] LDAPDN
+
+   The Delete Request consists only of the Distinguished Name of the
+   entry to be deleted.  The result of the delete attempted by the
+   server upon receipt of a Delete Request is returned in the Delete
+   Response, defined as follows:
+
+     DelResponse ::= [APPLICATION 11] LDAPResult
+
+   Upon receipt of a Delete Request, a server will attempt to perform
+   the entry removal requested. The result of the delete attempt will be
+   returned to the client in the Delete Response. Note that only leaf
+   objects may be deleted with this operation.
+
+4.7.  Modify RDN Operation
+
+   The Modify RDN Operation allows a client to change the last component
+   of the name of an entry in the Directory. The Modify RDN Request is
+   defined as follows:
+
+     ModifyRDNRequest ::=
+         [APPLICATION 12] SEQUENCE {
+              entry          LDAPDN,
+              newrdn         RelativeLDAPDN,
+              deleteoldrdn   BOOLEAN
+         }
+
+   Parameters of the Modify RDN Request are:
+
+   - entry: the name of the entry to be changed.
+
+   - newrdn: the RDN that will form the last component of the new name.
+
+   - deleteoldrdn: a boolean parameter that controls whether the old RDN
+     attribute values should be retained as attributes of the entry or
+     deleted from the entry.
+
+
+
+
+Yeong, Howes & Kille                                           [Page 13]
+\f
+RFC 1777                          LDAP                        March 1995
+
+
+   The result of the name change attempted by the server upon receipt of
+   a Modify RDN Request is returned in the Modify RDN Response, defined
+   as follows:
+
+     ModifyRDNResponse ::= [APPLICATION 13] LDAPResult
+
+   Upon receipt of a Modify RDN Request, a server will attempt to
+   perform the name change. The result of the name change attempt will
+   be returned to the client in the Modify RDN Response. The attributes
+   that make up the old RDN are deleted from the entry, or kept,
+   depending on the setting of the deleteoldrdn parameter.
+
+4.8.  Compare Operation
+
+   The Compare Operation allows a client to compare an assertion
+   provided with an entry in the Directory. The Compare Request is
+   defined as follows:
+
+     CompareRequest ::=
+         [APPLICATION 14] SEQUENCE {
+              entry          LDAPDN,
+              ava            AttributeValueAssertion
+         }
+
+   Parameters of the Compare Request are:
+
+   - entry: the name of the entry to be compared with.
+
+   - ava: the assertion with which the entry is to be compared.
+
+   The result of the compare attempted by the server upon receipt of a
+   Compare Request is returned in the Compare Response, defined as
+   follows:
+
+     CompareResponse ::= [APPLICATION 15] LDAPResult
+
+   Upon receipt of a Compare Request, a server will attempt to perform
+   the requested comparison. The result of the comparison will be
+   returned to the client in the Compare Response. Note that errors and
+   the result of comparison are all returned in the same construct.
+
+6.9.  Abandon Operation
+
+   The function of the Abandon Operation is to allow a client to request
+   that the server abandon an outstanding operation.  The Abandon
+   Request is defined as follows:
+
+     AbandonRequest ::= [APPLICATION 16] MessageID
+
+
+
+Yeong, Howes & Kille                                           [Page 14]
+\f
+RFC 1777                          LDAP                        March 1995
+
+
+   There is no response defined in the Abandon Operation. Upon
+   transmission of an Abandon Operation, a client may expect that the
+   operation identityfied by the Message ID in the Abandon Request has
+   been abandoned. In the event that a server receives an Abandon
+   Request on a Search Operation in the midst of transmitting responses
+   to that search, that server should cease transmitting responses to
+   the abandoned search immediately.
+
+5.  Protocol Element Encodings
+
+   The protocol elements of LDAP are encoded for exchange using the
+   Basic Encoding Rules (BER) [12] of ASN.1 [11]. However, due to the
+   high overhead involved in using certain elements of the BER, the
+   following additional restrictions are placed on BER-encodings of LDAP
+   protocol elements:
+
+   (1)  Only the definite form of length encoding will be used.
+
+   (2)  Bitstrings and octet strings and all character string types
+        will be encoded in the primitive form only.
+
+6.  Security Considerations
+
+   This version of the protocol provides facilities only for simple
+   authentication using a cleartext password, and for kerberos version 4
+   authentication.  Future versions of LDAP will likely include support
+   for other authentication methods.
+
+7.  Bibliography
+
+   [1] The Directory: Overview of Concepts, Models and Service.  CCITT
+       Recommendation X.500, 1988.
+
+   [2] Information Processing Systems -- Open Systems Interconnection --
+       The Directory: Overview of Concepts, Models and Service.  ISO/IEC
+       JTC 1/SC21; International Standard 9594-1, 1988
+
+   [3] Rose, M., "Directory Assistance Service", RFC 1202, Performance
+       Systems International, Inc., February 1991.
+
+   [4] Howes, T., Smith, M., and B. Beecher, "DIXIE Protocol
+       Specification, RFC 1249, University of Michigan, August 1991.
+
+   [5] Kille, S., "A String Representation of Distinguished Names", RFC
+       1779, ISODE Consortium, March 1995.
+
+
+
+
+
+
+Yeong, Howes & Kille                                           [Page 15]
+\f
+RFC 1777                          LDAP                        March 1995
+
+
+   [6] Howes, T., Kille, S., Yeong, W., and C. Robbins, "Lightweight
+       Directory Access Protocol", RFC 1488, University of Michigan,
+       ISODE Consortium, Performance Systems International, NeXor Ltd.,
+       July 1993.
+
+   [7] Kerberos Authentication and Authorization System.  S.P. Miller,
+       B.C. Neuman, J.I. Schiller, J.H. Saltzer; MIT Project Athena
+       Documentation Section E.2.1, December 1987.
+
+   [8] The Directory: Models.  CCITT Recommendation X.501 ISO/IEC JTC
+       1/SC21; International Standard 9594-2, 1988.
+
+  [10] The Directory: Abstract Service Definition.  CCITT Recommendation
+       X.511, ISO/IEC JTC 1/SC21; International Standard 9594-3, 1988.
+
+  [11] Specification of Abstract Syntax Notation One (ASN.1).  CCITT
+       Recommendation X.208, 1988.
+
+  [12] Specification of Basic Encoding Rules for Abstract Syntax
+       Notation One (ASN.1).  CCITT Recommendation X.209, 1988.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Yeong, Howes & Kille                                           [Page 16]
+\f
+RFC 1777                          LDAP                        March 1995
+
+
+10.  Authors' Addresses
+
+       Wengyik Yeong
+       PSI Inc.
+       510 Huntmar Park Drive
+       Herndon, VA 22070
+       USA
+
+       Phone:  +1 703-450-8001
+       EMail:  yeongw@psilink.com
+
+
+       Tim Howes
+       University of Michigan
+       ITD Research Systems
+       535 W William St.
+       Ann Arbor, MI 48103-4943
+       USA
+
+       Phone:  +1 313 747-4454
+       EMail:   tim@umich.edu
+
+
+       Steve Kille
+       ISODE Consortium
+       PO Box 505
+       London
+       SW11 1DX
+       UK
+
+       Phone:  +44-71-223-4062
+       EMail:  S.Kille@isode.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Yeong, Howes & Kille                                           [Page 17]
+\f
+RFC 1777                          LDAP                        March 1995
+
+
+Appendix A - Complete ASN.1 Definition
+
+Lightweight-Directory-Access-Protocol DEFINITIONS IMPLICIT TAGS ::=
+
+BEGIN
+
+LDAPMessage ::=
+    SEQUENCE {
+         messageID      MessageID,
+                        -- unique id in request,
+                        -- to be echoed in response(s)
+         protocolOp     CHOICE {
+                             searchRequest       SearchRequest,
+                             searchResponse      SearchResponse,
+                             modifyRequest       ModifyRequest,
+                             modifyResponse      ModifyResponse,
+                             addRequest          AddRequest,
+                             addResponse         AddResponse,
+                             delRequest          DelRequest,
+                             delResponse         DelResponse,
+                             modifyDNRequest     ModifyDNRequest,
+                             modifyDNResponse    ModifyDNResponse,
+                             compareDNRequest    CompareRequest,
+                             compareDNResponse   CompareResponse,
+                             bindRequest         BindRequest,
+                             bindResponse        BindResponse,
+                             abandonRequest      AbandonRequest,
+                             unbindRequest       UnbindRequest
+                        }
+    }
+
+BindRequest ::=
+    [APPLICATION 0] SEQUENCE {
+         version        INTEGER (1 .. 127),
+                        -- current version is 2
+         name           LDAPDN,
+                        -- null name implies an anonymous bind
+         authentication CHOICE {
+                             simple        [0] OCTET STRING,
+                                       -- a zero length octet string
+                                       -- implies an unauthenticated
+                                       -- bind.
+                             krbv42LDAP    [1] OCTET STRING,
+                             krbv42DSA     [2] OCTET STRING
+                                       -- values as returned by
+                                       -- krb_mk_req()
+                                       -- Other values in later versions
+                                       -- of this protocol.
+
+
+
+Yeong, Howes & Kille                                           [Page 18]
+\f
+RFC 1777                          LDAP                        March 1995
+
+
+                        }
+    }
+
+BindResponse ::= [APPLICATION 1] LDAPResult
+
+UnbindRequest ::= [APPLICATION 2] NULL
+
+SearchRequest ::=
+    [APPLICATION 3] SEQUENCE {
+         baseObject     LDAPDN,
+         scope          ENUMERATED {
+                             baseObject            (0),
+                             singleLevel           (1),
+                             wholeSubtree          (2)
+                        },
+         derefAliases   ENUMERATED {
+                             neverDerefAliases     (0),
+                             derefInSearching      (1),
+                             derefFindingBaseObj   (2),
+                             alwaysDerefAliases    (3)
+                        },
+         sizeLimit      INTEGER (0 .. maxInt),
+                        -- value of 0 implies no sizelimit
+         timeLimit      INTEGER (0 .. maxInt),
+                        -- value of 0 implies no timelimit
+         attrsOnly     BOOLEAN,
+                        -- TRUE, if only attributes (without values)
+                        -- to be returned.
+         filter         Filter,
+         attributes     SEQUENCE OF AttributeType
+    }
+
+SearchResponse ::=
+    CHOICE {
+         entry          [APPLICATION 4] SEQUENCE {
+                             objectName     LDAPDN,
+                             attributes     SEQUENCE OF SEQUENCE {
+                                              AttributeType,
+                                              SET OF
+                                                AttributeValue
+                                            }
+                        },
+         resultCode     [APPLICATION 5] LDAPResult
+    }
+
+ModifyRequest ::=
+    [APPLICATION 6] SEQUENCE {
+         object         LDAPDN,
+
+
+
+Yeong, Howes & Kille                                           [Page 19]
+\f
+RFC 1777                          LDAP                        March 1995
+
+
+         modifications  SEQUENCE OF SEQUENCE {
+                             operation     ENUMERATED {
+                                             add      (0),
+                                             delete   (1),
+                                             replace  (2)
+                                           },
+                             modification  SEQUENCE {
+                                             type     AttributeType,
+                                             values   SET OF
+                                                        AttributeValue
+                                           }
+                        }
+    }
+
+
+ModifyResponse ::= [APPLICATION 7] LDAPResult
+
+AddRequest ::=
+    [APPLICATION 8] SEQUENCE {
+         entry          LDAPDN,
+         attrs          SEQUENCE OF SEQUENCE {
+                             type          AttributeType,
+                             values        SET OF AttributeValue
+                        }
+    }
+
+AddResponse ::= [APPLICATION 9] LDAPResult
+
+DelRequest ::= [APPLICATION 10] LDAPDN
+
+DelResponse ::= [APPLICATION 11] LDAPResult
+
+ModifyRDNRequest ::=
+    [APPLICATION 12] SEQUENCE {
+         entry          LDAPDN,
+         newrdn         RelativeLDAPDN -- old RDN always deleted
+    }
+
+ModifyRDNResponse ::= [APPLICATION 13] LDAPResult
+
+CompareRequest ::=
+    [APPLICATION 14] SEQUENCE {
+         entry          LDAPDN,
+         ava            AttributeValueAssertion
+    }
+
+CompareResponse ::= [APPLICATION 15] LDAPResult
+
+
+
+
+Yeong, Howes & Kille                                           [Page 20]
+\f
+RFC 1777                          LDAP                        March 1995
+
+
+AbandonRequest ::= [APPLICATION 16] MessageID
+
+MessageID ::= INTEGER (0 .. maxInt)
+
+LDAPDN ::= LDAPString
+
+RelativeLDAPDN ::= LDAPString
+
+Filter ::=
+    CHOICE {
+        and            [0] SET OF Filter,
+        or             [1] SET OF Filter,
+        not            [2] Filter,
+        equalityMatch  [3] AttributeValueAssertion,
+        substrings     [4] SubstringFilter,
+        greaterOrEqual [5] AttributeValueAssertion,
+        lessOrEqual    [6] AttributeValueAssertion,
+        present        [7] AttributeType,
+        approxMatch    [8] AttributeValueAssertion
+    }
+
+LDAPResult ::=
+    SEQUENCE {
+        resultCode    ENUMERATED {
+                        success                      (0),
+                        operationsError              (1),
+                        protocolError                (2),
+                        timeLimitExceeded            (3),
+                        sizeLimitExceeded            (4),
+                        compareFalse                 (5),
+                        compareTrue                  (6),
+                        authMethodNotSupported       (7),
+                        strongAuthRequired           (8),
+                        noSuchAttribute              (16),
+                        undefinedAttributeType       (17),
+                        inappropriateMatching        (18),
+                        constraintViolation          (19),
+                        attributeOrValueExists       (20),
+                        invalidAttributeSyntax       (21),
+                        noSuchObject                 (32),
+                        aliasProblem                 (33),
+                        invalidDNSyntax              (34),
+                        isLeaf                       (35),
+                        aliasDereferencingProblem    (36),
+                        inappropriateAuthentication  (48),
+                        invalidCredentials           (49),
+                        insufficientAccessRights     (50),
+                        busy                         (51),
+
+
+
+Yeong, Howes & Kille                                           [Page 21]
+\f
+RFC 1777                          LDAP                        March 1995
+
+
+                        unavailable                  (52),
+                        unwillingToPerform           (53),
+                        loopDetect                   (54),
+                        namingViolation              (64),
+                        objectClassViolation         (65),
+                        notAllowedOnNonLeaf          (66),
+                        notAllowedOnRDN              (67),
+                        entryAlreadyExists           (68),
+                        objectClassModsProhibited    (69),
+                        other                        (80)
+                      },
+        matchedDN     LDAPDN,
+        errorMessage  LDAPString
+    }
+
+AttributeType ::= LDAPString
+                -- text name of the attribute, or dotted
+                -- OID representation
+
+AttributeValue ::= OCTET STRING
+
+AttributeValueAssertion ::=
+    SEQUENCE {
+        attributeType        AttributeType,
+        attributeValue       AttributeValue
+    }
+
+SubstringFilter ::=
+    SEQUENCE {
+        type               AttributeType,
+        SEQUENCE OF CHOICE {
+          initial          [0] LDAPString,
+          any              [1] LDAPString,
+          final            [2] LDAPString
+      }
+    }
+
+LDAPString ::= OCTET STRING
+
+maxInt INTEGER ::= 65535
+END
+
+
+
+
+
+
+
+
+
+
+Yeong, Howes & Kille                                           [Page 22]
+\f
diff --git a/doc/rfc/rfc1778.txt b/doc/rfc/rfc1778.txt
new file mode 100644 (file)
index 0000000..7d99b02
--- /dev/null
@@ -0,0 +1,675 @@
+
+
+
+
+
+
+Network Working Group                                           T. Howes
+Request for Comments: 1778                        University of Michigan
+Obsoletes: 1488                                                 S. Kille
+Category: Standards Track                               ISODE Consortium
+                                                                W. Yeong
+                                       Performance Systems International
+                                                              C. Robbins
+                                                              NeXor Ltd.
+                                                              March 1995
+
+
+        The String Representation of Standard Attribute Syntaxes
+
+Status of this Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Abstract
+
+   The Lightweight Directory Access Protocol (LDAP) [9] requires that
+   the contents of AttributeValue fields in protocol elements be octet
+   strings.  This document defines the requirements that must be
+   satisfied by encoding rules used to render X.500 Directory attribute
+   syntaxes into a form suitable for use in the LDAP, then goes on to
+   define the encoding rules for the standard set of attribute syntaxes
+   defined in [1,2] and [3].
+
+1.  Attribute Syntax Encoding Requirements.
+
+   This section defines general requirements for lightweight directory
+   protocol attribute syntax encodings. All documents defining attribute
+   syntax encodings for use by the lightweight directory protocols are
+   expected to conform to these requirements.
+
+   The encoding rules defined for a given attribute syntax must produce
+   octet strings.  To the greatest extent possible, encoded octet
+   strings should be usable in their native encoded form for display
+   purposes. In particular, encoding rules for attribute syntaxes
+   defining non-binary values should produce strings that can be
+   displayed with little or no translation by clients implementing the
+   lightweight directory protocols.
+
+
+
+
+
+
+Howes, Kille, Yeong & Robbins                                   [Page 1]
+\f
+RFC 1778                    Syntax Encoding                   March 1995
+
+
+2.  Standard Attribute Syntax Encodings
+
+   For the purposes of defining the encoding rules for the standard
+   attribute syntaxes, the following auxiliary BNF definitions will be
+   used:
+
+     <a> ::= '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' | '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'
+
+     <d> ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
+
+     <hex-digit> ::= <d> | 'a' | 'b' | 'c' | 'd' | 'e' | 'f' |
+                      'A' | 'B' | 'C' | 'D' | 'E' | 'F'
+
+     <k> ::= <a> | <d> | '-'
+
+     <p> ::= <a> | <d> | ''' | '(' | ')' | '+' | ',' | '-' | '.' |
+             '/' | ':' | '?' | ' '
+
+     <CRLF> ::= The ASCII newline character with hexadecimal value 0x0A
+
+     <letterstring> ::= <a> | <a> <letterstring>
+
+     <numericstring> ::= <d> | <d> <numericstring>
+
+     <keystring> ::= <a> | <a> <anhstring>
+
+     <anhstring> ::= <k> | <k> <anhstring>
+
+     <printablestring> ::= <p> | <p> <printablestring>
+
+     <space> ::= ' ' | ' ' <space>
+
+2.1.  Undefined
+
+   Values of type Undefined are encoded as if they were values of type
+   Octet String, with the string value being the BER-encoded version of
+   the value.
+
+2.2.  Case Ignore String
+
+   A string of type caseIgnoreStringSyntax is encoded as the string
+   value itself.
+
+
+
+
+Howes, Kille, Yeong & Robbins                                   [Page 2]
+\f
+RFC 1778                    Syntax Encoding                   March 1995
+
+
+2.3.  Case Exact String
+
+   The encoding of a string of type caseExactStringSyntax is the string
+   value itself.
+
+2.4.  Printable String
+
+   The encoding of a string of type printableStringSyntax is the string
+   value itself.
+
+2.5.  Numeric String
+
+   The encoding of a string of type numericStringSyntax is the string
+   value itself.
+
+2.6.  Octet String
+
+   The encoding of a string of type octetStringSyntax is the string
+   value itself.
+
+2.7.  Case Ignore IA5 String
+
+   The encoding of a string of type caseIgnoreIA5String is the string
+   value itself.
+
+2.8.  IA5 String
+
+   The encoding of a string of type iA5StringSyntax is the string value
+   itself.
+
+2.9.  T61 String
+
+   The encoding of a string of type t61StringSyntax is the string value
+   itself.
+
+2.10.  Case Ignore List
+
+   Values of type caseIgnoreListSyntax are encoded according to the
+   following BNF:
+
+<caseignorelist> ::= <caseignorestring> |
+                     <caseignorestring> '$' <caseignorelist>
+
+<caseignorestring> ::= a string encoded according to the rules for Case
+                       Ignore String as above.
+
+
+
+
+
+
+Howes, Kille, Yeong & Robbins                                   [Page 3]
+\f
+RFC 1778                    Syntax Encoding                   March 1995
+
+
+2.11.  Case Exact List
+
+   Values of type caseExactListSyntax are encoded according to the
+   following BNF:
+
+<caseexactlist> ::= <caseexactstring> |
+                     <caseexactstring> '$' <caseexactlist>
+
+<caseexactstring> ::= a string encoded according to the rules for Case
+                      Exact String as above.
+
+2.12.  Distinguished Name
+
+   Values of type distinguishedNameSyntax are encoded to have the
+   representation defined in [5].
+
+2.13.  Boolean
+
+   Values of type booleanSyntax are encoded according to the following
+   BNF:
+
+     <boolean> ::= "TRUE" | "FALSE"
+
+   Boolean values have an encoding of "TRUE" if they are logically true,
+   and have an encoding of "FALSE" otherwise.
+
+2.14.  Integer
+
+   Values of type integerSyntax are encoded as the decimal
+   representation of their values, with each decimal digit represented
+   by the its character equivalent. So the digit 1 is represented by the
+   character
+
+2.15.  Object Identifier
+
+   Values of type objectIdentifierSyntax are encoded according to the
+   following BNF:
+
+     <oid> ::= <descr> | <descr> '.' <numericoid> | <numericoid>
+
+     <descr> ::= <keystring>
+
+     <numericoid> ::= <numericstring> | <numericstring> '.' <numericoid>
+
+   In the above BNF, <descr> is the syntactic representation of an
+   object descriptor. When encoding values of type
+   objectIdentifierSyntax, the first encoding option should be used in
+   preference to the second, which should be used in preference to the
+
+
+
+Howes, Kille, Yeong & Robbins                                   [Page 4]
+\f
+RFC 1778                    Syntax Encoding                   March 1995
+
+
+   third wherever possible. That is, in encoding object identifiers,
+   object descriptors (where assigned and known by the implementation)
+   should be used in preference to numeric oids to the greatest extent
+   possible. For example, in encoding the object identifier representing
+   an organizationName, the descriptor "organizationName" is preferable
+   to "ds.4.10", which is in turn preferable to the string "2.5.4.10".
+
+2.16.  Telephone Number
+
+   Values of type telephoneNumberSyntax are encoded as if they were
+   Printable String types.
+
+2.17.  Telex Number
+
+   Values of type telexNumberSyntax are encoded according to the
+   following BNF:
+
+     <telex-number> ::= <actual-number> '$' <country> '$' <answerback>
+
+     <actual-number> ::= <printablestring>
+
+     <country> ::= <printablestring>
+
+     <answerback> ::= <printablestring>
+
+   In the above, <actual-number> is the syntactic representation of the
+   number portion of the TELEX number being encoded, <country> is the
+   TELEX country code, and <answerback> is the answerback code of a
+   TELEX terminal.
+
+2.18.  Teletex Terminal Identifier
+
+   Values of type teletexTerminalIdentifier are encoded according to the
+   following BNF:
+
+     <teletex-id> ::= <printablestring>  0*('$' <ttx-parm>)
+
+     <ttx-param> ::= <ttx-key> ':' <ttx-value>
+
+     <ttx-key> ::= 'graphic' | 'control' | 'misc' | 'page' | 'private'
+
+     <ttx-value> ::= <octetstring>
+
+   In the above, the first <printablestring> is the encoding of the
+   first portion of the teletex terminal identifier to be encoded, and
+   the subsequent 0 or more <printablestrings> are subsequent portions
+   of the teletex terminal identifier.
+
+
+
+
+Howes, Kille, Yeong & Robbins                                   [Page 5]
+\f
+RFC 1778                    Syntax Encoding                   March 1995
+
+
+2.19.  Facsimile Telephone Number
+
+   Values of type FacsimileTelephoneNumber are encoded according to the
+   following BNF:
+
+<fax-number> ::= <printablestring> [ '$' <faxparameters> ]
+
+<faxparameters> ::= <faxparm> | <faxparm> '$' <faxparameters>
+
+<faxparm> ::= 'twoDimensional' | 'fineResolution' | 'unlimitedLength' |
+              'b4Length' | 'a3Width' | 'b4Width' | 'uncompressed'
+
+   In the above, the first <printablestring> is the actual fax number,
+   and the <faxparm> tokens represent fax parameters.
+
+2.20.  Presentation Address
+
+   Values of type PresentationAddress are encoded to have the
+   representation described in [6].
+
+2.21.  UTC Time
+
+   Values of type uTCTimeSyntax are encoded as if they were Printable
+   Strings with the strings containing a UTCTime value.
+
+2.22.  Guide (search guide)
+
+   Values of type Guide, such as values of the searchGuide attribute,
+   are encoded according to the following BNF:
+
+<guide-value> ::= [ <object-class> '#' ] <criteria>
+
+<object-class> ::= an encoded value of type objectIdentifierSyntax
+
+<criteria> ::= <criteria-item> | <criteria-set> | '!' <criteria>
+
+<criteria-set> ::= [ '(' ] <criteria> '&' <criteria-set> [ ')' ] |
+                   [ '(' ] <criteria> '|' <criteria-set> [ ')' ]
+
+<criteria-item> ::= [ '(' ] <attributetype> '$' <match-type> [ ')' ]
+
+<match-type> ::= "EQ" | "SUBSTR" | "GE" | "LE" | "APPROX"
+
+
+
+
+
+
+
+
+
+Howes, Kille, Yeong & Robbins                                   [Page 6]
+\f
+RFC 1778                    Syntax Encoding                   March 1995
+
+
+2.23.  Postal Address
+
+   Values of type PostalAddress are encoded according to the following
+   BNF:
+
+     <postal-address> ::= <t61string> | <t61string> '$' <postal-address>
+
+   In the above, each <t61string> component of a postal address value is
+   encoded as a value of type t61StringSyntax.
+
+2.24.  User Password
+
+   Values of type userPasswordSyntax are encoded as if they were of type
+   octetStringSyntax.
+
+2.25.  User Certificate
+
+   Values of type userCertificate are encoded according to the following
+   BNF:
+
+     <certificate> ::= <version> '#' <serial> '#' <signature-algorithm-id>
+                     '#' <issuer> '#' <validity> '#' <subject>
+                     '#' <public-key-info> '#' <encrypted-sign-value>
+
+     <version> ::= <integervalue>
+
+     <serial> ::= <integervalue>
+
+     <signature-algorithm-id> ::= <algorithm-id>
+
+     <issuer> ::= an encoded Distinguished Name
+
+     <validity> ::= <not-before-time> '#' <not-after-time>
+
+     <not-before-time> ::= <utc-time>
+
+     <not-after-time> ::= <utc-time>
+
+     <algorithm-parameters> ::=  <null> | <integervalue> |
+                                 '{ASN}' <hex-string>
+
+     <subject> ::= an encoded Distinguished Name
+
+     <public-key-info> ::= <algorithm-id> '#' <encrypted-sign-value>
+
+     <encrypted-sign-value> ::= <hex-string> | <hex-string> '-' <d>
+
+     <algorithm-id> ::= <oid> '#' <algorithm-parameters>
+
+
+
+Howes, Kille, Yeong & Robbins                                   [Page 7]
+\f
+RFC 1778                    Syntax Encoding                   March 1995
+
+
+     <utc-time> ::= an encoded UTCTime value
+
+     <hex-string> ::= <hex-digit> | <hex-digit> <hex-string>
+
+2.26.  CA Certificate
+
+   Values of type cACertificate are encoded as if the values were of
+   type userCertificate.
+
+2.27.  Authority Revocation List
+
+   Values of type authorityRevocationList are encoded according to the
+   following BNF:
+
+<certificate-list> ::= <signature-algorithm-id> '#' <issuer> '#' <utc-time>
+                        [ '#' <revoked-certificates> ]
+                        '#' <signature-algorithm-id>
+                        '#' <encrypted-sign-value>
+
+<revoked-certificates> ::= 1*( '#' <revoked-certificate> )
+                        <signature-algorithm-id> '#' <encrypted-sign-value>
+
+<revoked-certificate> ::= <signature-algorithm-id> '#' <issuer> '#'
+                        <serial> '#' <utc-time>
+
+   The syntactic components <signature-algorithm-id>, <issuer>,
+   <encrypted-sign-value>, <utc-time>, <subject> and <serial> have the
+   same definitions as in the BNF for the userCertificate attribute
+   syntax.
+
+2.28.  Certificate Revocation List
+
+   Values of type certificateRevocationList are encoded as if the values
+   were of type authorityRevocationList.
+
+2.29.  Cross Certificate Pair
+
+   Values of type crossCertificatePair are encoded according to the
+   following BNF:
+
+     <certificate-pair> ::= <forward> '#' <reverse>
+                             | <forward>
+                             | <reverse>
+
+     <forward> ::= 'forward:' <certificate>
+
+     <reverse> ::= 'reverse:' <certificate>
+
+
+
+
+Howes, Kille, Yeong & Robbins                                   [Page 8]
+\f
+RFC 1778                    Syntax Encoding                   March 1995
+
+
+   The syntactic component <certificate> has the same definition as in
+   the BNF for the userCertificate attribute syntax.
+
+2.30.  Delivery Method
+
+   Values of type deliveryMethod are encoded according to the following
+   BNF:
+
+     <delivery-value> ::= <pdm> | <pdm> '$' <delivery-value>
+
+     <pdm> ::= 'any' | 'mhs' | 'physical' | 'telex' | 'teletex' |
+               'g3fax' | 'g4fax' | 'ia5' | 'videotex' | 'telephone'
+
+2.31.  Other Mailbox
+
+   Values of the type otherMailboxSyntax are encoded according to the
+   following BNF:
+
+     <otherMailbox> ::= <mailbox-type> '$' <mailbox>
+
+     <mailbox-type> ::= an encoded Printable String
+
+     <mailbox> ::= an encoded IA5 String
+
+   In the above, <mailbox-type> represents the type of mail system in
+   which the mailbox resides, for example "Internet" or "MCIMail"; and
+   <mailbox> is the actual mailbox in the mail system defined by
+   <mailbox-type>.
+
+2.32.  Mail Preference
+
+   Values of type mailPreferenceOption are encoded according to the
+   following BNF:
+
+     <mail-preference> ::= "NO-LISTS" | "ANY-LIST" | "PROFESSIONAL-LISTS"
+
+2.33.  MHS OR Address
+
+   Values of type MHS OR Address are encoded as strings, according to
+   the format defined in [10].
+
+
+
+
+
+
+
+
+
+
+
+Howes, Kille, Yeong & Robbins                                   [Page 9]
+\f
+RFC 1778                    Syntax Encoding                   March 1995
+
+
+2.34.  Distribution List Submit Permission
+
+   Values of type DLSubmitPermission are encoded as strings, according
+   to the following BNF:
+
+     <dlsubmit-perm> ::= <dlgroup_label> ':' <dlgroup-value>
+                             | <dl-label> ':' <dl-value>
+
+     <dlgroup-label> ::= 'group_member'
+
+     <dlgroup-value> ::= <name>
+
+     <name> ::= an encoded Distinguished Name
+
+     <dl-label> ::= 'individual' | 'dl_member' | 'pattern'
+
+     <dl-value> ::= <orname>
+
+     <orname> ::= <address> '#' <dn>
+            |  <address>
+
+     <address> ::= <add-label> ':' <oraddress>
+
+     <dn> ::= <dn-label> ':' <name>
+
+     <add-label> = 'X400'
+
+     <dn-label> = 'X500'
+
+   where <oraddress> is as defined in RFC 1327.
+
+2.35.  Photo
+
+   Values of type Photo are encoded as if they were octet strings
+   containing JPEG images in the JPEG File Interchange Format (JFIF), as
+   described in [8].
+
+2.36.  Fax
+
+   Values of type Fax are encoded as if they were octet strings
+   containing Group 3 Fax images as defined in [7].
+
+
+
+
+
+
+
+
+
+
+Howes, Kille, Yeong & Robbins                                  [Page 10]
+\f
+RFC 1778                    Syntax Encoding                   March 1995
+
+
+3.  Security Considerations
+
+   Security issues are not discussed in this memo.
+
+4.  Acknowledgements
+
+   Many of the attribute syntax encodings defined in this document are
+   adapted from those used in the QUIPU X.500 implementation. The
+   contributions of the authors of the QUIPU implementation in the
+   specification of the QUIPU syntaxes [4] are gratefully acknowledged.
+
+5.  Bibliography
+
+   [1] The Directory: Selected Attribute Syntaxes.  CCITT,
+       Recommendation X.520.
+
+   [2] Information Processing Systems -- Open Systems Interconnection --
+       The Directory: Selected Attribute Syntaxes.
+
+   [3] Barker, P., and S. Kille, "The COSINE and Internet X.500 Schema",
+       RFC 1274, University College London, November 1991.
+
+   [4] The ISO Development Environment: User's Manual -- Volume 5:
+       QUIPU.  Colin Robbins, Stephen E. Kille.
+
+   [5] Kille, S., "A String Representation of Distinguished Names", RFC
+       1779, ISODE Consortium, March 1995.
+
+   [6] Kille, S., "A String Representation for Presentation Addresses",
+       RFC 1278, University College London, November 1991.
+
+   [7] Terminal Equipment and Protocols for Telematic Services -
+       Standardization of Group 3 facsimile apparatus for document
+       transmission.  CCITT, Recommendation T.4.
+
+   [8] JPEG File Interchange Format (Version 1.02).  Eric Hamilton, C-
+       Cube Microsystems, Milpitas, CA, September 1, 1992.
+
+   [9] Yeong, W., Howes, T., and S. Kille, "Lightweight Directory Access
+       Protocol", RFC 1777, Performance Systems International,
+       University of Michigan, ISODE Consortium, March 1995.
+
+  [10] Alvestrand, H., Kille, S., Miles, R., Rose, M., and S.  Thompson,
+       "Mapping between X.400 and RFC-822 Message Bodies", RFC 1495,
+       SINTEF DELAB, ISODE Consortium, Soft*Switch, Inc., Dover Beach
+       Consulting, Inc., Soft*Switch, Inc., August 1993.
+
+
+
+
+
+Howes, Kille, Yeong & Robbins                                  [Page 11]
+\f
+RFC 1778                    Syntax Encoding                   March 1995
+
+
+6.  Authors' Addresses
+
+       Tim Howes
+       University of Michigan
+       ITD Research Systems
+       535 W William St.
+       Ann Arbor, MI 48103-4943
+       USA
+
+       Phone: +1 313 747-4454
+       EMail: tim@umich.edu
+
+
+       Steve Kille
+       ISODE Consortium
+       PO Box 505
+       London
+       SW11 1DX
+       UK
+
+       Phone: +44-71-223-4062
+       EMail: S.Kille@isode.com
+
+
+       Wengyik Yeong
+       PSI Inc.
+       510 Huntmar Park Drive
+       Herndon, VA 22070
+       USA
+
+       Phone: +1 703-450-8001
+       EMail: yeongw@psilink.com
+
+
+       Colin Robbins
+       NeXor Ltd
+       University Park
+       Nottingham
+       NG7 2RD
+       UK
+
+
+
+
+
+
+
+
+
+
+
+Howes, Kille, Yeong & Robbins                                  [Page 12]
+\f
diff --git a/doc/rfc/rfc1779.txt b/doc/rfc/rfc1779.txt
new file mode 100644 (file)
index 0000000..b4eba85
--- /dev/null
@@ -0,0 +1,454 @@
+
+
+
+
+
+
+Network Working Group                                           S. Kille
+Request for Comments: 1779                              ISODE Consortium
+Obsoletes: 1485                                               March 1995
+Category: Standards Track
+
+
+             A String Representation of Distinguished Names
+
+Status of this Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Abstract
+
+   The OSI Directory uses distinguished names as the primary keys to
+   entries in the directory.  Distinguished Names are encoded in ASN.1.
+   When a distinguished name is communicated between to users not using
+   a directory protocol (e.g., in a mail message), there is a need to
+   have a user-oriented string representation of distinguished name.
+   This specification defines a string format for representing names,
+   which is designed to give a clean representation of commonly used
+   names, whilst being able to represent any distinguished name.
+
+Table of Contents
+
+   1.   Why a notation is needed ...................................   2
+   2.   A notation for Distinguished Name ..........................   2
+       2.1    Goals ................................................   2
+       2.2    Informal definition ..................................   2
+       2.3    Formal definition ....................................   4
+   3.   Examples ...................................................   6
+   4.   Acknowledgements ...........................................   7
+   5.   References .................................................   7
+   6.   Security Considerations ....................................   8
+   7.   Author's Address ...........................................   8
+
+
+
+
+
+
+
+
+
+
+
+
+Kille                                                           [Page 1]
+\f
+RFC 1779                   DN Representation                  March 1995
+
+
+1.  Why a notation is needed
+
+   Many OSI Applications make use of Distinguished Names (DN) as defined
+   in the OSI Directory, commonly known as X.500 [1].  This
+   specification assumes familiarity with X.500, and the concept of
+   Distinguished Name.  It is important to have a common format to be
+   able to unambiguously represent a distinguished name.  This might be
+   done to represent a directory name on a business card or in an email
+   message.  There is a need for a format to support human to human
+   communication, which must be string based (not ASN.1) and user
+   oriented.  This notation is targeted towards a general user oriented
+   system, and in particular to represent the names of humans.  Other
+   syntaxes may be more appropriate for other uses of the directory.
+   For example, the OSF Syntax may be more appropriate for some system
+   oriented uses.  (The OSF Syntax uses "/" as a separator, and forms
+   names in a manner intended to resemble UNIX filenames).
+
+2.  A notation for Distinguished Name
+
+2.1  Goals
+
+   The following goals are laid out:
+
+    o  To provide an unambiguous representation of a distinguished name
+
+    o  To be an intuitive format for the majority of names
+
+    o  To be fully general, and able to represent any distinguished name
+
+    o  To be amenable to a number of different layouts to achieve an
+       attractive representation.
+
+    o  To give a clear representation of the contents of the
+       distinguished name
+
+2.2  Informal definition
+
+   This notation is designed to be convenient for common forms of name.
+   Some examples are given.  The author's directory distinguished name
+   would be written:
+
+   CN=Steve Kille,
+   O=ISODE Consortium, C=GB
+
+
+
+
+
+
+
+
+Kille                                                           [Page 2]
+\f
+RFC 1779                   DN Representation                  March 1995
+
+
+   This may be folded, perhaps to display in multi-column format.  For
+   example:
+
+   CN=Steve Kille,
+   O=ISODE Consortium,
+   C=GB
+
+   Another name might be:
+
+   CN=Christian Huitema, O=INRIA, C=FR
+
+   Semicolon (";") may be used as an alternate separator.  The
+   separators may be mixed, but this usage is discouraged.
+
+   CN=Christian Huitema; O=INRIA; C=FR
+
+   In running text, this would be written as <CN=Christian Huitema;
+   O=INRIA; C=FR>.  Another example, shows how different attribute types
+   are handled:
+
+   CN=James Hacker,
+   L=Basingstoke,
+   O=Widget Inc,
+   C=GB
+
+   Here is an example of a multi-valued Relative Distinguished Name,
+   where the namespace is flat within an organisation, and department is
+   used to disambiguate certain names:
+
+   OU=Sales + CN=J. Smith, O=Widget Inc., C=US
+
+   The final examples show both methods quoting of a comma in an
+   Organisation name:
+
+   CN=L. Eagle, O="Sue, Grabbit and Runn", C=GB
+
+   CN=L. Eagle, O=Sue\, Grabbit and Runn, C=GB
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Kille                                                           [Page 3]
+\f
+RFC 1779                   DN Representation                  March 1995
+
+
+2.3  Formal definition
+
+   A formal definition can now be given.  The structure is specified in
+   a BNF grammar in Figure 1.  This BNF uses the grammar defined in RFC
+   822, with the terminals enclosed in <> [2].  This definition is in an
+   abstract character set, and so may be written in any character set
+   supporting the explicitly defined special characters.  The quoting
+   mechanism is used for the following cases:
+
+    o  Strings containing ",", "+", "=" or """ , <CR>, "<",
+       ">", "#", or ";".
+
+    o  Strings with leading or trailing spaces
+
+    o  Strings containing consecutive spaces
+
+   There is an escape mechanism from the normal user oriented form, so
+   that this syntax may be used to print any valid distinguished name.
+   This is ugly.  It is expected to be used only in pathological cases.
+   There are two parts to this mechanism:
+
+   1.  Attributes types are represented in a (big-endian) dotted
+       notation.  (e.g., OID.2.6.53).
+
+   2.  Attribute values are represented in hexadecimal (e.g.  #0A56CF).
+       Each pair of hex digits defines an octet, which is the ASN.1 Basic
+       Encoding Rules value of the Attribute Value.
+
+   The keyword specification is optional in the BNF, but mandatory for
+   this specification.  This is so that the same BNF may be used for the
+   related specification on User Friendly Naming [5].  When this
+   specification is followed, the attribute type keywords must always be
+   present.
+
+   A list of valid keywords for well known attribute types used in
+   naming is given in Table 1.  Keywords may contain spaces, but shall
+   not have leading or trailing spaces.  This is a list of keywords
+   which must be supported.  These are chosen because they appear in
+   common forms of name, and can do so in a place which does not
+   correspond to the default schema used.  A register of valid keywords
+   is maintained by the IANA.
+
+
+
+
+
+
+
+
+
+
+Kille                                                           [Page 4]
+\f
+RFC 1779                   DN Representation                  March 1995
+
+
+   <name> ::= <name-component> ( <spaced-separator> )
+          | <name-component> <spaced-separator> <name>
+
+   <spaced-separator> ::= <optional-space>
+                   <separator>
+                   <optional-space>
+
+   <separator> ::=  "," | ";"
+
+   <optional-space> ::= ( <CR> ) *( " " )
+
+   <name-component> ::= <attribute>
+           | <attribute> <optional-space> "+"
+             <optional-space> <name-component>
+
+   <attribute> ::= <string>
+           | <key> <optional-space> "=" <optional-space> <string>
+
+   <key> ::= 1*( <keychar> ) | "OID." <oid> | "oid." <oid>
+   <keychar> ::= letters, numbers, and space
+
+   <oid> ::= <digitstring> | <digitstring> "." <oid>
+   <digitstring> ::= 1*<digit>
+   <digit> ::= digits 0-9
+
+   <string> ::= *( <stringchar> | <pair> )
+            | '"' *( <stringchar> | <special> | <pair> ) '"'
+            | "#" <hex>
+
+
+   <special> ::= "," | "=" | <CR> | "+" | "<" |  ">"
+            | "#" | ";"
+
+   <pair> ::= "\" ( <special> | "\" | '"')
+   <stringchar> ::= any character except <special> or "\" or '"'
+
+
+   <hex> ::= 2*<hexchar>
+   <hexchar> ::= 0-9, a-f, A-F
+
+
+
+               Figure 1:  BNF Grammar for Distinguished Name
+
+
+
+
+
+
+
+
+Kille                                                           [Page 5]
+\f
+RFC 1779                   DN Representation                  March 1995
+
+
+                       Key     Attribute (X.520 keys)
+                       ------------------------------
+                       CN      CommonName
+                       L       LocalityName
+                       ST      StateOrProvinceName
+                       O       OrganizationName
+                       OU      OrganizationalUnitName
+                       C       CountryName
+                       STREET  StreetAddress
+
+
+                      Table 1:  Standardised Keywords
+
+
+   Only string type attributes are considered, but other attribute
+   syntaxes could be supported locally (e.g., by use of the syntexes
+   defined in [3].)  It is assumed that the interface will translate
+   from the supplied string into an appropriate Directory String
+   encoding.  The "+" notation is used to specify multi-component RDNs.
+   In this case, the types for attributes in the RDN must be explicit.
+
+   The name is presented/input in a little-endian order (most
+   significant component last).  When an address is written in a context
+   where there is a need to delimit the entire address (e.g., in free
+   text), it is recommended that the delimiters <> are used.  The
+   terminator > is a special in the notation to facilitate this
+   delimitation.
+
+3.  Examples
+
+   This section gives a few examples of distinguished names written
+   using this notation:
+
+   CN=Marshall T. Rose, O=Dover Beach Consulting, L=Santa Clara,
+   ST=California, C=US
+
+   CN=FTAM Service, CN=Bells, OU=Computer Science,
+   O=University College London, C=GB
+
+   CN=Markus Kuhn, O=University of Erlangen, C=DE
+
+   CN=Steve Kille,
+   O=ISODE Consortium,
+   C=GB
+
+
+
+
+
+
+
+Kille                                                           [Page 6]
+\f
+RFC 1779                   DN Representation                  March 1995
+
+
+   CN=Steve Kille ,
+
+   O =   ISODE Consortium,
+   C=GB
+
+   CN=Steve Kille, O=ISODE Consortium, C=GB
+
+4.  Acknowledgements
+
+   This work was based on research work done at University College
+   London [4], and evolved by the IETF OSI-DS WG.
+
+   Input for this version of the document was received from:  Allan
+   Cargille (University of Wisconsin); John Dale (COS); Philip Gladstone
+   (Onsett); John Hawthorne (US Air Force); Roland Hedberg (University
+   of Umea); Kipp Hickman (Mosaic Communications Corp.)  Markus Kuhn
+   (University of Erlangen); Elisabeth Roudier (E3X); Mark Wahl (ISODE
+   Consortium).
+
+5.  References
+
+   [1] The Directory --- overview of concepts, models and services,
+       1993. CCITT X.500 Series Recommendations.
+
+   [2] Crocker, D., "Standard of the Format of ARPA-Internet Text
+       Messages", STD 11, RFC 822, University of Delaware, August 1982.
+
+   [3] Yeong, W., Howes, T., and S. Kille, "Lightweight Directory Access
+       Protocol", RFC 1777, Performance Systems International,
+       University of Michigan, ISODE Consortium, March 1995.
+
+   [4] S.E. Kille. Using the OSI directory to achieve user friendly
+       naming. Research Note RN/20/29, Department of Computer Science,
+       University College London, February 1990.
+
+   [5] Kille, S., "Using the OSI Directory to Achieve User Friendly
+       Naming", RFC 1781, ISODE Consortium, March 1995.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Kille                                                           [Page 7]
+\f
+RFC 1779                   DN Representation                  March 1995
+
+
+6.  Security Considerations
+
+   Security issues are not discussed in this memo.
+
+7.  Author's Address
+
+   Steve Kille
+   ISODE Consortium
+   The Dome
+   The Square
+   Richmond, Surrey
+   TW9 1DT
+   England
+
+   Phone:  +44-181-332-9091
+   EMail:  S.Kille@ISODE.COM
+
+   DN: CN=Steve Kille,
+   O=ISODE Consortium, C=GB
+
+   UFN: S. Kille,
+   ISODE Consortium, GB
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Kille                                                           [Page 8]
+\f
+
+
diff --git a/doc/rfc/rfc1798.txt b/doc/rfc/rfc1798.txt
new file mode 100644 (file)
index 0000000..96d477c
--- /dev/null
@@ -0,0 +1,507 @@
+
+
+
+
+
+
+Network Working Group                                           A. Young
+Request for Comments: 1798                              ISODE Consortium
+Category: Standards Track                                      June 1995
+
+
+         Connection-less Lightweight Directory Access Protocol
+
+Status of this Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+X.500
+
+   The protocol described in this document is designed to provide access
+   to the Directory while not incurring the resource requirements of the
+   Directory Access Protocol (DAP) [3].  In particular, it is aimed at
+   avoiding the elapsed time that is associated with connection-oriented
+   communication and it facilitates use of the Directory in a manner
+   analagous to the DNS [5,6].  It is specifically targeted at simple
+   lookup applications that require to read a small number of attribute
+   values from a single entry.  It is intended to be a complement to DAP
+   and LDAP [4].  The protocol specification draws heavily on that of
+   LDAP.
+
+1.  Background
+
+   The Directory can be used as a repository for many kinds of
+   information.  The full power of DAP is unnecessary for applications
+   that require simple read access to a few attribute values.
+   Applications addressing is a good example of this type of use where
+   an application entity needs to determine the Presentation Address
+   (PA) of a peer entity given that peer's Application Entity Title
+   (AET). If the AET is a Directory Name (DN) then the required result
+   can be obtained from the PA attribute of the Directory entry
+   identified by the AET.  This is very similar to DNS.
+
+
+
+
+
+
+
+
+
+
+
+
+Young                       Standards Track                     [Page 1]
+\f
+RFC 1798                         CLDAP                         June 1995
+
+
+   Use of DAP to achieve this functionality involves a significant
+   number of network exchanges:
+
+      ___________________________________________________________
+     |_#_|______Client_(DUA)________DAP________Server_(DSA)_____|
+     |  1|  N-Connect.request       ->                          |
+     |  2|                          <-    N-Connect.response    |
+     |  3|  T-Connect.request       ->                          |
+     |  4|                          <-    T-Connect.response    |
+     |   |  S-Connect.request,                                  |
+     |   |  P-Connect.request,                                  |
+     |   |  A-Associate.request,                                |
+     |  5|  DAP-Bind.request        ->                          |
+     |   |                                S-Connect.response,   |
+     |   |                                P-Connect.response,   |
+     |   |                                A-Associate.response, |
+     |  6|                          <-    DAP-Bind.response     |
+     |  7|  DAP-Read.request        ->                          |
+     |  8|                          <-    DAP-Read.response     |
+     |   |  S-Release.request,                                  |
+     |   |  P-Release.request,                                  |
+     |   |  A-Release.request,                                  |
+     |  9|  DAP-Unbind.request      ->                          |
+     |   |                                S-Release.response,   |
+     |   |                                P-Release.response,   |
+     |   |                                A-Release.response,   |
+     | 10|                          <-    DAP-Unbind.response   |
+     |   |  T-Disconnect.request,                               |
+     | 11|  N-Disconnect.request    ->                          |
+     |   |                                T-Disconnect.response,|
+     | 12|                          <-    N-Disconnect.response |
+     |___|______________________________________________________|
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Young                       Standards Track                     [Page 2]
+\f
+RFC 1798                         CLDAP                         June 1995
+
+
+   This is 10 packets before the application can continue, given that it
+   can probably do so after issuing the T-Disconnect.request.  (Some
+   minor variations arise depending upon the class of Network and
+   Transport service that is being used; for example use of TP4 over
+   CLNS reduces the packet count by two.) LDAP is no better in the case
+   where the LDAP server uses full DAP to communicate with the
+   Directory:
+
+  ____________________________________________________________________
+ |__#_|___Client_____LDAP_____LDAP_server______DAP_________DSA_______|
+ |  1 |  TCP SYN      ->                                             |
+ |  2 |               <-    TCP SYN ACK                              |
+ |  3 |  BindReq      ->                                             |
+ |  4 |                     N-Connect.req      ->                    |
+ |  5 |                                        <-    N-Connect.res   |
+ |  6 |                     T-Connect.req      ->                    |
+ |  7 |                                        <-    T-Connect.res   |
+ |  8 |                     DAP-Bind.req       ->                    |
+ |  9 |                                        <-    DAP-Bind.res    |
+ | 10 |               <-    BindRes                                  |
+ | 11 |  SearchReq    ->                                             |
+ | 12 |                     DAP-Search.req     ->                    |
+ | 13 |                                        <-    DAP-Search.res  |
+ | 14 |               <-    SearchRes                                |
+ | 15 |  TCP FIN      ->                                             |
+ | 16 |                     DAP-Unbind.req     ->                    |
+ | 17 |                                        <-    DAP-Unbind.res  |
+ | 18 |                     N-Disconnect.req   ->                    |
+ | 19 |                                        <-    N-Disconnect.res|
+ |____|______________________________________________________________|
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Young                       Standards Track                     [Page 3]
+\f
+RFC 1798                         CLDAP                         June 1995
+
+
+   Here there are 14 packets before the application can continue.  Even
+   if the LDAP server is on the same host as the DSA (so packet delay is
+   negligible), or if the DSA supports LDAP directly, then there are
+   still 6 packets.
+
+                  ____________________________________
+                 | #|   Client     LDAP   LDAP server|
+                 |__|________________________________|
+                 | 1|  TCP SYN      ->               |
+                 | 2|               <-    TCP SYN ACK|
+                 | 3|  BindReq      ->               |
+                 | 4|               <-    BindRes    |
+                 | 5|  SearchReq    ->               |
+                 |_6|_______________<-____SearchRes__|
+
+
+   This protocol provides for simple access to the Directory where the
+   delays inherent in the above exchanges are unacceptable and where the
+   additional functionality provided by connection-mode operation is not
+   required.
+
+2.  Protocol Model
+
+   CLDAP is based directly on LDAP [4] and inherits many of the key
+   aspects of the LDAP protocol:
+
+   - -  Many protocol data elements are encoding as ordinary strings
+        (e.g., Distinguished Names).
+
+   - -  A lightweight BER encoding is used to encode all protocol
+        elements.
+
+   It is different to LDAP in that:
+
+   - -  Protocol elements are carried directly over UDP or other
+        connection-less transport, bypassing much of the
+        session/presentation overhead and that of connections (LDAP uses
+        a connection-mode transport service).
+
+   - -  A restricted set of operations is available.
+
+   The definitions of most protocol elements are inherited from LDAP.
+
+   The general model adopted by this protocol is one of clients
+   performing protocol operations against servers. In this model, this
+   is accomplished by a client transmitting a protocol request
+   describing the operation to be performed to a server, which is then
+   responsible for performing the necessary operations on the Directory.
+
+
+
+Young                       Standards Track                     [Page 4]
+\f
+RFC 1798                         CLDAP                         June 1995
+
+
+   Upon completion of the necessary operations, the server returns a
+   response containing any results or errors to the requesting client.
+
+   Note that, although servers are required to return responses whenever
+   such responses are defined in the protocol, there is no requirement
+   for synchronous behaviour on the part of either client or server
+   implementations: requests and responses for multiple operations may
+   be exchanged by client and servers in any order, as long as servers
+   eventually send a response for every request that requires one.
+
+   Also, because the protocol is implemented over a connection-less
+   transport service clients must be prepared for either requests or
+   responses to be lost.  Clients should use a retry mechanism with
+   timeouts in order to achieve the desired level of reliability.  For
+   example, a client might send off a request and wait for two seconds.
+   If no reply is forthcoming, the request is sent again and the client
+   waits four seconds.  If there is still no reply, the client sends it
+   again and waits eight seconds, and so on, until some maximun time.
+   Such algorithms are widely used in other datagram-based protocol
+   implementations, such as the DNS.  It is not appropriate to mandate a
+   specific algorithm as this will depend upon the requirments and
+   operational environment of individual CLDAP client implementations.
+
+   It is not required that a client abandon any requests to which no
+   response has been received and for which a reply is no longer
+   required (because the request has been timed out), but they may do
+   so.
+
+   Consistent with the model of servers performing protocol operations
+   on behalf of clients, it is also to be noted that protocol servers
+   are expected to handle referrals without resorting to the return of
+   such referrals to the client. This protocol makes no provisions for
+   the return of referrals to clients, as the model is one of servers
+   ensuring the performance of all necessary operations in the
+   Directory, with only final results or errors being returned by
+   servers to clients.
+
+   Note that this protocol can be mapped to a strict subset of the
+   Directory abstract service, so it can be cleanly provided by the DAP.
+
+3.  Mapping Onto Transport Services
+
+   This protocol is designed to run over connection-less transports,
+   with all 8 bits in an octet being significant in the data stream.
+   Specifications for two underlying services are defined here, though
+   others are also possible.
+
+
+
+
+
+Young                       Standards Track                     [Page 5]
+\f
+RFC 1798                         CLDAP                         June 1995
+
+
+3.1.  User Datagram Protocol (UDP)
+
+   The CLDAPMessage PDUs are mapped directly onto UDP datagrams.  Only
+   one request may be sent in a single datagram. Only one response may
+   be sent in a single datagram.  Server implementations running over
+   the UDP should provide a protocol listener on port 389.
+
+3.2.  Connection-less Transport Service (CLTS)
+
+   Each LDAPMessage PDU is mapped directly onto T-Unit-Data.
+
+4.  Elements of Protocol
+
+   CLDAP messages are defined by the following ASN.1:
+
+    CLDAPMessage ::= SEQUENCE {
+        messageID       MessageID,
+        user            LDAPDN,         -- on request only --
+        protocolOp      CHOICE {
+                        searchRequest   SearchRequest,
+                        searchResponse  SEQUENCE OF
+                                            SearchResponse,
+                        abandonRequest  AbandonRequest
+        }
+    }
+
+   where MessageID, LDAPDN, SearchRequest, SearchResponse and
+   AbandonRequest are defined in the LDAP protocol.
+
+   The 'user' element is supplied only on requests (it should be zero
+   length and is ignored in responses). It may be used for logging
+   purposes but it is not required that a CLDAP server implementation
+   apply any particular semantics to this field.
+
+   Editorial note:
+       There has been some discussion about the desirability of
+       authentication with CLDAP requests and the addition of the fields
+       necessary to support this. This might take the form of a clear
+       text password (which would go against the current IAB drive to
+       remove such things from protocols) or some arbitrary credentials.
+       Such a field is not included.  It is felt that, in general,
+       authentication would incur sufficient overhead to negate the
+       advantages of the connectionless basis of CLDAP. If an
+       application requires authenticated access to the Directory then
+       CLDAP is not an appropriate protocol.
+
+
+
+
+
+
+Young                       Standards Track                     [Page 6]
+\f
+RFC 1798                         CLDAP                         June 1995
+
+
+   Within a searchResponse all but the last SearchResponse has choice
+   'entry' and the last SearchResponse has choice 'resultCode'.  Within
+   a searchResponse, as an encoding optimisation, the value of the
+   objectName LDAP DN may use a trailing '*' character to refer to the
+   baseObject of the corresponding searchRequest.  For example, if the
+   baseObject is specified as "o=UofM, c=US", then the following
+   objectName LDAPDNs in a response would have the indicated meanings
+
+          objectName returned   actual LDAPDN denoted
+          ____________________________________________________
+          "*"                   "o=UofM, c=US"
+          "cn=Babs Jensen, *"   "cn=Babs Jensen, o=UofM, c=US"
+
+4.1.  Errors
+
+The following error code is added to the LDAPResult.resultCode
+enumeration of [4]:
+
+                             resultsTooLarge              (70),
+
+   This error is returned when the LDAPMessage PDU containing the
+   results of an operation are too large to be sent in a single
+   datagram.
+
+4.2.  Example
+
+   A simple lookup can be performed in 4 packets. This is reduced to 2
+   if either the DSA implements the CLDAP protocol, the CLDAP server has
+   a cache of the desired results, or the CLDAP server and DSA are co-
+   located such that there is insignificant delay between them.
+
+    _______________________________________________________________
+   |_#|___Client_____CLDAP____CLDAP_server____DAP________DSA______|
+   | 1|  SearchReq    ->                                          |
+   | 2|                      DAP-Search.req   ->                  |
+   | 3|                                       <-    DAP-Search.res|
+   | 4|               <-     SearchRes                            |
+   |__|___________________________________________________________|
+
+5.  Implementation Considerations
+
+   The following subsections provide guidance on the implementation of
+   clients and servers using the CLDAP protocol.
+
+
+
+
+
+
+
+
+Young                       Standards Track                     [Page 7]
+\f
+RFC 1798                         CLDAP                         June 1995
+
+
+5.1.  Server Implementations
+
+   Given that the goal of this protocol is to minimise the elapsed time
+   between making a Directory request and receiving the response, a
+   server which uses DAP to access the directory should use techniques
+   that assist in this.
+
+   - -  A server should remain bound to the Directory during reasonably
+        long idle periods or should remain bound permanently.
+
+   - -  Cacheing of results is highly desirable but this must be
+        tempered by the need to provide up-to-date results given the
+        lack of a cache invalidation protocol in DAP (either implicit
+        via timers or explicit) and the lack of a dontUseCopy service
+        control in the protocol.
+
+   Of course these issues are irrelevant if the CLDAP protocol is
+   directly supported by a DSA.
+
+5.2.  Client Implementations
+
+   For simple lookup applications, use of a retry algorithm with
+   multiple servers similar to that commonly used in DNS stub resolver
+   implementations is recommended.  The location of a CLDAP server or
+   servers may be better specified using IP addresses (simple or
+   broadcast) rather than names that must first be looked up in another
+   directory such as DNS.
+
+6.  Security Considerations
+
+   This protocol provides no facilities for authentication. It is
+   expected that servers will bind to the Directory either anonymously
+   or using simple authentication without a password.
+
+7.  Bibliography
+
+   [1] The Directory: Overview of Concepts, Models and Service.  CCITT
+       Recommendation X.500, 1988.
+
+   [2] The Directory: Models.  CCITT Recommendation X.501 ISO/IEC JTC
+       1/SC21; International Standard 9594-2, 1988.
+
+   [3] The Directory: Abstract Service Definition.  CCITT Recommendation
+       X.511, ISO/IEC JTC 1/SC21; International Standard 9594-3, 1988.
+
+   [4] Yeong, W., Howes, T., and S. Kille, "X.500 Lightweight Directory
+       Access Protocol", RFC 1487, Performance Systems International,
+       University of Michigan, ISODE Consortium, July 1993.
+
+
+
+Young                       Standards Track                     [Page 8]
+\f
+RFC 1798                         CLDAP                         June 1995
+
+
+   [5] Mockapetris, P., "Domain Names - Implementation and
+       Specification", STD 13, RFC 1035, USC/Information Sciences
+       Institute, November 1987.
+
+   [6] Mockapetris, P., "Domain Names - Concepts and Facilities", STD
+       13, RFC 1034, USC/Information Sciences Institute, November 1987.
+
+8.  Acknowledgements
+
+   Many thanks to Tim Howes and Steve Kille for their detailed comments
+   and to other members of the working group.
+
+   This work was initiated by the Union Bank of Switzerland.
+
+9.  Author's Address
+
+   Alan Young
+   ISODE Consortium
+   The Dome, The Square
+   RICHMOND
+   GB - TW9 1DT
+
+   Phone: +44 81 332 9091
+   EMail: A.Young@isode.com
+   X.400:    i=A; s=Young; o=ISODE Consortium; p=ISODE; a=MAILNET; c=FI
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Young                       Standards Track                     [Page 9]
+\f
diff --git a/doc/rfc/rfc1823.txt b/doc/rfc/rfc1823.txt
new file mode 100644 (file)
index 0000000..835f1ef
--- /dev/null
@@ -0,0 +1,1235 @@
+
+
+
+
+
+
+Network Working Group                                           T. Howes
+Request for Comments: 1823                                      M. Smith
+Category: Informational                          University of  Michigan
+                                                             August 1995
+
+
+                 The LDAP Application Program Interface
+
+Status of this Memo
+
+   This memo provides information for the Internet community.  This memo
+   does not specify an Internet standard of any kind.  Distribution of
+   this memo is unlimited.
+
+1.  Introduction
+
+   This document defines a C language application program interface to
+   the lightweight directory access protocol (LDAP). The LDAP API is
+   designed to be powerful, yet simple to use. It defines compatible
+   synchronous and asynchronous interfaces to LDAP to suit a wide
+   variety of applications.  This document gives a brief overview of the
+   LDAP model, then an overview of how the API is used by an application
+   program to obtain LDAP information.  The API calls are described in
+   detail, followed by an appendix that provides some example code
+   demonstrating the use of the API.
+
+2.  Overview of the LDAP Model
+
+   LDAP is the lightweight directory access protocol, described in [2]
+   and [7]. It can provide a lightweight frontend to the X.500 directory
+   [1], or a stand-alone service. In either mode, LDAP is based on a
+   client-server model in which a client makes a TCP connection to an
+   LDAP server, over which it sends requests and receives responses.
+
+   The LDAP information model is based on the entry, which contains
+   information about some object (e.g., a person).  Entries are composed
+   of attributes, which have a type and one or more values. Each
+   attribute has a syntax that determines what kinds of values are
+   allowed in the attribute (e.g., ASCII characters, a jpeg photograph,
+   etc.) and how those values behave during directory operations (e.g.,
+   is case significant during comparisons).
+
+   Entries are organized in a tree structure, usually based on
+   political, geographical, and organizational boundaries. Each entry is
+   uniquely named relative to its sibling entries by its relative
+   distinguished name (RDN) consisting of one or more distinguished
+   attribute values from the entry.  At most one value from each
+   attribute may be used in the RDN.  For example, the entry for the
+
+
+
+Howes & Smith                Informational                      [Page 1]
+\f
+RFC 1823                        LDAP API                     August 1995
+
+
+   person Babs Jensen might be named with the "Barbara Jensen" value
+   from the commonName attribute. A globally unique name for an entry,
+   called a distinguished name or DN, is constructed by concatenating
+   the sequence of RDNs from the root of the tree down to the entry. For
+   example, if Babs worked for the University of Michigan, the DN of her
+   U-M entry might be "cn=Barbara Jensen, o=University of Michigan,
+   c=US". The DN format used by LDAP is defined in [4].
+
+   Operations are provided to authenticate, search for and retrieve
+   information, modify information, and add and delete entries from the
+   tree.  The next sections give an overview of how the API is used and
+   detailed descriptions of the LDAP API calls that implement all of
+   these functions.
+
+3.  Overview of LDAP API Use
+
+   An application generally uses the LDAP API in four simple steps.
+
+   o    Open a connection to an LDAP server. The ldap_open() call
+        returns a handle to the connection, allowing multiple
+        connections to be open at once.
+
+   o    Authenticate to the LDAP server and/or the X.500 DSA. The
+        ldap_bind() call and friends support a variety of
+        authentication methods.
+
+   o    Perform some LDAP operations and obtain some results.
+        ldap_search() and friends return results which can be parsed
+        by ldap_result2error(), ldap_first_entry(), ldap_next_entry(),
+        etc.
+
+   o    Close the connection. The ldap_unbind() call closes the
+        connection.
+
+   Operations can be performed either synchronously or asynchronously.
+   Synchronous calls end in _s. For example, a synchronous search can be
+   completed by calling ldap_search_s(). An asynchronous search can be
+   initiated by calling ldap_search(). All synchronous routines return
+   an indication of the outcome of the operation (e.g, the constant
+   LDAP_SUCCESS or some other error code).  The asynchronous routines
+   return the message id of the operation initiated. This id can be used
+   in subsequent calls to ldap_result() to obtain the result(s) of the
+   operation.  An asynchronous operation can be abandoned by calling
+   ldap_abandon().
+
+
+
+
+
+
+
+Howes & Smith                Informational                      [Page 2]
+\f
+RFC 1823                        LDAP API                     August 1995
+
+
+   Results and errors are returned in an opaque structure called
+   LDAPMessage.  Routines are provided to parse this structure, step
+   through entries and attributes returned, etc. Routines are also
+   provided to interpret errors. The next sections describe these
+   routines in more detail.
+
+4.  Calls for performing LDAP operations
+
+   This section describes each LDAP operation API call in detail. All
+   calls take a "connection handle", a pointer to an LDAP structure
+   containing per-connection information.  Many routines return results
+   in an LDAPMessage structure. These structures and others are
+   described as needed below.
+
+4.1.  Opening a connection
+
+   ldap_open() opens a connection to the LDAP server.
+
+              typedef struct ldap {
+                      /* ... opaque parameters ... */
+                      int     ld_deref;
+                      int     ld_timelimit;
+                      int     ld_sizelimit;
+                      int     ld_errno;
+                      char    *ld_matched;
+                      char    *ld_error;
+                      /* ... opaque parameters ... */
+              } LDAP;
+
+              LDAP *ldap_open( char *hostname, int portno );
+
+      Parameters are:
+
+      hostname Contains a space-separated list of hostnames or dotted
+               strings representing the IP address of hosts running an
+               LDAP server to connect to. The hosts are tried in the
+               order listed, stopping with the first one to which a
+               successful connection is made;
+
+      portno   contains the TCP port number to which to connect. The
+               default LDAP port can be obtained by supplying the
+               constant LDAP_PORT.
+
+   ldap_open() returns a "connection handle", a pointer to an LDAP
+   structure that should be passed to subsequent calls pertaining to the
+   connection. It returns NULL if the connection cannot be opened. One
+   of the ldap_bind calls described below must be completed before other
+   operations can be performed on the connection.
+
+
+
+Howes & Smith                Informational                      [Page 3]
+\f
+RFC 1823                        LDAP API                     August 1995
+
+
+   The calling program should assume nothing about the order of the
+   fields in the LDAP structure. There may be other fields in the
+   structure for internal library use. The fields shown above are
+   described as needed in the description of other calls below.
+
+4.2.  Authenticating to the directory
+
+   ldap_bind() and friends are used to authenticate to the directory.
+
+           int ldap_bind( LDAP *ld, char *dn, char *cred, int method );
+
+           int ldap_bind_s( LDAP *ld, char *dn, char *cred, int method );
+
+           int ldap_simple_bind( LDAP *ld, char *dn, char *passwd );
+
+           int ldap_simple_bind_s( LDAP *ld, char *dn, char *passwd );
+
+           int ldap_kerberos_bind( LDAP *ld, char *dn );
+
+           int ldap_kerberos_bind_s( LDAP *ld, char *dn );
+
+   Parameters are:
+
+   ld     The connection handle;
+
+   dn     The name of the entry to bind as;
+
+   cred   The credentials with which to authenticate;
+
+   method One of LDAP_AUTH_SIMPLE, LDAP_AUTH_KRBV41, or
+          LDAP_AUTH_KRBV42, indicating the authentication method to use;
+
+   passwd For ldap_simple_bind(), the password to compare to the entry's
+          userPassword attribute;
+
+   There are three types of bind calls, providing simple authentication,
+   kerberos authentication, and general routines to do either one. In
+   the case of Kerberos version 4 authentication using the general
+   ldap_bind() routines, the credentials are ignored, as the routines
+   assume a valid ticket granting ticket already exists which can be
+   used to retrieve the appropriate service tickets.
+
+   Synchronous versions of the routines have names that end in _s.
+   These routines return the result of the bind operation, either the
+   constant LDAP_SUCCESS if the operation was successful, or another
+   LDAP error code if it was not. See the section below on error
+   handling for more information about possible errors and how to
+   interpret them.
+
+
+
+Howes & Smith                Informational                      [Page 4]
+\f
+RFC 1823                        LDAP API                     August 1995
+
+
+   Asynchronous versions of these routines return the message id of the
+   bind operation initiated. A subsequent call to ldap_result(),
+   described below, can be used to obtain the result of the bind. In
+   case of error, these routines will return -1, setting the ld_errno
+   field in the LDAP structure appropriately.
+
+   Note that no other operations over the connection should be attempted
+   before a bind call has successfully completed. Subsequent bind calls
+   can be used to re-authenticate over the same connection.
+
+4.3.  Closing the connection
+
+   ldap_unbind() is used to unbind from the directory and close the
+   connection.
+
+           int ldap_unbind( LDAP *ld );
+
+   Parameters are:
+
+      ld   The connection handle.
+
+   ldap_unbind() works synchronously, unbinding from the directory,
+   closing the connection, and freeing up the ld structure before
+   returning. ldap_unbind() returns LDAP_SUCCESS (or another LDAP error
+   code if the request cannot be sent to the LDAP server).  After a call
+   to ldap_unbind(), the ld connection handle is invalid.
+
+4.4.  Searching
+
+   ldap_search() and friends are used to search the LDAP directory,
+   returning a requested set of attributes for each entry matched.
+   There are three variations.
+
+           struct timeval {
+                   long    tv_sec;
+                   long    tv_usec;
+           };
+           int ldap_search(
+                   LDAP    *ld,
+                   char    *base,
+                   int     scope,
+                   char    *filter,
+                   char    *attrs[],
+                   int     attrsonly
+           );
+           int ldap_search_s(
+                   LDAP            *ld,
+                   char            *base,
+
+
+
+Howes & Smith                Informational                      [Page 5]
+\f
+RFC 1823                        LDAP API                     August 1995
+
+
+                   int             scope,
+                   char            *filter,
+                   char            *attrs[],
+                   int             attrsonly,
+                   LDAPMessage     **res
+           );
+           int ldap_search_st(
+                   LDAP            *ld,
+                   char            *base,
+                   int             scope,
+                   char            *filter,
+                   char            *attrs[],
+                   int             attrsonly,
+                   struct timeval  *timeout,
+                   LDAPMessage     **res
+           );
+
+   Parameters are:
+
+   ld        The connection handle;
+
+   base      The dn of the entry at which to start the search;
+
+   scope     One of LDAP_SCOPE_BASE, LDAP_SCOPE_ONELEVEL, or
+             LDAP_SCOPE_SUBTREE, indicating the scope of the search;
+
+   filter    A character string as described in RFC 1558 [3],
+             representing the search filter;
+
+   attrs     A NULL-terminated array of strings indicating which
+             attributes to return for each matching entry. Passing
+             NULL for this parameter causes all available attributes
+             to be retrieved;
+
+   attrsonly A boolean value that should be zero if both attribute
+             types and values are to be returned, non-zero if only
+             types are wanted;
+
+   timeout   For the ldap_search_st() call, this specifies the local
+             search timeout value;
+
+   res       For the synchronous calls, this is a result parameter
+             which will contain the results of the search upon
+             completion of the call.
+
+   There are three fields in the ld connection handle which control how
+   the search is performed. They are:
+
+
+
+
+Howes & Smith                Informational                      [Page 6]
+\f
+RFC 1823                        LDAP API                     August 1995
+
+
+   ld_sizelimit A limit on the number of entries to return from the
+                search. A value of zero means no limit;
+
+   ld_timelimit A limit on the number of seconds to spend on the search.
+                A value of zero means no limit;
+
+   ld_deref     One of LDAP_DEREF_NEVER, LDAP_DEREF_SEARCHING,
+                LDAP_DEREF_FINDING, or LDAP_DEREF_ALWAYS, specifying
+                how aliases should be handled during the search. The
+                LDAP_DEREF_SEARCHING value means aliases should be
+                dereferenced during the search but not when locating
+                the base object of the search. The LDAP_DEREF_FINDING
+                value means aliases should be dereferenced when
+                locating the base object but not during the search.
+
+   An asynchronous search is initiated by calling ldap_search(). It
+   returns the message id of the initiated search. The results of the
+   search can be obtained by a subsequent call to ldap_result().  The
+   results can be parsed by the result parsing routines described in
+   detail later.  In case of error, -1 is returned and the ld_errno
+   field in the LDAP structure is set appropriately.
+
+   A synchronous search is performed by calling ldap_search_s() or
+   ldap_search_st(). The routines are identical, except that
+   ldap_search_st() takes an additional parameter specifying a timeout
+   for the search.  Both routines return an indication of the result of
+   the search, either LDAP_SUCCESS or some error indication (see Error
+   Handling below).  The entries returned from the search (if any) are
+   contained in the res parameter. This parameter is opaque to the
+   caller.  Entries, attributes, values, etc., should be extracted by
+   calling the parsing routines described below. The results contained
+   in res should be freed when no longer in use by calling
+   ldap_msgfree(), described later.
+
+4.5.  Reading an entry
+
+   LDAP does not support a read operation directly. Instead, this
+   operation is emulated by a search with base set to the DN of the
+   entry to read, scope set to LDAP_SCOPE_BASE, and filter set to
+   "(objectclass=*)". attrs contains the list of attributes to return.
+
+4.6.  Listing the children of an entry
+
+   LDAP does not support a list operation directly. Instead, this
+   operation is emulated by a search with base set to the DN of the
+   entry to list, scope set to LDAP_SCOPE_ONELEVEL, and filter set to
+   "(objectclass=*)". attrs contains the list of attributes to return
+   for each child entry.
+
+
+
+Howes & Smith                Informational                      [Page 7]
+\f
+RFC 1823                        LDAP API                     August 1995
+
+
+4.7.  Modifying an entry
+
+   The ldap_modify() and ldap_modify_s() routines are used to modify an
+   existing LDAP entry.
+
+           typedef struct ldapmod {
+                   int             mod_op;
+                   char            *mod_type;
+                   union {
+                           char            **modv_strvals;
+                           struct berval   **modv_bvals;
+                   } mod_vals;
+           } LDAPMod;
+           #define mod_values      mod_vals.modv_strvals
+           #define mod_bvalues     mod_vals.modv_bvals
+
+           int ldap_modify( LDAP *ld, char *dn, LDAPMod *mods[] );
+
+           int ldap_modify_s( LDAP *ld, char *dn, LDAPMod *mods[] );
+
+   Parameters are:
+
+   ld       The connection handle;
+
+   dn       The name of the entry to modify;
+
+   mods     A NULL-terminated array of modifications to make to the
+            entry.
+
+   The fields in the LDAPMod structure have the following meanings:
+
+   mod_op   The modification operation to perform. It should be one of
+            LDAP_MOD_ADD, LDAP_MOD_DELETE, or LDAP_MOD_REPLACE. This
+            field also indicates the type of values included in the
+            mod_vals union. It is ORed with LDAP_MOD_BVALUES to select
+            the mod_bvalues form. Otherwise, the mod_values form is
+            used;
+
+   mod_type The type of the attribute to modify;
+
+   mod_vals The values (if any) to add, delete, or replace. Only one of
+            the mod_values or mod_bvalues variants should be used,
+            selected by ORing the mod_op field with the constant
+            LDAP_MOD_BVALUES. mod_values is a NULL-terminated array of
+            zero-terminated strings and mod_bvalues is a NULL-terminated
+            array of berval structures that can be used to pass binary
+            values such as images.
+
+
+
+
+Howes & Smith                Informational                      [Page 8]
+\f
+RFC 1823                        LDAP API                     August 1995
+
+
+   For LDAP_MOD_ADD modifications, the given values are added to the
+   entry, creating the attribute if necessary.  For LDAP_MOD_DELETE
+   modifications, the given values are deleted from the entry, removing
+   the attribute if no values remain.  If the entire attribute is to be
+   deleted, the mod_vals field should be set to NULL.  For
+   LDAP_MOD_REPLACE modifications, the attribute will have the listed
+   values after the modification, having been created if necessary.  All
+   modifications are performed in the order in which they are listed.
+
+   ldap_modify_s() returns the LDAP error code  resulting  from the
+   modify  operation.   This  code  can  be interpreted by ldap_perror()
+   and friends.
+
+   ldap_modify() returns the message id of the request it initiates, or
+   -1 on error.  The result of the operation can be obtained by calling
+   ldap_result().
+
+4.8.  Modifying the RDN of an entry
+
+   The ldap_modrdn() and ldap_modrdn_s() routines are used to change the
+   name of an LDAP entry.
+
+           int ldap_modrdn(
+                   LDAP    *ld,
+                   char    *dn,
+                   char    *newrdn,
+                   int     deleteoldrdn
+           );
+           int ldap_modrdn_s(
+                   LDAP    *ld,
+                   char    *dn,
+                   char    *newrdn,
+                   int     deleteoldrdn
+           );
+
+   Parameters are:
+
+   ld            The connection handle;
+
+   dn            The name of the entry whose RDN is to be changed;
+
+   newrdn        The new RDN to give the entry;
+
+   deleteoldrdn  A boolean value, if non-zero indicating that the old
+                 RDN value(s) should be removed, if zero indicating that
+                 the old RDN value(s) should be retained as non-
+                 distinguished values of the entry.
+
+
+
+
+Howes & Smith                Informational                      [Page 9]
+\f
+RFC 1823                        LDAP API                     August 1995
+
+
+   The ldap_modrdn_s() routine is synchronous, returning the LDAP error
+   code indicating the outcome of the operation.
+
+   The ldap_modrdn() routine is asynchronous, returning the message id
+   of the operation it initiates, or -1 in case of trouble. The result
+   of the operation can be obtained by calling ldap_result().
+
+4.9.  Adding an entry
+
+   ldap_add() and ldap_add_s() are used to add entries to the LDAP
+   directory.
+
+           int ldap_add( LDAP *ld, char *dn, LDAPMod *attrs[] );
+
+           int ldap_add_s( LDAP *ld, char *dn, LDAPMod *attrs[] );
+
+   Parameters are:
+
+   ld    The connection handle;
+
+   dn    The name of the entry to add;
+
+   attrs The entry's attributes, specified using the LDAPMod structure
+         defined for ldap_modify(). The mod_type and mod_vals fields
+         should be filled in.  The mod_op field is ignored unless ORed
+         with the constant LDAP_MOD_BVALUES, used to select the
+         mod_bvalues case of the mod_vals union.
+
+   Note that the parent of the entry must already exist.
+
+   ldap_add_s() is synchronous, returning the LDAP error code indicating
+   the outcome of the operation.
+
+   ldap_add() is asynchronous, returning the message id of the operation
+   it initiates, or -1 in case of trouble. The result of the operation
+   can be obtained by calling ldap_result().
+
+4.10.  Deleting an entry
+
+   ldap_delete() and ldap_delete_s() are used to delete entries from the
+   LDAP directory.
+
+           int ldap_delete( LDAP *ld, char *dn );
+
+           int ldap_delete_s( LDAP *ld, char *dn );
+
+
+
+
+
+
+Howes & Smith                Informational                     [Page 10]
+\f
+RFC 1823                        LDAP API                     August 1995
+
+
+   Parameters are:
+
+   ld       The connection handle;
+
+   dn       The name of the entry to delete.
+
+   Note that the entry to delete must be a leaf entry (i.e., it must
+   have no children). Deletion of entire subtrees is not supported by
+   LDAP.
+
+   ldap_delete_s() is synchronous, returning the LDAP error code
+   indicating the outcome of the operation.
+
+   ldap_delete() is asynchronous, returning the message id of the
+   operation it initiates, or -1 in case of trouble. The result of the
+   operation can be obtained by calling ldap_result().
+
+5.  Calls for abandoning an operation
+
+   ldap_abandon() is used to abandon an operation in progress.
+
+           int ldap_abandon( LDAP *ld, int msgid );
+
+   ldap_abandon() abandons the operation with message id msgid. It
+   returns zero if the abandon was successful, -1 otherwise. After a
+   successful call to ldap_abandon(), results with the given message id
+   are never returned from a call to ldap_result().
+
+6.  Calls for obtaining results
+
+   ldap_result() is used to obtain the result of a previous
+   asynchronously initiated operation. ldap_msgfree() frees the results
+   obtained from a previous call to ldap_result(), or a synchronous
+   search routine.
+
+           int ldap_result(
+                   LDAP            *ld,
+                   int             msgid,
+                   int             all,
+                   struct timeval  *timeout,
+                   LDAPMessage     **res
+           );
+
+           int ldap_msgfree( LDAPMessage *res );
+
+
+
+
+
+
+
+Howes & Smith                Informational                     [Page 11]
+\f
+RFC 1823                        LDAP API                     August 1995
+
+
+   Parameters are:
+
+   ld       The connection handle;
+
+   msgid    The message id of the operation whose results are to be
+            returned, or the constant LDAP_RES_ANY if any result is
+            desired;
+
+   all      A boolean parameter that only has meaning for search
+            results. If non-zero it indicates that all results of a
+            search should be retrieved before any are returned. If zero,
+            search results (entries) will be returned one at a time as
+            they arrive;
+
+   timeout  A timeout specifying how long to wait for results to be
+            returned.  A NULL value causes ldap_result() to block until
+            results are available.  A timeout value of zero second
+            specifies a polling behavior;
+
+   res      For ldap_result(), a result parameter that will contain the
+            result(s) of the operation. For ldap_msgfree(), the result
+            chain to be freed, obtained from a previous call to
+            ldap_result() or ldap_search_s() or ldap_search_st().
+
+   Upon successful completion, ldap_result() returns the type of the
+   result returned in the res parameter. This will be one of the
+   following constants.
+
+             LDAP_RES_BIND
+             LDAP_RES_SEARCH_ENTRY
+             LDAP_RES_SEARCH_RESULT
+             LDAP_RES_MODIFY
+             LDAP_RES_ADD
+             LDAP_RES_DELETE
+             LDAP_RES_MODRDN
+             LDAP_RES_COMPARE
+
+   ldap_result() returns 0 if the timeout expired and -1 if an error
+   occurs, in which case the ld_errno field of the ld structure will be
+   set accordingly.
+
+   ldap_msgfree() frees the result structure pointed to be res and
+   returns the type of the message it freed.
+
+
+
+
+
+
+
+
+Howes & Smith                Informational                     [Page 12]
+\f
+RFC 1823                        LDAP API                     August 1995
+
+
+7.  Calls for error handling
+
+   The following calls are used to interpret errors returned by other
+   LDAP API routines.
+
+           int ldap_result2error(
+                   LDAP            *ld,
+                   LDAPMessage     *res,
+                   int             freeit
+           );
+
+           char *ldap_err2string( int err );
+
+           void ldap_perror( LDAP *ld, char *msg );
+
+   Parameters are:
+
+   ld       The connection handle;
+
+   res      The result of an LDAP operation as returned by ldap_result()
+            or one of the synchronous API operation calls;
+
+   freeit   A boolean parameter indicating whether the res parameter
+            should be freed (non-zero) or not (zero);
+
+   err      An LDAP error code, as returned by ldap_result2error() or
+            one of the synchronous API operation calls;
+
+   msg      A message to be displayed before the LDAP error message.
+
+   ldap_result2error() is used to convert the LDAP result message
+   obtained from ldap_result(), or the res parameter returned by one of
+   the synchronous API operation calls, into a numeric LDAP error code.
+   It also parses the ld_matched and ld_error portions of the result
+   message and puts them into the connection handle information. All the
+   synchronous operation routines call ldap_result2error() before
+   returning, ensuring that these fields are set correctly. The relevant
+   fields in the connection structue are:
+
+   ld_matched In the event of an LDAP_NO_SUCH_OBJECT error return, this
+              parameter contains the extent of the DN matched;
+
+   ld_error   This parameter contains the error message sent in the
+              result by the LDAP server.
+
+   ld_errno   The LDAP error code indicating the outcome of the
+              operation. It is one of the following constants:
+
+
+
+
+Howes & Smith                Informational                     [Page 13]
+\f
+RFC 1823                        LDAP API                     August 1995
+
+
+           LDAP_SUCCESS
+           LDAP_OPERATIONS_ERROR
+           LDAP_PROTOCOL_ERROR
+           LDAP_TIMELIMIT_EXCEEDED
+           LDAP_SIZELIMIT_EXCEEDED
+           LDAP_COMPARE_FALSE
+           LDAP_COMPARE_TRUE
+           LDAP_STRONG_AUTH_NOT_SUPPORTED
+           LDAP_STRONG_AUTH_REQUIRED
+           LDAP_NO_SUCH_ATTRIBUTE
+           LDAP_UNDEFINED_TYPE
+           LDAP_INAPPROPRIATE_MATCHING
+           LDAP_CONSTRAINT_VIOLATION
+           LDAP_TYPE_OR_VALUE_EXISTS
+           LDAP_INVALID_SYNTAX
+           LDAP_NO_SUCH_OBJECT
+           LDAP_ALIAS_PROBLEM
+           LDAP_INVALID_DN_SYNTAX
+           LDAP_IS_LEAF
+           LDAP_ALIAS_DEREF_PROBLEM
+           LDAP_INAPPROPRIATE_AUTH
+           LDAP_INVALID_CREDENTIALS
+           LDAP_INSUFFICIENT_ACCESS
+           LDAP_BUSY
+           LDAP_UNAVAILABLE
+           LDAP_UNWILLING_TO_PERFORM
+           LDAP_LOOP_DETECT
+           LDAP_NAMING_VIOLATION
+           LDAP_OBJECT_CLASS_VIOLATION
+           LDAP_NOT_ALLOWED_ON_NONLEAF
+           LDAP_NOT_ALLOWED_ON_RDN
+           LDAP_ALREADY_EXISTS
+           LDAP_NO_OBJECT_CLASS_MODS
+           LDAP_RESULTS_TOO_LARGE
+           LDAP_OTHER
+           LDAP_SERVER_DOWN
+           LDAP_LOCAL_ERROR
+           LDAP_ENCODING_ERROR
+           LDAP_DECODING_ERROR
+           LDAP_TIMEOUT
+           LDAP_AUTH_UNKNOWN
+           LDAP_FILTER_ERROR
+           LDAP_USER_CANCELLED
+           LDAP_PARAM_ERROR
+           LDAP_NO_MEMORY
+
+
+
+
+
+
+Howes & Smith                Informational                     [Page 14]
+\f
+RFC 1823                        LDAP API                     August 1995
+
+
+   ldap_err2string() is used to convert a numeric LDAP error code, as
+   returned by ldap_result2error() or one of the synchronous API
+   operation calls, into an informative NULL-terminated character string
+   message describing the error.  It returns a pointer to static data.
+
+   ldap_perror() is used to print the message supplied in msg, followed
+   by an indication of the error contained in the ld_errno field of the
+   ld connection handle, to standard error.
+
+8.  Calls for parsing search entries
+
+   The following calls are used to parse the entries returned by
+   ldap_search() and friends. These entries are returned in an opaque
+   structure that should only be accessed by calling the routines
+   described below. Routines are provided to step through the entries
+   returned, step through the attributes of an entry, retrieve the name
+   of an entry, and retrieve the values associated with a given
+   attribute in an entry.
+
+8.1.  Stepping through a set of entries
+
+   The ldap_first_entry() and ldap_next_entry() routines are used to
+   step through a set of entries in a search result.
+   ldap_count_entries() is used to count the number of entries returned.
+
+           LDAPMesage *ldap_first_entry( LDAP *ld, LDAPMessage *res );
+
+           LDAPMesage *ldap_next_entry( LDAP *ld, LDAPMessage *entry );
+
+           int ldap_count_entries( LDAP *ld, LDAPMessage *res );
+
+   Parameters are:
+
+   ld     The connection handle;
+
+   res    The search result, as obtained by a call to one of the syn-
+          chronous search routines or ldap_result();
+
+   entry  The entry returned by a previous call to ldap_first_entry() or
+          ldap_next_entry().
+
+   ldap_first_entry() and ldap_next_entry() will return NULL when no
+   more entries exist to be returned. NULL is also returned if an error
+   occurs while stepping through the entries, in which case the ld_errno
+   field of the ld connection handle will be set to indicate the error.
+
+   ldap_count_entries() returns the number of entries contained in a
+   chain of entries. It can also be used to count the number of entries
+
+
+
+Howes & Smith                Informational                     [Page 15]
+\f
+RFC 1823                        LDAP API                     August 1995
+
+
+   that remain in a chain if called with an entry returned by
+   ldap_first_entry() or ldap_next_entry().
+
+8.2.  Stepping through the attributes of an entry
+
+   The ldap_first_attribute() and ldap_next_attribute() calls are used
+   to step through the list of attribute types returned with an entry.
+
+           char *ldap_first_attribute(
+                   LDAP            *ld,
+                   LDAPMessage     *entry,
+                   void            **ptr
+           );
+           char *ldap_next_attribute(
+                   LDAP            *ld,
+                   LDAPMessage     *entry,
+                   void            *ptr
+           );
+
+   Parameters are:
+
+   ld     The connection handle;
+
+   entry  The entry whose attributes are to be stepped through, as
+          returned by ldap_first_entry() or ldap_next_entry();
+
+   ptr    In ldap_first_attribute(), the address of a pointer used
+          internally to keep track of the current position in the entry.
+          In ldap_next_attribute(), the pointer returned by a previous
+          call to ldap_first_attribute().
+
+   ldap_first_attribute() and ldap_next_attribute() will return NULL
+   when the end of the attributes is reached, or if there is an error,
+   in which case the ld_errno field in the ld connection handle will be
+   set to indicate the error.
+
+   Both routines return a pointer to a per-connection buffer containing
+   the current attribute name. This should be treated like static data.
+   ldap_first_attribute() will allocate and return in ptr a pointer to a
+   BerElement used to keep track of the current position. This pointer
+   should be passed in subsequent calls to ldap_next_attribute() to step
+   through the entry's attributes.
+
+   The attribute names returned are suitable for passing in a call to
+   ldap_get_values() and friends to retrieve the associated values.
+
+
+
+
+
+
+Howes & Smith                Informational                     [Page 16]
+\f
+RFC 1823                        LDAP API                     August 1995
+
+
+8.3.  Retrieving the values of an attribute
+
+   ldap_get_values() and ldap_get_values_len() are used to retrieve the
+   values of a given attribute from an entry. ldap_count_values() and
+   ldap_count_values_len() are used to count the returned values.
+   ldap_value_free() and ldap_value_free_len() are used to free the
+   values.
+
+           typedef struct berval {
+                   unsigned long   bv_len;
+                   char            *bv_val;
+           };
+
+           char **ldap_get_values(
+                   LDAP            *ld,
+                   LDAPMessage     *entry,
+                   char            *attr
+           );
+
+           struct berval **ldap_get_values_len(
+                   LDAP            *ld,
+                   LDAPMessage     *entry,
+                   char            *attr
+           );
+
+           int ldap_count_values( char **vals );
+
+           int ldap_count_values_len( struct berval **vals );
+
+           int ldap_value_free( char **vals );
+
+           int ldap_value_free_len( struct berval **vals );
+
+   Parameters are:
+
+   ld     The connection handle;
+
+   entry  The entry from which to retrieve values, as returned by
+          ldap_first_entry() or ldap_next_entry();
+
+   attr   The attribute whose values are to be retrieved, as returned by
+          ldap_first_attribute() or ldap_next_attribute(), or a caller-
+          supplied string (e.g., "mail");
+
+   vals   The values returned by a previous call to ldap_get_values() or
+          ldap_get_values_len().
+
+
+
+
+
+Howes & Smith                Informational                     [Page 17]
+\f
+RFC 1823                        LDAP API                     August 1995
+
+
+   Two forms of the various calls are provided. The first form is only
+   suitable for use with non-binary character string data only. The
+   second _len form is used with any kind of data.
+
+   Note that the values returned are malloc'ed and should be freed by
+   calling either ldap_value_free() or ldap_value_free_len() when no
+   longer in use.
+
+8.4.  Retrieving the name of an entry
+
+   ldap_get_dn() is used to retrieve the name of an entry.
+   ldap_explode_dn() is used to break up the name into its component
+   parts. ldap_dn2ufn() is used to convert the name into a more "user
+   friendly" format.
+
+           char *ldap_get_dn( LDAP *ld, LDAPMessage *entry );
+
+           char **ldap_explode_dn( char *dn, int notypes );
+
+           char *ldap_dn2ufn( char *dn );
+
+   Parameters are:
+
+   ld      The connection handle;
+
+   entry   The entry whose name is to be retrieved, as returned by
+           ldap_first_entry() or ldap_next_entry();
+
+   dn      The dn to explode, as returned by ldap_get_dn();
+
+   notypes A boolean parameter, if non-zero indicating that the dn com-
+           ponents should have their type information stripped off
+           (i.e., "cn=Babs" would become "Babs").
+
+   ldap_get_dn() will return NULL if there is some error parsing the dn,
+   setting ld_errno in the ld connection handle to indicate the error.
+   It returns a pointer to malloc'ed space that the caller should free
+   by calling free() when it is no longer in use.  Note the format of
+   the DNs returned is given by [4].
+
+   ldap_explode_dn() returns a char * array containing the RDN
+   components of the DN supplied, with or without types as indicated by
+   the notypes parameter. The array returned should be freed when it is
+   no longer in use by calling ldap_value_free().
+
+   ldap_dn2ufn() converts the DN into the user friendly format described
+   in [5]. The UFN returned is malloc'ed space that should be freed by a
+   call to free() when no longer in use.
+
+
+
+Howes & Smith                Informational                     [Page 18]
+\f
+RFC 1823                        LDAP API                     August 1995
+
+
+9.  Security Considerations
+
+   LDAP supports minimal security during connection authentication.
+
+10.  Acknowledgements
+
+   This material is based upon work supported by the National Science
+   Foundation under Grant No. NCR-9416667.
+
+11.  Bibliography
+
+   [1] The Directory: Selected Attribute Syntaxes.  CCITT,
+       Recommendation X.520.
+
+   [2] Howes, T., Kille, S., Yeong, W., and C. Robbins, "The String
+       Representation of Standard Attribute Syntaxes", University of
+       Michigan, ISODE Consortium, Performance Systems International,
+       NeXor Ltd., RFC 1778, March 1995.
+
+   [3] Howes, T., "A String Representation of LDAP Search Filters", RFC
+       1558, University of Michigan, December 1993.
+
+   [4] Kille, S., "A String Representation of Distinguished Names", RFC
+       1779, ISODE Consortium, March 1995.
+
+   [5] Kille, S., "Using the OSI Directory to Achieve User Friendly
+       Naming",  RFC 1781, ISODE Consortium, March 1995.
+
+   [6] S.P. Miller, B.C. Neuman, J.I. Schiller, J.H. Saltzer, "Kerberos
+       Authentication and Authorization System", MIT Project Athena
+       Documentation Section  E.2.1, December 1987
+
+   [7] Yeong, W., Howes, T., and S. Kille, "Lightweight Directory Access
+       Protocol," RFC 1777, Performance Systems International,
+       University of Michigan, ISODE Consortium, March 1995.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Howes & Smith                Informational                     [Page 19]
+\f
+RFC 1823                        LDAP API                     August 1995
+
+
+12.  Authors' Addresses
+
+       Tim Howes
+       University of Michigan
+       ITD Research Systems
+       535 W William St.
+       Ann Arbor, MI 48103-4943
+       USA
+
+       Phone: +1 313 747-4454
+       EMail: tim@umich.edu
+
+
+       Mark Smith
+       University of Michigan
+       ITD Research Systems
+       535 W William St.
+       Ann Arbor, MI 48103-4943
+       USA
+
+       Phone: +1 313 764-2277
+       EMail: mcs@umich.edu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Howes & Smith                Informational                     [Page 20]
+\f
+RFC 1823                        LDAP API                     August 1995
+
+
+13.  Appendix A - Sample LDAP API Code
+
+   #include <ldap.h>
+
+   main()
+   {
+           LDAP            *ld;
+           LDAPMessage     *res, *e;
+           int             i;
+           char            *a, *dn;
+           void            *ptr;
+           char            **vals;
+
+           /* open a connection */
+           if ( (ld = ldap_open( "dotted.host.name", LDAP_PORT ))
+                   == NULL )
+                   exit( 1 );
+
+           /* authenticate as nobody */
+           if ( ldap_simple_bind_s( ld, NULL, NULL ) != LDAP_SUCCESS ) {
+                   ldap_perror( ld, "ldap_simple_bind_s" );
+                   exit( 1 );
+           }
+
+           /* search for entries with cn of "Babs Jensen",
+                   return all attrs  */
+           if ( ldap_search_s( ld, "o=University of Michigan, c=US",
+               LDAP_SCOPE_SUBTREE, "(cn=Babs Jensen)", NULL, 0, &res )
+               != LDAP_SUCCESS ) {
+                   ldap_perror( ld, "ldap_search_s" );
+                   exit( 1 );
+           }
+
+           /* step through each entry returned */
+           for ( e = ldap_first_entry( ld, res ); e != NULL;
+               e = ldap_next_entry( ld, e ) ) {
+                   /* print its name */
+                   dn = ldap_get_dn( ld, e );
+                   printf( "dn: %s0, dn );
+                   free( dn );
+
+                   /* print each attribute */
+                   for ( a = ldap_first_attribute( ld, e, &ptr );
+                           a != NULL;
+                       a = ldap_next_attribute( ld, e, ptr ) ) {
+                           printf( "attribute: %s0, a );
+
+                           /* print each value */
+
+
+
+Howes & Smith                Informational                     [Page 21]
+\f
+RFC 1823                        LDAP API                     August 1995
+
+
+                           vals = ldap_get_values( ld, e, a );
+                           for ( i = 0; vals[i] != NULL; i++ ) {
+                                   printf( "value: %s0, vals[i] );
+                           }
+                           ldap_value_free( vals );
+                   }
+           }
+           /* free the search results */
+           ldap_msgfree( res );
+
+           /* close and free connection resources */
+           ldap_unbind( ld );
+   }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Howes & Smith                Informational                     [Page 22]
+\f
diff --git a/include/Make-template b/include/Make-template
new file mode 100644 (file)
index 0000000..c0a26fb
--- /dev/null
@@ -0,0 +1,63 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1994 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP include file makefile
+#
+#-----------------------------------------------------------------------------
+
+LDAPSRC=..
+
+all:   ldapconfig.h FORCE
+       @if [ ! -z "$(SYSEXITSPATH)" -a ! -r sysexits.h ]; then \
+           echo "$(LN) $(SYSEXITSPATH) sysexits.h"; \
+           $(LN) $(SYSEXITSPATH) sysexits.h; \
+       else \
+           exit 0; \
+       fi
+
+ldapconfig.h:  ldapconfig.h.edit Makefile
+       @$(RM) $@
+       @echo "/*" > $@;  \
+        echo " * This file was automatically generated.  Do not edit it." >> $@; \
+        echo " * Instead, edit the file ldapconfig.h.edit.  See the LDAP" >> $@; \
+        echo " * INSTALL file for more information." >> $@; \
+        echo " */ " >> $@; \
+        echo "" >> $@; \
+       $(SED) -e 's;%ETCDIR%;$(RUNTIMEETCDIR);' ldapconfig.h.edit >> $@; \
+       $(CHMOD) 444 $@
+
+install: all FORCE
+               -$(MKDIR) -p $(INCLUDEDIR)
+               $(INSTALL) $(INSTALLFLAGS) -m 644 ldap.h $(INCLUDEDIR)
+               $(INSTALL) $(INSTALLFLAGS) -m 644 lber.h $(INCLUDEDIR)
+               $(INSTALL) $(INSTALLFLAGS) -m 644 proto-lber.h $(INCLUDEDIR)
+               $(INSTALL) $(INSTALLFLAGS) -m 644 proto-ldap.h $(INCLUDEDIR)
+               $(INSTALL) $(INSTALLFLAGS) -m 644 disptmpl.h $(INCLUDEDIR)
+               $(INSTALL) $(INSTALLFLAGS) -m 644 srchpref.h $(INCLUDEDIR)
+
+depend:        FORCE
+
+clean: FORCE
+
+veryclean:     clean
+       $(RM) ldapconfig.h
+       @if [ ! -z "$(SYSEXITSPATH)" ]; then \
+           echo "$(RM) sysexits.h"; \
+           $(RM) sysexits.h; \
+       else \
+           exit 0; \
+       fi
+
+links:
+       @echo "making links in `$(PWD)`
+       @$(LN) .src/*.h .
+       @cp .src/ldapconfig.h.edit .
+       @-$(RM) ldapconfig.h
diff --git a/include/avl.h b/include/avl.h
new file mode 100644 (file)
index 0000000..745cc17
--- /dev/null
@@ -0,0 +1,56 @@
+/* avl.h - avl tree definitions */
+/*
+ * Copyright (c) 1993 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+
+#ifndef _AVL
+#define _AVL
+
+/*
+ * this structure represents a generic avl tree node.
+ */
+
+typedef struct avlnode {
+       caddr_t         avl_data;
+       char            avl_bf;
+       struct avlnode  *avl_left;
+       struct avlnode  *avl_right;
+} Avlnode;
+
+#define NULLAVL        ((Avlnode *) NULL)
+
+/* balance factor values */
+#define LH     -1
+#define EH     0
+#define RH     1
+
+/* avl routines */
+#define avl_getone(x)  (x == 0 ? 0 : (x)->avl_data)
+#define avl_onenode(x) (x == 0 || ((x)->avl_left == 0 && (x)->avl_right == 0))
+extern int             avl_insert();
+extern caddr_t         avl_delete();
+extern caddr_t         avl_find();
+extern caddr_t         avl_getfirst();
+extern caddr_t         avl_getnext();
+extern int             avl_dup_error();
+extern int             avl_apply();
+
+/* apply traversal types */
+#define AVL_PREORDER   1
+#define AVL_INORDER    2
+#define AVL_POSTORDER  3
+/* what apply returns if it ran out of nodes */
+#define AVL_NOMORE     -6
+
+typedef int    (*IFP)();
+
+#endif /* _AVL */
diff --git a/include/disptmpl.h b/include/disptmpl.h
new file mode 100644 (file)
index 0000000..c4e06ef
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * Copyright (c) 1993, 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ *
+ * disptmpl.h:  display template library defines
+ * 7 March 1994 by Mark C Smith
+ */
+
+#ifndef _DISPTMPL_H
+#define _DISPTMPL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define LDAP_TEMPLATE_VERSION  1
+
+/*
+ * general types of items (confined to most significant byte)
+ */
+#define LDAP_SYN_TYPE_TEXT             0x01000000L
+#define LDAP_SYN_TYPE_IMAGE            0x02000000L
+#define LDAP_SYN_TYPE_BOOLEAN          0x04000000L
+#define LDAP_SYN_TYPE_BUTTON           0x08000000L
+#define LDAP_SYN_TYPE_ACTION           0x10000000L
+
+
+/*
+ * syntax options (confined to second most significant byte)
+ */
+#define LDAP_SYN_OPT_DEFER             0x00010000L
+
+
+/* 
+ * display template item syntax ids (defined by common agreement)
+ * these are the valid values for the ti_syntaxid of the tmplitem
+ * struct (defined below).  A general type is encoded in the
+ * most-significant 8 bits, and some options are encoded in the next
+ * 8 bits.  The lower 16 bits are reserved for the distinct types.
+ */
+#define LDAP_SYN_CASEIGNORESTR ( 1 | LDAP_SYN_TYPE_TEXT )
+#define LDAP_SYN_MULTILINESTR  ( 2 | LDAP_SYN_TYPE_TEXT )
+#define LDAP_SYN_DN            ( 3 | LDAP_SYN_TYPE_TEXT )
+#define LDAP_SYN_BOOLEAN       ( 4 | LDAP_SYN_TYPE_BOOLEAN )
+#define LDAP_SYN_JPEGIMAGE     ( 5 | LDAP_SYN_TYPE_IMAGE )
+#define LDAP_SYN_JPEGBUTTON    ( 6 | LDAP_SYN_TYPE_BUTTON | LDAP_SYN_OPT_DEFER )
+#define LDAP_SYN_FAXIMAGE      ( 7 | LDAP_SYN_TYPE_IMAGE )
+#define LDAP_SYN_FAXBUTTON     ( 8 | LDAP_SYN_TYPE_BUTTON | LDAP_SYN_OPT_DEFER )
+#define LDAP_SYN_AUDIOBUTTON   ( 9 | LDAP_SYN_TYPE_BUTTON | LDAP_SYN_OPT_DEFER )
+#define LDAP_SYN_TIME          ( 10 | LDAP_SYN_TYPE_TEXT )
+#define LDAP_SYN_DATE          ( 11 | LDAP_SYN_TYPE_TEXT )
+#define LDAP_SYN_LABELEDURL    ( 12 | LDAP_SYN_TYPE_TEXT )
+#define LDAP_SYN_SEARCHACTION  ( 13 | LDAP_SYN_TYPE_ACTION )
+#define LDAP_SYN_LINKACTION    ( 14 | LDAP_SYN_TYPE_ACTION )
+#define LDAP_SYN_ADDDNACTION   ( 15 | LDAP_SYN_TYPE_ACTION )
+#define LDAP_SYN_VERIFYDNACTION ( 16 | LDAP_SYN_TYPE_ACTION )
+#define LDAP_SYN_RFC822ADDR    ( 17 | LDAP_SYN_TYPE_TEXT )
+
+
+/*
+ * handy macros
+ */
+#define LDAP_GET_SYN_TYPE( syid )      ((syid) & 0xFF000000L )
+#define LDAP_GET_SYN_OPTIONS( syid )   ((syid) & 0x00FF0000L )
+
+
+/*
+ * display options for output routines (used by entry2text and friends)
+ */
+/*
+ * use calculated label width (based on length of longest label in
+ * template) instead of contant width
+ */
+#define LDAP_DISP_OPT_AUTOLABELWIDTH   0x00000001L
+#define LDAP_DISP_OPT_HTMLBODYONLY     0x00000002L
+
+/*
+ * perform search actions (applies to ldap_entry2text_search only) 
+ */
+#define LDAP_DISP_OPT_DOSEARCHACTIONS  0x00000002L
+
+/*
+ * include additional info. relevant to "non leaf" entries only
+ * used by ldap_entry2html and ldap_entry2html_search to include "Browse"
+ * and "Move Up" HREFs
+ */
+#define LDAP_DISP_OPT_NONLEAF          0x00000004L
+
+
+/*
+ * display template item options (may not apply to all types)
+ * if this bit is set in ti_options, it applies.
+ */
+#define LDAP_DITEM_OPT_READONLY                0x00000001L
+#define LDAP_DITEM_OPT_SORTVALUES      0x00000002L
+#define LDAP_DITEM_OPT_SINGLEVALUED    0x00000004L
+#define LDAP_DITEM_OPT_HIDEIFEMPTY     0x00000008L
+#define LDAP_DITEM_OPT_VALUEREQUIRED   0x00000010L
+#define LDAP_DITEM_OPT_HIDEIFFALSE     0x00000020L     /* booleans only */
+
+
+
+/*
+ * display template item structure
+ */
+struct ldap_tmplitem {
+    unsigned long              ti_syntaxid;
+    unsigned long              ti_options;
+    char                       *ti_attrname;
+    char                       *ti_label;
+    char                       **ti_args;
+    struct ldap_tmplitem       *ti_next_in_row;
+    struct ldap_tmplitem       *ti_next_in_col;
+    void                       *ti_appdata;
+};
+
+
+#define NULLTMPLITEM   ((struct ldap_tmplitem *)0)
+
+#define LDAP_SET_TMPLITEM_APPDATA( ti, datap ) \
+       (ti)->ti_appdata = (void *)(datap)
+
+#define LDAP_GET_TMPLITEM_APPDATA( ti, type )  \
+       (type)((ti)->ti_appdata)
+
+#define LDAP_IS_TMPLITEM_OPTION_SET( ti, option )      \
+       (((ti)->ti_options & option ) != 0 )
+
+
+/*
+ * object class array structure
+ */
+struct ldap_oclist {
+    char               **oc_objclasses;
+    struct ldap_oclist *oc_next;
+};
+
+#define NULLOCLIST     ((struct ldap_oclist *)0)
+
+
+/*
+ * add defaults list
+ */
+struct ldap_adddeflist {
+    int                        ad_source;
+#define LDAP_ADSRC_CONSTANTVALUE       1
+#define LDAP_ADSRC_ADDERSDN            2
+    char               *ad_attrname;
+    char               *ad_value;
+    struct ldap_adddeflist     *ad_next;
+};
+
+#define NULLADLIST     ((struct ldap_adddeflist *)0)
+
+
+/*
+ * display template global options
+ * if this bit is set in dt_options, it applies.
+ */
+/*
+ * users should be allowed to try to add objects of these entries
+ */
+#define LDAP_DTMPL_OPT_ADDABLE         0x00000001L
+
+/*
+ * users should be allowed to do "modify RDN" operation of these entries
+ */
+#define LDAP_DTMPL_OPT_ALLOWMODRDN     0x00000002L
+
+/*
+ * this template is an alternate view, not a primary view
+ */
+#define LDAP_DTMPL_OPT_ALTVIEW         0x00000004L
+
+
+/*
+ * display template structure
+ */
+struct ldap_disptmpl {
+    char                       *dt_name;
+    char                       *dt_pluralname;
+    char                       *dt_iconname;
+    unsigned long              dt_options;
+    char                       *dt_authattrname;
+    char                       *dt_defrdnattrname;
+    char                       *dt_defaddlocation;
+    struct ldap_oclist         *dt_oclist;
+    struct ldap_adddeflist     *dt_adddeflist;
+    struct ldap_tmplitem       *dt_items;
+    void                       *dt_appdata;
+    struct ldap_disptmpl       *dt_next;
+};
+
+#define NULLDISPTMPL   ((struct ldap_disptmpl *)0)
+
+#define LDAP_SET_DISPTMPL_APPDATA( dt, datap ) \
+       (dt)->dt_appdata = (void *)(datap)
+
+#define LDAP_GET_DISPTMPL_APPDATA( dt, type )  \
+       (type)((dt)->dt_appdata)
+
+#define LDAP_IS_DISPTMPL_OPTION_SET( dt, option )      \
+       (((dt)->dt_options & option ) != 0 )
+
+#define LDAP_TMPL_ERR_VERSION  1
+#define LDAP_TMPL_ERR_MEM      2
+#define LDAP_TMPL_ERR_SYNTAX   3
+#define LDAP_TMPL_ERR_FILE     4
+
+/*
+ * buffer size needed for entry2text and vals2text
+ */
+#define LDAP_DTMPL_BUFSIZ      8192
+
+
+#ifndef NEEDPROTOS
+
+typedef int (*writeptype)();
+
+int ldap_init_templates();
+int ldap_init_templates_buf();
+void ldap_free_templates();
+struct ldap_disptmpl *ldap_first_disptmpl();
+struct ldap_disptmpl *ldap_next_disptmpl();
+struct ldap_disptmpl *ldap_name2template();
+struct ldap_disptmpl *ldap_oc2template();
+char **ldap_tmplattrs();
+struct ldap_tmplitem *ldap_first_tmplrow();
+struct ldap_tmplitem *ldap_next_tmplrow();
+struct ldap_tmplitem *ldap_first_tmplcol();
+struct ldap_tmplitem *ldap_next_tmplcol();
+int ldap_entry2text_search();
+int ldap_entry2text();
+int ldap_vals2text();
+int ldap_entry2html_search();
+int ldap_entry2html();
+int ldap_vals2html();
+
+#else /* !NEEDPROTOS */
+
+typedef int (*writeptype)( void *writeparm, char *p, int len );
+
+LDAPFUNCDECL int
+ldap_init_templates( char *file, struct ldap_disptmpl **tmpllistp );
+
+LDAPFUNCDECL int
+ldap_init_templates_buf( char *buf, long buflen,
+       struct ldap_disptmpl **tmpllistp );
+
+LDAPFUNCDECL void
+ldap_free_templates( struct ldap_disptmpl *tmpllist );
+
+LDAPFUNCDECL struct ldap_disptmpl *
+ldap_first_disptmpl( struct ldap_disptmpl *tmpllist );
+
+LDAPFUNCDECL struct ldap_disptmpl *
+ldap_next_disptmpl( struct ldap_disptmpl *tmpllist,
+       struct ldap_disptmpl *tmpl );
+
+LDAPFUNCDECL struct ldap_disptmpl *
+ldap_name2template( char *name, struct ldap_disptmpl *tmpllist );
+
+LDAPFUNCDECL struct ldap_disptmpl *
+ldap_oc2template( char **oclist, struct ldap_disptmpl *tmpllist );
+
+LDAPFUNCDECL char **
+ldap_tmplattrs( struct ldap_disptmpl *tmpl, char **includeattrs, int exclude,
+        unsigned long syntaxmask );
+
+LDAPFUNCDECL struct ldap_tmplitem *
+ldap_first_tmplrow( struct ldap_disptmpl *tmpl );
+
+LDAPFUNCDECL struct ldap_tmplitem *
+ldap_next_tmplrow( struct ldap_disptmpl *tmpl, struct ldap_tmplitem *row );
+
+LDAPFUNCDECL struct ldap_tmplitem *
+ldap_first_tmplcol( struct ldap_disptmpl *tmpl, struct ldap_tmplitem *row );
+
+LDAPFUNCDECL struct ldap_tmplitem *
+ldap_next_tmplcol( struct ldap_disptmpl *tmpl, struct ldap_tmplitem *row,
+       struct ldap_tmplitem *col );
+
+LDAPFUNCDECL int
+ldap_entry2text( LDAP *ld, char *buf, LDAPMessage *entry,
+       struct ldap_disptmpl *tmpl, char **defattrs, char ***defvals,
+       writeptype writeproc, void *writeparm, char *eol, int rdncount,
+       unsigned long opts );
+
+LDAPFUNCDECL int
+ldap_vals2text( LDAP *ld, char *buf, char **vals, char *label, int labelwidth,
+       unsigned long syntaxid, writeptype writeproc, void *writeparm,
+       char *eol, int rdncount );
+
+LDAPFUNCDECL int
+ldap_entry2text_search( LDAP *ld, char *dn, char *base, LDAPMessage *entry,
+       struct ldap_disptmpl *tmpllist, char **defattrs, char ***defvals,
+       writeptype writeproc, void *writeparm, char *eol, int rdncount,
+       unsigned long opts );
+
+LDAPFUNCDECL int
+ldap_entry2html( LDAP *ld, char *buf, LDAPMessage *entry,
+       struct ldap_disptmpl *tmpl, char **defattrs, char ***defvals,
+       writeptype writeproc, void *writeparm, char *eol, int rdncount,
+       unsigned long opts, char *urlprefix, char *base );
+
+LDAPFUNCDECL int
+ldap_vals2html( LDAP *ld, char *buf, char **vals, char *label, int labelwidth,
+       unsigned long syntaxid, writeptype writeproc, void *writeparm,
+       char *eol, int rdncount, char *urlprefix );
+
+LDAPFUNCDECL int
+ldap_entry2html_search( LDAP *ld, char *dn, char *base, LDAPMessage *entry,
+       struct ldap_disptmpl *tmpllist, char **defattrs, char ***defvals,
+       writeptype writeproc, void *writeparm, char *eol, int rdncount,
+       unsigned long opts, char *urlprefix );
+#endif /* !NEEDPROTOS */
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _DISPTMPL_H */
diff --git a/include/lber.h b/include/lber.h
new file mode 100644 (file)
index 0000000..9998f0b
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#ifndef _LBER_H
+#define _LBER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined( NEEDPROTOS ) && defined(__STDC__)
+#define NEEDPROTOS     1
+#endif
+
+/* BER classes and mask */
+#define LBER_CLASS_UNIVERSAL   0x00
+#define LBER_CLASS_APPLICATION 0x40
+#define LBER_CLASS_CONTEXT     0x80
+#define LBER_CLASS_PRIVATE     0xc0
+#define LBER_CLASS_MASK                0xc0
+
+/* BER encoding type and mask */
+#define LBER_PRIMITIVE         0x00
+#define LBER_CONSTRUCTED       0x20
+#define LBER_ENCODING_MASK     0x20
+
+#define LBER_BIG_TAG_MASK      0x1f
+#define LBER_MORE_TAG_MASK     0x80
+
+/*
+ * Note that LBER_ERROR and LBER_DEFAULT are values that can never appear
+ * as valid BER tags, and so it is safe to use them to report errors.  In
+ * fact, any tag for which the following is true is invalid:
+ *     (( tag & 0x00000080 ) != 0 ) && (( tag & 0xFFFFFF00 ) != 0 )
+ */
+#define LBER_ERROR             0xffffffffL
+#define LBER_DEFAULT           0xffffffffL
+
+/* general BER types we know about */
+#define LBER_BOOLEAN           0x01L
+#define LBER_INTEGER           0x02L
+#define LBER_BITSTRING         0x03L
+#define LBER_OCTETSTRING       0x04L
+#define LBER_NULL              0x05L
+#define LBER_ENUMERATED                0x0aL
+#define LBER_SEQUENCE          0x30L   /* constructed */
+#define LBER_SET               0x31L   /* constructed */
+
+#define OLD_LBER_SEQUENCE      0x10L   /* w/o constructed bit - broken */
+#define OLD_LBER_SET           0x11L   /* w/o constructed bit - broken */
+
+#ifdef NEEDPROTOS
+typedef int (*BERTranslateProc)( char **bufp, unsigned long *buflenp,
+       int free_input );
+#else /* NEEDPROTOS */
+typedef int (*BERTranslateProc)();
+#endif /* NEEDPROTOS */
+
+typedef struct berelement {
+       char            *ber_buf;
+       char            *ber_ptr;
+       char            *ber_end;
+       struct seqorset *ber_sos;
+       unsigned long   ber_tag;
+       unsigned long   ber_len;
+       int             ber_usertag;
+       char            ber_options;
+#define LBER_USE_DER           0x01
+#define LBER_USE_INDEFINITE_LEN        0x02
+#define LBER_TRANSLATE_STRINGS 0x04
+       char            *ber_rwptr;
+       BERTranslateProc ber_encode_translate_proc;
+       BERTranslateProc ber_decode_translate_proc;
+} BerElement;
+#define NULLBER        ((BerElement *) 0)
+
+typedef struct sockbuf {
+#ifndef MACOS
+       int             sb_sd;
+#else /* MACOS */
+       void            *sb_sd;
+#endif /* MACOS */
+       BerElement      sb_ber;
+
+       int             sb_naddr;       /* > 0 implies using CLDAP (UDP) */
+       void            *sb_useaddr;    /* pointer to sockaddr to use next */
+       void            *sb_fromaddr;   /* pointer to message source sockaddr */
+       void            **sb_addrs;     /* actually an array of pointers to
+                                               sockaddrs */
+
+       int             sb_options;     /* to support copying ber elements */
+#define LBER_TO_FILE           0x01    /* to a file referenced by sb_fd   */
+#define LBER_TO_FILE_ONLY      0x02    /* only write to file, not network */
+#define LBER_MAX_INCOMING_SIZE 0x04    /* impose limit on incoming stuff  */
+#define LBER_NO_READ_AHEAD     0x08    /* read only as much as requested  */
+       int             sb_fd;
+       long            sb_max_incoming;
+} Sockbuf;
+#define READBUFSIZ     8192
+
+typedef struct seqorset {
+       BerElement      *sos_ber;
+       unsigned long   sos_clen;
+       unsigned long   sos_tag;
+       char            *sos_first;
+       char            *sos_ptr;
+       struct seqorset *sos_next;
+} Seqorset;
+#define NULLSEQORSET   ((Seqorset *) 0)
+
+/* structure for returning a sequence of octet strings + length */
+struct berval {
+       unsigned long   bv_len;
+       char            *bv_val;
+};
+
+#ifndef NEEDPROTOS
+extern BerElement *ber_alloc();
+extern BerElement *der_alloc();
+extern BerElement *ber_alloc_t();
+extern BerElement *ber_dup();
+extern int lber_debug;
+extern void ber_bvfree();
+extern void ber_bvecfree();
+extern struct berval *ber_bvdup();
+extern void ber_dump();
+extern void ber_sos_dump();
+extern void lber_bprint();
+extern void ber_reset();
+extern void ber_init();
+#else /* NEEDPROTOS */
+#if defined(WINSOCK)
+#include "proto-lb.h"
+#else
+#include "proto-lber.h"
+#endif
+#endif /* NEEDPROTOS */
+
+#if !defined(__alpha) || defined(VMS)
+
+#define LBER_HTONL( l )        htonl( l )
+#define LBER_NTOHL( l )        ntohl( l )
+
+#else /* __alpha */
+/*
+ * htonl and ntohl on the DEC Alpha under OSF 1 seem to only swap the
+ * lower-order 32-bits of a (64-bit) long, so we define correct versions
+ * here.
+ */
+#define LBER_HTONL( l )        (((long)htonl( (l) & 0x00000000FFFFFFFF )) << 32 \
+                       | htonl( ( (l) & 0xFFFFFFFF00000000 ) >> 32 ))
+
+#define LBER_NTOHL( l )        (((long)ntohl( (l) & 0x00000000FFFFFFFF )) << 32 \
+                       | ntohl( ( (l) & 0xFFFFFFFF00000000 ) >> 32 ))
+#endif /* __alpha */
+
+
+/*
+ * SAFEMEMCPY is an overlap-safe copy from s to d of n bytes
+ */
+#ifdef MACOS
+#define SAFEMEMCPY( d, s, n )  BlockMoveData( (Ptr)s, (Ptr)d, n )
+#else /* MACOS */
+#ifdef sunos4
+#define SAFEMEMCPY( d, s, n )  bcopy( s, d, n )
+#else /* sunos4 */
+#define SAFEMEMCPY( d, s, n )  memmove( d, s, n )
+#endif /* sunos4 */
+#endif /* MACOS */
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _LBER_H */
diff --git a/include/ldap.h b/include/ldap.h
new file mode 100644 (file)
index 0000000..1eab5bd
--- /dev/null
@@ -0,0 +1,592 @@
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#ifndef _LDAP_H
+#define _LDAP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifdef WINSOCK
+#include "msdos.h"
+#include <winsock.h>
+#endif
+
+#if !defined( NEEDPROTOS ) && defined(__STDC__)
+#define NEEDPROTOS     1
+#endif
+
+#define LDAP_PORT      389
+#define LDAP_VERSION1  1
+#define LDAP_VERSION2  2
+#define LDAP_VERSION   LDAP_VERSION2
+
+#define COMPAT20
+#define COMPAT30
+#if defined(COMPAT20) || defined(COMPAT30)
+#define COMPAT
+#endif
+
+#define LDAP_MAX_ATTR_LEN      100
+
+/* debugging stuff */
+#ifdef LDAP_DEBUG
+extern int     ldap_debug;
+#ifdef LDAP_SYSLOG
+extern int     ldap_syslog;
+extern int     ldap_syslog_level;
+#endif
+#define LDAP_DEBUG_TRACE       0x001
+#define LDAP_DEBUG_PACKETS     0x002
+#define LDAP_DEBUG_ARGS                0x004
+#define LDAP_DEBUG_CONNS       0x008
+#define LDAP_DEBUG_BER         0x010
+#define LDAP_DEBUG_FILTER      0x020
+#define LDAP_DEBUG_CONFIG      0x040
+#define LDAP_DEBUG_ACL         0x080
+#define LDAP_DEBUG_STATS       0x100
+#define LDAP_DEBUG_STATS2      0x200
+#define LDAP_DEBUG_SHELL       0x400
+#define LDAP_DEBUG_PARSE       0x800
+#define LDAP_DEBUG_ANY         0xffff
+
+#ifdef LDAP_SYSLOG
+#define Debug( level, fmt, arg1, arg2, arg3 )  \
+       { \
+               if ( ldap_debug & level ) \
+                       fprintf( stderr, fmt, arg1, arg2, arg3 ); \
+               if ( ldap_syslog & level ) \
+                       syslog( ldap_syslog_level, fmt, arg1, arg2, arg3 ); \
+       }
+#else /* LDAP_SYSLOG */
+#ifndef WINSOCK
+#define Debug( level, fmt, arg1, arg2, arg3 ) \
+               if ( ldap_debug & level ) \
+                       fprintf( stderr, fmt, arg1, arg2, arg3 );
+#else /* !WINSOCK */
+extern void Debug( int level, char* fmt, ... );
+#endif /* !WINSOCK */
+#endif /* LDAP_SYSLOG */
+#else /* LDAP_DEBUG */
+#define Debug( level, fmt, arg1, arg2, arg3 )
+#endif /* LDAP_DEBUG */
+
+/* 
+ * specific LDAP instantiations of BER types we know about
+ */
+
+/* general stuff */
+#define LDAP_TAG_MESSAGE       0x30L   /* tag is 16 + constructed bit */
+#define OLD_LDAP_TAG_MESSAGE   0x10L   /* forgot the constructed bit  */
+#define LDAP_TAG_MSGID         0x02L
+
+/* possible operations a client can invoke */
+#define LDAP_REQ_BIND                  0x60L   /* application + constructed */
+#define LDAP_REQ_UNBIND                        0x42L   /* application + primitive   */
+#define LDAP_REQ_SEARCH                        0x63L   /* application + constructed */
+#define LDAP_REQ_MODIFY                        0x66L   /* application + constructed */
+#define LDAP_REQ_ADD                   0x68L   /* application + constructed */
+#define LDAP_REQ_DELETE                        0x4aL   /* application + primitive   */
+#define LDAP_REQ_MODRDN                        0x6cL   /* application + constructed */
+#define LDAP_REQ_COMPARE               0x6eL   /* application + constructed */
+#define LDAP_REQ_ABANDON               0x50L   /* application + primitive   */
+
+/* version 3.0 compatibility stuff */
+#define LDAP_REQ_UNBIND_30             0x62L
+#define LDAP_REQ_DELETE_30             0x6aL
+#define LDAP_REQ_ABANDON_30            0x70L
+
+/* 
+ * old broken stuff for backwards compatibility - forgot application tag
+ * and constructed/primitive bit
+ */
+#define OLD_LDAP_REQ_BIND              0x00L
+#define OLD_LDAP_REQ_UNBIND            0x02L
+#define OLD_LDAP_REQ_SEARCH            0x03L
+#define OLD_LDAP_REQ_MODIFY            0x06L
+#define OLD_LDAP_REQ_ADD               0x08L
+#define OLD_LDAP_REQ_DELETE            0x0aL
+#define OLD_LDAP_REQ_MODRDN            0x0cL
+#define OLD_LDAP_REQ_COMPARE           0x0eL
+#define OLD_LDAP_REQ_ABANDON           0x10L
+
+/* possible result types a server can return */
+#define LDAP_RES_BIND                  0x61L   /* application + constructed */
+#define LDAP_RES_SEARCH_ENTRY          0x64L   /* application + constructed */
+#define LDAP_RES_SEARCH_RESULT         0x65L   /* application + constructed */
+#define LDAP_RES_MODIFY                        0x67L   /* application + constructed */
+#define LDAP_RES_ADD                   0x69L   /* application + constructed */
+#define LDAP_RES_DELETE                        0x6bL   /* application + constructed */
+#define LDAP_RES_MODRDN                        0x6dL   /* application + constructed */
+#define LDAP_RES_COMPARE               0x6fL   /* application + constructed */
+#define LDAP_RES_ANY                   (-1L)
+
+/* old broken stuff for backwards compatibility */
+#define OLD_LDAP_RES_BIND              0x01L
+#define OLD_LDAP_RES_SEARCH_ENTRY      0x04L
+#define OLD_LDAP_RES_SEARCH_RESULT     0x05L
+#define OLD_LDAP_RES_MODIFY            0x07L
+#define OLD_LDAP_RES_ADD               0x09L
+#define OLD_LDAP_RES_DELETE            0x0bL
+#define OLD_LDAP_RES_MODRDN            0x0dL
+#define OLD_LDAP_RES_COMPARE           0x0fL
+
+/* authentication methods available */
+#define LDAP_AUTH_NONE         0x00L   /* no authentication              */
+#define LDAP_AUTH_SIMPLE       0x80L   /* context specific + primitive   */
+#define LDAP_AUTH_KRBV4                0xffL   /* means do both of the following */
+#define LDAP_AUTH_KRBV41       0x81L   /* context specific + primitive   */
+#define LDAP_AUTH_KRBV42       0x82L   /* context specific + primitive   */
+
+/* 3.0 compatibility auth methods */
+#define LDAP_AUTH_SIMPLE_30    0xa0L   /* context specific + constructed */
+#define LDAP_AUTH_KRBV41_30    0xa1L   /* context specific + constructed */
+#define LDAP_AUTH_KRBV42_30    0xa2L   /* context specific + constructed */
+
+/* old broken stuff */
+#define OLD_LDAP_AUTH_SIMPLE   0x00L
+#define OLD_LDAP_AUTH_KRBV4    0x01L
+#define OLD_LDAP_AUTH_KRBV42   0x02L
+
+/* filter types */
+#define LDAP_FILTER_AND                0xa0L   /* context specific + constructed */
+#define LDAP_FILTER_OR         0xa1L   /* context specific + constructed */
+#define LDAP_FILTER_NOT                0xa2L   /* context specific + constructed */
+#define LDAP_FILTER_EQUALITY   0xa3L   /* context specific + constructed */
+#define LDAP_FILTER_SUBSTRINGS 0xa4L   /* context specific + constructed */
+#define LDAP_FILTER_GE         0xa5L   /* context specific + constructed */
+#define LDAP_FILTER_LE         0xa6L   /* context specific + constructed */
+#define LDAP_FILTER_PRESENT    0x87L   /* context specific + primitive   */
+#define LDAP_FILTER_APPROX     0xa8L   /* context specific + constructed */
+
+/* 3.0 compatibility filter types */
+#define LDAP_FILTER_PRESENT_30 0xa7L   /* context specific + constructed */
+
+/* old broken stuff */
+#define OLD_LDAP_FILTER_AND            0x00L
+#define OLD_LDAP_FILTER_OR             0x01L
+#define OLD_LDAP_FILTER_NOT            0x02L
+#define OLD_LDAP_FILTER_EQUALITY       0x03L
+#define OLD_LDAP_FILTER_SUBSTRINGS     0x04L
+#define OLD_LDAP_FILTER_GE             0x05L
+#define OLD_LDAP_FILTER_LE             0x06L
+#define OLD_LDAP_FILTER_PRESENT                0x07L
+#define OLD_LDAP_FILTER_APPROX         0x08L
+
+/* substring filter component types */
+#define LDAP_SUBSTRING_INITIAL 0x80L   /* context specific */
+#define LDAP_SUBSTRING_ANY     0x81L   /* context specific */
+#define LDAP_SUBSTRING_FINAL   0x82L   /* context specific */
+
+/* 3.0 compatibility substring filter component types */
+#define LDAP_SUBSTRING_INITIAL_30      0xa0L   /* context specific */
+#define LDAP_SUBSTRING_ANY_30          0xa1L   /* context specific */
+#define LDAP_SUBSTRING_FINAL_30                0xa2L   /* context specific */
+
+/* old broken stuff */
+#define OLD_LDAP_SUBSTRING_INITIAL     0x00L
+#define OLD_LDAP_SUBSTRING_ANY         0x01L
+#define OLD_LDAP_SUBSTRING_FINAL       0x02L
+
+/* search scopes */
+#define LDAP_SCOPE_BASE                0x00
+#define LDAP_SCOPE_ONELEVEL    0x01
+#define LDAP_SCOPE_SUBTREE     0x02
+
+/* for modifications */
+typedef struct ldapmod {
+       int             mod_op;
+#define LDAP_MOD_ADD           0x00
+#define LDAP_MOD_DELETE                0x01
+#define LDAP_MOD_REPLACE       0x02
+#define LDAP_MOD_BVALUES       0x80
+       char            *mod_type;
+       union {
+               char            **modv_strvals;
+               struct berval   **modv_bvals;
+       } mod_vals;
+#define mod_values     mod_vals.modv_strvals
+#define mod_bvalues    mod_vals.modv_bvals
+       struct ldapmod  *mod_next;
+} LDAPMod;
+
+/* 
+ * possible error codes we can return
+ */
+
+#define LDAP_SUCCESS                   0x00
+#define LDAP_OPERATIONS_ERROR          0x01
+#define LDAP_PROTOCOL_ERROR            0x02
+#define LDAP_TIMELIMIT_EXCEEDED                0x03
+#define LDAP_SIZELIMIT_EXCEEDED                0x04
+#define LDAP_COMPARE_FALSE             0x05
+#define LDAP_COMPARE_TRUE              0x06
+#define LDAP_STRONG_AUTH_NOT_SUPPORTED 0x07
+#define LDAP_STRONG_AUTH_REQUIRED      0x08
+#define LDAP_PARTIAL_RESULTS           0x09
+
+#define LDAP_NO_SUCH_ATTRIBUTE         0x10
+#define LDAP_UNDEFINED_TYPE            0x11
+#define LDAP_INAPPROPRIATE_MATCHING    0x12
+#define LDAP_CONSTRAINT_VIOLATION      0x13
+#define LDAP_TYPE_OR_VALUE_EXISTS      0x14
+#define LDAP_INVALID_SYNTAX            0x15
+
+#define LDAP_NO_SUCH_OBJECT            0x20
+#define LDAP_ALIAS_PROBLEM             0x21
+#define LDAP_INVALID_DN_SYNTAX         0x22
+#define LDAP_IS_LEAF                   0x23
+#define LDAP_ALIAS_DEREF_PROBLEM       0x24
+
+#define NAME_ERROR(n)  ((n & 0xf0) == 0x20)
+
+#define LDAP_INAPPROPRIATE_AUTH                0x30
+#define LDAP_INVALID_CREDENTIALS       0x31
+#define LDAP_INSUFFICIENT_ACCESS       0x32
+#define LDAP_BUSY                      0x33
+#define LDAP_UNAVAILABLE               0x34
+#define LDAP_UNWILLING_TO_PERFORM      0x35
+#define LDAP_LOOP_DETECT               0x36
+
+#define LDAP_NAMING_VIOLATION          0x40
+#define LDAP_OBJECT_CLASS_VIOLATION    0x41
+#define LDAP_NOT_ALLOWED_ON_NONLEAF    0x42
+#define LDAP_NOT_ALLOWED_ON_RDN                0x43
+#define LDAP_ALREADY_EXISTS            0x44
+#define LDAP_NO_OBJECT_CLASS_MODS      0x45
+#define LDAP_RESULTS_TOO_LARGE         0x46
+
+#define LDAP_OTHER                     0x50
+#define LDAP_SERVER_DOWN               0x51
+#define LDAP_LOCAL_ERROR               0x52
+#define LDAP_ENCODING_ERROR            0x53
+#define LDAP_DECODING_ERROR            0x54
+#define LDAP_TIMEOUT                   0x55
+#define LDAP_AUTH_UNKNOWN              0x56
+#define LDAP_FILTER_ERROR              0x57
+#define LDAP_USER_CANCELLED            0x58
+#define LDAP_PARAM_ERROR               0x59
+#define LDAP_NO_MEMORY                 0x5a
+
+
+/* default limit on nesting of referrals */
+#define LDAP_DEFAULT_REFHOPLIMIT       5
+
+/*
+ * This structure represents both ldap messages and ldap responses.
+ * These are really the same, except in the case of search responses,
+ * where a response has multiple messages.
+ */
+
+typedef struct ldapmsg {
+       int             lm_msgid;       /* the message id */
+       int             lm_msgtype;     /* the message type */
+       BerElement      *lm_ber;        /* the ber encoded message contents */
+       struct ldapmsg  *lm_chain;      /* for search - next msg in the resp */
+       struct ldapmsg  *lm_next;       /* next response */
+       unsigned long   lm_time;        /* used to maintain cache */
+} LDAPMessage;
+#define NULLMSG        ((LDAPMessage *) NULL)
+
+
+#ifdef LDAP_REFERRALS
+/*
+ * structure for tracking LDAP server host, ports, DNs, etc.
+ */
+typedef struct ldap_server {
+       char                    *lsrv_host;
+       char                    *lsrv_dn;       /* if NULL, use default */
+       int                     lsrv_port;
+       struct ldap_server      *lsrv_next;
+} LDAPServer;
+
+
+/*
+ * structure for representing an LDAP server connection
+ */
+typedef struct ldap_conn {
+       Sockbuf                 *lconn_sb;
+       int                     lconn_refcnt;
+       unsigned long           lconn_lastused; /* time */
+       int                     lconn_status;
+#define LDAP_CONNST_NEEDSOCKET         1
+#define LDAP_CONNST_CONNECTING         2
+#define LDAP_CONNST_CONNECTED          3
+       LDAPServer              *lconn_server;
+       char                    *lconn_krbinstance;
+       struct ldap_conn        *lconn_next;
+} LDAPConn;
+
+
+/*
+ * structure used to track outstanding requests
+ */
+typedef struct ldapreq {
+       int             lr_msgid;       /* the message id */
+       int             lr_status;      /* status of request */
+#define LDAP_REQST_INPROGRESS  1
+#define LDAP_REQST_CHASINGREFS 2
+#define LDAP_REQST_NOTCONNECTED        3
+#define LDAP_REQST_WRITING     4
+       int             lr_outrefcnt;   /* count of outstanding referrals */
+       int             lr_origid;      /* original request's message id */
+       int             lr_parentcnt;   /* count of parent requests */
+       int             lr_res_msgtype; /* result message type */
+       int             lr_res_errno;   /* result LDAP errno */
+       char            *lr_res_error;  /* result error string */
+       char            *lr_res_matched;/* result matched DN string */
+       BerElement      *lr_ber;        /* ber encoded request contents */
+       LDAPConn        *lr_conn;       /* connection used to send request */
+       struct ldapreq  *lr_parent;     /* request that spawned this referral */
+       struct ldapreq  *lr_refnext;    /* next referral spawned */
+       struct ldapreq  *lr_prev;       /* previous request */
+       struct ldapreq  *lr_next;       /* next request */
+} LDAPRequest;
+#endif /* LDAP_REFERRALS */
+
+
+/*
+ * structure for client cache
+ */
+#define LDAP_CACHE_BUCKETS     31      /* cache hash table size */
+typedef struct ldapcache {
+       LDAPMessage     *lc_buckets[LDAP_CACHE_BUCKETS];/* hash table */
+       LDAPMessage     *lc_requests;                   /* unfulfilled reqs */
+       long            lc_timeout;                     /* request timeout */
+       long            lc_maxmem;                      /* memory to use */
+       long            lc_memused;                     /* memory in use */
+       int             lc_enabled;                     /* enabled? */
+       unsigned long   lc_options;                     /* options */
+#define LDAP_CACHE_OPT_CACHENOERRS     0x00000001
+#define LDAP_CACHE_OPT_CACHEALLERRS    0x00000002
+}  LDAPCache;
+#define NULLLDCACHE ((LDAPCache *)NULL)
+
+/*
+ * structures for ldap getfilter routines
+ */
+
+typedef struct ldap_filt_info {
+       char                    *lfi_filter;
+       char                    *lfi_desc;
+       int                     lfi_scope;      /* LDAP_SCOPE_BASE, etc */
+       int                     lfi_isexact;    /* exact match filter? */
+       struct ldap_filt_info   *lfi_next;
+} LDAPFiltInfo;
+
+typedef struct ldap_filt_list {
+    char                       *lfl_tag;
+    char                       *lfl_pattern;
+    char                       *lfl_delims;
+    LDAPFiltInfo               *lfl_ilist;
+    struct ldap_filt_list      *lfl_next;
+} LDAPFiltList;
+
+
+#define LDAP_FILT_MAXSIZ       1024
+
+typedef struct ldap_filt_desc {
+       LDAPFiltList            *lfd_filtlist;
+       LDAPFiltInfo            *lfd_curfip;
+       LDAPFiltInfo            lfd_retfi;
+       char                    lfd_filter[ LDAP_FILT_MAXSIZ ];
+       char                    *lfd_curval;
+       char                    *lfd_curvalcopy;
+       char                    **lfd_curvalwords;
+       char                    *lfd_filtprefix;
+       char                    *lfd_filtsuffix;
+} LDAPFiltDesc;
+
+
+/*
+ * structure representing an ldap connection
+ */
+
+typedef struct ldap {
+       Sockbuf         ld_sb;          /* socket descriptor & buffer */
+       char            *ld_host;
+       int             ld_version;
+       char            ld_lberoptions;
+       int             ld_deref;
+#define LDAP_DEREF_NEVER       0
+#define LDAP_DEREF_SEARCHING   1
+#define LDAP_DEREF_FINDING     2
+#define LDAP_DEREF_ALWAYS      3
+
+       int             ld_timelimit;
+       int             ld_sizelimit;
+#define LDAP_NO_LIMIT          0
+
+       LDAPFiltDesc    *ld_filtd;      /* from getfilter for ufn searches */
+       char            *ld_ufnprefix;  /* for incomplete ufn's */
+
+       int             ld_errno;
+       char            *ld_error;
+       char            *ld_matched;
+       int             ld_msgid;
+
+       /* do not mess with these */
+#ifdef LDAP_REFERRALS
+       LDAPRequest     *ld_requests;   /* list of outstanding requests */
+#else /* LDAP_REFERRALS */
+       LDAPMessage     *ld_requests;   /* list of outstanding requests */
+#endif /* LDAP_REFERRALS */
+       LDAPMessage     *ld_responses;  /* list of outstanding responses */
+       int             *ld_abandoned;  /* array of abandoned requests */
+       char            ld_attrbuffer[LDAP_MAX_ATTR_LEN];
+       LDAPCache       *ld_cache;      /* non-null if cache is initialized */
+       char            *ld_cldapdn;    /* DN used in connectionless search */
+
+       /* it is OK to change these next four values directly */
+       int             ld_cldaptries;  /* connectionless search retry count */
+       int             ld_cldaptimeout;/* time between retries */
+       int             ld_refhoplimit; /* limit on referral nesting */
+       unsigned long   ld_options;     /* boolean options */
+#ifdef LDAP_DNS
+#define LDAP_OPT_DNS           0x00000001      /* use DN & DNS */
+#endif /* LDAP_DNS */
+#ifdef LDAP_REFERRALS
+#define LDAP_OPT_REFERRALS     0x00000002      /* chase referrals */
+#endif /* LDAP_REFERRALS */
+#define LDAP_OPT_RESTART       0x00000004      /* restart if EINTR occurs */
+
+       /* do not mess with the rest though */
+       char            *ld_defhost;    /* full name of default server */
+       int             ld_defport;     /* port of default server */
+       BERTranslateProc ld_lber_encode_translate_proc;
+       BERTranslateProc ld_lber_decode_translate_proc;
+#ifdef LDAP_REFERRALS
+       LDAPConn        *ld_defconn;    /* default connection */
+       LDAPConn        *ld_conns;      /* list of server connections */
+       void            *ld_selectinfo; /* platform specifics for select */
+       int             (*ld_rebindproc)( struct ldap *ld, char **dnp,
+                               char **passwdp, int *authmethodp, int freeit );
+                               /* routine to get info needed for re-bind */
+#endif /* LDAP_REFERRALS */
+} LDAP;
+
+
+/*
+ * structure for ldap friendly mapping routines
+ */
+
+typedef struct friendly {
+       char    *f_unfriendly;
+       char    *f_friendly;
+} FriendlyMap;
+
+
+/*
+ * handy macro to check whether LDAP struct is set up for CLDAP or not
+ */
+#define LDAP_IS_CLDAP( ld )    ( ld->ld_sb.sb_naddr > 0 )
+
+
+/*
+ * types for ldap URL handling
+ */
+typedef struct ldap_url_desc {
+    char       *lud_host;
+    int                lud_port;
+    char       *lud_dn;
+    char       **lud_attrs;
+    int                lud_scope;
+    char       *lud_filter;
+    char       *lud_string;    /* for internal use only */
+} LDAPURLDesc;
+#define NULLLDAPURLDESC        ((LDAPURLDesc *)NULL)
+
+#define LDAP_URL_ERR_NOTLDAP   1       /* URL doesn't begin with "ldap://" */
+#define LDAP_URL_ERR_NODN      2       /* URL has no DN (required) */
+#define LDAP_URL_ERR_BADSCOPE  3       /* URL scope string is invalid */
+#define LDAP_URL_ERR_MEM       4       /* can't allocate memory space */
+
+
+#ifndef NEEDPROTOS
+extern LDAP *ldap_open();
+extern LDAP *ldap_init();
+#ifdef STR_TRANSLATION
+extern void ldap_set_string_translators();
+#ifdef LDAP_CHARSET_8859
+extern int ldap_t61_to_8859();
+extern int ldap_8859_to_t61();
+#endif /* LDAP_CHARSET_8859 */
+#endif /* STR_TRANSLATION */
+extern LDAPMessage *ldap_first_entry();
+extern LDAPMessage *ldap_next_entry();
+extern char *ldap_get_dn();
+extern char *ldap_dn2ufn();
+extern char **ldap_explode_dn();
+extern char *ldap_first_attribute();
+extern char *ldap_next_attribute();
+extern char **ldap_get_values();
+extern struct berval **ldap_get_values_len();
+extern void ldap_value_free();
+extern void ldap_value_free_len();
+extern int ldap_count_values();
+extern int ldap_count_values_len();
+extern char *ldap_err2string();
+extern void ldap_getfilter_free();
+extern LDAPFiltDesc *ldap_init_getfilter();
+extern LDAPFiltDesc *ldap_init_getfilter_buf();
+extern LDAPFiltInfo *ldap_getfirstfilter();
+extern LDAPFiltInfo *ldap_getnextfilter();
+extern void ldap_setfilteraffixes();
+extern void ldap_build_filter();
+extern void ldap_flush_cache();
+extern void ldap_set_cache_options();
+extern void ldap_uncache_entry();
+extern void ldap_uncache_request();
+extern char *ldap_friendly_name();
+extern void ldap_free_friendlymap();
+extern LDAP *cldap_open();
+extern void cldap_setretryinfo();
+extern void cldap_close();
+extern LDAPFiltDesc *ldap_ufn_setfilter();
+extern int ldap_ufn_timeout();
+extern int ldap_sort_entries();
+extern int ldap_sort_values();
+extern int ldap_sort_strcasecmp();
+void ldap_free_urldesc();
+void ldap_set_rebind_proc();
+void ldap_enable_translation();
+
+
+#if defined(ultrix) || defined(VMS) || defined( nextstep )
+extern char *strdup();
+#endif
+
+#else /* NEEDPROTOS */
+#if !defined(MACOS) && !defined(DOS) && !defined(_WIN32) && !defined(WINSOCK)
+#include <sys/time.h>
+#endif
+#if defined(WINSOCK)
+#include "proto-ld.h"
+#else
+#include "proto-ldap.h"
+#endif
+
+#ifdef VMS
+extern char *strdup( const char *s );
+#endif
+#if defined(ultrix) || defined( nextstep )
+extern char *strdup();
+#endif
+
+#endif /* NEEDPROTOS */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _LDAP_H */
diff --git a/include/ldapconfig.h.edit b/include/ldapconfig.h.edit
new file mode 100644 (file)
index 0000000..723bde2
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+
+/*
+ * config.h for LDAP -- edit this file to customize LDAP client behavior.
+ * NO platform-specific definitions should be placed in this file.
+ * Note that this is NOT used by the LDAP or LBER libraries.
+ */
+
+/*
+ * SHARED DEFINITIONS - things you should change
+ */
+       /* default ldap host */
+#define LDAPHOST       "localhost"
+       /* default place to start searching */
+#define DEFAULT_BASE   "o=Your Organization Name, c=US"
+
+/*********************************************************************
+ *                                                                   *
+ * You probably do not need to edit anything below this point        *
+ *                                                                   *
+ *********************************************************************/
+
+/*
+ * SHARED DEFINITIONS - other things you can change
+ */
+       /* default attribute to use when sorting entries, NULL => sort by DN */
+#define SORT_ATTR      NULL
+       /* default count of DN components to show in entry displays */
+#define DEFAULT_RDNCOUNT       2
+       /* default config file locations */
+#define FILTERFILE     "%ETCDIR%/ldapfilter.conf"
+#define TEMPLATEFILE   "%ETCDIR%/ldaptemplates.conf"
+#define SEARCHFILE     "%ETCDIR%/ldapsearchprefs.conf"
+#define FRIENDLYFILE   "%ETCDIR%/ldapfriendly"
+
+/*
+ * FINGER DEFINITIONS
+ */
+       /* who to bind as */
+#define FINGER_BINDDN          NULL
+       /* where to search */
+#define FINGER_BASE            DEFAULT_BASE
+       /* banner to print */
+#define FINGER_BANNER          "X.500 Finger Service...\r\n"
+       /* who to report errors to */
+#define FINGER_ERRORS          "your local system administrator"
+       /* what to say if no matches are found */
+#define FINGER_NOMATCH         "Search failed to find anything.\r\n"
+       /* what to say if the service may be unavailable */
+#define FINGER_UNAVAILABLE     \
+"The X.500 service may be temporarily unavailable.\r\n\
+Please try again later.\r\n"
+       /* printed if a match has no email address - for disptmp default */
+#define FINGER_NOEMAIL1        "None registered in this service."
+#define FINGER_NOEMAIL2        NULL
+#define FINGER_NOEMAIL { FINGER_NOEMAIL1, FINGER_NOEMAIL2, NULL }
+       /* maximum number of matches returned */
+#define FINGER_SIZELIMIT       50
+       /* max number of hits displayed in full before a list is presented */
+#define FINGER_LISTLIMIT       1
+       /* what to exec for "finger @host" */
+#define FINGER_CMD             "/usr/ucb/finger"
+       /* how to treat aliases when searching */
+#define FINGER_DEREF           LDAP_DEREF_FINDING
+       /* attribute to use when sorting results */
+#define FINGER_SORT_ATTR       SORT_ATTR
+       /* enable ufn support */
+#define FINGER_UFN
+       /* timeout for searches */
+#define FINGER_TIMEOUT         60
+       /* number of DN components to show in entry displays */
+#define FINGER_RDNCOUNT                DEFAULT_RDNCOUNT        
+
+/*
+ * GO500 GOPHER GATEWAY DEFINITIONS
+ */
+       /* who to bind as */
+#define GO500_BINDDN   NULL
+       /* where to search */
+#define GO500_BASE     DEFAULT_BASE
+       /* port on which to listen */
+#define GO500_PORT     5555
+       /* how to handle aliases */
+#define GO500_DEREF    LDAP_DEREF_FINDING
+       /* attribute to use when sorting results */
+#define GO500_SORT_ATTR        SORT_ATTR
+       /* timeout for searches */
+#define GO500_TIMEOUT  180
+       /* enable ufn support */
+#define GO500_UFN
+       /*
+        * only set and uncomment this if your hostname() does not return
+        * a fully qualified hostname
+        */
+/* #define GO500_HOSTNAME      "fully.qualified.hostname.here" */
+       /* number of DN components to show in entry displays */
+#define GO500_RDNCOUNT         DEFAULT_RDNCOUNT        
+
+/*
+ * GO500GW GOPHER GATEWAY DEFINITIONS
+ */
+       /* who to bind as */
+#define GO500GW_BINDDN         NULL
+       /* where the helpfile lives */
+#define GO500GW_HELPFILE       "%ETCDIR%/go500gw.help"
+       /* port on which to listen */
+#define GO500GW_PORT           7777
+       /* timeout on all searches */
+#define GO500GW_TIMEOUT                180
+       /* enable ufn support */
+#define GO500GW_UFN
+       /* attribute to use when sorting results */
+#define GO500GW_SORT_ATTR      SORT_ATTR
+       /*
+        * only set and uncomment this if your hostname() does not return
+        * a fully qualified hostname
+        */
+/* #define GO500GW_HOSTNAME    "fully.qualified.hostname.here" */
+       /* number of DN components to show in entry displays */
+#define GO500GW_RDNCOUNT       DEFAULT_RDNCOUNT        
+
+/*
+ * RCPT500 MAIL RESPONDER GATEWAY DEFINITIONS
+ */
+       /* who to bind as */
+#define RCPT500_BINDDN         NULL
+       /* where the helpfile lives */
+#define RCPT500_HELPFILE       "%ETCDIR%/rcpt500.help"
+       /* maximum number of matches returned */
+#define RCPT500_SIZELIMIT      50
+       /* address replies will appear to come from */
+#define RCPT500_FROM           "\"X.500 Query Program\" <X500-Query>"
+       /* command that will accept an RFC822 message text on standard
+          input, and send it.  sendmail -t does this nicely. */
+#define RCPT500_PIPEMAILCMD    "/usr/lib/sendmail -t"
+        /* where to search */
+#define RCPT500_BASE             DEFAULT_BASE
+       /* attribute to use when sorting results */
+#define RCPT500_SORT_ATTR      SORT_ATTR
+       /* max number of hits displayed in full before a list is presented */
+#define RCPT500_LISTLIMIT      1
+       /* enable ufn support */
+#define RCPT500_UFN
+       /* number of DN components to show in entry displays */
+#define RCPT500_RDNCOUNT       DEFAULT_RDNCOUNT        
+
+/*
+ * LDAPSEARCH TOOL
+ */
+       /* who to bind as */
+#define LDAPSEARCH_BINDDN      NULL
+       /* search base */
+#define LDAPSEARCH_BASE                DEFAULT_BASE
+
+/*
+ * LDAPMODIFY TOOL
+ */
+       /* who to bind as */
+#define LDAPMODIFY_BINDDN      NULL
+       /* search base */
+#define LDAPMODIFY_BASE                DEFAULT_BASE
+
+/*
+ * LDAPDELETE TOOL
+ */
+       /* who to bind as */
+#define LDAPDELETE_BINDDN      NULL
+       /* search base */
+#define LDAPDELETE_BASE                DEFAULT_BASE
+
+/*
+ * LDAPMODRDN TOOL
+ */
+       /* who to bind as */
+#define LDAPMODRDN_BINDDN      NULL
+       /* search base */
+#define LDAPMODRDN_BASE                DEFAULT_BASE
+
+/*
+ * MAIL500 MAILER DEFINITIONS
+ */
+       /* who to bind as */
+#define MAIL500_BINDDN         NULL
+       /* max number of ambiguous matches reported */
+#define MAIL500_MAXAMBIGUOUS   10
+       /* max subscribers allowed (size limit when searching for them ) */
+#define MAIL500_MAXGROUPMEMBERS        LDAP_NO_LIMIT
+       /* timeout for all searches */
+#define MAIL500_TIMEOUT                180
+       /* sendmail location - mail500 needs to exec this */
+#define MAIL500_SENDMAIL       "/usr/lib/sendmail"
+
+/*
+ * UD DEFINITIONS
+ */
+       /* ud configuration file */
+#define UD_CONFIG_FILE         "%ETCDIR%/ud.conf"
+       /* default editor */
+#define UD_DEFAULT_EDITOR      "/usr/ucb/vi"
+       /* default bbasename of user config file */
+#define UD_USER_CONFIG_FILE    ".udrc"
+       /* default user to bind as */
+#define UD_BINDDN              NULL
+       /* default password to bind with */
+#define UD_PASSWD              NULL
+       /* default search base */
+#define UD_BASE                        DEFAULT_BASE
+       /* default base where groups are created */
+#define UD_WHERE_GROUPS_ARE_CREATED    ""
+       /* default base below which all groups live */
+#define UD_WHERE_ALL_GROUPS_LIVE       ""
+
+/*
+ * FAX500 DEFINITIONS
+ */
+       /* what to bind as */
+#define FAX_BINDDN     NULL
+       /* how long to wait for searches */
+#define FAX_TIMEOUT            180
+       /* maximum number of ambiguous matches reported */
+#define FAX_MAXAMBIGUOUS       10
+       /* maximum number of members allowed */
+#define FAX_MAXMEMBERS         LDAP_NO_LIMIT
+       /* program to send mail */
+#define FAX_SENDMAIL           "/usr/lib/sendmail"
+
+/*
+ * RP500 DEFINITIONS
+ */
+       /* what to bind as */
+#define RP_BINDDN      NULL
+       /* prefix to add to non-fully-qualified numbers */
+#define RP_PHONEPREFIX ""
+
+/*
+ * SLAPD DEFINITIONS
+ */
+       /* location of the default slapd config file */
+#define SLAPD_DEFAULT_CONFIGFILE       "%ETCDIR%/slapd.conf"
+       /* default sizelimit on number of entries from a search */
+#define SLAPD_DEFAULT_SIZELIMIT                500
+       /* default timelimit to spend on a search */
+#define SLAPD_DEFAULT_TIMELIMIT                3600
+       /* location of the slapd pid file */
+#define SLAPD_PIDFILE                  "%ETCDIR%/slapd.pid"
+       /* location of the slapd args file */
+#define SLAPD_ARGSFILE                 "%ETCDIR%/slapd.args"
+       /* dn of the special "monitor" entry */
+#define SLAPD_MONITOR_DN               "cn=monitor"
+       /* dn of the special "config" entry */
+#define SLAPD_CONFIG_DN                        "cn=config"
+       /* minimum max ids that a single index entry can map to in ldbm */
+#define SLAPD_LDBM_MIN_MAXIDS          4000
+
+#endif /* _CONFIG_H */
diff --git a/include/ldapconfig.h.um b/include/ldapconfig.h.um
new file mode 100644 (file)
index 0000000..ecaf918
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+
+/*
+ * config.h for LDAP -- edit this file to customize LDAP client behavior.
+ * NO platform-specific definitions should be placed in this file.
+ * Note that this is NOT used by the LDAP or LBER libraries.
+ */
+
+/*
+ * SHARED DEFINITIONS - things you should change
+ */
+       /* default ldap host */
+#define LDAPHOST       "ldap.itd.umich.edu"
+       /* default place to start searching */
+#define DEFAULT_BASE   "o=University of Michigan, c=US"
+
+/*********************************************************************
+ *                                                                   *
+ * You probably do not need to edit anything below this point        *
+ *                                                                   *
+ *********************************************************************/
+
+/*
+ * SHARED DEFINITIONS - other things you can change
+ */
+       /* default attribute to use when sorting entries, NULL => sort by DN */
+#define SORT_ATTR      NULL
+       /* default count of DN components to show in entry displays */
+#define DEFAULT_RDNCOUNT       2
+       /* default config file locations */
+#define FILTERFILE     "%ETCDIR%/ldapfilter.conf"
+#define TEMPLATEFILE   "%ETCDIR%/ldaptemplates.conf"
+#define SEARCHFILE     "%ETCDIR%/ldapsearchprefs.conf"
+#define FRIENDLYFILE   "%ETCDIR%/ldapfriendly"
+
+/*
+ * FINGER DEFINITIONS
+ */
+       /* who to bind as */
+#define FINGER_BINDDN          "cn=finger, ou=Miscellaneous Servers, o=University of Michigan, c=US"
+       /* where to search */
+#define FINGER_BASE            DEFAULT_BASE
+       /* banner to print */
+#define FINGER_BANNER          "X.500 Finger Service...\r\n"
+       /* who to report errors to */
+#define FINGER_ERRORS          "x500@umich.edu"
+       /* what to say if no matches are found */
+#define FINGER_NOMATCH         \
+"Search failed to find anything.  Currently, this service contains\r\n\
+information only on University of Michigan faculty, staff, and students.\r\n\
+Other likely places to finger are:\r\n\
+        um.cc.umich.edu\r\n\
+        azure.engin.umich.edu\r\n"
+       /* what to say if the service may be unavailable */
+#define FINGER_UNAVAILABLE     \
+"The X.500 service may be temporarily unavailable.\r\n\
+Please try again later.\r\n"
+       /* printed if a match has no email address - for disptmp default */
+#define FINGER_NOEMAIL1        "None registered in this service.  Try fingering at:"
+#define FINGER_NOEMAIL2        "um.cc.umich.edu or azure.engin.umich.edu"
+#define FINGER_NOEMAIL { FINGER_NOEMAIL1, FINGER_NOEMAIL2, NULL }
+       /* maximum number of matches returned */
+#define FINGER_SIZELIMIT       50
+       /* max number of hits displayed in full before a list is presented */
+#define FINGER_LISTLIMIT       1
+       /* what to exec for "finger @host" */
+#define FINGER_CMD             "/usr/ucb/finger"
+       /* how to treat aliases when searching */
+#define FINGER_DEREF           LDAP_DEREF_FINDING
+       /* attribute to use when sorting results */
+#define FINGER_SORT_ATTR       SORT_ATTR
+       /* enable ufn support */
+#define FINGER_UFN
+       /* timeout for searches */
+#define FINGER_TIMEOUT         60
+       /* number of DN components to show in entry displays */
+#define FINGER_RDNCOUNT                DEFAULT_RDNCOUNT        
+
+/*
+ * GO500 GOPHER GATEWAY DEFINITIONS
+ */
+       /* who to bind as */
+#define GO500_BINDDN   "cn=go500, ou=Miscellaneous Servers, o=University of Michigan, c=US"
+       /* where to search */
+#define GO500_BASE     DEFAULT_BASE
+       /* port on which to listen */
+#define GO500_PORT     5555
+       /* how to handle aliases */
+#define GO500_DEREF    LDAP_DEREF_FINDING
+       /* attribute to use when sorting results */
+#define GO500_SORT_ATTR        SORT_ATTR
+       /* timeout for searches */
+#define GO500_TIMEOUT  60
+       /* enable ufn support */
+#define GO500_UFN
+       /*
+        * only set and uncomment this if your hostname() does not return
+        * a fully qualified hostname
+        */
+/* #define GO500_HOSTNAME      "fully.qualified.hostname.here" */
+       /* number of DN components to show in entry displays */
+#define GO500_RDNCOUNT         DEFAULT_RDNCOUNT        
+
+/*
+ * GO500GW GOPHER GATEWAY DEFINITIONS
+ */
+       /* who to bind as */
+#define GO500GW_BINDDN         "cn=go500gw, ou=Miscellaneous Servers, o=University of Michigan, c=US"
+       /* where the helpfile lives */
+#define GO500GW_HELPFILE       "%ETCDIR%/go500gw.help"
+       /* port on which to listen */
+#define GO500GW_PORT           7777
+       /* timeout on all searches */
+#define GO500GW_TIMEOUT                180
+       /* enable ufn support */
+#define GO500GW_UFN
+       /* attribute to use when sorting results */
+#define GO500GW_SORT_ATTR      SORT_ATTR
+       /*
+        * only set and uncomment this if your hostname() does not return
+        * a fully qualified hostname
+        */
+/* #define GO500GW_HOSTNAME    "fully.qualified.hostname.here" */
+       /* number of DN components to show in entry displays */
+#define GO500GW_RDNCOUNT       DEFAULT_RDNCOUNT        
+
+/*
+ * RCPT500 MAIL RESPONDER GATEWAY DEFINITIONS
+ */
+       /* who to bind as */
+#define RCPT500_BINDDN         "cn=Rcpt500, ou=Miscellaneous Servers, o=University of Michigan, c=US"
+       /* where the helpfile lives */
+#define RCPT500_HELPFILE       "%ETCDIR%/rcpt500.help"
+       /* maximum number of matches returned */
+#define RCPT500_SIZELIMIT      50
+       /* address replies will appear to come from */
+#define RCPT500_FROM           "\"X.500 Query Program\" <X500-Query>"
+       /* command that will accept an RFC822 message text on standard
+          input, and send it.  sendmail -t does this nicely. */
+#define RCPT500_PIPEMAILCMD    "/usr/lib/sendmail -t"
+        /* where to search */
+#define RCPT500_BASE             DEFAULT_BASE
+       /* attribute to use when sorting results */
+#define RCPT500_SORT_ATTR      SORT_ATTR
+       /* max number of hits displayed in full before a list is presented */
+#define RCPT500_LISTLIMIT      3
+       /* enable ufn support */
+#define RCPT500_UFN
+       /* number of DN components to show in entry displays */
+#define RCPT500_RDNCOUNT       DEFAULT_RDNCOUNT        
+
+/*
+ * LDAPSEARCH TOOL
+ */
+       /* who to bind as */
+#define LDAPSEARCH_BINDDN      "cn=LDAP Search Tool, ou=Miscellaneous Servers, o=University of Michigan, c=US"
+       /* search base */
+#define LDAPSEARCH_BASE                DEFAULT_BASE
+
+/*
+ * LDAPMODIFY TOOL
+ */
+       /* who to bind as */
+#define LDAPMODIFY_BINDDN      "cn=Manager, o=University of Michigan, c=US"
+       /* search base */
+#define LDAPMODIFY_BASE                DEFAULT_BASE
+
+/*
+ * LDAPDELETE TOOL
+ */
+       /* who to bind as */
+#define LDAPDELETE_BINDDN      "cn=Manager, o=University of Michigan, c=US"
+       /* search base */
+#define LDAPDELETE_BASE                DEFAULT_BASE
+
+/*
+ * LDAPMODRDN TOOL
+ */
+       /* who to bind as */
+#define LDAPMODRDN_BINDDN      "cn=Manager, o=University of Michigan, c=US"
+       /* search base */
+#define LDAPMODRDN_BASE                DEFAULT_BASE
+
+/*
+ * MAIL500 MAILER DEFINITIONS
+ */
+       /* who to bind as */
+#define MAIL500_BINDDN         "cn=mail500, ou=Miscellaneous Servers, o=University of Michigan, c=US"
+       /* max number of ambiguous matches reported */
+#define MAIL500_MAXAMBIGUOUS   10
+       /* max subscribers allowed (size limit when searching for them ) */
+#define MAIL500_MAXGROUPMEMBERS        LDAP_NO_LIMIT
+       /* timeout for all searches */
+#define MAIL500_TIMEOUT                180
+       /* sendmail location - mail500 needs to exec this */
+#define MAIL500_SENDMAIL       "/usr/lib/sendmail"
+
+/*
+ * UD DEFINITIONS
+ */
+       /* ud configuration file */
+#define UD_CONFIG_FILE         "%ETCDIR%/ud.conf"
+       /* default editor */
+#define UD_DEFAULT_EDITOR      "/usr/ucb/vi"
+       /* default bbasename of user config file */
+#define UD_USER_CONFIG_FILE    ".udrc"
+       /* default user to bind as */
+#define UD_BINDDN              "cn=ud, ou=Miscellaneous Servers, o=University of Michigan, c=US"
+       /* default password to bind with */
+#define UD_PASSWD              NULL
+       /* default search base */
+#define UD_BASE                        DEFAULT_BASE
+       /* default base where groups are created */
+#define UD_WHERE_GROUPS_ARE_CREATED    "ou=User Groups, ou=Groups, o=University of Michigan, c=US"
+       /* default base below which all groups live */
+#define UD_WHERE_ALL_GROUPS_LIVE       "ou=Groups, o=University of Michigan, c=US"
+
+/*
+ * FAX500 DEFINITIONS
+ */
+       /* what to bind as */
+#define FAX_BINDDN     "cn=mail500, ou=Miscellaneous Servers, o=University of Michigan, c=US"
+       /* how long to wait for searches */
+#define FAX_TIMEOUT            180
+       /* maximum number of ambiguous matches reported */
+#define FAX_MAXAMBIGUOUS       10
+       /* maximum number of members allowed */
+#define FAX_MAXMEMBERS         LDAP_NO_LIMIT
+       /* program to send mail */
+#define FAX_SENDMAIL           "/usr/lib/sendmail"
+
+/*
+ * RP500 DEFINITIONS
+ */
+       /* what to bind as */
+#define RP_BINDDN      "cn=rp500, ou=Miscellaneous Servers, o=University of Michigan, c=US"
+       /* prefix to add to non-fully-qualified numbers */
+#define RP_PHONEPREFIX "1313"
+
+/*
+ * SLAPD DEFINITIONS
+ */
+       /* location of the default slapd config file */
+#define SLAPD_DEFAULT_CONFIGFILE       "%ETCDIR%/slapd.conf"
+       /* default sizelimit on number of entries from a search */
+#define SLAPD_DEFAULT_SIZELIMIT                500
+       /* default timelimit to spend on a search */
+#define SLAPD_DEFAULT_TIMELIMIT                3600
+       /* location of the slapd pid file */
+#define SLAPD_PIDFILE                  "%ETCDIR%/slapd.pid"
+       /* location of the slapd args file */
+#define SLAPD_ARGSFILE                 "%ETCDIR%/slapd.args"
+       /* dn of the special "monitor" entry */
+#define SLAPD_MONITOR_DN               "cn=monitor"
+       /* dn of the special "config" entry */
+#define SLAPD_CONFIG_DN                        "cn=config"
+       /* minimum max ids that a single index entry can map to in ldbm */
+#define SLAPD_LDBM_MIN_MAXIDS          4000
+
+#endif /* _CONFIG_H */
diff --git a/include/ldbm.h b/include/ldbm.h
new file mode 100644 (file)
index 0000000..95bd55f
--- /dev/null
@@ -0,0 +1,165 @@
+/* ldbm.h - ldap dbm compatibility routine header file */
+
+#ifndef _LDBM_H_
+#define _LDBM_H_
+
+#ifdef LDBM_USE_GDBM
+
+/*****************************************************************
+ *                                                               *
+ * use gdbm if possible                                          *
+ *                                                               *
+ *****************************************************************/
+
+#include <gdbm.h>
+
+typedef datum          Datum;
+
+typedef GDBM_FILE      LDBM;
+
+extern gdbm_error      gdbm_errno;
+
+/* for ldbm_open */
+#define LDBM_READER    GDBM_READER
+#define LDBM_WRITER    GDBM_WRITER
+#define LDBM_WRCREAT   GDBM_WRCREAT
+#define LDBM_NEWDB     GDBM_NEWDB
+#define LDBM_FAST      GDBM_FAST
+
+#define LDBM_SUFFIX    ".gdbm"
+
+/* for ldbm_insert */
+#define LDBM_INSERT    GDBM_INSERT
+#define LDBM_REPLACE   GDBM_REPLACE
+#define LDBM_SYNC      0x80000000
+
+#else /* end of gdbm */
+
+#ifdef LDBM_USE_DBHASH
+
+/*****************************************************************
+ *                                                               *
+ * use berkeley db hash package                                  *
+ *                                                               *
+ *****************************************************************/
+
+#include <sys/types.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <db.h>
+
+typedef DBT    Datum;
+#define dsize  size
+#define dptr   data
+
+typedef DB     *LDBM;
+
+#define DB_TYPE                DB_HASH
+
+/* for ldbm_open */
+#define LDBM_READER    O_RDONLY
+#define LDBM_WRITER    O_RDWR
+#define LDBM_WRCREAT   (O_RDWR|O_CREAT)
+#define LDBM_NEWDB     (O_RDWR|O_TRUNC|O_CREAT)
+#define LDBM_FAST      0
+
+#define LDBM_SUFFIX    ".dbh"
+
+/* for ldbm_insert */
+#define LDBM_INSERT    R_NOOVERWRITE
+#define LDBM_REPLACE   0
+#define LDBM_SYNC      0x80000000
+
+extern int     errno;
+
+#else /* end of db hash */
+
+#ifdef LDBM_USE_DBBTREE
+
+/*****************************************************************
+ *                                                               *
+ * use berkeley db btree package                                 *
+ *                                                               *
+ *****************************************************************/
+
+#include <sys/types.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <db.h>
+
+typedef DBT    Datum;
+#define dsize  size
+#define dptr   data
+
+typedef DB     *LDBM;
+
+#define DB_TYPE                DB_BTREE
+
+/* for ldbm_open */
+#define LDBM_READER    O_RDONLY
+#define LDBM_WRITER    O_RDWR
+#define LDBM_WRCREAT   (O_RDWR|O_CREAT)
+#define LDBM_NEWDB     (O_RDWR|O_TRUNC|O_CREAT)
+#define LDBM_FAST      0
+
+#define LDBM_SUFFIX    ".dbb"
+#define LDBM_ORDERED   1
+
+/* for ldbm_insert */
+#define LDBM_INSERT    R_NOOVERWRITE
+#define LDBM_REPLACE   0
+#define LDBM_SYNC      0x80000000
+
+extern int     errno;
+
+#else /* end of db btree */
+
+#ifdef LDBM_USE_NDBM
+
+/*****************************************************************
+ *                                                               *
+ * if none of the above use ndbm, the standard unix thing        *
+ *                                                               *
+ *****************************************************************/
+
+#include <ndbm.h>
+#ifndef O_RDONLY
+#include <fcntl.h>
+#endif
+
+typedef datum  Datum;
+
+typedef DBM    *LDBM;
+
+/* for ldbm_open */
+#define LDBM_READER    O_RDONLY
+#define LDBM_WRITER    O_WRONLY
+#define LDBM_WRCREAT   (O_RDWR|O_CREAT)
+#define LDBM_NEWDB     (O_RDWR|O_TRUNC|O_CREAT)
+#define LDBM_FAST      0
+
+#define LDBM_SUFFIX    ".ndbm"
+
+/* for ldbm_insert */
+#define LDBM_INSERT    DBM_INSERT
+#define LDBM_REPLACE   DBM_REPLACE
+#define LDBM_SYNC      0
+
+#endif /* ndbm */
+#endif /* db hash */
+#endif /* db btree */
+#endif /* gdbm */
+
+LDBM   ldbm_open( char *name, int rw, int mode, int dbcachesize );
+void   ldbm_close( LDBM ldbm );
+void   ldbm_sync( LDBM ldbm );
+void   ldbm_datum_free( LDBM ldbm, Datum data );
+Datum  ldbm_datum_dup( LDBM ldbm, Datum data );
+Datum  ldbm_fetch( LDBM ldbm, Datum key );
+int    ldbm_store( LDBM ldbm, Datum key, Datum data, int flags );
+int    ldbm_delete( LDBM ldbm, Datum key );
+Datum  ldbm_firstkey( LDBM ldbm );
+Datum  ldbm_nextkey( LDBM ldbm, Datum key );
+int    ldbm_errno( LDBM ldbm );
+
+#endif /* _ldbm_h_ */
diff --git a/include/ldif.h b/include/ldif.h
new file mode 100644 (file)
index 0000000..dd2b339
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1996 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#ifndef _LDIF_H
+#define _LDIF_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LINE_WIDTH      76      /* maximum length of LDIF lines */
+
+/*
+ * Macro to calculate maximum number of bytes that the base64 equivalent
+ * of an item that is "vlen" bytes long will take up.  Base64 encoding
+ * uses one byte for every six bits in the value plus up to two pad bytes.
+ */
+#define LDIF_BASE64_LEN(vlen)  (((vlen) * 4 / 3 ) + 3)
+
+/*
+ * Macro to calculate maximum size that an LDIF-encoded type (length
+ * tlen) and value (length vlen) will take up:  room for type + ":: " +
+ * first newline + base64 value + continued lines.  Each continued line
+ * needs room for a newline and a leading space character.
+ */
+#define LDIF_SIZE_NEEDED(tlen,vlen) \
+    ((tlen) + 4 + LDIF_BASE64_LEN(vlen) \
+    + ((LDIF_BASE64_LEN(vlen) + tlen + 3) / LINE_WIDTH * 2 ))
+
+
+#ifdef NEEDPROTOS
+int str_parse_line( char *line, char **type, char **value, int *vlen);
+char * str_getline( char **next );
+void put_type_and_value( char **out, char *t, char *val, int vlen );
+char *ldif_type_and_value( char *type, char *val, int vlen );
+#else /* NEEDPROTOS */
+int str_parse_line();
+char * str_getline();
+void put_type_and_value();
+char *ldif_type_and_value();
+#endif /* NEEDPROTOS */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LDIF_H */
diff --git a/include/lthread.h b/include/lthread.h
new file mode 100644 (file)
index 0000000..d1b34d8
--- /dev/null
@@ -0,0 +1,174 @@
+/* lthread.h - ldap threads header file */
+
+#ifndef _LTHREAD_H
+#define _LTHREAD_H
+
+#if defined( THREAD_SUNOS4_LWP )
+/***********************************
+ *                                 *
+ * thread definitions for sunos4   *
+ *                                 *
+ ***********************************/
+
+#define _THREAD
+
+#include <lwp/lwp.h>
+#include <lwp/stackdep.h>
+
+typedef void   *(*VFP)();
+
+/* thread attributes and thread type */
+typedef int            pthread_attr_t;
+typedef thread_t       pthread_t;
+
+/* default attr states */
+#define pthread_mutexattr_default      NULL
+#define pthread_condattr_default       NULL
+
+/* thread state - joinable or not */
+#define PTHREAD_CREATE_JOINABLE        0
+#define PTHREAD_CREATE_DETACHED        1
+/* thread scope - who is in scheduling pool */
+#define PTHREAD_SCOPE_PROCESS  0
+#define PTHREAD_SCOPE_SYSTEM   1
+
+/* mutex attributes and mutex type */
+typedef int    pthread_mutexattr_t;
+typedef mon_t  pthread_mutex_t;
+
+/* mutex and condition variable scope - process or system */
+#define PTHREAD_SHARE_PRIVATE  0
+#define PTHREAD_SHARE_PROCESS  1
+
+/* condition variable attributes and condition variable type */
+typedef int    pthread_condattr_t;
+typedef struct lwpcv {
+       int             lcv_created;
+       cv_t            lcv_cv;
+} pthread_cond_t;
+
+#else /* end sunos4 */
+
+#if defined( THREAD_SUNOS5_LWP )
+/***********************************
+ *                                 *
+ * thread definitions for sunos5   *
+ *                                 *
+ ***********************************/
+
+#define _THREAD
+
+#include <thread.h>
+#include <synch.h>
+
+typedef void   *(*VFP)();
+
+/* sunos5 threads are preemptive */
+#define PTHREAD_PREEMPTIVE     1
+
+/* thread attributes and thread type */
+typedef int            pthread_attr_t;
+typedef thread_t       pthread_t;
+
+/* default attr states */
+#define pthread_mutexattr_default      NULL
+#define pthread_condattr_default       NULL
+
+/* thread state - joinable or not */
+#define PTHREAD_CREATE_JOINABLE 0
+#define PTHREAD_CREATE_DETACHED THR_DETACHED
+/* thread scope - who is in scheduling pool */
+#define PTHREAD_SCOPE_PROCESS   0
+#define PTHREAD_SCOPE_SYSTEM    THR_BOUND
+
+/* mutex attributes and mutex type */
+typedef int    pthread_mutexattr_t;
+typedef mutex_t        pthread_mutex_t;
+
+/* mutex and condition variable scope - process or system */
+#define PTHREAD_SHARE_PRIVATE   USYNC_THREAD
+#define PTHREAD_SHARE_PROCESS   USYNC_PROCESS
+
+/* condition variable attributes and condition variable type */
+typedef int     pthread_condattr_t;
+typedef cond_t pthread_cond_t;
+
+#else /* end sunos5 */
+
+#if defined( THREAD_MIT_PTHREADS )
+/***********************************
+ *                                 *
+ * definitions for mit pthreads    *
+ *                                 *
+ ***********************************/
+
+#define _THREAD
+
+#include <pthread.h>
+
+#else /* end mit pthreads */
+
+#if defined( THREAD_DCE_PTHREADS )
+/***********************************
+ *                                 *
+ * definitions for mit pthreads    *
+ *                                 *
+ ***********************************/
+
+#define _THREAD
+
+#include <pthread.h>
+
+/* dce threads are preemptive */
+#define PTHREAD_PREEMPTIVE     1
+
+#define pthread_attr_init( a )         pthread_attr_create( a )
+#define pthread_attr_destroy( a )      pthread_attr_delete( a )
+#define pthread_attr_setdetachstate( a, b ) \
+                                       pthread_attr_setdetach_np( a, b )
+
+#endif /* dce pthreads */
+#endif /* mit pthreads */
+#endif /* sunos5 */
+#endif /* sunos4 */
+
+#ifndef _THREAD
+
+/***********************************
+ *                                 *
+ * thread definitions for no       *
+ * underlying library support      *
+ *                                 *
+ ***********************************/
+
+typedef void   *(*VFP)();
+
+/* thread attributes and thread type */
+typedef int    pthread_attr_t;
+typedef int    pthread_t;
+
+/* default attr states */
+#define pthread_mutexattr_default      NULL
+#define pthread_condattr_default       NULL
+
+/* thread state - joinable or not */
+#define PTHREAD_CREATE_JOINABLE 0
+#define PTHREAD_CREATE_DETACHED 0
+/* thread scope - who is in scheduling pool */
+#define PTHREAD_SCOPE_PROCESS   0
+#define PTHREAD_SCOPE_SYSTEM    0
+
+/* mutex attributes and mutex type */
+typedef int    pthread_mutexattr_t;
+typedef int    pthread_mutex_t;
+
+/* mutex and condition variable scope - process or system */
+#define PTHREAD_SHARE_PRIVATE   0
+#define PTHREAD_SHARE_PROCESS   0
+
+/* condition variable attributes and condition variable type */
+typedef int     pthread_condattr_t;
+typedef int    pthread_cond_t;
+
+#endif /* no threads support */
+#endif /* _LTHREAD_H */
diff --git a/include/portable.h b/include/portable.h
new file mode 100644 (file)
index 0000000..a91b27a
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#ifndef _PORTABLE_H
+#define _PORTABLE_H
+
+/*
+ * portable.h for LDAP -- this is where we define common stuff to make
+ * life easier on various Unix systems.
+ *
+ * Unless you are porting LDAP to a new platform, you should not need to
+ * edit this file.
+ */
+
+
+#ifndef SYSV
+#if defined( hpux ) || defined( sunos5 ) || defined ( sgi ) || defined( SVR4 )
+#define SYSV
+#endif
+#endif
+
+
+/*
+ * under System V, use sysconf() instead of getdtablesize
+ */
+#if !defined( USE_SYSCONF ) && defined( SYSV )
+#define USE_SYSCONF
+#endif
+
+
+/*
+ * under System V, daemons should use setsid() instead of detaching from their
+ * tty themselves
+ */
+#if !defined( USE_SETSID ) && defined( SYSV )
+#define USE_SETSID
+#endif
+
+
+/*
+ * System V has socket options in filio.h
+ */
+#if !defined( NEED_FILIO ) && defined( SYSV ) && !defined( hpux )
+#define NEED_FILIO
+#endif
+
+/*
+ * use lockf() under System V
+ */
+#if !defined( USE_LOCKF ) && ( defined( SYSV ) || defined( aix ))
+#define USE_LOCKF
+#endif
+
+/*
+ * on many systems, we should use waitpid() instead of waitN()
+ */
+#if !defined( USE_WAITPID ) && ( defined( SYSV ) || defined( sunos4 ) || defined( ultrix ) || defined( aix ))
+#define USE_WAITPID
+#endif
+
+
+/*
+ * define the wait status argument type
+ */
+#if ( defined( SunOS ) && SunOS < 40 ) || defined( nextstep )
+#define WAITSTATUSTYPE union wait
+#else
+#define WAITSTATUSTYPE int
+#endif
+
+/*
+ * define the flags for wait
+ */
+#ifdef sunos5
+#define WAIT_FLAGS     ( WNOHANG | WUNTRACED | WCONTINUED )
+#else
+#define WAIT_FLAGS     ( WNOHANG | WUNTRACED )
+#endif
+
+
+/*
+ * defined the options for openlog (syslog)
+ */
+#ifdef ultrix
+#define OPENLOG_OPTIONS                LOG_PID
+#else
+#define OPENLOG_OPTIONS                ( LOG_PID | LOG_NOWAIT )
+#endif
+
+
+/*
+ * some systems don't have the BSD re_comp and re_exec routines
+ */
+#ifndef NEED_BSDREGEX
+#if defined( SYSV ) || defined( VMS ) || defined( netbsd ) || defined( freebsd ) || defined( linux )
+#define NEED_BSDREGEX
+#endif
+#endif
+
+/*
+ * many systems do not have the setpwfile() library routine... we just
+ * enable use for those systems we know have it.
+ */
+#ifndef HAVE_SETPWFILE
+#if defined( sunos4 ) || defined( ultrix ) || defined( __osf__ )
+#define HAVE_SETPWFILE
+#endif
+#endif
+
+/*
+ * Are sys_errlist and sys_nerr declared in stdio.h?
+ */
+#ifndef SYSERRLIST_IN_STDIO
+#if defined( freebsd ) 
+#define SYSERRLIST_IN_STDIO
+#endif
+#endif
+
+/*
+ * for select()
+ */
+#if !defined(FD_SET) && !defined(WINSOCK)
+#define NFDBITS         32
+#define FD_SETSIZE      32
+#define FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
+#define FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
+#define FD_ISSET(n, p)  ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
+#define FD_ZERO(p)      bzero((char *)(p), sizeof(*(p)))
+#endif /* FD_SET */
+
+#if defined( hpux ) && defined( __STDC__ )
+/*
+ * Under HP/UX, select seems to want (int *) instead of fd_set.  Non-ANSI
+ * compilers don't like recursive macros, so ignore the problem if __STDC__
+ * is not defined.
+ */
+#define select(a,b,c,d,e) select(a, (int *)b, (int *)c, (int *)d, e)
+#endif /* hpux && __STDC__ */
+
+
+/*
+ * for signal() -- what do signal handling functions return?
+ */
+#ifndef SIG_FN
+#ifdef sunos5
+#   define SIG_FN void          /* signal-catching functions return void */
+#else /* sunos5 */
+# ifdef BSD
+#  if (BSD >= 199006) || defined(NeXT) || defined(__osf__) || defined(sun) || defined(ultrix) || defined(apollo) || defined(POSIX_SIGNALS)
+#   define SIG_FN void          /* signal-catching functions return void */
+#  else
+#   define SIG_FN int           /* signal-catching functions return int */
+#  endif
+# else /* BSD */
+#  define SIG_FN void           /* signal-catching functions return void */
+# endif /* BSD */
+#endif /* sunos5 */
+#endif /* SIG_FN */
+
+/*
+ * call signal or sigset (signal does not block the signal while
+ * in the handler on sys v and sigset does not exist on bsd)
+ */
+#ifdef SYSV
+#define SIGNAL sigset
+#else
+#define SIGNAL signal
+#endif
+
+/*
+ * toupper and tolower macros are different under bsd and sys v
+ */
+#if defined( SYSV ) && !defined( hpux )
+#define TOUPPER(c)     (isascii(c) && islower(c) ? _toupper(c) : c)
+#define TOLOWER(c)     (isascii(c) && isupper(c) ? _tolower(c) : c)
+#else
+#define TOUPPER(c)     (isascii(c) && islower(c) ? toupper(c) : c)
+#define TOLOWER(c)     (isascii(c) && isupper(c) ? tolower(c) : c)
+#endif
+
+/*
+ * put a cover on the tty-related ioctl calls we need to use
+ */
+#if defined( NeXT ) || (defined(SunOS) && SunOS < 40)
+#define TERMIO_TYPE struct sgttyb
+#define TERMFLAG_TYPE int
+#define GETATTR( fd, tiop )    ioctl((fd), TIOCGETP, (caddr_t)(tiop))
+#define SETATTR( fd, tiop )    ioctl((fd), TIOCSETP, (caddr_t)(tiop))
+#define GETFLAGS( tio )                (tio).sg_flags
+#define SETFLAGS( tio, flags ) (tio).sg_flags = (flags)
+#else
+#define USE_TERMIOS
+#define TERMIO_TYPE struct termios
+#define TERMFLAG_TYPE tcflag_t
+#define GETATTR( fd, tiop )    tcgetattr((fd), (tiop))
+#define SETATTR( fd, tiop )    tcsetattr((fd), TCSANOW /* 0 */, (tiop))
+#define GETFLAGS( tio )                (tio).c_lflag
+#define SETFLAGS( tio, flags ) (tio).c_lflag = (flags)
+#endif
+
+
+#if defined( ultrix ) || defined( nextstep )
+extern char *strdup();
+#endif /* ultrix || nextstep */
+
+#endif /* _PORTABLE_H */
diff --git a/include/proto-lber.h b/include/proto-lber.h
new file mode 100644 (file)
index 0000000..c846872
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * lber-proto.h
+ * function prototypes for lber library
+ */
+
+#ifdef LDAP_DEBUG
+extern int lber_debug;
+#endif
+
+#ifndef LDAPFUNCDECL
+#ifdef _WIN32
+#define LDAPFUNCDECL   __declspec( dllexport )
+#else /* _WIN32 */
+#define LDAPFUNCDECL
+#endif /* _WIN32 */
+#endif /* LDAPFUNCDECL */
+
+/*
+ * in bprint.c:
+ */
+LDAPFUNCDECL void lber_bprint( char *data, int len );
+
+/*
+ * in decode.c:
+ */
+LDAPFUNCDECL unsigned long ber_get_tag( BerElement *ber );
+LDAPFUNCDECL unsigned long ber_skip_tag( BerElement *ber, unsigned long *len );
+LDAPFUNCDECL unsigned long ber_peek_tag( BerElement *ber, unsigned long *len );
+LDAPFUNCDECL unsigned long ber_get_int( BerElement *ber, long *num );
+LDAPFUNCDECL unsigned long ber_get_stringb( BerElement *ber, char *buf,
+       unsigned long *len );
+LDAPFUNCDECL unsigned long ber_get_stringa( BerElement *ber, char **buf );
+LDAPFUNCDECL unsigned long ber_get_stringal( BerElement *ber, struct berval **bv );
+LDAPFUNCDECL unsigned long ber_get_bitstringa( BerElement *ber, char **buf,
+       unsigned long *len );
+LDAPFUNCDECL unsigned long ber_get_null( BerElement *ber );
+LDAPFUNCDECL unsigned long ber_get_boolean( BerElement *ber, int *boolval );
+LDAPFUNCDECL unsigned long ber_first_element( BerElement *ber, unsigned long *len,
+       char **last );
+LDAPFUNCDECL unsigned long ber_next_element( BerElement *ber, unsigned long *len,
+       char *last );
+#if defined( MACOS ) || defined( BC31 ) || defined( _WIN32 )
+LDAPFUNCDECL unsigned long ber_scanf( BerElement *ber, char *fmt, ... );
+#else
+LDAPFUNCDECL unsigned long ber_scanf();
+#endif
+LDAPFUNCDECL void ber_bvfree( struct berval *bv );
+LDAPFUNCDECL void ber_bvecfree( struct berval **bv );
+LDAPFUNCDECL struct berval *ber_bvdup( struct berval *bv );
+#ifdef STR_TRANSLATION
+LDAPFUNCDECL void ber_set_string_translators( BerElement *ber,
+       BERTranslateProc encode_proc, BERTranslateProc decode_proc );
+#endif /* STR_TRANSLATION */
+
+/*
+ * in encode.c
+ */
+LDAPFUNCDECL int ber_put_enum( BerElement *ber, long num, unsigned long tag );
+LDAPFUNCDECL int ber_put_int( BerElement *ber, long num, unsigned long tag );
+LDAPFUNCDECL int ber_put_ostring( BerElement *ber, char *str, unsigned long len,
+       unsigned long tag );
+LDAPFUNCDECL int ber_put_string( BerElement *ber, char *str, unsigned long tag );
+LDAPFUNCDECL int ber_put_bitstring( BerElement *ber, char *str,
+       unsigned long bitlen, unsigned long tag );
+LDAPFUNCDECL int ber_put_null( BerElement *ber, unsigned long tag );
+LDAPFUNCDECL int ber_put_boolean( BerElement *ber, int boolval,
+       unsigned long tag );
+LDAPFUNCDECL int ber_start_seq( BerElement *ber, unsigned long tag );
+LDAPFUNCDECL int ber_start_set( BerElement *ber, unsigned long tag );
+LDAPFUNCDECL int ber_put_seq( BerElement *ber );
+LDAPFUNCDECL int ber_put_set( BerElement *ber );
+#if defined( MACOS ) || defined( BC31 ) || defined( _WIN32 )
+LDAPFUNCDECL int ber_printf( BerElement *ber, char *fmt, ... );
+#else
+LDAPFUNCDECL int ber_printf();
+#endif
+
+/*
+ * in io.c:
+ */
+LDAPFUNCDECL long ber_read( BerElement *ber, char *buf, unsigned long len );
+LDAPFUNCDECL long ber_write( BerElement *ber, char *buf, unsigned long len,
+       int nosos );
+LDAPFUNCDECL void ber_free( BerElement *ber, int freebuf );
+LDAPFUNCDECL int ber_flush( Sockbuf *sb, BerElement *ber, int freeit );
+LDAPFUNCDECL BerElement *ber_alloc( void );
+LDAPFUNCDECL BerElement *der_alloc( void );
+LDAPFUNCDECL BerElement *ber_alloc_t( int options );
+LDAPFUNCDECL BerElement *ber_dup( BerElement *ber );
+LDAPFUNCDECL void ber_dump( BerElement *ber, int inout );
+LDAPFUNCDECL void ber_sos_dump( Seqorset *sos );
+LDAPFUNCDECL unsigned long ber_get_next( Sockbuf *sb, unsigned long *len,
+       BerElement *ber );
+LDAPFUNCDECL void ber_init( BerElement *ber, int options );
+LDAPFUNCDECL void ber_reset( BerElement *ber, int was_writing );
+
+#ifdef NEEDGETOPT
+/*
+ * in getopt.c
+ */
+int getopt( int nargc, char **nargv, char *ostr );
+#endif /* NEEDGETOPT */
diff --git a/include/proto-ldap.h b/include/proto-ldap.h
new file mode 100644 (file)
index 0000000..971ab5b
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ * proto-ldap.h
+ * function prototypes for ldap library
+ */
+
+
+#ifndef LDAPFUNCDECL
+#ifdef _WIN32
+#define LDAPFUNCDECL   __declspec( dllexport )
+#else /* _WIN32 */
+#define LDAPFUNCDECL
+#endif /* _WIN32 */
+#endif /* LDAPFUNCDECL */
+
+
+/*
+ * in abandon.c:
+ */
+LDAPFUNCDECL int ldap_abandon( LDAP *ld, int msgid );
+
+/*
+ * in add.c:
+ */
+LDAPFUNCDECL int ldap_add( LDAP *ld, char *dn, LDAPMod **attrs );
+LDAPFUNCDECL int ldap_add_s( LDAP *ld, char *dn, LDAPMod **attrs );
+
+/*
+ * in bind.c:
+ */
+LDAPFUNCDECL int ldap_bind( LDAP *ld, char *who, char *passwd, int authmethod );
+LDAPFUNCDECL int ldap_bind_s( LDAP *ld, char *who, char *cred, int method );
+#ifdef LDAP_REFERRALS
+LDAPFUNCDECL void ldap_set_rebind_proc( LDAP *ld, int (*rebindproc)( LDAP *ld,
+       char **dnp, char **passwdp, int *authmethodp, int freeit ));
+#endif /* LDAP_REFERRALS */
+
+/*
+ * in sbind.c:
+ */
+LDAPFUNCDECL int ldap_simple_bind( LDAP *ld, char *who, char *passwd );
+LDAPFUNCDECL int ldap_simple_bind_s( LDAP *ld, char *who, char *passwd );
+
+/*
+ * in kbind.c:
+ */
+LDAPFUNCDECL int ldap_kerberos_bind_s( LDAP *ld, char *who );
+LDAPFUNCDECL int ldap_kerberos_bind1( LDAP *ld, char *who );
+LDAPFUNCDECL int ldap_kerberos_bind1_s( LDAP *ld, char *who );
+LDAPFUNCDECL int ldap_kerberos_bind2( LDAP *ld, char *who );
+LDAPFUNCDECL int ldap_kerberos_bind2_s( LDAP *ld, char *who );
+
+#ifndef NO_CACHE
+/*
+ * in cache.c
+ */
+LDAPFUNCDECL int ldap_enable_cache( LDAP *ld, long timeout, long maxmem );
+LDAPFUNCDECL void ldap_disable_cache( LDAP *ld );
+LDAPFUNCDECL void ldap_set_cache_options( LDAP *ld, unsigned long opts );
+LDAPFUNCDECL void ldap_destroy_cache( LDAP *ld );
+LDAPFUNCDECL void ldap_flush_cache( LDAP *ld );
+LDAPFUNCDECL void ldap_uncache_entry( LDAP *ld, char *dn );
+LDAPFUNCDECL void ldap_uncache_request( LDAP *ld, int msgid );
+#endif /* !NO_CACHE */
+
+/*
+ * in compare.c:
+ */
+LDAPFUNCDECL int ldap_compare( LDAP *ld, char *dn, char *attr, char *value );
+LDAPFUNCDECL int ldap_compare_s( LDAP *ld, char *dn, char *attr, char *value );
+
+/*
+ * in delete.c:
+ */
+LDAPFUNCDECL int ldap_delete( LDAP *ld, char *dn );
+LDAPFUNCDECL int ldap_delete_s( LDAP *ld, char *dn );
+
+/*
+ * in error.c:
+ */
+LDAPFUNCDECL int ldap_result2error( LDAP *ld, LDAPMessage *r, int freeit );
+LDAPFUNCDECL char *ldap_err2string( int err );
+LDAPFUNCDECL void ldap_perror( LDAP *ld, char *s );
+
+/*
+ * in modify.c:
+ */
+LDAPFUNCDECL int ldap_modify( LDAP *ld, char *dn, LDAPMod **mods );
+LDAPFUNCDECL int ldap_modify_s( LDAP *ld, char *dn, LDAPMod **mods );
+
+/*
+ * in modrdn.c:
+ */
+LDAPFUNCDECL int ldap_modrdn( LDAP *ld, char *dn, char *newrdn );
+LDAPFUNCDECL int ldap_modrdn_s( LDAP *ld, char *dn, char *newrdn );
+LDAPFUNCDECL int ldap_modrdn2( LDAP *ld, char *dn, char *newrdn,
+       int deleteoldrdn );
+LDAPFUNCDECL int ldap_modrdn2_s( LDAP *ld, char *dn, char *newrdn,
+       int deleteoldrdn);
+
+/*
+ * in open.c:
+ */
+LDAPFUNCDECL LDAP *ldap_open( char *host, int port );
+LDAPFUNCDECL LDAP *ldap_init( char *defhost, int defport );
+
+/*
+ * in getentry.c:
+ */
+LDAPFUNCDECL LDAPMessage *ldap_first_entry( LDAP *ld, LDAPMessage *chain );
+LDAPFUNCDECL LDAPMessage *ldap_next_entry( LDAP *ld, LDAPMessage *entry );
+LDAPFUNCDECL int ldap_count_entries( LDAP *ld, LDAPMessage *chain );
+
+/*
+ * in addentry.c
+ */
+LDAPFUNCDECL LDAPMessage *ldap_delete_result_entry( LDAPMessage **list,
+       LDAPMessage *e );
+LDAPFUNCDECL void ldap_add_result_entry( LDAPMessage **list, LDAPMessage *e );
+
+/*
+ * in getdn.c
+ */
+LDAPFUNCDECL char *ldap_get_dn( LDAP *ld, LDAPMessage *entry );
+LDAPFUNCDECL char *ldap_dn2ufn( char *dn );
+LDAPFUNCDECL char **ldap_explode_dn( char *dn, int notypes );
+LDAPFUNCDECL char **ldap_explode_dns( char *dn );
+LDAPFUNCDECL int ldap_is_dns_dn( char *dn );
+
+/*
+ * in getattr.c
+ */
+LDAPFUNCDECL char *ldap_first_attribute( LDAP *ld, LDAPMessage *entry,
+       BerElement **ber );
+LDAPFUNCDECL char *ldap_next_attribute( LDAP *ld, LDAPMessage *entry,
+       BerElement *ber );
+
+/*
+ * in getvalues.c
+ */
+LDAPFUNCDECL char **ldap_get_values( LDAP *ld, LDAPMessage *entry, char *target );
+LDAPFUNCDECL struct berval **ldap_get_values_len( LDAP *ld, LDAPMessage *entry,
+       char *target );
+LDAPFUNCDECL int ldap_count_values( char **vals );
+LDAPFUNCDECL int ldap_count_values_len( struct berval **vals );
+LDAPFUNCDECL void ldap_value_free( char **vals );
+LDAPFUNCDECL void ldap_value_free_len( struct berval **vals );
+
+/*
+ * in result.c:
+ */
+LDAPFUNCDECL int ldap_result( LDAP *ld, int msgid, int all,
+       struct timeval *timeout, LDAPMessage **result );
+LDAPFUNCDECL int ldap_msgfree( LDAPMessage *lm );
+LDAPFUNCDECL int ldap_msgdelete( LDAP *ld, int msgid );
+
+/*
+ * in search.c:
+ */
+LDAPFUNCDECL int ldap_search( LDAP *ld, char *base, int scope, char *filter,
+       char **attrs, int attrsonly );
+LDAPFUNCDECL int ldap_search_s( LDAP *ld, char *base, int scope, char *filter,
+       char **attrs, int attrsonly, LDAPMessage **res );
+LDAPFUNCDECL int ldap_search_st( LDAP *ld, char *base, int scope, char *filter,
+    char **attrs, int attrsonly, struct timeval *timeout, LDAPMessage **res );
+
+/*
+ * in ufn.c
+ */
+LDAPFUNCDECL int ldap_ufn_search_c( LDAP *ld, char *ufn, char **attrs,
+       int attrsonly, LDAPMessage **res, int (*cancelproc)( void *cl ),
+       void *cancelparm );
+LDAPFUNCDECL int ldap_ufn_search_ct( LDAP *ld, char *ufn, char **attrs,
+       int attrsonly, LDAPMessage **res, int (*cancelproc)( void *cl ),
+       void *cancelparm, char *tag1, char *tag2, char *tag3 );
+LDAPFUNCDECL int ldap_ufn_search_s( LDAP *ld, char *ufn, char **attrs,
+       int attrsonly, LDAPMessage **res );
+LDAPFUNCDECL LDAPFiltDesc *ldap_ufn_setfilter( LDAP *ld, char *fname );
+LDAPFUNCDECL void ldap_ufn_setprefix( LDAP *ld, char *prefix );
+LDAPFUNCDECL int ldap_ufn_timeout( void *tvparam );
+
+
+/*
+ * in unbind.c
+ */
+LDAPFUNCDECL int ldap_unbind( LDAP *ld );
+LDAPFUNCDECL int ldap_unbind_s( LDAP *ld );
+
+
+/*
+ * in getfilter.c
+ */
+LDAPFUNCDECL LDAPFiltDesc *ldap_init_getfilter( char *fname );
+LDAPFUNCDECL LDAPFiltDesc *ldap_init_getfilter_buf( char *buf, long buflen );
+LDAPFUNCDECL LDAPFiltInfo *ldap_getfirstfilter( LDAPFiltDesc *lfdp, char *tagpat,
+       char *value );
+LDAPFUNCDECL LDAPFiltInfo *ldap_getnextfilter( LDAPFiltDesc *lfdp );
+LDAPFUNCDECL void ldap_setfilteraffixes( LDAPFiltDesc *lfdp, char *prefix, char *suffix );
+LDAPFUNCDECL void ldap_build_filter( char *buf, unsigned long buflen,
+       char *pattern, char *prefix, char *suffix, char *attr,
+       char *value, char **valwords );
+
+/*
+ * in free.c
+ */
+LDAPFUNCDECL void ldap_getfilter_free( LDAPFiltDesc *lfdp );
+LDAPFUNCDECL void ldap_mods_free( LDAPMod **mods, int freemods );
+
+/*
+ * in friendly.c
+ */
+LDAPFUNCDECL char *ldap_friendly_name( char *filename, char *uname,
+       FriendlyMap **map );
+LDAPFUNCDECL void ldap_free_friendlymap( FriendlyMap **map );
+
+
+/*
+ * in cldap.c
+ */
+LDAPFUNCDECL LDAP *cldap_open( char *host, int port );
+LDAPFUNCDECL void cldap_close( LDAP *ld );
+LDAPFUNCDECL int cldap_search_s( LDAP *ld, char *base, int scope, char *filter,
+       char **attrs, int attrsonly, LDAPMessage **res, char *logdn );
+LDAPFUNCDECL void cldap_setretryinfo( LDAP *ld, int tries, int timeout );
+
+
+/*
+ * in sort.c
+ */
+LDAPFUNCDECL int ldap_sort_entries( LDAP *ld, LDAPMessage **chain, char *attr,
+       int (*cmp)() );
+LDAPFUNCDECL int ldap_sort_values( LDAP *ld, char **vals, int (*cmp)() );
+LDAPFUNCDECL int ldap_sort_strcasecmp( char **a, char **b );
+
+
+/*
+ * in url.c
+ */
+LDAPFUNCDECL int ldap_is_ldap_url( char *url );
+LDAPFUNCDECL int ldap_url_parse( char *url, LDAPURLDesc **ludpp );
+LDAPFUNCDECL void ldap_free_urldesc( LDAPURLDesc *ludp );
+LDAPFUNCDECL int ldap_url_search( LDAP *ld, char *url, int attrsonly );
+LDAPFUNCDECL int ldap_url_search_s( LDAP *ld, char *url, int attrsonly,
+       LDAPMessage **res );
+LDAPFUNCDECL int ldap_url_search_st( LDAP *ld, char *url, int attrsonly,
+       struct timeval *timeout, LDAPMessage **res );
+
+
+/*
+ * in charset.c
+ */
+#ifdef STR_TRANSLATION
+LDAPFUNCDECL void ldap_set_string_translators( LDAP *ld,
+       BERTranslateProc encode_proc, BERTranslateProc decode_proc );
+LDAPFUNCDECL int ldap_translate_from_t61( LDAP *ld, char **bufp,
+       unsigned long *lenp, int free_input );
+LDAPFUNCDECL int ldap_translate_to_t61( LDAP *ld, char **bufp,
+       unsigned long *lenp, int free_input );
+LDAPFUNCDECL void ldap_enable_translation( LDAP *ld, LDAPMessage *entry,
+       int enable );
+
+#ifdef LDAP_CHARSET_8859
+LDAPFUNCDECL int ldap_t61_to_8859( char **bufp, unsigned long *buflenp,
+       int free_input );
+LDAPFUNCDECL int ldap_8859_to_t61( char **bufp, unsigned long *buflenp,
+       int free_input );
+#endif /* LDAP_CHARSET_8859 */
+#endif /* STR_TRANSLATION */
+
+
+#ifdef WINSOCK
+/*
+ * in msdos/winsock/wsa.c
+ */
+LDAPFUNCDECL void ldap_memfree( void *p );
+#endif /* WINSOCK */
diff --git a/include/regex.h b/include/regex.h
new file mode 100644 (file)
index 0000000..e006929
--- /dev/null
@@ -0,0 +1,43 @@
+#if defined( MACOS ) || defined( DOS ) || defined( _WIN32 ) || defined( NEED_BSDREGEX )
+/*
+ * Copyright (c) 1993 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+/*
+ * regex.h -- includes for regular expression matching routines
+ * 13 August 1993 Mark C Smith
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined( NEEDPROTOS ) && defined( __STDC__ )
+#define NEEDPROTOS
+#endif
+
+#ifdef NEEDPROTOS
+char *re_comp( char *pat );
+int re_exec( char *lp );
+void re_modw( char *s );
+int re_subs( char *src, char *dst );
+#else /* NEEDPROTOS */
+char *re_comp();
+int re_exec();
+void re_modw();
+int re_subs();
+#endif /* NEEDPROTOS */
+
+#define re_fail( m, p )
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* MACOS or DOS or NEED_BSDREGEX */
diff --git a/include/srchpref.h b/include/srchpref.h
new file mode 100644 (file)
index 0000000..a1d65cf
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 1993, 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ *
+ * searchpref.h:  display template library defines
+ * 16 May 1994 by Gordon Good
+ */
+
+
+#ifndef _SRCHPREF_H
+#define _SRCHPREF_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+struct ldap_searchattr {
+       char                            *sa_attrlabel;
+       char                            *sa_attr;
+                                       /* max 32 matchtypes for now */
+       unsigned long                   sa_matchtypebitmap;
+       char                            *sa_selectattr;
+       char                            *sa_selecttext;
+       struct ldap_searchattr          *sa_next;
+};
+
+struct ldap_searchmatch {
+       char                            *sm_matchprompt;
+       char                            *sm_filter;
+       struct ldap_searchmatch         *sm_next;
+};
+
+struct ldap_searchobj {
+       char                            *so_objtypeprompt;
+       unsigned long                   so_options;
+       char                            *so_prompt;
+       short                           so_defaultscope;
+       char                            *so_filterprefix;
+       char                            *so_filtertag;
+       char                            *so_defaultselectattr;
+       char                            *so_defaultselecttext;
+       struct ldap_searchattr          *so_salist;
+       struct ldap_searchmatch         *so_smlist;
+       struct ldap_searchobj           *so_next;
+};
+
+#define NULLSEARCHOBJ                  ((struct ldap_searchobj *)0)
+
+/*
+ * global search object options
+ */
+#define LDAP_SEARCHOBJ_OPT_INTERNAL    0x00000001
+
+#define LDAP_IS_SEARCHOBJ_OPTION_SET( so, option )     \
+       (((so)->so_options & option ) != 0 )
+
+#define LDAP_SEARCHPREF_VERSION_ZERO   0
+#define LDAP_SEARCHPREF_VERSION                1
+
+#define LDAP_SEARCHPREF_ERR_VERSION    1
+#define LDAP_SEARCHPREF_ERR_MEM                2
+#define LDAP_SEARCHPREF_ERR_SYNTAX     3
+#define LDAP_SEARCHPREF_ERR_FILE       4
+
+
+#ifndef NEEDPROTOS
+int                    ldap_init_searchprefs();
+int                    ldap_init_searchprefs_buf();
+void                   ldap_free_searchprefs();
+struct ldap_searchobj  *ldap_first_searchobj();
+struct ldap_searchobj  *ldap_next_searchobj();
+
+#else /* !NEEDPROTOS */
+
+LDAPFUNCDECL int
+ldap_init_searchprefs( char *file, struct ldap_searchobj **solistp );
+
+LDAPFUNCDECL int
+ldap_init_searchprefs_buf( char *buf, long buflen,
+       struct ldap_searchobj **solistp );
+
+LDAPFUNCDECL void
+ldap_free_searchprefs( struct ldap_searchobj *solist );
+
+LDAPFUNCDECL struct ldap_searchobj *
+ldap_first_searchobj( struct ldap_searchobj *solist );
+
+LDAPFUNCDECL struct ldap_searchobj *
+ldap_next_searchobj( struct ldap_searchobj *sollist,
+       struct ldap_searchobj *so );
+
+#endif /* !NEEDPROTOS */
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _SRCHPREF_H */
diff --git a/include/sysexits-compat.h b/include/sysexits-compat.h
new file mode 100644 (file)
index 0000000..9be67fa
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ *
+ *     @(#)sysexits.h  4.5 (Berkeley) 7/6/88
+ */
+
+/*
+**  SYSEXITS.H -- Exit status codes for system programs.
+**
+**     This include file attempts to categorize possible error
+**     exit statuses for system programs, notably delivermail
+**     and the Berkeley network.
+**
+**     Error numbers begin at EX__BASE to reduce the possibility of
+**     clashing with other exit statuses that random programs may
+**     already return.  The meaning of the codes is approximately
+**     as follows:
+**
+**     EX_USAGE -- The command was used incorrectly, e.g., with
+**             the wrong number of arguments, a bad flag, a bad
+**             syntax in a parameter, or whatever.
+**     EX_DATAERR -- The input data was incorrect in some way.
+**             This should only be used for user's data & not
+**             system files.
+**     EX_NOINPUT -- An input file (not a system file) did not
+**             exist or was not readable.  This could also include
+**             errors like "No message" to a mailer (if it cared
+**             to catch it).
+**     EX_NOUSER -- The user specified did not exist.  This might
+**             be used for mail addresses or remote logins.
+**     EX_NOHOST -- The host specified did not exist.  This is used
+**             in mail addresses or network requests.
+**     EX_UNAVAILABLE -- A service is unavailable.  This can occur
+**             if a support program or file does not exist.  This
+**             can also be used as a catchall message when something
+**             you wanted to do doesn't work, but you don't know
+**             why.
+**     EX_SOFTWARE -- An internal software error has been detected.
+**             This should be limited to non-operating system related
+**             errors as possible.
+**     EX_OSERR -- An operating system error has been detected.
+**             This is intended to be used for such things as "cannot
+**             fork", "cannot create pipe", or the like.  It includes
+**             things like getuid returning a user that does not
+**             exist in the passwd file.
+**     EX_OSFILE -- Some system file (e.g., /etc/passwd, /etc/utmp,
+**             etc.) does not exist, cannot be opened, or has some
+**             sort of error (e.g., syntax error).
+**     EX_CANTCREAT -- A (user specified) output file cannot be
+**             created.
+**     EX_IOERR -- An error occurred while doing I/O on some file.
+**     EX_TEMPFAIL -- temporary failure, indicating something that
+**             is not really an error.  In sendmail, this means
+**             that a mailer (e.g.) could not create a connection,
+**             and the request should be reattempted later.
+**     EX_PROTOCOL -- the remote system returned something that
+**             was "not possible" during a protocol exchange.
+**     EX_NOPERM -- You did not have sufficient permission to
+**             perform the operation.  This is not intended for
+**             file system problems, which should use NOINPUT or
+**             CANTCREAT, but rather for higher level permissions.
+**             For example, kre uses this to restrict who students
+**             can send mail to.
+**
+**     Maintained by Eric Allman (eric@berkeley, ucbvax!eric) --
+**             please mail changes to me.
+**
+**                     @(#)sysexits.h  4.5             7/6/88
+*/
+
+# define EX_OK         0       /* successful termination */
+
+# define EX__BASE      64      /* base value for error messages */
+
+# define EX_USAGE      64      /* command line usage error */
+# define EX_DATAERR    65      /* data format error */
+# define EX_NOINPUT    66      /* cannot open input */
+# define EX_NOUSER     67      /* addressee unknown */
+# define EX_NOHOST     68      /* host name unknown */
+# define EX_UNAVAILABLE        69      /* service unavailable */
+# define EX_SOFTWARE   70      /* internal software error */
+# define EX_OSERR      71      /* system error (e.g., can't fork) */
+# define EX_OSFILE     72      /* critical OS file missing */
+# define EX_CANTCREAT  73      /* can't create (user) output file */
+# define EX_IOERR      74      /* input/output error */
+# define EX_TEMPFAIL   75      /* temp failure; user is invited to retry */
+# define EX_PROTOCOL   76      /* remote error in protocol */
+# define EX_NOPERM     77      /* permission denied */
+# define EX_CONFIG     78      /* configuration error */
diff --git a/libraries/Make-template b/libraries/Make-template
new file mode 100644 (file)
index 0000000..7f6c06d
--- /dev/null
@@ -0,0 +1,86 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1994 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP libraries Makefile
+#
+#-----------------------------------------------------------------------------
+
+############################################################################
+#                                                                          #
+# You should not have to edit anything below this point                    #
+#                                                                          #
+############################################################################
+
+#
+# rules to make the software
+#
+
+all:   FORCE
+       @echo "making all in `$(PWD)`"
+       @for i in *; do \
+           if [ -d $$i -a $$i != "RCS" ]; then \
+               echo; echo "  cd $$i; $(MAKE) $(MFLAGS) all"; \
+               ( cd $$i; $(MAKE) $(MFLAGS) all ); \
+           fi; \
+       done
+
+
+#
+# rules to install the software
+#
+
+install:       FORCE
+       @echo "making install in `$(PWD)`"
+       @for i in *; do \
+           if [ -d $$i -a $$i != "RCS" ]; then \
+               echo; echo "  cd $$i; $(MAKE) $(MFLAGS) install"; \
+               ( cd $$i; $(MAKE) $(MFLAGS) install ); \
+           fi; \
+       done
+
+#
+# rules to make clean
+#
+clean: FORCE
+       @echo "making clean in `$(PWD)`"
+       @for i in *; do \
+           if [ -d $$i -a $$i != "RCS" ]; then \
+               echo; echo "  cd $$i; $(MAKE) $(MFLAGS) clean"; \
+               ( cd $$i; $(MAKE) $(MFLAGS) clean ); \
+           fi; \
+       done
+
+veryclean:     clean
+
+#
+# rules to make depend
+#
+#
+depend:        FORCE
+       @echo "making depend in `$(PWD)`"
+       @for i in *; do \
+           if [ -d $$i -a $$i != "RCS" ]; then \
+               echo; echo "  cd $$i; $(MAKE) $(MFLAGS) depend"; \
+               ( cd $$i; $(MAKE) $(MFLAGS) depend ); \
+           fi; \
+       done
+
+links:
+       @echo "making links in `$(PWD)`"; \
+       for i in .src/*; do \
+           if [ -d $$i -a $$i != ".src/RCS" ]; then \
+               d=`basename $$i`; \
+               ( $(MKDIR) $$d; cd $$d; $(LN) ../.src/$$d .src; \
+                 $(LN) ../.src/$$d/Make-template . ; \
+                 $(MAKE) $(MFLAGS) MKDIR="$(MKDIR)" LN="$(LN)" \
+                   -f Make-template links ) ; \
+           fi; \
+       done
diff --git a/libraries/libavl/Make-template b/libraries/libavl/Make-template
new file mode 100644 (file)
index 0000000..4707379
--- /dev/null
@@ -0,0 +1,71 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1995 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       avl library makefile
+#
+#-----------------------------------------------------------------------------
+
+LDAPSRC        = ../..
+
+SRCS   = avl.c
+OBJS   = avl.o
+
+HDIR   = ../../include
+
+INCLUDES= -I$(HDIR)
+DEFINES        = $(DEFS)
+
+CFLAGS = $(INCLUDES) $(DEFINES) $(ACFLAGS)
+
+all:   libavl.a
+
+libavl.a:      version.o
+       $(AR) ruv $@ $(OBJS) version.o
+       @if [ ! -z "$(RANLIB)" ]; then \
+               $(RANLIB) $@; \
+       fi; \
+       $(RM) ../$@; \
+       $(LN) libavl/$@ ../$@
+
+testavl:       libavl.a testavl.o
+       $(CC) $(ALDFLAGS) -o $@ testavl.o -L. -lavl $(ALIBS)
+
+version.c:     $(OBJS)
+       $(RM) $@
+       (u=$${USER-root} v=`$(CAT) ../../build/version` d=`$(PWD)` \
+       h=`$(HOSTNAME)` t=`$(DATE)`; $(SED) -e "s|%WHEN%|$${t}|" \
+       -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+       -e "s|%VERSION%|$${v}|" \
+       < Version.c > $@)
+
+install:       all
+
+lint:  FORCE
+       $(LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+5lint: FORCE
+       $(5LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+clean: FORCE
+       $(RM) libavl.a ../libavl.a testavl *.o core a.out version.c
+
+depend:        FORCE
+       $(MKDEP) $(INCLUDES) $(DEFINES) $(SRCS)
+
+links:
+       @$(LN) .src/*.[ch] .
+
+# DO NOT DELETE THIS LINE -- mkdep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+avl.o: avl.c ../../include/avl.h
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/libraries/libavl/Version.c b/libraries/libavl/Version.c
new file mode 100644 (file)
index 0000000..182138d
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+static char Version[] = "  libavl.a v%VERSION% (%WHEN%)\n\t%WHOANDWHERE%\n";
diff --git a/libraries/libavl/avl.c b/libraries/libavl/avl.c
new file mode 100644 (file)
index 0000000..2614167
--- /dev/null
@@ -0,0 +1,778 @@
+/* avl.c - routines to implement an avl tree */
+/*
+ * Copyright (c) 1993 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#ifndef lint
+static char copyright[] = "@(#) Copyright (c) 1993 Regents of the University of Michigan.\nAll rights reserved.\n";
+static char avl_version[] = "AVL library version 1.0\n";
+#endif
+
+#include <sys/types.h>
+#include <stdio.h>
+#include "avl.h"
+
+#define ROTATERIGHT(x) { \
+       Avlnode *tmp;\
+       if ( *x == NULL || (*x)->avl_left == NULL ) {\
+               (void) printf("RR error\n"); exit(1); \
+       }\
+       tmp = (*x)->avl_left;\
+       (*x)->avl_left = tmp->avl_right;\
+       tmp->avl_right = *x;\
+       *x = tmp;\
+}
+#define ROTATELEFT(x)  { \
+       Avlnode *tmp;\
+       if ( *x == NULL || (*x)->avl_right == NULL ) {\
+               (void) printf("RL error\n"); exit(1); \
+       }\
+       tmp = (*x)->avl_right;\
+       (*x)->avl_right = tmp->avl_left;\
+       tmp->avl_left = *x;\
+       *x = tmp;\
+}
+
+/*
+ * ravl_insert - called from avl_insert() to do a recursive insert into
+ * and balance of an avl tree.
+ */
+
+static
+ravl_insert( iroot, data, taller, fcmp, fdup, depth )
+    Avlnode    **iroot;
+    caddr_t    data;
+    int                *taller;
+    IFP                fcmp;           /* comparison function */
+    IFP                fdup;           /* function to call for duplicates */
+    int                depth;
+{
+       int     rc, cmp, tallersub;
+       Avlnode *l, *r;
+
+       if ( *iroot == 0 ) {
+               if ( (*iroot = (Avlnode *) malloc( sizeof( Avlnode ) ))
+                   == NULL ) {
+                       return( -1 );
+               }
+               (*iroot)->avl_left = 0;
+               (*iroot)->avl_right = 0;
+               (*iroot)->avl_bf = 0;
+               (*iroot)->avl_data = data;
+               *taller = 1;
+               return( 0 );
+       }
+
+       cmp = (*fcmp)( data, (*iroot)->avl_data );
+
+       /* equal - duplicate name */
+       if ( cmp == 0 ) {
+               *taller = 0;
+               return( (*fdup)( (*iroot)->avl_data, data ) );
+       }
+
+       /* go right */
+       else if ( cmp > 0 ) {
+               rc = ravl_insert( &((*iroot)->avl_right), data, &tallersub,
+                  fcmp, fdup, depth );
+               if ( tallersub )
+                       switch ( (*iroot)->avl_bf ) {
+                       case LH : /* left high - balance is restored */
+                               (*iroot)->avl_bf = EH;
+                               *taller = 0;
+                               break;
+                       case EH : /* equal height - now right heavy */
+                               (*iroot)->avl_bf = RH;
+                               *taller = 1;
+                               break;
+                       case RH : /* right heavy to start - right balance */
+                               r = (*iroot)->avl_right;
+                               switch ( r->avl_bf ) {
+                               case LH : /* double rotation left */
+                                       l = r->avl_left;
+                                       switch ( l->avl_bf ) {
+                                       case LH : (*iroot)->avl_bf = EH;
+                                                 r->avl_bf = RH;
+                                                 break;
+                                       case EH : (*iroot)->avl_bf = EH;
+                                                 r->avl_bf = EH;
+                                                 break;
+                                       case RH : (*iroot)->avl_bf = LH;
+                                                 r->avl_bf = EH;
+                                                 break;
+                                       }
+                                       l->avl_bf = EH;
+                                       ROTATERIGHT( (&r) )
+                                       (*iroot)->avl_right = r;
+                                       ROTATELEFT( iroot )
+                                       *taller = 0;
+                                       break;
+                               case EH : /* This should never happen */
+                                       break;
+                               case RH : /* single rotation left */
+                                       (*iroot)->avl_bf = EH;
+                                       r->avl_bf = EH;
+                                       ROTATELEFT( iroot )
+                                       *taller = 0;
+                                       break;
+                               }
+                               break;
+                       }
+               else
+                       *taller = 0;
+       }
+
+       /* go left */
+       else {
+               rc = ravl_insert( &((*iroot)->avl_left), data, &tallersub,
+                  fcmp, fdup, depth );
+               if ( tallersub )
+                       switch ( (*iroot)->avl_bf ) {
+                       case LH : /* left high to start - left balance */
+                               l = (*iroot)->avl_left;
+                               switch ( l->avl_bf ) {
+                               case LH : /* single rotation right */
+                                       (*iroot)->avl_bf = EH;
+                                       l->avl_bf = EH;
+                                       ROTATERIGHT( iroot )
+                                       *taller = 0;
+                                       break;
+                               case EH : /* this should never happen */
+                                       break;
+                               case RH : /* double rotation right */
+                                       r = l->avl_right;
+                                       switch ( r->avl_bf ) {
+                                       case LH : (*iroot)->avl_bf = RH;
+                                                 l->avl_bf = EH;
+                                                 break;
+                                       case EH : (*iroot)->avl_bf = EH;
+                                                 l->avl_bf = EH;
+                                                 break;
+                                       case RH : (*iroot)->avl_bf = EH;
+                                                 l->avl_bf = LH;
+                                                 break;
+                                       }
+                                       r->avl_bf = EH;
+                                       ROTATELEFT( (&l) )
+                                       (*iroot)->avl_left = l;
+                                       ROTATERIGHT( iroot )
+                                       *taller = 0;
+                                       break;
+                               }
+                               break;
+                       case EH : /* equal height - now left heavy */
+                               (*iroot)->avl_bf = LH;
+                               *taller = 1;
+                               break;
+                       case RH : /* right high - balance is restored */
+                               (*iroot)->avl_bf = EH;
+                               *taller = 0;
+                               break;
+                       }
+               else
+                       *taller = 0;
+       }
+
+       return( rc );
+}
+
+/*
+ * avl_insert -- insert a node containing data data into the avl tree
+ * with root root.  fcmp is a function to call to compare the data portion
+ * of two nodes.  it should take two arguments and return <, >, or == 0,
+ * depending on whether its first argument is <, >, or == its second
+ * argument (like strcmp, e.g.).  fdup is a function to call when a duplicate
+ * node is inserted.  it should return 0, or -1 and its return value
+ * will be the return value from avl_insert in the case of a duplicate node.
+ * the function will be called with the original node's data as its first
+ * argument and with the incoming duplicate node's data as its second
+ * argument.  this could be used, for example, to keep a count with each
+ * node.
+ *
+ * NOTE: this routine may malloc memory
+ */
+
+avl_insert( root, data, fcmp, fdup )
+    Avlnode    **root;
+    caddr_t    data;
+    IFP                fcmp;
+    IFP                fdup;
+{
+       int     taller;
+
+       return( ravl_insert( root, data, &taller, fcmp, fdup, 0 ) );
+}
+
+/* 
+ * right_balance() - called from delete when root's right subtree has
+ * been shortened because of a deletion.
+ */
+
+static
+right_balance( root )
+    Avlnode    **root;
+{
+       int     shorter;
+       Avlnode *r, *l;
+
+       switch( (*root)->avl_bf ) {
+       case RH:        /* was right high - equal now */
+               (*root)->avl_bf = EH;
+               shorter = 1;
+               break;
+       case EH:        /* was equal - left high now */
+               (*root)->avl_bf = LH;
+               shorter = 0;
+               break;
+       case LH:        /* was right high - balance */
+               l = (*root)->avl_left;
+               switch ( l->avl_bf ) {
+               case RH : /* double rotation left */
+                       r = l->avl_right;
+                       switch ( r->avl_bf ) {
+                       case RH :
+                               (*root)->avl_bf = EH;
+                               l->avl_bf = LH;
+                               break;
+                       case EH :
+                               (*root)->avl_bf = EH;
+                               l->avl_bf = EH;
+                               break;
+                       case LH :
+                               (*root)->avl_bf = RH;
+                               l->avl_bf = EH;
+                               break;
+                       }
+                       r->avl_bf = EH;
+                       ROTATELEFT( (&l) )
+                       (*root)->avl_left = l;
+                       ROTATERIGHT( root )
+                       shorter = 1;
+                       break;
+               case EH : /* right rotation */
+                       (*root)->avl_bf = LH;
+                       l->avl_bf = RH;
+                       ROTATERIGHT( root );
+                       shorter = 0;
+                       break;
+               case LH : /* single rotation right */
+                       (*root)->avl_bf = EH;
+                       l->avl_bf = EH;
+                       ROTATERIGHT( root )
+                       shorter = 1;
+                       break;
+               }
+               break;
+       }
+
+       return( shorter );
+}
+
+/* 
+ * left_balance() - called from delete when root's left subtree has
+ * been shortened because of a deletion.
+ */
+
+static
+left_balance( root )
+    Avlnode    **root;
+{
+       int     shorter;
+       Avlnode *r, *l;
+
+       switch( (*root)->avl_bf ) {
+       case LH:        /* was left high - equal now */
+               (*root)->avl_bf = EH;
+               shorter = 1;
+               break;
+       case EH:        /* was equal - right high now */
+               (*root)->avl_bf = RH;
+               shorter = 0;
+               break;
+       case RH:        /* was right high - balance */
+               r = (*root)->avl_right;
+               switch ( r->avl_bf ) {
+               case LH : /* double rotation left */
+                       l = r->avl_left;
+                       switch ( l->avl_bf ) {
+                       case LH :
+                               (*root)->avl_bf = EH;
+                               r->avl_bf = RH;
+                               break;
+                       case EH :
+                               (*root)->avl_bf = EH;
+                               r->avl_bf = EH;
+                               break;
+                       case RH :
+                               (*root)->avl_bf = LH;
+                               r->avl_bf = EH;
+                               break;
+                       }
+                       l->avl_bf = EH;
+                       ROTATERIGHT( (&r) )
+                       (*root)->avl_right = r;
+                       ROTATELEFT( root )
+                       shorter = 1;
+                       break;
+               case EH : /* single rotation left */
+                       (*root)->avl_bf = RH;
+                       r->avl_bf = LH;
+                       ROTATELEFT( root );
+                       shorter = 0;
+                       break;
+               case RH : /* single rotation left */
+                       (*root)->avl_bf = EH;
+                       r->avl_bf = EH;
+                       ROTATELEFT( root )
+                       shorter = 1;
+                       break;
+               }
+               break;
+       }
+
+       return( shorter );
+}
+
+/*
+ * ravl_delete() - called from avl_delete to do recursive deletion of a
+ * node from an avl tree.  It finds the node recursively, deletes it,
+ * and returns shorter if the tree is shorter after the deletion and
+ * rebalancing.
+ */
+
+static caddr_t
+ravl_delete( root, data, fcmp, shorter )
+    Avlnode    **root;
+    caddr_t    data;
+    IFP                fcmp;
+    int                *shorter;
+{
+       int     shortersubtree = 0;
+       int     cmp;
+       caddr_t savedata;
+       Avlnode *minnode, *savenode;
+
+       if ( *root == NULLAVL )
+               return( 0 );
+
+       cmp = (*fcmp)( data, (*root)->avl_data );
+
+       /* found it! */
+       if ( cmp == 0 ) {
+               savenode = *root;
+               savedata = savenode->avl_data;
+
+               /* simple cases: no left child */
+               if ( (*root)->avl_left == 0 ) {
+                       *root = (*root)->avl_right;
+                       *shorter = 1;
+                       free( (char *) savenode );
+                       return( savedata );
+               /* no right child */
+               } else if ( (*root)->avl_right == 0 ) {
+                       *root = (*root)->avl_left;
+                       *shorter = 1;
+                       free( (char *) savenode );
+                       return( savedata );
+               }
+
+               /* 
+                * avl_getmin will return to us the smallest node greater
+                * than the one we are trying to delete.  deleting this node
+                * from the right subtree is guaranteed to end in one of the
+                * simple cases above.
+                */
+
+               minnode = (*root)->avl_right;
+               while ( minnode->avl_left != NULLAVL )
+                       minnode = minnode->avl_left;
+
+               /* swap the data */
+               (*root)->avl_data = minnode->avl_data;
+               minnode->avl_data = savedata;
+
+               savedata = ravl_delete( &(*root)->avl_right, data, fcmp,
+                   &shortersubtree );
+
+               if ( shortersubtree )
+                       *shorter = right_balance( root );
+               else
+                       *shorter = 0;
+       /* go left */
+       } else if ( cmp < 0 ) {
+               if ( (savedata = ravl_delete( &(*root)->avl_left, data, fcmp,
+                   &shortersubtree )) == 0 ) {
+                       *shorter = 0;
+                       return( 0 );
+               }
+
+               /* left subtree shorter? */
+               if ( shortersubtree )
+                       *shorter = left_balance( root );
+               else
+                       *shorter = 0;
+       /* go right */
+       } else {
+               if ( (savedata = ravl_delete( &(*root)->avl_right, data, fcmp,
+                   &shortersubtree )) == 0 ) {
+                       *shorter = 0;
+                       return( 0 );
+               }
+
+               if ( shortersubtree ) 
+                       *shorter = right_balance( root );
+               else
+                       *shorter = 0;
+       }
+
+       return( savedata );
+}
+
+/*
+ * avl_delete() - deletes the node containing data (according to fcmp) from
+ * the avl tree rooted at root.
+ */
+
+caddr_t
+avl_delete( root, data, fcmp )
+    Avlnode    **root;
+    caddr_t    data;
+    IFP                fcmp;
+{
+       int     shorter;
+
+       return( ravl_delete( root, data, fcmp, &shorter ) );
+}
+
+static
+avl_inapply( root, fn, arg, stopflag )
+    Avlnode    *root;
+    IFP                fn;
+    caddr_t    arg;
+    int                stopflag;
+{
+       if ( root == 0 )
+               return( AVL_NOMORE );
+
+       if ( root->avl_left != 0 )
+               if ( avl_inapply( root->avl_left, fn, arg, stopflag ) 
+                   == stopflag )
+                       return( stopflag );
+
+       if ( (*fn)( root->avl_data, arg ) == stopflag )
+               return( stopflag );
+
+       if ( root->avl_right == 0 )
+               return( AVL_NOMORE );
+       else
+               return( avl_inapply( root->avl_right, fn, arg, stopflag ) );
+}
+
+static
+avl_postapply( root, fn, arg, stopflag )
+    Avlnode    *root;
+    IFP                fn;
+    caddr_t    arg;
+    int                stopflag;
+{
+       if ( root == 0 )
+               return( AVL_NOMORE );
+
+       if ( root->avl_left != 0 )
+               if ( avl_postapply( root->avl_left, fn, arg, stopflag ) 
+                   == stopflag )
+                       return( stopflag );
+
+       if ( root->avl_right != 0 )
+               if ( avl_postapply( root->avl_right, fn, arg, stopflag ) 
+                   == stopflag )
+                       return( stopflag );
+
+       return( (*fn)( root->avl_data, arg ) );
+}
+
+static
+avl_preapply( root, fn, arg, stopflag )
+    Avlnode    *root;
+    IFP                fn;
+    caddr_t    arg;
+    int                stopflag;
+{
+       if ( root == 0 )
+               return( AVL_NOMORE );
+
+       if ( (*fn)( root->avl_data, arg ) == stopflag )
+               return( stopflag );
+
+       if ( root->avl_left != 0 )
+               if ( avl_preapply( root->avl_left, fn, arg, stopflag ) 
+                   == stopflag )
+                       return( stopflag );
+
+       if ( root->avl_right == 0 )
+               return( AVL_NOMORE );
+       else
+               return( avl_preapply( root->avl_right, fn, arg, stopflag ) );
+}
+
+/*
+ * avl_apply -- avl tree root is traversed, function fn is called with
+ * arguments arg and the data portion of each node.  if fn returns stopflag,
+ * the traversal is cut short, otherwise it continues.  Do not use -6 as
+ * a stopflag, as this is what is used to indicate the traversal ran out
+ * of nodes.
+ */
+
+avl_apply( root, fn, arg, stopflag, type )
+    Avlnode    *root;
+    IFP                fn;
+    caddr_t    arg;
+    int                stopflag;
+    int                type;
+{
+       switch ( type ) {
+       case AVL_INORDER:
+               return( avl_inapply( root, fn, arg, stopflag ) );
+       case AVL_PREORDER:
+               return( avl_preapply( root, fn, arg, stopflag ) );
+       case AVL_POSTORDER:
+               return( avl_postapply( root, fn, arg, stopflag ) );
+       default:
+               fprintf( stderr, "Invalid traversal type %d\n", type );
+               return( -1 );
+       }
+
+       /* NOTREACHED */
+}
+
+/*
+ * avl_prefixapply - traverse avl tree root, applying function fprefix
+ * to any nodes that match.  fcmp is called with data as its first arg
+ * and the current node's data as its second arg.  it should return
+ * 0 if they match, < 0 if data is less, and > 0 if data is greater.
+ * the idea is to efficiently find all nodes that are prefixes of
+ * some key...  Like avl_apply, this routine also takes a stopflag
+ * and will return prematurely if fmatch returns this value.  Otherwise,
+ * AVL_NOMORE is returned.
+ */
+
+avl_prefixapply( root, data, fmatch, marg, fcmp, carg, stopflag )
+    Avlnode    *root;
+    caddr_t    data;
+    IFP                fmatch;
+    caddr_t    marg;
+    IFP                fcmp;
+    caddr_t    carg;
+    int                stopflag;
+{
+       int     cmp;
+
+       if ( root == 0 )
+               return( AVL_NOMORE );
+
+       cmp = (*fcmp)( data, root->avl_data, carg );
+       if ( cmp == 0 ) {
+               if ( (*fmatch)( root->avl_data, marg ) == stopflag )
+                       return( stopflag );
+
+               if ( root->avl_left != 0 )
+                       if ( avl_prefixapply( root->avl_left, data, fmatch,
+                           marg, fcmp, carg, stopflag ) == stopflag )
+                               return( stopflag );
+
+               if ( root->avl_right != 0 )
+                       return( avl_prefixapply( root->avl_right, data, fmatch,
+                           marg, fcmp, carg, stopflag ) );
+               else
+                       return( AVL_NOMORE );
+
+       } else if ( cmp < 0 ) {
+               if ( root->avl_left != 0 )
+                       return( avl_prefixapply( root->avl_left, data, fmatch,
+                           marg, fcmp, carg, stopflag ) );
+       } else {
+               if ( root->avl_right != 0 )
+                       return( avl_prefixapply( root->avl_right, data, fmatch,
+                           marg, fcmp, carg, stopflag ) );
+       }
+
+       return( AVL_NOMORE );
+}
+
+/*
+ * avl_free -- traverse avltree root, freeing the memory it is using.
+ * the dfree() is called to free the data portion of each node.  The
+ * number of items actually freed is returned.
+ */
+
+avl_free( root, dfree )
+    Avlnode    *root;
+    IFP                dfree;
+{
+       int     nleft, nright;
+
+       if ( root == 0 )
+               return( 0 );
+
+       nleft = nright = 0;
+       if ( root->avl_left != 0 )
+               nleft = avl_free( root->avl_left, dfree );
+
+       if ( root->avl_right != 0 )
+               nright = avl_free( root->avl_right, dfree );
+
+       if ( dfree )
+               (*dfree)( root->avl_data );
+
+       return( nleft + nright + 1 );
+}
+
+/*
+ * avl_find -- search avltree root for a node with data data.  the function
+ * cmp is used to compare things.  it is called with data as its first arg 
+ * and the current node data as its second.  it should return 0 if they match,
+ * < 0 if arg1 is less than arg2 and > 0 if arg1 is greater than arg2.
+ */
+
+caddr_t
+avl_find( root, data, fcmp )
+    Avlnode    *root;
+    caddr_t    data;
+    IFP        fcmp;
+{
+       int     cmp;
+
+       while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
+               if ( cmp < 0 )
+                       root = root->avl_left;
+               else
+                       root = root->avl_right;
+       }
+
+       return( root ? root->avl_data : 0 );
+}
+
+/*
+ * avl_find_lin -- search avltree root linearly for a node with data data. 
+ * the function cmp is used to compare things.  it is called with data as its
+ * first arg and the current node data as its second.  it should return 0 if
+ * they match, non-zero otherwise.
+ */
+
+caddr_t
+avl_find_lin( root, data, fcmp )
+    Avlnode    *root;
+    caddr_t    data;
+    IFP                fcmp;
+{
+       caddr_t res;
+
+       if ( root == 0 )
+               return( NULL );
+
+       if ( (*fcmp)( data, root->avl_data ) == 0 )
+               return( root->avl_data );
+
+       if ( root->avl_left != 0 )
+               if ( (res = avl_find_lin( root->avl_left, data, fcmp ))
+                   != NULL )
+                       return( res );
+
+       if ( root->avl_right == 0 )
+               return( NULL );
+       else
+               return( avl_find_lin( root->avl_right, data, fcmp ) );
+}
+
+static caddr_t *avl_list;
+static int     avl_maxlist;
+static int     avl_nextlist;
+
+#define AVL_GRABSIZE   100
+
+/* ARGSUSED */
+static
+avl_buildlist( data, arg )
+    caddr_t    data;
+    int        arg;
+{
+       static int      slots;
+
+       if ( avl_list == (caddr_t *) 0 ) {
+               avl_list = (caddr_t *) malloc(AVL_GRABSIZE * sizeof(caddr_t));
+               slots = AVL_GRABSIZE;
+               avl_maxlist = 0;
+       } else if ( avl_maxlist == slots ) {
+               slots += AVL_GRABSIZE;
+               avl_list = (caddr_t *) realloc( (char *) avl_list,
+                   (unsigned) slots * sizeof(caddr_t));
+       }
+
+       avl_list[ avl_maxlist++ ] = data;
+
+       return( 0 );
+}
+
+/*
+ * avl_getfirst() and avl_getnext() are provided as alternate tree
+ * traversal methods, to be used when a single function cannot be
+ * provided to be called with every node in the tree.  avl_getfirst()
+ * traverses the tree and builds a linear list of all the nodes,
+ * returning the first node.  avl_getnext() returns the next thing
+ * on the list built by avl_getfirst().  This means that avl_getfirst()
+ * can take a while, and that the tree should not be messed with while
+ * being traversed in this way, and that multiple traversals (even of
+ * different trees) cannot be active at once.
+ */
+
+caddr_t
+avl_getfirst( root )
+    Avlnode    *root;
+{
+       if ( avl_list ) {
+               free( (char *) avl_list);
+               avl_list = (caddr_t *) 0;
+       }
+       avl_maxlist = 0;
+       avl_nextlist = 0;
+
+       if ( root == 0 )
+               return( 0 );
+
+       (void) avl_apply( root, avl_buildlist, (caddr_t) 0, -1, AVL_INORDER );
+
+       return( avl_list[ avl_nextlist++ ] );
+}
+
+caddr_t
+avl_getnext()
+{
+       if ( avl_list == 0 )
+               return( 0 );
+
+       if ( avl_nextlist == avl_maxlist ) {
+               free( (caddr_t) avl_list);
+               avl_list = (caddr_t *) 0;
+               return( 0 );
+       }
+
+       return( avl_list[ avl_nextlist++ ] );
+}
+
+avl_dup_error()
+{
+       return( -1 );
+}
+
+avl_dup_ok()
+{
+       return( 0 );
+}
diff --git a/libraries/libavl/testavl.c b/libraries/libavl/testavl.c
new file mode 100644 (file)
index 0000000..71939f4
--- /dev/null
@@ -0,0 +1,117 @@
+/* testavl.c - Test Tim Howes AVL code */
+#include <sys/types.h>
+#include <stdio.h>
+#include "avl.h"
+
+char *strdup( s )
+char   *s;
+{
+       char    *new;
+
+       if ( (new = (char *) malloc( strlen( s ) + 1 )) == NULL )
+               return( NULL );
+
+       strcpy( new, s );
+
+       return( new );
+}
+
+main( argc, argv )
+int    argc;
+char   **argv;
+{
+       Avlnode *tree = NULLAVL;
+       char    command[ 10 ];
+       char    name[ 80 ];
+       char    *p;
+       int     free(), strcmp();
+
+       printf( "> " );
+       while ( fgets( command, sizeof( command ), stdin ) != NULL ) {
+               switch( *command ) {
+               case 'n':       /* new tree */
+                       ( void ) avl_free( tree, free );
+                       tree = NULLAVL;
+                       break;
+               case 'p':       /* print */
+                       ( void ) myprint( tree );
+                       break;
+               case 't':       /* traverse with first, next */
+                       printf( "***\n" );
+                       for ( p = (char * ) avl_getfirst( tree );
+                           p != NULL; p = (char *) avl_getnext( tree, p ) )
+                               printf( "%s\n", p );
+                       printf( "***\n" );
+                       break;
+               case 'f':       /* find */
+                       printf( "data? " );
+                       if ( fgets( name, sizeof( name ), stdin ) == NULL )
+                               exit( 0 );
+                       name[ strlen( name ) - 1 ] = '\0';
+                       if ( (p = (char *) avl_find( tree, name, strcmp ))
+                           == NULL )
+                               printf( "Not found.\n\n" );
+                       else
+                               printf( "%s\n\n", p );
+                       break;
+               case 'i':       /* insert */
+                       printf( "data? " );
+                       if ( fgets( name, sizeof( name ), stdin ) == NULL )
+                               exit( 0 );
+                       name[ strlen( name ) - 1 ] = '\0';
+                       if ( avl_insert( &tree, strdup( name ), strcmp, 
+                           avl_dup_error ) != OK )
+                               printf( "\nNot inserted!\n" );
+                       break;
+               case 'd':       /* delete */
+                       printf( "data? " );
+                       if ( fgets( name, sizeof( name ), stdin ) == NULL )
+                               exit( 0 );
+                       name[ strlen( name ) - 1 ] = '\0';
+                       if ( avl_delete( &tree, name, strcmp ) == NULL )
+                               printf( "\nNot found!\n" );
+                       break;
+               case 'q':       /* quit */
+                       exit( 0 );
+                       break;
+               case '\n':
+                       break;
+               default:
+                       printf("Commands: insert, delete, print, new, quit\n");
+               }
+
+               printf( "> " );
+       }
+       /* NOTREACHED */
+}
+
+static ravl_print( root, depth )
+Avlnode        *root;
+int    depth;
+{
+       int     i;
+
+       if ( root == 0 )
+               return;
+
+       ravl_print( root->avl_right, depth+1 );
+
+       for ( i = 0; i < depth; i++ )
+               printf( "   " );
+       printf( "%s %d\n", root->avl_data, root->avl_bf );
+
+       ravl_print( root->avl_left, depth+1 );
+}
+
+myprint( root )
+Avlnode        *root;
+{
+       printf( "********\n" );
+
+       if ( root == 0 )
+               printf( "\tNULL\n" );
+       else
+               ( void ) ravl_print( root, 0 );
+
+       printf( "********\n" );
+}
diff --git a/libraries/liblber/Make-template b/libraries/liblber/Make-template
new file mode 100644 (file)
index 0000000..f1b9dd4
--- /dev/null
@@ -0,0 +1,85 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1990 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       lightweight ber library makefile
+#
+#-----------------------------------------------------------------------------
+
+LDAPSRC        = ../..
+SRCS   = decode.c encode.c io.c bprint.c
+OBJS   = decode.o encode.o io.o bprint.o
+
+HDIR   = ../../include
+
+INCLUDES= -I$(HDIR)
+DEFINES        = $(DEFS)
+CFLAGS = $(INCLUDES) $(DEFINES) $(ACFLAGS)
+
+all:   liblber.a
+
+liblber.a:     version.o
+       $(AR) ruv $@ $(OBJS) version.o
+       @if [ ! -z "$(RANLIB)" ]; then \
+               $(RANLIB) $@; \
+       fi; \
+       $(RM) ../$@; \
+       $(LN) liblber/$@ ../$@
+
+idtest:        idtest.o
+       $(CC) $(ALDFLAGS) -o $@ idtest.c $(ISODEINCLUDEFLAG) \
+               $(KRBINCLUDEFLAG) $(ISODELIBFLAG) $(ISODELIBS) \
+               $(KRBLIBLFAG) $(KRBLIBS) $(ALIBS)
+
+etest: liblber.a etest.o
+       $(CC) $(ALDFLAGS) -o $@ etest.o ./liblber.a $(ALIBS)
+
+dtest: liblber.a dtest.o
+       $(CC) $(ALDFLAGS) -o $@ dtest.o ./liblber.a $(ALIBS)
+
+version.c: $(OBJS)
+       $(RM) $@
+       (u=$${USER-root} v=`$(CAT) ../../build/version` d=`$(PWD)` \
+       h=`$(HOSTNAME)` t=`$(DATE)`; $(SED) -e "s|%WHEN%|$${t}|" \
+       -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+       -e "s|%VERSION%|$${v}|" \
+       < Version.c > $@)
+
+install:       liblber.a FORCE
+       -$(MKDIR) -p $(LIBDIR)
+       $(INSTALL) $(INSTALLFLAGS) -m 644 liblber.a $(LIBDIR)
+       @if [ ! -z "$(RANLIB)" ]; then \
+               (cd /tmp; $(RANLIB) $(LIBDIR)/liblber.a) \
+       fi
+
+lint:  FORCE
+       $(LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+5lint: FORCE
+       $(5LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+clean: FORCE
+       $(RM) liblber.a ../liblber.a *.o core a.out version.c dtest etest idtest
+
+depend:        FORCE
+       $(MKDEP) $(INCLUDES) $(DEFINES) $(SRCS)
+
+links:
+       @$(LN) .src/ldap* .src/*.[ch] .
+
+# DO NOT DELETE THIS LINE -- mkdep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+decode.o: decode.c ../../include/lber.h
+encode.o: encode.c ../../include/lber.h
+io.o: io.c ../../include/lber.h
+bprint.o: bprint.c ../../include/lber.h
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/libraries/liblber/Version.c b/libraries/liblber/Version.c
new file mode 100644 (file)
index 0000000..ae3b655
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 1991 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+static char Version[] = "  liblber.a v%VERSION% (%WHEN%)\n\t%WHOANDWHERE%\n";
diff --git a/libraries/liblber/bprint.c b/libraries/liblber/bprint.c
new file mode 100644 (file)
index 0000000..e4b6fd2
--- /dev/null
@@ -0,0 +1,60 @@
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "lber.h"
+
+/*
+ * Print arbitrary stuff, for debugging.
+ */
+
+#ifdef LDAP_DEBUG
+
+#ifndef NO_USERINTERFACE
+#define BPLEN  48
+
+void
+lber_bprint( char *data, int len )
+{
+    static char        hexdig[] = "0123456789abcdef";
+    char       out[ BPLEN ];
+    int                i = 0;
+
+    memset( out, 0, BPLEN );
+    for ( ;; ) {
+       if ( len < 1 ) {
+           fprintf( stderr, "\t%s\n", ( i == 0 ) ? "(end)" : out );
+           break;
+       }
+
+#ifndef HEX
+       if ( isgraph( (unsigned char)*data )) {
+           out[ i ] = ' ';
+           out[ i+1 ] = *data;
+       } else {
+#endif
+           out[ i ] = hexdig[ ( *data & 0xf0 ) >> 4 ];
+           out[ i+1 ] = hexdig[ *data & 0x0f ];
+#ifndef HEX
+       }
+#endif
+       i += 2;
+       len--;
+       data++;
+
+       if ( i > BPLEN - 2 ) {
+           fprintf( stderr, "\t%s\n", out );
+           memset( out, 0, BPLEN );
+           i = 0;
+           continue;
+       }
+       out[ i++ ] = ' ';
+    }
+}
+#else /* NO_USERINTERFACE */
+void
+lber_bprint( char *data, int len )
+{
+}
+#endif /* NO_USERINTERFACE */
+
+#endif
diff --git a/libraries/liblber/decode.c b/libraries/liblber/decode.c
new file mode 100644 (file)
index 0000000..a722c9e
--- /dev/null
@@ -0,0 +1,598 @@
+/* decode.c - ber input decoding routines */
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#ifdef MACOS
+#include <stdlib.h>
+#include <stdarg.h>
+#include "macos.h"
+#else /* MACOS */
+#if defined(NeXT) || defined(VMS)
+#include <stdlib.h>
+#else /* next || vms */
+#include <malloc.h>
+#endif /* next || vms */
+#if defined(BC31) || defined(_WIN32)
+#include <stdarg.h>
+#else /* BC31 || _WIN32 */
+#include <varargs.h>
+#endif /* BC31 || _WIN32 */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#ifdef PCNFS
+#include <tklib.h>
+#endif /* PCNFS */
+#endif /* MACOS */
+
+#if defined( DOS ) || defined( _WIN32 )
+#include "msdos.h"
+#endif /* DOS */
+
+#include <string.h>
+#include "lber.h"
+
+#ifdef LDAP_DEBUG
+int    lber_debug;
+#endif
+
+#ifdef NEEDPROTOS
+static int ber_getnint( BerElement *ber, long *num, int len );
+#endif /* NEEDPROTOS */
+
+
+/* return the tag - LBER_DEFAULT returned means trouble */
+unsigned long
+ber_get_tag( BerElement *ber )
+{
+       unsigned char   xbyte;
+       unsigned long   tag;
+       char            *tagp;
+       int             i;
+
+       if ( ber_read( ber, (char *) &xbyte, 1 ) != 1 )
+               return( LBER_DEFAULT );
+
+       if ( (xbyte & LBER_BIG_TAG_MASK) != LBER_BIG_TAG_MASK )
+               return( (unsigned long) xbyte );
+
+       tagp = (char *) &tag;
+       tagp[0] = xbyte;
+       for ( i = 1; i < sizeof(long); i++ ) {
+               if ( ber_read( ber, (char *) &xbyte, 1 ) != 1 )
+                       return( LBER_DEFAULT );
+
+               tagp[i] = xbyte;
+
+               if ( ! (xbyte & LBER_MORE_TAG_MASK) )
+                       break;
+       }
+
+       /* tag too big! */
+       if ( i == sizeof(long) )
+               return( LBER_DEFAULT );
+
+       /* want leading, not trailing 0's */
+       return( tag >> (sizeof(long) - i - 1) );
+}
+
+unsigned long
+ber_skip_tag( BerElement *ber, unsigned long *len )
+{
+       unsigned long   tag;
+       unsigned char   lc;
+       int             noctets, diff;
+       unsigned long   netlen;
+
+       /*
+        * Any ber element looks like this: tag length contents.
+        * Assuming everything's ok, we return the tag byte (we
+        * can assume a single byte), and return the length in len.
+        *
+        * Assumptions:
+        *      1) definite lengths
+        *      2) primitive encodings used whenever possible
+        */
+
+       /*
+        * First, we read the tag.
+        */
+
+       if ( (tag = ber_get_tag( ber )) == LBER_DEFAULT )
+               return( LBER_DEFAULT );
+
+       /*
+        * Next, read the length.  The first byte contains the length of
+        * the length.  If bit 8 is set, the length is the long form,
+        * otherwise it's the short form.  We don't allow a length that's
+        * greater than what we can hold in an unsigned long.
+        */
+
+       *len = netlen = 0;
+       if ( ber_read( ber, (char *) &lc, 1 ) != 1 )
+               return( LBER_DEFAULT );
+       if ( lc & 0x80 ) {
+               noctets = (lc & 0x7f);
+               if ( noctets > sizeof(unsigned long) )
+                       return( LBER_DEFAULT );
+               diff = sizeof(unsigned long) - noctets;
+               if ( ber_read( ber, (char *) &netlen + diff, noctets )
+                   != noctets )
+                       return( LBER_DEFAULT );
+               *len = LBER_NTOHL( netlen );
+       } else {
+               *len = lc;
+       }
+
+       return( tag );
+}
+
+unsigned long
+ber_peek_tag( BerElement *ber, unsigned long *len )
+{
+       char            *save;
+       unsigned long   tag;
+
+       save = ber->ber_ptr;
+       tag = ber_skip_tag( ber, len );
+       ber->ber_ptr = save;
+
+       return( tag );
+}
+
+static int
+ber_getnint( BerElement *ber, long *num, int len )
+{
+       int     diff, sign, i;
+       long    netnum;
+
+       /*
+        * The tag and length have already been stripped off.  We should
+        * be sitting right before len bytes of 2's complement integer,
+        * ready to be read straight into an int.  We may have to sign
+        * extend after we read it in.
+        */
+
+       if ( len > sizeof(long) )
+               return( -1 );
+
+       netnum = 0;
+       diff = sizeof(long) - len;
+       /* read into the low-order bytes of netnum */
+       if ( ber_read( ber, ((char *) &netnum) + diff, len ) != len )
+               return( -1 );
+
+       /* sign extend if necessary */
+       sign = ((0x80 << ((len - 1) * 8)) & netnum);
+       if ( sign && len < sizeof(long) ) {
+               for ( i = sizeof(long) - 1; i > len - 1; i-- ) {
+                       netnum |= (0xffL << (i * 8));
+               }
+       }
+       *num = LBER_NTOHL( netnum );
+
+       return( len );
+}
+
+unsigned long
+ber_get_int( BerElement *ber, long *num )
+{
+       unsigned long   tag, len;
+
+       if ( (tag = ber_skip_tag( ber, &len )) == LBER_DEFAULT )
+               return( LBER_DEFAULT );
+
+       if ( ber_getnint( ber, num, (int)len ) != len )
+               return( LBER_DEFAULT );
+       else
+               return( tag );
+}
+
+unsigned long
+ber_get_stringb( BerElement *ber, char *buf, unsigned long *len )
+{
+       unsigned long   datalen, tag;
+#ifdef STR_TRANSLATION
+       char            *transbuf;
+#endif /* STR_TRANSLATION */
+
+       if ( (tag = ber_skip_tag( ber, &datalen )) == LBER_DEFAULT )
+               return( LBER_DEFAULT );
+       if ( datalen > (*len - 1) )
+               return( LBER_DEFAULT );
+
+       if ( ber_read( ber, buf, datalen ) != datalen )
+               return( LBER_DEFAULT );
+
+       buf[datalen] = '\0';
+
+#ifdef STR_TRANSLATION
+       if ( datalen > 0 && ( ber->ber_options & LBER_TRANSLATE_STRINGS ) != 0
+           && ber->ber_decode_translate_proc != NULL ) {
+               transbuf = buf;
+               ++datalen;
+               if ( (*(ber->ber_decode_translate_proc))( &transbuf, &datalen,
+                   0 ) != 0 ) {
+                       return( LBER_DEFAULT );
+               }
+               if ( datalen > *len ) {
+                       free( transbuf );
+                       return( LBER_DEFAULT );
+               }
+               SAFEMEMCPY( buf, transbuf, datalen );
+               free( transbuf );
+               --datalen;
+       }
+#endif /* STR_TRANSLATION */
+
+       *len = datalen;
+       return( tag );
+}
+
+unsigned long
+ber_get_stringa( BerElement *ber, char **buf )
+{
+       unsigned long   datalen, tag;
+
+       if ( (tag = ber_skip_tag( ber, &datalen )) == LBER_DEFAULT )
+               return( LBER_DEFAULT );
+
+       if ( (*buf = (char *) malloc( (size_t)datalen + 1 )) == NULL )
+               return( LBER_DEFAULT );
+
+       if ( ber_read( ber, *buf, datalen ) != datalen )
+               return( LBER_DEFAULT );
+       (*buf)[datalen] = '\0';
+
+#ifdef STR_TRANSLATION
+       if ( datalen > 0 && ( ber->ber_options & LBER_TRANSLATE_STRINGS ) != 0
+           && ber->ber_decode_translate_proc != NULL ) {
+               ++datalen;
+               if ( (*(ber->ber_decode_translate_proc))( buf, &datalen, 1 )
+                   != 0 ) {
+                       free( *buf );
+                       return( LBER_DEFAULT );
+               }
+       }
+#endif /* STR_TRANSLATION */
+
+       return( tag );
+}
+
+unsigned long
+ber_get_stringal( BerElement *ber, struct berval **bv )
+{
+       unsigned long   len, tag;
+
+       if ( (*bv = (struct berval *) malloc( sizeof(struct berval) )) == NULL )
+               return( LBER_DEFAULT );
+
+       if ( (tag = ber_skip_tag( ber, &len )) == LBER_DEFAULT )
+               return( LBER_DEFAULT );
+
+       if ( ((*bv)->bv_val = (char *) malloc( (size_t)len + 1 )) == NULL )
+               return( LBER_DEFAULT );
+
+       if ( ber_read( ber, (*bv)->bv_val, len ) != len )
+               return( LBER_DEFAULT );
+       ((*bv)->bv_val)[len] = '\0';
+       (*bv)->bv_len = len;
+
+#ifdef STR_TRANSLATION
+       if ( len > 0 && ( ber->ber_options & LBER_TRANSLATE_STRINGS ) != 0
+           && ber->ber_decode_translate_proc != NULL ) {
+               ++len;
+               if ( (*(ber->ber_decode_translate_proc))( &((*bv)->bv_val),
+                   &len, 1 ) != 0 ) {
+                       free( (*bv)->bv_val );
+                       return( LBER_DEFAULT );
+               }
+               (*bv)->bv_len = len - 1;
+       }
+#endif /* STR_TRANSLATION */
+
+       return( tag );
+}
+
+unsigned long
+ber_get_bitstringa( BerElement *ber, char **buf, unsigned long *blen )
+{
+       unsigned long   datalen, tag;
+       unsigned char   unusedbits;
+
+       if ( (tag = ber_skip_tag( ber, &datalen )) == LBER_DEFAULT )
+               return( LBER_DEFAULT );
+       --datalen;
+
+       if ( (*buf = (char *) malloc( (size_t)datalen )) == NULL )
+               return( LBER_DEFAULT );
+
+       if ( ber_read( ber, (char *)&unusedbits, 1 ) != 1 )
+               return( LBER_DEFAULT );
+
+       if ( ber_read( ber, *buf, datalen ) != datalen )
+               return( LBER_DEFAULT );
+
+       *blen = datalen * 8 - unusedbits;
+       return( tag );
+}
+
+unsigned long
+ber_get_null( BerElement *ber )
+{
+       unsigned long   len, tag;
+
+       if ( (tag = ber_skip_tag( ber, &len )) == LBER_DEFAULT )
+               return( LBER_DEFAULT );
+
+       if ( len != 0 )
+               return( LBER_DEFAULT );
+
+       return( tag );
+}
+
+unsigned long
+ber_get_boolean( BerElement *ber, int *boolval )
+{
+       long    longbool;
+       int     rc;
+
+       rc = ber_get_int( ber, &longbool );
+       *boolval = longbool;
+
+       return( rc );
+}
+
+unsigned long
+ber_first_element( BerElement *ber, unsigned long *len, char **last )
+{
+       /* skip the sequence header, use the len to mark where to stop */
+       if ( ber_skip_tag( ber, len ) == LBER_DEFAULT ) {
+               return( LBER_DEFAULT );
+       }
+
+       *last = ber->ber_ptr + *len;
+
+       if ( *last == ber->ber_ptr ) {
+               return( LBER_DEFAULT );
+       }
+
+       return( ber_peek_tag( ber, len ) );
+}
+
+unsigned long
+ber_next_element( BerElement *ber, unsigned long *len, char *last )
+{
+       if ( ber->ber_ptr == last ) {
+               return( LBER_DEFAULT );
+       }
+
+       return( ber_peek_tag( ber, len ) );
+}
+
+/* VARARGS */
+unsigned long
+ber_scanf(
+#if defined( MACOS ) || defined( BC31 ) || defined( _WIN32 )
+       BerElement *ber, char *fmt, ... )
+#else
+       va_alist )
+va_dcl
+#endif
+{
+       va_list         ap;
+#if !defined( MACOS ) && !defined( BC31 ) && !defined( _WIN32 )
+       BerElement      *ber;
+       char            *fmt;
+#endif
+       char            *last;
+       char            *s, **ss, ***sss;
+       struct berval   ***bv, **bvp, *bval;
+       int             *i, j;
+       long            *l, rc, tag;
+       unsigned long   len;
+
+#if defined( MACOS ) || defined( BC31 ) || defined( _WIN32 )
+       va_start( ap, fmt );
+#else
+       va_start( ap );
+       ber = va_arg( ap, BerElement * );
+       fmt = va_arg( ap, char * );
+#endif
+
+#ifdef LDAP_DEBUG
+       if ( lber_debug & 64 ) {
+               fprintf( stderr, "ber_scanf fmt (%s) ber:\n", fmt );
+               ber_dump( ber, 1 );
+       }
+#endif
+
+       for ( rc = 0; *fmt && rc != LBER_DEFAULT; fmt++ ) {
+               switch ( *fmt ) {
+               case 'a':       /* octet string - allocate storage as needed */
+                       ss = va_arg( ap, char ** );
+                       rc = ber_get_stringa( ber, ss );
+                       break;
+
+               case 'b':       /* boolean */
+                       i = va_arg( ap, int * );
+                       rc = ber_get_boolean( ber, i );
+                       break;
+
+               case 'e':       /* enumerated */
+               case 'i':       /* int */
+                       l = va_arg( ap, long * );
+                       rc = ber_get_int( ber, l );
+                       break;
+
+               case 'l':       /* length of next item */
+                       l = va_arg( ap, long * );
+                       rc = ber_peek_tag( ber, (unsigned long *)l );
+                       break;
+
+               case 'n':       /* null */
+                       rc = ber_get_null( ber );
+                       break;
+
+               case 's':       /* octet string - in a buffer */
+                       s = va_arg( ap, char * );
+                       l = va_arg( ap, long * );
+                       rc = ber_get_stringb( ber, s, (unsigned long *)l );
+                       break;
+
+               case 'o':       /* octet string in a supplied berval */
+                       bval = va_arg( ap, struct berval * );
+                       ber_peek_tag( ber, &bval->bv_len );
+                       rc = ber_get_stringa( ber, &bval->bv_val );
+                       break;
+
+               case 'O':       /* octet string - allocate & include length */
+                       bvp = va_arg( ap, struct berval ** );
+                       rc = ber_get_stringal( ber, bvp );
+                       break;
+
+               case 'B':       /* bit string - allocate storage as needed */
+                       ss = va_arg( ap, char ** );
+                       l = va_arg( ap, long * ); /* for length, in bits */
+                       rc = ber_get_bitstringa( ber, ss, (unsigned long *)l );
+                       break;
+
+               case 't':       /* tag of next item */
+                       i = va_arg( ap, int * );
+                       *i = rc = ber_peek_tag( ber, &len );
+                       break;
+
+               case 'T':       /* skip tag of next item */
+                       i = va_arg( ap, int * );
+                       *i = rc = ber_skip_tag( ber, &len );
+                       break;
+
+               case 'v':       /* sequence of strings */
+                       sss = va_arg( ap, char *** );
+                       *sss = NULL;
+                       j = 0;
+                       for ( tag = ber_first_element( ber, &len, &last );
+                           tag != LBER_DEFAULT && rc != LBER_DEFAULT;
+                           tag = ber_next_element( ber, &len, last ) ) {
+                               if ( *sss == NULL ) {
+                                       *sss = (char **) malloc(
+                                           2 * sizeof(char *) );
+                               } else {
+                                       *sss = (char **) realloc( *sss,
+                                           (j + 2) * sizeof(char *) );
+                               }
+                               rc = ber_get_stringa( ber, &((*sss)[j]) );
+                               j++;
+                       }
+                       if ( j > 0 )
+                               (*sss)[j] = NULL;
+                       break;
+
+               case 'V':       /* sequence of strings + lengths */
+                       bv = va_arg( ap, struct berval *** );
+                       *bv = NULL;
+                       j = 0;
+                       for ( tag = ber_first_element( ber, &len, &last );
+                           tag != LBER_DEFAULT && rc != LBER_DEFAULT;
+                           tag = ber_next_element( ber, &len, last ) ) {
+                               if ( *bv == NULL ) {
+                                       *bv = (struct berval **) malloc(
+                                           2 * sizeof(struct berval *) );
+                               } else {
+                                       *bv = (struct berval **) realloc( *bv,
+                                           (j + 2) * sizeof(struct berval *) );
+                               }
+                               rc = ber_get_stringal( ber, &((*bv)[j]) );
+                               j++;
+                       }
+                       if ( j > 0 )
+                               (*bv)[j] = NULL;
+                       break;
+
+               case 'x':       /* skip the next element - whatever it is */
+                       if ( (rc = ber_skip_tag( ber, &len )) == LBER_DEFAULT )
+                               break;
+                       ber->ber_ptr += len;
+                       break;
+
+               case '{':       /* begin sequence */
+               case '[':       /* begin set */
+                       if ( *(fmt + 1) != 'v' && *(fmt + 1) != 'V' )
+                               rc = ber_skip_tag( ber, &len );
+                       break;
+
+               case '}':       /* end sequence */
+               case ']':       /* end set */
+                       break;
+
+               default:
+#ifndef NO_USERINTERFACE
+                       fprintf( stderr, "unknown fmt %c\n", *fmt );
+#endif /* NO_USERINTERFACE */
+                       rc = LBER_DEFAULT;
+                       break;
+               }
+       }
+
+       va_end( ap );
+
+       return( rc );
+}
+
+void
+ber_bvfree( struct berval *bv )
+{
+       if ( bv->bv_val != NULL )
+               free( bv->bv_val );
+       free( (char *) bv );
+}
+
+void
+ber_bvecfree( struct berval **bv )
+{
+       int     i;
+
+       for ( i = 0; bv[i] != NULL; i++ )
+               ber_bvfree( bv[i] );
+       free( (char *) bv );
+}
+
+struct berval *
+ber_bvdup( struct berval *bv )
+{
+       struct berval   *new;
+
+       if ( (new = (struct berval *) malloc( sizeof(struct berval) ))
+           == NULL ) {
+               return( NULL );
+       }
+       if ( (new->bv_val = (char *) malloc( bv->bv_len + 1 )) == NULL ) {
+               return( NULL );
+       }
+       SAFEMEMCPY( new->bv_val, bv->bv_val, (size_t) bv->bv_len );
+       new->bv_val[bv->bv_len] = '\0';
+       new->bv_len = bv->bv_len;
+
+       return( new );
+}
+
+
+#ifdef STR_TRANSLATION
+void
+ber_set_string_translators( BerElement *ber, BERTranslateProc encode_proc,
+       BERTranslateProc decode_proc )
+{
+    ber->ber_encode_translate_proc = encode_proc;
+    ber->ber_decode_translate_proc = decode_proc;
+}
+#endif /* STR_TRANSLATION */
diff --git a/libraries/liblber/dtest.c b/libraries/liblber/dtest.c
new file mode 100644 (file)
index 0000000..cd63b9f
--- /dev/null
@@ -0,0 +1,61 @@
+/* dtest.c - lber decoding test program */
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#ifdef MACOS
+#include <stdlib.h>
+#include <console.h>
+#else /* MACOS */
+#include <sys/types.h>
+#include <sys/socket.h>
+#endif /* MACOS */
+#include "lber.h"
+
+static usage( char *name )
+{
+       fprintf( stderr, "usage: %s fmt\n", name );
+}
+
+main( int argc, char **argv )
+{
+       long            i, i2, num;
+       unsigned long   len;
+       int             tag;
+       char            *str, *s1, *s2;
+       BerElement      ber;
+       Sockbuf         sb;
+       extern char     *optarg;
+
+#ifdef MACOS
+       ccommand( &argv );
+       cshow( stdout );
+#endif /* MACOS */
+
+       bzero( &sb, sizeof(sb) );
+       sb.sb_sd = 0;
+       sb.sb_ber.ber_buf = NULL;
+       if ( (tag = ber_get_next( &sb, &len, &ber )) == -1 ) {
+               perror( "ber_get_next" );
+               exit( 1 );
+       }
+       printf( "message has tag 0x%x and length %ld\n", tag, len );
+
+       if ( ber_scanf( &ber, "i", &i ) == -1 ) {
+               fprintf( stderr, "ber_scanf returns -1\n" );
+               exit( 1 );
+       }
+       printf( "got int %d\n", i );
+
+       return( 0 );
+}
diff --git a/libraries/liblber/encode.c b/libraries/liblber/encode.c
new file mode 100644 (file)
index 0000000..cd95f89
--- /dev/null
@@ -0,0 +1,644 @@
+/* encode.c - ber output encoding routines */
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#ifdef MACOS
+#include <stdlib.h>
+#include <stdarg.h>
+#include "macos.h"
+#else /* MACOS */
+#if defined(NeXT) || defined(VMS)
+#include <stdlib.h>
+#else /* next || vms */
+#include <malloc.h>
+#endif /* next || vms */
+#if defined( BC31 ) || defined( _WIN32 )
+#include <stdarg.h>
+#else /* BC31 || _WIN32 */
+#include <varargs.h>
+#endif /* BC31 || _WIN32 */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#ifdef PCNFS
+#include <tklib.h>
+#endif /* PCNFS */
+#endif /* MACOS */
+#ifndef VMS
+#include <memory.h>
+#endif
+#include <string.h>
+#include "lber.h"
+
+#if defined( DOS ) || defined( _WIN32 )
+#include "msdos.h"
+#endif /* DOS */
+
+#ifdef NEEDPROTOS
+static int ber_put_len( BerElement *ber, unsigned long len, int nosos );
+static int ber_start_seqorset( BerElement *ber, unsigned long tag );
+static int ber_put_seqorset( BerElement *ber );
+static int ber_put_int_or_enum( BerElement *ber, long num, unsigned long tag );
+#endif /* NEEDPROTOS */
+
+
+static int
+ber_calc_taglen( unsigned long tag )
+{
+       int     i;
+       long    mask;
+
+       /* find the first non-all-zero byte in the tag */
+       for ( i = sizeof(long) - 1; i > 0; i-- ) {
+               mask = (0xffL << (i * 8));
+               /* not all zero */
+               if ( tag & mask )
+                       break;
+       }
+
+       return( i + 1 );
+}
+
+static int
+ber_put_tag( BerElement        *ber, unsigned long tag, int nosos )
+{
+       int             taglen;
+       unsigned long   ntag;
+
+       taglen = ber_calc_taglen( tag );
+
+       ntag = LBER_HTONL( tag );
+
+       return( ber_write( ber, ((char *) &ntag) + sizeof(long) - taglen,
+           taglen, nosos ) );
+}
+
+static int
+ber_calc_lenlen( unsigned long len )
+{
+       /*
+        * short len if it's less than 128 - one byte giving the len,
+        * with bit 8 0.
+        */
+
+       if ( len <= 0x7F )
+               return( 1 );
+
+       /*
+        * long len otherwise - one byte with bit 8 set, giving the
+        * length of the length, followed by the length itself.
+        */
+
+       if ( len <= 0xFF )
+               return( 2 );
+       if ( len <= 0xFFFFL )
+               return( 3 );
+       if ( len <= 0xFFFFFFL )
+               return( 4 );
+
+       return( 5 );
+}
+
+static int
+ber_put_len( BerElement *ber, unsigned long len, int nosos )
+{
+       int             i;
+       char            lenlen;
+       long            mask;
+       unsigned long   netlen;
+
+       /*
+        * short len if it's less than 128 - one byte giving the len,
+        * with bit 8 0.
+        */
+
+       if ( len <= 127 ) {
+               netlen = LBER_HTONL( len );
+               return( ber_write( ber, (char *) &netlen + sizeof(long) - 1,
+                   1, nosos ) );
+       }
+
+       /*
+        * long len otherwise - one byte with bit 8 set, giving the
+        * length of the length, followed by the length itself.
+        */
+
+       /* find the first non-all-zero byte */
+       for ( i = sizeof(long) - 1; i > 0; i-- ) {
+               mask = (0xffL << (i * 8));
+               /* not all zero */
+               if ( len & mask )
+                       break;
+       }
+       lenlen = ++i;
+       if ( lenlen > 4 )
+               return( -1 );
+       lenlen |= 0x80;
+
+       /* write the length of the length */
+       if ( ber_write( ber, &lenlen, 1, nosos ) != 1 )
+               return( -1 );
+
+       /* write the length itself */
+       netlen = LBER_HTONL( len );
+       if ( ber_write( ber, (char *) &netlen + (sizeof(long) - i), i, nosos )
+           != i )
+               return( -1 );
+
+       return( i + 1 );
+}
+
+static int
+ber_put_int_or_enum( BerElement *ber, long num, unsigned long tag )
+{
+       int     i, sign, taglen;
+       int     len, lenlen;
+       long    netnum, mask;
+
+       sign = (num < 0);
+
+       /*
+        * high bit is set - look for first non-all-one byte
+        * high bit is clear - look for first non-all-zero byte
+        */
+       for ( i = sizeof(long) - 1; i > 0; i-- ) {
+               mask = (0xffL << (i * 8));
+
+               if ( sign ) {
+                       /* not all ones */
+                       if ( (num & mask) != mask )
+                               break;
+               } else {
+                       /* not all zero */
+                       if ( num & mask )
+                               break;
+               }
+       }
+
+       /*
+        * we now have the "leading byte".  if the high bit on this
+        * byte matches the sign bit, we need to "back up" a byte.
+        */
+       mask = (num & (0x80L << (i * 8)));
+       if ( (mask && !sign) || (sign && !mask) )
+               i++;
+
+       len = i + 1;
+
+       if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
+               return( -1 );
+
+       if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 )
+               return( -1 );
+       i++;
+       netnum = LBER_HTONL( num );
+       if ( ber_write( ber, (char *) &netnum + (sizeof(long) - i), i, 0 )
+          != i )
+               return( -1 );
+
+       /* length of tag + length + contents */
+       return( taglen + lenlen + i );
+}
+
+int
+ber_put_enum( BerElement *ber, long num, unsigned long tag )
+{
+       if ( tag == LBER_DEFAULT )
+               tag = LBER_ENUMERATED;
+
+       return( ber_put_int_or_enum( ber, num, tag ) );
+}
+
+int
+ber_put_int( BerElement *ber, long num, unsigned long tag )
+{
+       if ( tag == LBER_DEFAULT )
+               tag = LBER_INTEGER;
+
+       return( ber_put_int_or_enum( ber, num, tag ) );
+}
+
+int
+ber_put_ostring( BerElement *ber, char *str, unsigned long len,
+       unsigned long tag )
+{
+       int     taglen, lenlen, rc;
+#ifdef STR_TRANSLATION
+       int     free_str;
+#endif /* STR_TRANSLATION */
+
+       if ( tag == LBER_DEFAULT )
+               tag = LBER_OCTETSTRING;
+
+       if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
+               return( -1 );
+
+#ifdef STR_TRANSLATION
+       if ( len > 0 && ( ber->ber_options & LBER_TRANSLATE_STRINGS ) != 0 &&
+           ber->ber_encode_translate_proc != NULL ) {
+               if ( (*(ber->ber_encode_translate_proc))( &str, &len, 0 )
+                   != 0 ) {
+                       return( -1 );
+               }
+               free_str = 1;
+       } else {
+               free_str = 0;
+       }
+#endif /* STR_TRANSLATION */
+
+       if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 ||
+               ber_write( ber, str, len, 0 ) != len ) {
+               rc = -1;
+       } else {
+               /* return length of tag + length + contents */
+               rc = taglen + lenlen + len;
+       }
+
+#ifdef STR_TRANSLATION
+       if ( free_str ) {
+               free( str );
+       }
+#endif /* STR_TRANSLATION */
+
+       return( rc );
+}
+
+int
+ber_put_string( BerElement *ber, char *str, unsigned long tag )
+{
+       return( ber_put_ostring( ber, str, strlen( str ), tag ));
+}
+
+int
+ber_put_bitstring( BerElement *ber, char *str,
+       unsigned long blen /* in bits */, unsigned long tag )
+{
+       int             taglen, lenlen, len;
+       unsigned char   unusedbits;
+
+       if ( tag == LBER_DEFAULT )
+               tag = LBER_BITSTRING;
+
+       if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
+               return( -1 );
+
+       len = ( blen + 7 ) / 8;
+       unusedbits = len * 8 - blen;
+       if ( (lenlen = ber_put_len( ber, len + 1, 0 )) == -1 )
+               return( -1 );
+
+       if ( ber_write( ber, (char *)&unusedbits, 1, 0 ) != 1 )
+               return( -1 );
+
+       if ( ber_write( ber, str, len, 0 ) != len )
+               return( -1 );
+
+       /* return length of tag + length + unused bit count + contents */
+       return( taglen + 1 + lenlen + len );
+}
+
+int
+ber_put_null( BerElement *ber, unsigned long tag )
+{
+       int     taglen;
+
+       if ( tag == LBER_DEFAULT )
+               tag = LBER_NULL;
+
+       if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
+               return( -1 );
+
+       if ( ber_put_len( ber, 0, 0 ) != 1 )
+               return( -1 );
+
+       return( taglen + 1 );
+}
+
+int
+ber_put_boolean( BerElement *ber, int boolval, unsigned long tag )
+{
+       int             taglen;
+       unsigned char   trueval = 0xff;
+       unsigned char   falseval = 0x00;
+
+       if ( tag == LBER_DEFAULT )
+               tag = LBER_BOOLEAN;
+
+       if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
+               return( -1 );
+
+       if ( ber_put_len( ber, 1, 0 ) != 1 )
+               return( -1 );
+
+       if ( ber_write( ber, (char *)(boolval ? &trueval : &falseval), 1, 0 )
+           != 1 )
+               return( -1 );
+
+       return( taglen + 2 );
+}
+
+#define FOUR_BYTE_LEN  5
+
+static int
+ber_start_seqorset( BerElement *ber, unsigned long tag )
+{
+       Seqorset        *new;
+
+       if ( (new = (Seqorset *) calloc( sizeof(Seqorset), 1 ))
+           == NULLSEQORSET )
+               return( -1 );
+       new->sos_ber = ber;
+       if ( ber->ber_sos == NULLSEQORSET )
+               new->sos_first = ber->ber_ptr;
+       else
+               new->sos_first = ber->ber_sos->sos_ptr;
+
+       /* Set aside room for a 4 byte length field */
+       new->sos_ptr = new->sos_first + ber_calc_taglen( tag ) + FOUR_BYTE_LEN;
+       new->sos_tag = tag;
+
+       new->sos_next = ber->ber_sos;
+       ber->ber_sos = new;
+
+       return( 0 );
+}
+
+int
+ber_start_seq( BerElement *ber, unsigned long tag )
+{
+       if ( tag == LBER_DEFAULT )
+               tag = LBER_SEQUENCE;
+
+       return( ber_start_seqorset( ber, tag ) );
+}
+
+int
+ber_start_set( BerElement *ber, unsigned long tag )
+{
+       if ( tag == LBER_DEFAULT )
+               tag = LBER_SET;
+
+       return( ber_start_seqorset( ber, tag ) );
+}
+
+static int
+ber_put_seqorset( BerElement *ber )
+{
+       unsigned long   len, netlen;
+       int             taglen, lenlen;
+       unsigned char   ltag = 0x80 + FOUR_BYTE_LEN - 1;
+       Seqorset        *next;
+       Seqorset        **sos = &ber->ber_sos;
+
+       /*
+        * If this is the toplevel sequence or set, we need to actually
+        * write the stuff out.  Otherwise, it's already been put in
+        * the appropriate buffer and will be written when the toplevel
+        * one is written.  In this case all we need to do is update the
+        * length and tag.
+        */
+
+       len = (*sos)->sos_clen;
+       netlen = LBER_HTONL( len );
+       if ( sizeof(long) > 4 && len > 0xFFFFFFFFL )
+               return( -1 );
+
+       if ( ber->ber_options & LBER_USE_DER ) {
+               lenlen = ber_calc_lenlen( len );
+       } else {
+               lenlen = FOUR_BYTE_LEN;
+       }
+
+       if ( (next = (*sos)->sos_next) == NULLSEQORSET ) {
+               /* write the tag */
+               if ( (taglen = ber_put_tag( ber, (*sos)->sos_tag, 1 )) == -1 )
+                       return( -1 );
+
+               if ( ber->ber_options & LBER_USE_DER ) {
+                       /* Write the length in the minimum # of octets */
+                       if ( ber_put_len( ber, len, 1 ) == -1 )
+                               return( -1 );
+
+                       if (lenlen != FOUR_BYTE_LEN) {
+                               /*
+                                * We set aside FOUR_BYTE_LEN bytes for
+                                * the length field.  Move the data if
+                                * we don't actually need that much
+                                */
+                               SAFEMEMCPY( (*sos)->sos_first + taglen +
+                                   lenlen, (*sos)->sos_first + taglen +
+                                   FOUR_BYTE_LEN, len );
+                       }
+               } else {
+                       /* Fill FOUR_BYTE_LEN bytes for length field */
+                       /* one byte of length length */
+                       if ( ber_write( ber, (char *)&ltag, 1, 1 ) != 1 )
+                               return( -1 );
+
+                       /* the length itself */
+                       if ( ber_write( ber, (char *) &netlen + sizeof(long)
+                           - (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1, 1 )
+                           != FOUR_BYTE_LEN - 1 )
+                               return( -1 );
+               }
+               /* The ber_ptr is at the set/seq start - move it to the end */
+               (*sos)->sos_ber->ber_ptr += len;
+       } else {
+               unsigned long   ntag;
+
+               /* the tag */
+               taglen = ber_calc_taglen( (*sos)->sos_tag );
+               ntag = LBER_HTONL( (*sos)->sos_tag );
+               SAFEMEMCPY( (*sos)->sos_first, (char *) &ntag +
+                   sizeof(long) - taglen, taglen );
+
+               if ( ber->ber_options & LBER_USE_DER ) {
+                       ltag = (lenlen == 1) ? len : 0x80 + (lenlen - 1);
+               }
+
+               /* one byte of length length */
+               SAFEMEMCPY( (*sos)->sos_first + 1, &ltag, 1 );
+
+               if ( ber->ber_options & LBER_USE_DER ) {
+                       if (lenlen > 1) {
+                               /* Write the length itself */
+                               SAFEMEMCPY( (*sos)->sos_first + 2,
+                                   (char *)&netlen + sizeof(unsigned long) -
+                                   (lenlen - 1),
+                                   lenlen - 1 );
+                       }
+                       if (lenlen != FOUR_BYTE_LEN) {
+                               /*
+                                * We set aside FOUR_BYTE_LEN bytes for
+                                * the length field.  Move the data if
+                                * we don't actually need that much
+                                */
+                               SAFEMEMCPY( (*sos)->sos_first + taglen +
+                                   lenlen, (*sos)->sos_first + taglen +
+                                   FOUR_BYTE_LEN, len );
+                       }
+               } else {
+                       /* the length itself */
+                       SAFEMEMCPY( (*sos)->sos_first + taglen + 1,
+                           (char *) &netlen + sizeof(long) -
+                           (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1 );
+               }
+
+               next->sos_clen += (taglen + lenlen + len);
+               next->sos_ptr += (taglen + lenlen + len);
+       }
+
+       /* we're done with this seqorset, so free it up */
+       free( (char *) (*sos) );
+       *sos = next;
+
+       return( taglen + lenlen + len );
+}
+
+int
+ber_put_seq( BerElement *ber )
+{
+       return( ber_put_seqorset( ber ) );
+}
+
+int
+ber_put_set( BerElement *ber )
+{
+       return( ber_put_seqorset( ber ) );
+}
+
+/* VARARGS */
+int
+ber_printf(
+#if defined( MACOS ) || defined( _WIN32 ) || defined( BC31 )
+       BerElement *ber, char *fmt, ... )
+#else /* MACOS || _WIN32 || BC31 */
+       va_alist )
+va_dcl
+#endif /* MACOS || _WIN32 || BC31 */
+{
+       va_list         ap;
+#if !defined( MACOS ) && !defined( _WIN32 ) && !defined( BC31 )
+       BerElement      *ber;
+       char            *fmt;
+#endif /* !MACOS && !_WIN32 && !BC31 */
+       char            *s, **ss;
+       struct berval   **bv;
+       int             rc, i;
+       unsigned long   len;
+
+#if defined( MACOS ) || defined( _WIN32 ) || defined( BC31 )
+       va_start( ap, fmt );
+#else /* MACOS || _WIN32 || BC31 */
+       va_start( ap );
+       ber = va_arg( ap, BerElement * );
+       fmt = va_arg( ap, char * );
+#endif /* MACOS || _WIN32 || BC31 */
+
+       for ( rc = 0; *fmt && rc != -1; fmt++ ) {
+               switch ( *fmt ) {
+               case 'b':       /* boolean */
+                       i = va_arg( ap, int );
+                       rc = ber_put_boolean( ber, i, ber->ber_tag );
+                       break;
+
+               case 'i':       /* int */
+                       i = va_arg( ap, int );
+                       rc = ber_put_int( ber, i, ber->ber_tag );
+                       break;
+
+               case 'e':       /* enumeration */
+                       i = va_arg( ap, int );
+                       rc = ber_put_enum( ber, i, ber->ber_tag );
+                       break;
+
+               case 'n':       /* null */
+                       rc = ber_put_null( ber, ber->ber_tag );
+                       break;
+
+               case 'o':       /* octet string (non-null terminated) */
+                       s = va_arg( ap, char * );
+                       len = va_arg( ap, int );
+                       rc = ber_put_ostring( ber, s, len, ber->ber_tag );
+                       break;
+
+               case 's':       /* string */
+                       s = va_arg( ap, char * );
+                       rc = ber_put_string( ber, s, ber->ber_tag );
+                       break;
+
+               case 'B':       /* bit string */
+                       s = va_arg( ap, char * );
+                       len = va_arg( ap, int );        /* in bits */
+                       rc = ber_put_bitstring( ber, s, len, ber->ber_tag );
+                       break;
+
+               case 't':       /* tag for the next element */
+                       ber->ber_tag = va_arg( ap, unsigned long );
+                       ber->ber_usertag = 1;
+                       break;
+
+               case 'v':       /* vector of strings */
+                       if ( (ss = va_arg( ap, char ** )) == NULL )
+                               break;
+                       for ( i = 0; ss[i] != NULL; i++ ) {
+                               if ( (rc = ber_put_string( ber, ss[i],
+                                   ber->ber_tag )) == -1 )
+                                       break;
+                       }
+                       break;
+
+               case 'V':       /* sequences of strings + lengths */
+                       if ( (bv = va_arg( ap, struct berval ** )) == NULL )
+                               break;
+                       for ( i = 0; bv[i] != NULL; i++ ) {
+                               if ( (rc = ber_put_ostring( ber, bv[i]->bv_val,
+                                   bv[i]->bv_len, ber->ber_tag )) == -1 )
+                                       break;
+                       }
+                       break;
+
+               case '{':       /* begin sequence */
+                       rc = ber_start_seq( ber, ber->ber_tag );
+                       break;
+
+               case '}':       /* end sequence */
+                       rc = ber_put_seqorset( ber );
+                       break;
+
+               case '[':       /* begin set */
+                       rc = ber_start_set( ber, ber->ber_tag );
+                       break;
+
+               case ']':       /* end set */
+                       rc = ber_put_seqorset( ber );
+                       break;
+
+               default:
+#ifndef NO_USERINTERFACE
+                       fprintf( stderr, "unknown fmt %c\n", *fmt );
+#endif /* NO_USERINTERFACE */
+                       rc = -1;
+                       break;
+               }
+
+               if ( ber->ber_usertag == 0 )
+                       ber->ber_tag = LBER_DEFAULT;
+               else
+                       ber->ber_usertag = 0;
+       }
+
+       va_end( ap );
+
+       return( rc );
+}
diff --git a/libraries/liblber/etest.c b/libraries/liblber/etest.c
new file mode 100644 (file)
index 0000000..50ac00d
--- /dev/null
@@ -0,0 +1,166 @@
+/* test.c - lber encoding test program */
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#ifdef MACOS
+#include <stdlib.h>
+#include <unix.h>
+#include <fcntl.h>
+#include <console.h>
+#else /* MACOS */
+#include <sys/types.h>
+#include <sys/socket.h>
+#endif /* MACOS */
+#include "lber.h"
+
+static usage( char *name )
+{
+       fprintf( stderr, "usage: %s fmtstring\n", name );
+}
+
+main( int argc, char **argv )
+{
+       int             i, num, len;
+       char            *s, *p;
+       Seqorset        *sos = NULLSEQORSET;
+       BerElement      *ber;
+       Sockbuf         sb;
+       extern char     *optarg;
+
+       if ( argc < 2 ) {
+               usage( argv[0] );
+               exit( 1 );
+       }
+
+       bzero( &sb, sizeof(sb) );
+       sb.sb_sd = 1;
+       sb.sb_ber.ber_buf = NULL;
+
+#ifdef MACOS
+       ccommand( &argv );
+       cshow( stdout );
+
+       if (( sb.sb_sd = open( "lber-test", O_WRONLY|O_CREAT|O_TRUNC|O_BINARY ))
+               < 0 ) {
+           perror( "open" );
+           exit( 1 );
+       }
+#endif /* MACOS */
+
+       if ( (ber = ber_alloc()) == NULLBER ) {
+               perror( "ber_alloc" );
+               exit( 1 );
+       }
+
+       num = 7;
+       if ( ber_printf( ber, "{ti}", 0x1f44, num ) == -1 ) {
+               fprintf( stderr, "ber_printf returns -1" );
+               exit( 1 );
+       }
+
+       if ( ber_flush( &sb, ber, 1 ) == -1 ) {
+               perror( "ber_flush" );
+               exit( 1 );
+       }
+#ifdef notdef
+       for ( s = argv[1]; *s; s++ ) {
+               if ( fgets( buf, sizeof(buf), stdin ) == NULL )
+                       break;
+               if ( (p = strchr( buf, '\n' )) != NULL )
+                       *p = '\0';
+
+               switch ( *s ) {
+               case 'i':       /* int */
+               case 'b':       /* boolean */
+                       i = atoi( buf );
+                       if ( ber_printf( ber, "i", i ) == -1 ) {
+                               fprintf( stderr, "ber_printf i\n" );
+                               exit( 1 );
+                       }
+                       break;
+
+               case 'e':       /* enumeration */
+                       i = va_arg( ap, int );
+                       rc = ber_put_enum( ber, i, (char)ber->ber_tag );
+                       break;
+
+               case 'n':       /* null */
+                       rc = ber_put_null( ber, (char)ber->ber_tag );
+                       break;
+
+               case 'o':       /* octet string (non-null terminated) */
+                       s = va_arg( ap, char * );
+                       len = va_arg( ap, int );
+                       rc = ber_put_ostring( ber, s, len, (char)ber->ber_tag );
+                       break;
+
+               case 's':       /* string */
+                       s = va_arg( ap, char * );
+                       rc = ber_put_string( ber, s, (char)ber->ber_tag );
+                       break;
+
+               case 'B':       /* bit string */
+                       s = va_arg( ap, char * );
+                       len = va_arg( ap, int );        /* in bits */
+                       rc = ber_put_bitstring( ber, s, len, (char)ber->ber_tag );
+                       break;
+
+               case 't':       /* tag for the next element */
+                       ber->ber_tag = va_arg( ap, int );
+                       ber->ber_usertag = 1;
+                       break;
+
+               case 'v':       /* vector of strings */
+                       if ( (ss = va_arg( ap, char ** )) == NULL )
+                               break;
+                       for ( i = 0; ss[i] != NULL; i++ ) {
+                               if ( (rc = ber_put_string( ber, ss[i],
+                                   (char)ber->ber_tag )) == -1 )
+                                       break;
+                       }
+                       break;
+
+               case 'V':       /* sequences of strings + lengths */
+                       if ( (bv = va_arg( ap, struct berval ** )) == NULL )
+                               break;
+                       for ( i = 0; bv[i] != NULL; i++ ) {
+                               if ( (rc = ber_put_ostring( ber, bv[i]->bv_val,
+                                   bv[i]->bv_len, (char)ber->ber_tag )) == -1 )
+                                       break;
+                       }
+                       break;
+
+               case '{':       /* begin sequence */
+                       rc = ber_start_seq( ber, (char)ber->ber_tag );
+                       break;
+
+               case '}':       /* end sequence */
+                       rc = ber_put_seqorset( ber );
+                       break;
+
+               case '[':       /* begin set */
+                       rc = ber_start_set( ber, (char)ber->ber_tag );
+                       break;
+
+               case ']':       /* end set */
+                       rc = ber_put_seqorset( ber );
+                       break;
+
+               default:
+#ifndef NO_USERINTERFACE
+                       fprintf( stderr, "unknown fmt %c\n", *fmt );
+#endif /* NO_USERINTERFACE */
+                       rc = -1;
+                       break;
+               }
+               }
+       }
+
+#endif
+
+       return( 0 );
+}
diff --git a/libraries/liblber/idtest.c b/libraries/liblber/idtest.c
new file mode 100644 (file)
index 0000000..1ad58fa
--- /dev/null
@@ -0,0 +1,62 @@
+/* idtest.c - ber decoding test program using isode libraries */
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <psap.h>
+#include <quipu/attr.h>
+
+static usage( char *name )
+{
+       fprintf( stderr, "usage: %s\n", name );
+}
+
+main( int argc, char **argv )
+{
+       PE      pe;
+       PS      psin, psout, pserr;
+
+       /* read the pe from standard in */
+       if ( (psin = ps_alloc( std_open )) == NULLPS ) {
+               perror( "ps_alloc" );
+               exit( 1 );
+       }
+       if ( std_setup( psin, stdin ) == NOTOK ) {
+               perror( "std_setup" );
+               exit( 1 );
+       }
+       /* write the pe to standard out */
+       if ( (psout = ps_alloc( std_open )) == NULLPS ) {
+               perror( "ps_alloc" );
+               exit( 1 );
+       }
+       if ( std_setup( psout, stdout ) == NOTOK ) {
+               perror( "std_setup" );
+               exit( 1 );
+       }
+       /* pretty print it to standard error */
+       if ( (pserr = ps_alloc( std_open )) == NULLPS ) {
+               perror( "ps_alloc" );
+               exit( 1 );
+       }
+       if ( std_setup( pserr, stderr ) == NOTOK ) {
+               perror( "std_setup" );
+               exit( 1 );
+       }
+
+       while ( (pe = ps2pe( psin )) != NULLPE ) {
+               pe2pl( pserr, pe );
+               pe2ps( psout, pe );
+       }
+
+       exit( 0 );
+}
diff --git a/libraries/liblber/io.c b/libraries/liblber/io.c
new file mode 100644 (file)
index 0000000..081f386
--- /dev/null
@@ -0,0 +1,601 @@
+/* io.c - ber general i/o routines */
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+
+#if defined( DOS ) || defined( _WIN32 )
+#include "msdos.h"
+#endif /* DOS || _WIN32 */
+
+#ifdef MACOS
+#include <stdlib.h>
+#include "macos.h"
+#else /* MACOS */
+#if defined(NeXT) || defined(VMS)
+#include <stdlib.h>
+#else /* next || vms */
+#include <malloc.h>
+#endif /* next || vms */
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#ifdef PCNFS
+#include <tklib.h>
+#endif /* PCNFS */
+#endif /* MACOS */
+
+#ifndef VMS
+#include <memory.h>
+#endif
+#include <string.h>
+#include "lber.h"
+
+#ifdef _WIN32
+#include <winsock.h>
+#include <io.h>
+#endif /* _WIN32 */
+
+#ifdef NEEDPROTOS
+static int ber_realloc( BerElement *ber, unsigned long len );
+static int ber_filbuf( Sockbuf *sb, long len );
+static long BerRead( Sockbuf *sb, char *buf, long len );
+#ifdef PCNFS
+static int BerWrite( Sockbuf *sb, char *buf, long len );
+#endif /* PCNFS */
+#else
+int ber_filbuf();
+long BerRead();
+static int ber_realloc();
+#endif /* NEEDPROTOS */
+
+#define bergetc( sb, len )    ( sb->sb_ber.ber_end > sb->sb_ber.ber_ptr ? \
+                         (unsigned char)*sb->sb_ber.ber_ptr++ : \
+                         ber_filbuf( sb, len ))
+
+#ifdef MACOS
+/*
+ * MacTCP/OpenTransport
+ */
+#define read( s, b, l ) tcpread( s, 0, (unsigned char *)b, l, NULL )
+#define MAX_WRITE      65535
+#define BerWrite( sb, b, l )   tcpwrite( sb->sb_sd, (unsigned char *)(b), (l<MAX_WRITE)? l : MAX_WRITE )
+#else /* MACOS */
+#ifdef DOS
+#ifdef PCNFS
+/*
+ * PCNFS (under DOS)
+ */
+#define read( s, b, l ) recv( s, b, l, 0 )
+#define BerWrite( s, b, l ) send( s->sb_sd, b, (int) l, 0 )
+#endif /* PCNFS */
+#ifdef NCSA
+/*
+ * NCSA Telnet TCP/IP stack (under DOS)
+ */
+#define read( s, b, l ) nread( s, b, l )
+#define BerWrite( s, b, l ) netwrite( s->sb_sd, b, l )
+#endif /* NCSA */
+#ifdef WINSOCK
+/*
+ * Windows Socket API (under DOS/Windows 3.x)
+ */
+#define read( s, b, l ) recv( s, b, l, 0 )
+#define BerWrite( s, b, l ) send( s->sb_sd, b, l, 0 )
+#endif /* WINSOCK */
+#else /* DOS */
+#ifdef _WIN32
+/*
+ * 32-bit Windows Socket API (under Windows NT or Windows 95)
+ */
+#define read( s, b, l )                recv( s, b, l, 0 )
+#define BerWrite( s, b, l )    send( s->sb_sd, b, l, 0 )
+#else /* _WIN32 */
+#ifdef VMS
+/*
+ * VMS -- each write must be 64K or smaller
+ */
+#define MAX_WRITE 65535
+#define BerWrite( sb, b, l ) write( sb->sb_sd, b, (l<MAX_WRITE)? l : MAX_WRITE)
+#else /* VMS */
+/*
+ * everything else (Unix/BSD 4.3 socket API)
+ */
+#define BerWrite( sb, b, l )   write( sb->sb_sd, b, l )
+#endif /* VMS */
+#define udp_read( sb, b, l, al ) recvfrom(sb->sb_sd, (char *)b, l, 0, \
+               (struct sockaddr *)sb->sb_fromaddr, \
+               (al = sizeof(struct sockaddr), &al))
+#define udp_write( sb, b, l ) sendto(sb->sb_sd, (char *)(b), l, 0, \
+               (struct sockaddr *)sb->sb_useaddr, sizeof(struct sockaddr))
+#endif /* _WIN32 */
+#endif /* DOS */
+#endif /* MACOS */
+
+#ifndef udp_read
+#define udp_read( sb, b, l, al )       CLDAP NOT SUPPORTED
+#define udp_write( sb, b, l )          CLDAP NOT SUPPORTED
+#endif /* udp_read */
+
+#define EXBUFSIZ       1024
+
+int
+ber_filbuf( Sockbuf *sb, long len )
+{
+       short   rc;
+#ifdef CLDAP
+       int     addrlen;
+#endif /* CLDAP */
+
+       if ( sb->sb_ber.ber_buf == NULL ) {
+               if ( (sb->sb_ber.ber_buf = (char *) malloc( READBUFSIZ )) ==
+                   NULL )
+                       return( -1 );
+               sb->sb_ber.ber_ptr = sb->sb_ber.ber_buf;
+               sb->sb_ber.ber_end = sb->sb_ber.ber_buf;
+       }
+
+       if ( sb->sb_naddr > 0 ) {
+#ifdef CLDAP
+               rc = udp_read(sb, sb->sb_ber.ber_buf, READBUFSIZ, addrlen );
+#ifdef LDAP_DEBUG
+               if ( lber_debug ) {
+                       fprintf( stderr, "ber_filbuf udp_read %d bytes\n",
+                               rc );
+                       if ( lber_debug > 1 && rc > 0 )
+                               lber_bprint( sb->sb_ber.ber_buf, rc );
+               }
+#endif /* LDAP_DEBUG */
+#else /* CLDAP */
+               rc = -1;
+#endif /* CLDAP */
+       } else {
+               rc = read( sb->sb_sd, sb->sb_ber.ber_buf,
+                   ((sb->sb_options & LBER_NO_READ_AHEAD) &&
+                   (len < READBUFSIZ)) ?
+                   len : READBUFSIZ );
+       }
+
+       if ( rc > 0 ) {
+               sb->sb_ber.ber_ptr = sb->sb_ber.ber_buf + 1;
+               sb->sb_ber.ber_end = sb->sb_ber.ber_buf + rc;
+               return( (unsigned char)*sb->sb_ber.ber_buf );
+       }
+
+       return( -1 );
+}
+
+
+long
+BerRead( Sockbuf *sb, char *buf, long len )
+{
+       int     c;
+       long    nread = 0;
+
+       while ( len > 0 ) {
+               if ( (c = bergetc( sb, len )) < 0 ) {
+                       if ( nread > 0 )
+                               break;
+                       return( c );
+               }
+               *buf++ = c;
+               nread++;
+               len--;
+       }
+
+       return( nread );
+}
+
+
+long
+ber_read( BerElement *ber, char *buf, unsigned long len )
+{
+       unsigned long   actuallen, nleft;
+
+       nleft = ber->ber_end - ber->ber_ptr;
+       actuallen = nleft < len ? nleft : len;
+
+       SAFEMEMCPY( buf, ber->ber_ptr, (size_t)actuallen );
+
+       ber->ber_ptr += actuallen;
+
+       return( (long)actuallen );
+}
+
+long
+ber_write( BerElement *ber, char *buf, unsigned long len, int nosos )
+{
+       if ( nosos || ber->ber_sos == NULL ) {
+               if ( ber->ber_ptr + len > ber->ber_end ) {
+                       if ( ber_realloc( ber, len ) != 0 )
+                               return( -1 );
+               }
+               SAFEMEMCPY( ber->ber_ptr, buf, (size_t)len );
+               ber->ber_ptr += len;
+               return( len );
+       } else {
+               if ( ber->ber_sos->sos_ptr + len > ber->ber_end ) {
+                       if ( ber_realloc( ber, len ) != 0 )
+                               return( -1 );
+               }
+               SAFEMEMCPY( ber->ber_sos->sos_ptr, buf, (size_t)len );
+               ber->ber_sos->sos_ptr += len;
+               ber->ber_sos->sos_clen += len;
+               return( len );
+       }
+}
+
+static int
+ber_realloc( BerElement *ber, unsigned long len )
+{
+       unsigned long   need, have, total;
+       Seqorset        *s;
+       long            off;
+       char            *oldbuf;
+
+       have = (ber->ber_end - ber->ber_buf) / EXBUFSIZ;
+       need = (len < EXBUFSIZ ? 1 : (len + (EXBUFSIZ - 1)) / EXBUFSIZ);
+       total = have * EXBUFSIZ + need * EXBUFSIZ;
+
+       oldbuf = ber->ber_buf;
+
+       if ( ber->ber_buf == NULL ) {
+               if ( (ber->ber_buf = (char *) malloc( (size_t)total )) == NULL )
+                       return( -1 );
+       } else if ( (ber->ber_buf = (char *) realloc( ber->ber_buf,
+           (size_t)total )) == NULL )
+               return( -1 );
+
+       ber->ber_end = ber->ber_buf + total;
+
+       /*
+        * If the stinking thing was moved, we need to go through and
+        * reset all the sos and ber pointers.  Offsets would've been
+        * a better idea... oh well.
+        */
+
+       if ( ber->ber_buf != oldbuf ) {
+               ber->ber_ptr = ber->ber_buf + (ber->ber_ptr - oldbuf);
+
+               for ( s = ber->ber_sos; s != NULLSEQORSET; s = s->sos_next ) {
+                       off = s->sos_first - oldbuf;
+                       s->sos_first = ber->ber_buf + off;
+
+                       off = s->sos_ptr - oldbuf;
+                       s->sos_ptr = ber->ber_buf + off;
+               }
+       }
+
+       return( 0 );
+}
+
+void
+ber_free( BerElement *ber, int freebuf )
+{
+       if ( freebuf && ber->ber_buf != NULL )
+               free( ber->ber_buf );
+       free( (char *) ber );
+}
+
+int
+ber_flush( Sockbuf *sb, BerElement *ber, int freeit )
+{
+       long    nwritten, towrite, rc;
+
+       if ( ber->ber_rwptr == NULL ) {
+               ber->ber_rwptr = ber->ber_buf;
+       }
+       towrite = ber->ber_ptr - ber->ber_rwptr;
+
+#ifdef LDAP_DEBUG
+       if ( lber_debug ) {
+               fprintf( stderr, "ber_flush: %ld bytes to sd %ld%s\n", towrite,
+                   sb->sb_sd, ber->ber_rwptr != ber->ber_buf ? " (re-flush)"
+                   : "" );
+               if ( lber_debug > 1 )
+                       lber_bprint( ber->ber_rwptr, towrite );
+       }
+#endif
+#if !defined(MACOS) && !defined(DOS)
+       if ( sb->sb_options & (LBER_TO_FILE | LBER_TO_FILE_ONLY) ) {
+               rc = write( sb->sb_fd, ber->ber_buf, towrite );
+               if ( sb->sb_options & LBER_TO_FILE_ONLY ) {
+                       return( (int)rc );
+               }
+       }
+#endif
+
+       nwritten = 0;
+       do {
+               if (sb->sb_naddr > 0) {
+#ifdef CLDAP
+                       rc = udp_write( sb, ber->ber_buf + nwritten,
+                           (size_t)towrite );
+#else /* CLDAP */
+                       rc = -1;
+#endif /* CLDAP */
+                       if ( rc <= 0 )
+                               return( -1 );
+                       /* fake error if write was not atomic */
+                       if (rc < towrite) {
+#if !defined( MACOS ) && !defined( DOS )
+                           errno = EMSGSIZE;
+#endif
+                           return( -1 );
+                       }
+               } else {
+                       if ( (rc = BerWrite( sb, ber->ber_rwptr,
+                           (size_t) towrite )) <= 0 ) {
+                               return( -1 );
+                       }
+               }
+               towrite -= rc;
+               nwritten += rc;
+               ber->ber_rwptr += rc;
+       } while ( towrite > 0 );
+
+       if ( freeit )
+               ber_free( ber, 1 );
+
+       return( 0 );
+}
+
+BerElement *
+ber_alloc_t( int options )
+{
+       BerElement      *ber;
+
+       if ( (ber = (BerElement *) calloc( 1, sizeof(BerElement) )) == NULLBER )
+               return( NULLBER );
+       ber->ber_tag = LBER_DEFAULT;
+       ber->ber_options = options;
+
+       return( ber );
+}
+
+BerElement *
+ber_alloc()
+{
+       return( ber_alloc_t( 0 ) );
+}
+
+BerElement *
+der_alloc()
+{
+       return( ber_alloc_t( LBER_USE_DER ) );
+}
+
+BerElement *
+ber_dup( BerElement *ber )
+{
+       BerElement      *new;
+
+       if ( (new = ber_alloc()) == NULLBER )
+               return( NULLBER );
+
+       *new = *ber;
+
+       return( new );
+}
+
+
+void
+ber_init( BerElement *ber, int options )
+{
+       (void) memset( (char *)ber, '\0', sizeof( BerElement ));
+       ber->ber_tag = LBER_DEFAULT;
+       ber->ber_options = options;
+}
+
+
+void
+ber_reset( BerElement *ber, int was_writing )
+{
+       if ( was_writing ) {
+               ber->ber_end = ber->ber_ptr;
+               ber->ber_ptr = ber->ber_buf;
+       } else {
+               ber->ber_ptr = ber->ber_end;
+       }
+
+       ber->ber_rwptr = NULL;
+}
+
+
+#ifdef LDAP_DEBUG
+
+void
+ber_dump( BerElement *ber, int inout )
+{
+       fprintf( stderr, "ber_dump: buf 0x%lx, ptr 0x%lx, end 0x%lx\n",
+           ber->ber_buf, ber->ber_ptr, ber->ber_end );
+       if ( inout == 1 ) {
+               fprintf( stderr, "          current len %ld, contents:\n",
+                   ber->ber_end - ber->ber_ptr );
+               lber_bprint( ber->ber_ptr, ber->ber_end - ber->ber_ptr );
+       } else {
+               fprintf( stderr, "          current len %ld, contents:\n",
+                   ber->ber_ptr - ber->ber_buf );
+               lber_bprint( ber->ber_buf, ber->ber_ptr - ber->ber_buf );
+       }
+}
+
+void
+ber_sos_dump( Seqorset *sos )
+{
+       fprintf( stderr, "*** sos dump ***\n" );
+       while ( sos != NULLSEQORSET ) {
+               fprintf( stderr, "ber_sos_dump: clen %ld first 0x%lx ptr 0x%lx\n",
+                   sos->sos_clen, sos->sos_first, sos->sos_ptr );
+               fprintf( stderr, "              current len %ld contents:\n",
+                   sos->sos_ptr - sos->sos_first );
+               lber_bprint( sos->sos_first, sos->sos_ptr - sos->sos_first );
+
+               sos = sos->sos_next;
+       }
+       fprintf( stderr, "*** end dump ***\n" );
+}
+
+#endif
+
+/* return the tag - LBER_DEFAULT returned means trouble */
+static unsigned long
+get_tag( Sockbuf *sb )
+{
+       unsigned char   xbyte;
+       unsigned long   tag;
+       char            *tagp;
+       int             i;
+
+       if ( BerRead( sb, (char *) &xbyte, 1 ) != 1 )
+               return( LBER_DEFAULT );
+
+       if ( (xbyte & LBER_BIG_TAG_MASK) != LBER_BIG_TAG_MASK )
+               return( (unsigned long) xbyte );
+
+       tagp = (char *) &tag;
+       tagp[0] = xbyte;
+       for ( i = 1; i < sizeof(long); i++ ) {
+               if ( BerRead( sb, (char *) &xbyte, 1 ) != 1 )
+                       return( LBER_DEFAULT );
+
+               tagp[i] = xbyte;
+
+               if ( ! (xbyte & LBER_MORE_TAG_MASK) )
+                       break;
+       }
+
+       /* tag too big! */
+       if ( i == sizeof(long) )
+               return( LBER_DEFAULT );
+
+       /* want leading, not trailing 0's */
+       return( tag >> (sizeof(long) - i - 1) );
+}
+
+unsigned long
+ber_get_next( Sockbuf *sb, unsigned long *len, BerElement *ber )
+{
+       unsigned long   tag, netlen, toread;
+       unsigned char   lc;
+       long            rc;
+       int             noctets, diff;
+
+#ifdef LDAP_DEBUG
+       if ( lber_debug )
+               fprintf( stderr, "ber_get_next\n" );
+#endif
+
+       /*
+        * Any ber element looks like this: tag length contents.
+        * Assuming everything's ok, we return the tag byte (we
+        * can assume a single byte), return the length in len,
+        * and the rest of the undecoded element in buf.
+        *
+        * Assumptions:
+        *      1) small tags (less than 128)
+        *      2) definite lengths
+        *      3) primitive encodings used whenever possible
+        */
+
+       /*
+        * first time through - malloc the buffer, set up ptrs, and
+        * read the tag and the length and as much of the rest as we can
+        */
+
+       if ( ber->ber_rwptr == NULL ) {
+               /*
+                * First, we read the tag.
+                */
+
+               if ( (tag = get_tag( sb )) == LBER_DEFAULT ) {
+                       return( LBER_DEFAULT );
+               }
+               ber->ber_tag = tag;
+
+               /*
+                * Next, read the length.  The first byte contains the length
+                * of the length.  If bit 8 is set, the length is the long
+                * form, otherwise it's the short form.  We don't allow a
+                * length that's greater than what we can hold in an unsigned
+                * long.
+                */
+
+               *len = netlen = 0;
+               if ( BerRead( sb, (char *) &lc, 1 ) != 1 ) {
+                       return( LBER_DEFAULT );
+               }
+               if ( lc & 0x80 ) {
+                       noctets = (lc & 0x7f);
+                       if ( noctets > sizeof(unsigned long) )
+                               return( LBER_DEFAULT );
+                       diff = sizeof(unsigned long) - noctets;
+                       if ( BerRead( sb, (char *) &netlen + diff, noctets ) !=
+                           noctets ) {
+                               return( LBER_DEFAULT );
+                       }
+                       *len = LBER_NTOHL( netlen );
+               } else {
+                       *len = lc;
+               }
+               ber->ber_len = *len;
+
+               /*
+                * Finally, malloc a buffer for the contents and read it in.
+                * It's this buffer that's passed to all the other ber decoding
+                * routines.
+                */
+
+#if defined( DOS ) && !defined( _WIN32 )
+               if ( *len > 65535 ) {   /* DOS can't allocate > 64K */
+                   return( LBER_DEFAULT );
+               }
+#endif /* DOS && !_WIN32 */
+
+               if ( ( sb->sb_options & LBER_MAX_INCOMING_SIZE ) &&
+                   *len > sb->sb_max_incoming ) {
+                       return( LBER_DEFAULT );
+               }
+
+               if ( (ber->ber_buf = (char *) malloc( (size_t)*len )) == NULL ) {
+                       return( LBER_DEFAULT );
+               }
+               ber->ber_ptr = ber->ber_buf;
+               ber->ber_end = ber->ber_buf + *len;
+               ber->ber_rwptr = ber->ber_buf;
+       }
+
+       toread = (unsigned long)ber->ber_end - (unsigned long)ber->ber_rwptr;
+       do {
+               if ( (rc = BerRead( sb, ber->ber_rwptr, (long)toread )) <= 0 ) {
+                       return( LBER_DEFAULT );
+               }
+
+               toread -= rc;
+               ber->ber_rwptr += rc;
+       } while ( toread > 0 );
+
+#ifdef LDAP_DEBUG
+       if ( lber_debug ) {
+               fprintf( stderr, "ber_get_next: tag 0x%lx len %ld contents:\n",
+                   tag, ber->ber_len );
+               if ( lber_debug > 1 )
+                       ber_dump( ber, 1 );
+       }
+#endif
+
+       *len = ber->ber_len;
+       ber->ber_rwptr = NULL;
+       return( ber->ber_tag );
+}
diff --git a/libraries/libldap/Make-template b/libraries/libldap/Make-template
new file mode 100644 (file)
index 0000000..9ca5d7f
--- /dev/null
@@ -0,0 +1,143 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1994 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP library makefile
+#
+#-----------------------------------------------------------------------------
+
+LDAPSRC        = ../..
+
+SRCS   = bind.c open.c result.c error.c compare.c search.c \
+       modify.c add.c modrdn.c delete.c abandon.c ufn.c cache.c \
+       getfilter.c regex.c sbind.c kbind.c unbind.c friendly.c cldap.c \
+       free.c disptmpl.c srchpref.c dsparse.c tmplout.c sort.c \
+       getdn.c getentry.c getattr.c getvalues.c addentry.c \
+       request.c getdxbyname.c os-ip.c url.c charset.c
+OBJS   = bind.o open.o result.o error.o compare.o search.o \
+       modify.o add.o modrdn.o delete.o abandon.o ufn.o cache.o \
+       getfilter.o regex.o sbind.o kbind.o unbind.o friendly.o cldap.o \
+       free.o disptmpl.o srchpref.o dsparse.o tmplout.o sort.o \
+       getdn.o getentry.o getattr.o getvalues.o addentry.o \
+       request.o getdxbyname.o os-ip.o url.o charset.o
+
+HDIR   = ../../include
+
+INCLUDES= -I$(HDIR) $(KRBINCLUDEFLAG)
+DEFINES        = $(DEFS) -DFILTERFILE="\"$(RUNTIMEETCDIR)/ldapfilter.conf\"" \
+       -DTEMPLATEFILE="\"$(RUNTIMEETCDIR)/ldaptemplates.conf\""
+
+CFLAGS = $(INCLUDES) $(DEFINES) $(ACFLAGS)
+LIBS   = -L. -L../liblber -lldap -llber $(KRBLIBFLAG) $(KRBLIBS) $(ALIBS)
+
+all:   libldap.a ltest ttest
+
+libldap.a:     version.o
+       $(AR) ruv $@ $(OBJS) version.o
+       @if [ ! -z "$(RANLIB)" ]; then \
+               $(RANLIB) $@; \
+       fi; \
+       $(RM) ../$@; \
+       $(LN) libldap/$@ ../$@
+
+ltest: libldap.a test.o ../liblber/liblber.a
+       $(CC) $(ALDFLAGS) -o $@ test.o $(LIBS)
+
+ttest: libldap.a tmpltest.o ../liblber/liblber.a
+       $(CC) $(ALDFLAGS) -o $@ tmpltest.o $(LIBS)
+
+version.c:     $(OBJS)
+       $(RM) $@
+       (u=$${USER-root} v=`$(CAT) ../../build/version` d=`$(PWD)` \
+       h=`$(HOSTNAME)` t=`$(DATE)`; $(SED) -e "s|%WHEN%|$${t}|" \
+       -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+       -e "s|%VERSION%|$${v}|" \
+       < Version.c > $@)
+
+install:       libldap.a ldapfilter.conf ldapfriendly ldaptemplates.conf ldapsearchprefs.conf FORCE
+       -$(MKDIR) -p $(LIBDIR)
+       $(INSTALL) $(INSTALLFLAGS) -m 644 libldap.a $(LIBDIR)
+       @if [ ! -z "$(RANLIB)" ]; then \
+               (cd /tmp; $(RANLIB) $(LIBDIR)/libldap.a) \
+       fi
+       -$(MKDIR) -p $(ETCDIR)
+       -$(MV) $(ETCDIR)/ldapfriendly $(ETCDIR)/ldapfriendly-
+       $(INSTALL) $(INSTALLFLAGS) -m 644 ldapfriendly $(ETCDIR)
+       -$(MV) $(ETCDIR)/ldapfilter.conf $(ETCDIR)/ldapfilter.conf-
+       $(INSTALL) $(INSTALLFLAGS) -m 644 ldapfilter.conf $(ETCDIR)
+       -$(MV) $(ETCDIR)/ldaptemplates.conf $(ETCDIR)/ldaptemplates.conf-
+       $(INSTALL) $(INSTALLFLAGS) -m 644 ldaptemplates.conf $(ETCDIR)
+       -$(MV) $(ETCDIR)/ldapsearchprefs.conf $(ETCDIR)/ldapsearchprefs.conf-
+       $(INSTALL) $(INSTALLFLAGS) -m 644 ldapsearchprefs.conf $(ETCDIR)
+
+lint:  FORCE
+       $(LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+5lint: FORCE
+       $(5LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+clean: FORCE
+       $(RM) libldap.a ../libldap.a ltest ttest *.o core a.out *.log version.c
+
+depend:        FORCE
+       $(MKDEP) $(INCLUDES) $(DEFINES) $(SRCS)
+
+links:
+       @$(LN) .src/*.[ch] .src/ldapfriendly .src/ldapfilter.conf \
+               .src/ldaptemplates.conf .src/ldapsearchprefs.conf .
+
+# DO NOT DELETE THIS LINE -- mkdep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+bind.o: bind.c ../../include/lber.h ../../include/ldap.h
+open.o: open.c ../../include/lber.h ../../include/ldap.h ldap-int.h
+result.o: result.c ../../include/portable.h ../../include/lber.h
+result.o: ../../include/ldap.h ldap-int.h
+error.o: error.c ../../include/lber.h ../../include/ldap.h
+compare.o: compare.c ../../include/lber.h ../../include/ldap.h ldap-int.h
+search.o: search.c ../../include/lber.h ../../include/ldap.h ldap-int.h
+modify.o: modify.c ../../include/lber.h ../../include/ldap.h ldap-int.h
+add.o: add.c ../../include/lber.h ../../include/ldap.h ldap-int.h
+modrdn.o: modrdn.c ../../include/lber.h ../../include/ldap.h ldap-int.h
+delete.o: delete.c ../../include/lber.h ../../include/ldap.h ldap-int.h
+abandon.o: abandon.c ../../include/lber.h ../../include/ldap.h ldap-int.h
+ufn.o: ufn.c ../../include/lber.h ../../include/ldap.h
+cache.o: cache.c ../../include/lber.h ../../include/ldap.h ldap-int.h
+getfilter.o: getfilter.c ../../include/lber.h ../../include/ldap.h
+getfilter.o: ../../include/regex.h
+regex.o: regex.c ../../include/portable.h
+sbind.o: sbind.c ../../include/lber.h ../../include/ldap.h ldap-int.h
+kbind.o: kbind.c ../../include/lber.h ../../include/ldap.h ldap-int.h
+unbind.o: unbind.c ../../include/lber.h ../../include/ldap.h ldap-int.h
+friendly.o: friendly.c ../../include/lber.h ../../include/ldap.h
+cldap.o: cldap.c ../../include/lber.h ../../include/ldap.h ldap-int.h
+free.o: free.c ../../include/lber.h ../../include/ldap.h
+disptmpl.o: disptmpl.c ../../include/lber.h ../../include/ldap.h
+disptmpl.o: ../../include/disptmpl.h
+srchpref.o: srchpref.c ../../include/lber.h ../../include/ldap.h
+srchpref.o: ../../include/srchpref.h
+dsparse.o: dsparse.c ../../include/lber.h ../../include/ldap.h
+tmplout.o: tmplout.c ../../include/lber.h ../../include/ldap.h
+tmplout.o: ../../include/disptmpl.h
+sort.o: sort.c ../../include/lber.h ../../include/ldap.h
+getdn.o: getdn.c ../../include/lber.h ../../include/ldap.h
+getentry.o: getentry.c ../../include/lber.h ../../include/ldap.h
+getattr.o: getattr.c ../../include/lber.h ../../include/ldap.h ldap-int.h
+getvalues.o: getvalues.c ../../include/lber.h ../../include/ldap.h
+addentry.o: addentry.c ../../include/lber.h ../../include/ldap.h
+request.o: request.c ../../include/portable.h ../../include/lber.h
+request.o: ../../include/ldap.h ldap-int.h
+getdxbyname.o: getdxbyname.c
+os-ip.o: os-ip.c ../../include/portable.h ../../include/lber.h
+os-ip.o: ../../include/ldap.h
+url.o: url.c ../../include/lber.h ../../include/ldap.h ldap-int.h
+charset.o: charset.c
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/libraries/libldap/Version.c b/libraries/libldap/Version.c
new file mode 100644 (file)
index 0000000..87512f7
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 1991 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+static char Version[] = "  libldap.a v%VERSION% (%WHEN%)\n\t%WHOANDWHERE%\n";
diff --git a/libraries/libldap/abandon.c b/libraries/libldap/abandon.c
new file mode 100644 (file)
index 0000000..1832426
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  abandon.c
+ */
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#if !defined( MACOS ) && !defined( DOS )
+#include <sys/types.h>
+#include <sys/socket.h>
+#endif
+
+#if defined( DOS ) || defined( _WIN32 )
+#include <malloc.h>
+#include "msdos.h"
+#endif /* DOS */
+
+#ifdef MACOS
+#include <stdlib.h>
+#include "macos.h"
+#endif /* MACOS */
+
+#include "lber.h"
+#include "ldap.h"
+#include "ldap-int.h"
+
+#ifdef NEEDPROTOS
+static int do_abandon( LDAP *ld, int origid, int msgid );
+#else /* NEEDPROTOS */
+static int do_abandon();
+#endif /* NEEDPROTOS */
+/*
+ * ldap_abandon - perform an ldap (and X.500) abandon operation. Parameters:
+ *
+ *     ld              LDAP descriptor
+ *     msgid           The message id of the operation to abandon
+ *
+ * ldap_abandon returns 0 if everything went ok, -1 otherwise.
+ *
+ * Example:
+ *     ldap_abandon( ld, msgid );
+ */
+int
+ldap_abandon( LDAP *ld, int msgid )
+{
+       Debug( LDAP_DEBUG_TRACE, "ldap_abandon %d\n", msgid, 0, 0 );
+       return( do_abandon( ld, msgid, msgid ));
+}
+
+
+static int
+do_abandon( LDAP *ld, int origid, int msgid )
+{
+       BerElement      *ber;
+       int             i, err, sendabandon;
+       Sockbuf         *sb;
+#ifdef LDAP_REFERRALS
+       LDAPRequest     *lr;
+#endif /* LDAP_REFERRALS */
+
+       /*
+        * An abandon request looks like this:
+        *      AbandonRequest ::= MessageID
+        */
+
+       Debug( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n",
+               origid, msgid, 0 );
+
+       sendabandon = 1;
+
+#ifdef LDAP_REFERRALS
+       /* find the request that we are abandoning */
+       for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) {
+               if ( lr->lr_msgid == msgid ) {  /* this message */
+                       break;
+               }
+               if ( lr->lr_origid == msgid ) { /* child:  abandon it */
+                       do_abandon( ld, msgid, lr->lr_msgid );
+               }
+       }
+
+       if ( lr != NULL ) {
+               if ( origid == msgid && lr->lr_parent != NULL ) {
+                       /* don't let caller abandon child requests! */
+                       ld->ld_errno = LDAP_PARAM_ERROR;
+                       return( -1 );
+               }
+               if ( lr->lr_status != LDAP_REQST_INPROGRESS ) {
+                       /* no need to send abandon message */
+                       sendabandon = 0;
+               }
+       }
+#endif /* LDAP_REFERRALS */
+
+       if ( ldap_msgdelete( ld, msgid ) == 0 ) {
+               ld->ld_errno = LDAP_SUCCESS;
+               return( 0 );
+       }
+
+       err = 0;
+       if ( sendabandon ) {
+               /* create a message to send */
+               if ( (ber = alloc_ber_with_options( ld )) == NULLBER ) {
+                       err = -1;
+                       ld->ld_errno = LDAP_NO_MEMORY;
+               } else {
+#ifdef CLDAP
+                       if ( ld->ld_sb.sb_naddr > 0 ) {
+                               err = ber_printf( ber, "{isti}",
+                                   ++ld->ld_msgid, ld->ld_cldapdn,
+                                   LDAP_REQ_ABANDON, msgid );
+                       } else {
+#endif /* CLDAP */
+                               err = ber_printf( ber, "{iti}", ++ld->ld_msgid,
+                                   LDAP_REQ_ABANDON, msgid );
+#ifdef CLDAP
+                       }
+#endif /* CLDAP */
+
+                       if ( err == -1 ) {
+                               ld->ld_errno = LDAP_ENCODING_ERROR;
+                               ber_free( ber, 1 );
+                       } else {
+                               /* send the message */
+#ifdef LDAP_REFERRALS
+                               if ( lr != NULL ) {
+                                       sb = lr->lr_conn->lconn_sb;
+                               } else {
+                                       sb = &ld->ld_sb;
+                               }
+#else /* LDAP_REFERRALS */
+                               sb = &ld->ld_sb;
+#endif /* LDAP_REFERRALS */
+                               if ( ber_flush( sb, ber, 1 ) != 0 ) {
+                                       ld->ld_errno = LDAP_SERVER_DOWN;
+                                       err = -1;
+                               } else {
+                                       err = 0;
+                               }
+                       }
+               }
+       }
+
+#ifdef LDAP_REFERRALS
+       if ( lr != NULL ) {
+               if ( sendabandon ) {
+                       free_connection( ld, lr->lr_conn, 0, 1 );
+               }
+               if ( origid == msgid ) {
+                       free_request( ld, lr );
+               }
+       }
+#endif /* LDAP_REFERRALS */
+
+
+       if ( ld->ld_abandoned == NULL ) {
+               if ( (ld->ld_abandoned = (int *) malloc( 2 * sizeof(int) ))
+                   == NULL ) {
+                       ld->ld_errno = LDAP_NO_MEMORY;
+                       return( -1 );
+               }
+               i = 0;
+       } else {
+               for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
+                       ;       /* NULL */
+               if ( (ld->ld_abandoned = (int *) realloc( (char *)
+                   ld->ld_abandoned, (i + 2) * sizeof(int) )) == NULL ) {
+                       ld->ld_errno = LDAP_NO_MEMORY;
+                       return( -1 );
+               }
+       }
+       ld->ld_abandoned[i] = msgid;
+       ld->ld_abandoned[i + 1] = -1;
+
+       if ( err != -1 ) {
+               ld->ld_errno = LDAP_SUCCESS;
+       }
+       return( err );
+}
diff --git a/libraries/libldap/add.c b/libraries/libldap/add.c
new file mode 100644 (file)
index 0000000..b79cd09
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  add.c
+ */
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef MACOS
+#include "macos.h"
+#endif /* MACOS */
+
+#if defined( DOS ) || defined( _WIN32 )
+#include <malloc.h>
+#include "msdos.h"
+#endif /* DOS */
+
+#if !defined( MACOS ) && !defined( DOS )
+#include <sys/types.h>
+#include <sys/socket.h>
+#endif /* !MACOS && !DOS */
+
+#include "lber.h"
+#include "ldap.h"
+#include "ldap-int.h"
+
+/*
+ * ldap_add - initiate an ldap (and X.500) add operation.  Parameters:
+ *
+ *     ld              LDAP descriptor
+ *     dn              DN of the entry to add
+ *     mods            List of attributes for the entry.  This is a null-
+ *                     terminated array of pointers to LDAPMod structures.
+ *                     only the type and values in the structures need be
+ *                     filled in.
+ *
+ * Example:
+ *     LDAPMod *attrs[] = { 
+ *                     { 0, "cn", { "babs jensen", "babs", 0 } },
+ *                     { 0, "sn", { "jensen", 0 } },
+ *                     { 0, "objectClass", { "person", 0 } },
+ *                     0
+ *             }
+ *     msgid = ldap_add( ld, dn, attrs );
+ */
+int
+ldap_add( LDAP *ld, char *dn, LDAPMod **attrs )
+{
+       BerElement      *ber;
+       int             i, rc;
+
+       /*
+        * An add request looks like this:
+        *      AddRequest ::= SEQUENCE {
+        *              entry   DistinguishedName,
+        *              attrs   SEQUENCE OF SEQUENCE {
+        *                      type    AttributeType,
+        *                      values  SET OF AttributeValue
+        *              }
+        *      }
+        */
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_add\n", 0, 0, 0 );
+
+       /* create a message to send */
+       if ( (ber = alloc_ber_with_options( ld )) == NULLBER ) {
+               return( -1 );
+       }
+
+       if ( ber_printf( ber, "{it{s{", ++ld->ld_msgid, LDAP_REQ_ADD, dn )
+           == -1 ) {
+               ld->ld_errno = LDAP_ENCODING_ERROR;
+               ber_free( ber, 1 );
+               return( -1 );
+       }
+
+       /* for each attribute in the entry... */
+       for ( i = 0; attrs[i] != NULL; i++ ) {
+               if ( ( attrs[i]->mod_op & LDAP_MOD_BVALUES) != 0 ) {
+                       rc = ber_printf( ber, "{s[V]}", attrs[i]->mod_type,
+                           attrs[i]->mod_values );
+               } else {
+                       rc = ber_printf( ber, "{s[v]}", attrs[i]->mod_type,
+                           attrs[i]->mod_values );
+               }
+               if ( rc == -1 ) {
+                       ld->ld_errno = LDAP_ENCODING_ERROR;
+                       ber_free( ber, 1 );
+                       return( -1 );
+               }
+       }
+
+       if ( ber_printf( ber, "}}}" ) == -1 ) {
+               ld->ld_errno = LDAP_ENCODING_ERROR;
+               ber_free( ber, 1 );
+               return( -1 );
+       }
+
+       /* send the message */
+       return( send_initial_request( ld, LDAP_REQ_ADD, dn, ber ));
+}
+
+int
+ldap_add_s( LDAP *ld, char *dn, LDAPMod **attrs )
+{
+       int             msgid;
+       LDAPMessage     *res;
+
+       if ( (msgid = ldap_add( ld, dn, attrs )) == -1 )
+               return( ld->ld_errno );
+
+       if ( ldap_result( ld, msgid, 1, (struct timeval *) NULL, &res ) == -1 )
+               return( ld->ld_errno );
+
+       return( ldap_result2error( ld, res, 1 ) );
+}
+
diff --git a/libraries/libldap/addentry.c b/libraries/libldap/addentry.c
new file mode 100644 (file)
index 0000000..a0fc417
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  addentry.c
+ */
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#ifdef MACOS
+#include <stdlib.h>
+#include "macos.h"
+#else /* MACOS */
+#if defined( DOS ) || defined( _WIN32 )
+#include <malloc.h>
+#include "msdos.h"
+#else /* DOS */
+#include <sys/types.h>
+#include <sys/socket.h>
+#endif /* DOS */
+#endif /* MACOS */
+
+#include "lber.h"
+#include "ldap.h"
+
+LDAPMessage *
+ldap_delete_result_entry( LDAPMessage **list, LDAPMessage *e )
+{
+       LDAPMessage     *tmp, *prev = NULL;
+
+       for ( tmp = *list; tmp != NULL && tmp != e; tmp = tmp->lm_chain )
+               prev = tmp;
+
+       if ( tmp == NULL )
+               return( NULL );
+
+       if ( prev == NULL )
+               *list = tmp->lm_chain;
+       else
+               prev->lm_chain = tmp->lm_chain;
+       tmp->lm_chain = NULL;
+
+       return( tmp );
+}
+
+void
+ldap_add_result_entry( LDAPMessage **list, LDAPMessage *e )
+{
+       e->lm_chain = *list;
+       *list = e;
+}
diff --git a/libraries/libldap/bind.c b/libraries/libldap/bind.c
new file mode 100644 (file)
index 0000000..0a04873
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  bind.c
+ */
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef MACOS
+#include <stdlib.h>
+#include "macos.h"
+#else /* MACOS */
+#ifdef DOS
+#include "msdos.h"
+#ifdef NCSA
+#include "externs.h"
+#endif /* NCSA */
+#else /* DOS */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#endif /* DOS */
+#endif /* MACOS */
+
+#include "lber.h"
+#include "ldap.h"
+
+
+/*
+ * ldap_bind - bind to the ldap server (and X.500).  The dn and password
+ * of the entry to which to bind are supplied, along with the authentication
+ * method to use.  The msgid of the bind request is returned on success,
+ * -1 if there's trouble.  Note, the kerberos support assumes the user already
+ * has a valid tgt for now.  ldap_result() should be called to find out the
+ * outcome of the bind request.
+ *
+ * Example:
+ *     ldap_bind( ld, "cn=manager, o=university of michigan, c=us", "secret",
+ *         LDAP_AUTH_SIMPLE )
+ */
+
+int
+ldap_bind( LDAP *ld, char *dn, char *passwd, int authmethod )
+{
+       /*
+        * The bind request looks like this:
+        *      BindRequest ::= SEQUENCE {
+        *              version         INTEGER,
+        *              name            DistinguishedName,       -- who
+        *              authentication  CHOICE {
+        *                      simple          [0] OCTET STRING -- passwd
+#ifdef KERBEROS
+        *                      krbv42ldap      [1] OCTET STRING
+        *                      krbv42dsa       [2] OCTET STRING
+#endif
+        *              }
+        *      }
+        * all wrapped up in an LDAPMessage sequence.
+        */
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_bind\n", 0, 0, 0 );
+
+       switch ( authmethod ) {
+       case LDAP_AUTH_SIMPLE:
+               return( ldap_simple_bind( ld, dn, passwd ) );
+
+#ifdef KERBEROS
+       case LDAP_AUTH_KRBV41:
+               return( ldap_kerberos_bind1( ld, dn ) );
+
+       case LDAP_AUTH_KRBV42:
+               return( ldap_kerberos_bind2( ld, dn ) );
+#endif
+
+       default:
+               ld->ld_errno = LDAP_AUTH_UNKNOWN;
+               return( -1 );
+       }
+}
+
+/*
+ * ldap_bind_s - bind to the ldap server (and X.500).  The dn and password
+ * of the entry to which to bind are supplied, along with the authentication
+ * method to use.  This routine just calls whichever bind routine is
+ * appropriate and returns the result of the bind (e.g. LDAP_SUCCESS or
+ * some other error indication).  Note, the kerberos support assumes the
+ * user already has a valid tgt for now.
+ *
+ * Examples:
+ *     ldap_bind_s( ld, "cn=manager, o=university of michigan, c=us",
+ *         "secret", LDAP_AUTH_SIMPLE )
+ *     ldap_bind_s( ld, "cn=manager, o=university of michigan, c=us",
+ *         NULL, LDAP_AUTH_KRBV4 )
+ */
+int
+ldap_bind_s( LDAP *ld, char *dn, char *passwd, int authmethod )
+{
+       Debug( LDAP_DEBUG_TRACE, "ldap_bind_s\n", 0, 0, 0 );
+
+       switch ( authmethod ) {
+       case LDAP_AUTH_SIMPLE:
+               return( ldap_simple_bind_s( ld, dn, passwd ) );
+
+#ifdef KERBEROS
+       case LDAP_AUTH_KRBV4:
+               return( ldap_kerberos_bind_s( ld, dn ) );
+
+       case LDAP_AUTH_KRBV41:
+               return( ldap_kerberos_bind1_s( ld, dn ) );
+
+       case LDAP_AUTH_KRBV42:
+               return( ldap_kerberos_bind2_s( ld, dn ) );
+#endif
+
+       default:
+               return( ld->ld_errno = LDAP_AUTH_UNKNOWN );
+       }
+}
+
+
+#ifdef LDAP_REFERRALS
+void
+ldap_set_rebind_proc( LDAP *ld, int (*rebindproc)( LDAP *ld, char **dnp,
+       char **passwdp, int *authmethodp, int freeit ))
+{
+       ld->ld_rebindproc = rebindproc;
+}
+#endif /* LDAP_REFERRALS */
diff --git a/libraries/libldap/cache.c b/libraries/libldap/cache.c
new file mode 100644 (file)
index 0000000..197f4fb
--- /dev/null
@@ -0,0 +1,654 @@
+/*
+ *  Copyright (c) 1993 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  cache.c - local caching support for LDAP
+ */
+
+#ifndef NO_CACHE
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1993 The Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef MACOS
+#include <stdlib.h>
+#include <time.h>
+#include "macos.h"
+#else /* MACOS */
+#if defined( DOS ) || defined( _WIN32 )
+#include <malloc.h>
+#include "msdos.h"
+#ifdef NCSA
+#include "externs.h"
+#endif /* NCSA */
+#ifdef WINSOCK
+#include <time.h>
+#endif /* WINSOCK */
+#else /* DOS */
+#include <sys/types.h>
+#include <sys/socket.h>
+#endif /* DOS */
+#endif /* MACOS */
+#include "lber.h"
+#include "ldap.h"
+#include "ldap-int.h"
+
+#ifdef NEEDPROTOS
+static int             cache_hash( BerElement *ber );
+static LDAPMessage     *msg_dup( LDAPMessage *msg );
+static int             request_cmp( BerElement *req1, BerElement *req2 );
+static int             chain_contains_dn( LDAPMessage *msg, char *dn );
+static long            msg_size( LDAPMessage *msg );
+static void            check_cache_memused( LDAPCache *lc );
+static void            uncache_entry_or_req( LDAP *ld, char *dn, int msgid );
+#else /* NEEDPROTOS */
+static int             cache_hash();
+static LDAPMessage     *msg_dup();
+static int             request_cmp();
+static int             chain_contains_dn();
+static long            msg_size();
+static void            check_cache_memused();
+static void            uncache_entry_or_req();
+#endif /* NEEDPROTOS */
+
+
+int
+ldap_enable_cache( LDAP *ld, long timeout, long maxmem )
+{
+       if ( ld->ld_cache == NULLLDCACHE ) {
+               if (( ld->ld_cache = (LDAPCache *)malloc( sizeof( LDAPCache )))
+                   == NULLLDCACHE ) {
+                       ld->ld_errno = LDAP_NO_MEMORY;
+                       return( -1 );
+               }
+               (void) memset( ld->ld_cache, 0, sizeof( LDAPCache ));
+               ld->ld_cache->lc_memused = sizeof( LDAPCache );
+       }
+
+       ld->ld_cache->lc_timeout = timeout;
+       ld->ld_cache->lc_maxmem = maxmem;
+       check_cache_memused( ld->ld_cache );
+       ld->ld_cache->lc_enabled = 1;
+       return( 0 );
+}
+
+
+void
+ldap_disable_cache( LDAP *ld )
+{
+       if ( ld->ld_cache != NULLLDCACHE ) {
+               ld->ld_cache->lc_enabled = 0;
+       }
+}
+
+
+
+void
+ldap_set_cache_options( LDAP *ld, unsigned long opts )
+{
+       if ( ld->ld_cache != NULLLDCACHE ) {
+               ld->ld_cache->lc_options = opts;
+       }
+}
+       
+
+void
+ldap_destroy_cache( LDAP *ld )
+{
+       if ( ld->ld_cache != NULLLDCACHE ) {
+               ldap_flush_cache( ld );
+               free( (char *)ld->ld_cache );
+               ld->ld_cache = NULLLDCACHE;
+       }
+}
+
+
+void
+ldap_flush_cache( LDAP *ld )
+{
+       int             i;
+       LDAPMessage     *m, *next;
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_flush_cache\n", 0, 0, 0 );
+
+       if ( ld->ld_cache != NULLLDCACHE ) {
+               /* delete all requests in the queue */
+               for ( m = ld->ld_cache->lc_requests; m != NULLMSG; m = next ) {
+                       next = m->lm_next;
+                       ldap_msgfree( m );
+               }
+               ld->ld_cache->lc_requests = NULLMSG;
+
+               /* delete all messages in the cache */
+               for ( i = 0; i < LDAP_CACHE_BUCKETS; ++i ) {
+                       for ( m = ld->ld_cache->lc_buckets[ i ];
+                           m != NULLMSG; m = next ) {
+                               next = m->lm_next;
+                               ldap_msgfree( m );
+                       }
+                       ld->ld_cache->lc_buckets[ i ] = NULLMSG;
+               }
+               ld->ld_cache->lc_memused = sizeof( LDAPCache );
+       }
+}
+
+
+void
+ldap_uncache_request( LDAP *ld, int msgid )
+{
+       Debug( LDAP_DEBUG_TRACE, "ldap_uncache_request %d ld_cache %x\n",
+           msgid, ld->ld_cache, 0 );
+
+       uncache_entry_or_req( ld, NULL, msgid );
+}
+
+
+void
+ldap_uncache_entry( LDAP *ld, char *dn )
+{
+       Debug( LDAP_DEBUG_TRACE, "ldap_uncache_entry %s ld_cache %x\n",
+           dn, ld->ld_cache, 0 );
+
+       uncache_entry_or_req( ld, dn, 0 );
+}
+
+
+static void
+uncache_entry_or_req( LDAP *ld,
+       char *dn,               /* if non-NULL, uncache entry */
+       int msgid )             /* request to uncache (if dn == NULL) */
+{
+       int             i;
+       LDAPMessage     *m, *prev, *next;
+
+       Debug( LDAP_DEBUG_TRACE,
+           "ldap_uncache_entry_or_req  dn %s  msgid %d  ld_cache %x\n",
+           dn, msgid, ld->ld_cache );
+
+       if ( ld->ld_cache == NULLLDCACHE ) {
+           return;
+       }
+
+       /* first check the request queue */
+       prev = NULLMSG;
+       for ( m = ld->ld_cache->lc_requests; m != NULLMSG; m = next ) {
+               next = m->lm_next;
+               if (( dn != NULL && chain_contains_dn( m, dn )) ||
+                       ( dn == NULL && m->lm_msgid == msgid )) {
+                       if ( prev == NULLMSG ) {
+                               ld->ld_cache->lc_requests = next;
+                       } else {
+                               prev->lm_next = next;
+                       }
+                       ld->ld_cache->lc_memused -= msg_size( m );
+                       ldap_msgfree( m );
+               } else {
+                       prev = m;
+               }
+       }
+
+       /* now check the rest of the cache */
+       for ( i = 0; i < LDAP_CACHE_BUCKETS; ++i ) {
+               prev = NULLMSG;
+               for ( m = ld->ld_cache->lc_buckets[ i ]; m != NULLMSG;
+                   m = next ) {
+                       next = m->lm_next;
+                       if (( dn != NULL && chain_contains_dn( m, dn )) ||
+                               ( dn == NULL && m->lm_msgid == msgid )) {
+                               if ( prev == NULLMSG ) {
+                                       ld->ld_cache->lc_buckets[ i ] = next;
+                               } else {
+                                       prev->lm_next = next;
+                               }
+                               ld->ld_cache->lc_memused -= msg_size( m );
+                               ldap_msgfree( m );
+                       } else {
+                               prev = m;
+                       }
+               }
+       }
+}
+
+
+void
+add_request_to_cache( LDAP *ld, unsigned long msgtype, BerElement *request )
+{
+       LDAPMessage     *new;
+       long            len;
+
+       Debug( LDAP_DEBUG_TRACE, "add_request_to_cache\n", 0, 0, 0 );
+
+       ld->ld_errno = LDAP_SUCCESS;
+       if ( ld->ld_cache == NULLLDCACHE ||
+           ( ld->ld_cache->lc_enabled == 0 )) {
+               return;
+       }
+
+       if (( new = (LDAPMessage *) calloc( 1, sizeof(LDAPMessage) ))
+           != NULL ) {
+               if (( new->lm_ber = alloc_ber_with_options( ld )) == NULLBER ) {
+                       free( (char *)new );
+                       return;
+               }
+               len = request->ber_ptr - request->ber_buf;
+               if (( new->lm_ber->ber_buf = (char *) malloc( (size_t)len ))
+                   == NULL ) {
+                       ber_free( new->lm_ber, 0 );
+                       free( (char *)new );
+                       ld->ld_errno = LDAP_NO_MEMORY;
+                       return;
+               }
+               SAFEMEMCPY( new->lm_ber->ber_buf, request->ber_buf,
+                   (size_t)len );
+               new->lm_ber->ber_ptr = new->lm_ber->ber_buf;
+               new->lm_ber->ber_end = new->lm_ber->ber_buf + len;
+               new->lm_msgid = ld->ld_msgid;
+               new->lm_msgtype = msgtype;;
+               new->lm_next = ld->ld_cache->lc_requests;
+               ld->ld_cache->lc_requests = new;
+       } else {
+               ld->ld_errno = LDAP_NO_MEMORY;
+       }
+}
+
+
+void
+add_result_to_cache( LDAP *ld, LDAPMessage *result )
+{
+       LDAPMessage     *m, **mp, *req, *new, *prev;
+       int             err, keep;
+
+       Debug( LDAP_DEBUG_TRACE, "add_result_to_cache: id %d, type %d\n", 
+               result->lm_msgid, result->lm_msgtype, 0 );
+
+       if ( ld->ld_cache == NULLLDCACHE ||
+           ( ld->ld_cache->lc_enabled == 0 )) {
+               Debug( LDAP_DEBUG_TRACE, "artc: cache disabled\n", 0, 0, 0 );
+               return;
+       }
+
+       if ( result->lm_msgtype != LDAP_RES_SEARCH_ENTRY &&
+           result->lm_msgtype != LDAP_RES_SEARCH_RESULT &&
+           result->lm_msgtype != LDAP_RES_COMPARE ) {
+               /*
+                * only cache search and compare operations
+                */
+               Debug( LDAP_DEBUG_TRACE,
+                   "artc: only caching search & compare operations\n", 0, 0, 0 );
+               return;
+       }
+
+       /*
+        * if corresponding request is in the lc_requests list, add this
+        * result to it.  if this result completes the results for the
+        * request, add the request/result chain to the cache proper.
+        */
+       prev = NULLMSG;
+       for ( m = ld->ld_cache->lc_requests; m != NULL; m = m->lm_next ) {
+               if ( m->lm_msgid == result->lm_msgid ) {
+                       break;
+               }
+               prev = m;
+       }
+
+       if ( m != NULLMSG ) {   /* found request; add to end of chain */
+               req = m;
+               for ( ; m->lm_chain != NULLMSG; m = m->lm_chain )
+                       ;
+               if (( new = msg_dup( result )) != NULLMSG ) {
+                       new->lm_chain = NULLMSG;
+                       m->lm_chain = new;
+                       Debug( LDAP_DEBUG_TRACE,
+                           "artc: result added to cache request chain\n",
+                           0, 0, 0 );
+               }
+               if ( result->lm_msgtype == LDAP_RES_SEARCH_RESULT ||
+                   result->lm_msgtype == LDAP_RES_COMPARE ) {
+                       /*
+                        * this result completes the chain of results
+                        * add to cache proper if appropriate
+                        */
+                       keep = 0;       /* pessimistic */
+                       err = ldap_result2error( ld, result, 0 );
+                       if ( err == LDAP_SUCCESS ||
+                           ( result->lm_msgtype == LDAP_RES_COMPARE &&
+                           ( err == LDAP_COMPARE_FALSE ||
+                           err == LDAP_COMPARE_TRUE ||
+                           err == LDAP_NO_SUCH_ATTRIBUTE ))) {
+                               keep = 1;
+                       }
+
+                       if ( ld->ld_cache->lc_options == 0 ) {
+                               if ( err == LDAP_SIZELIMIT_EXCEEDED ) {
+                                   keep = 1;
+                               }
+                       } else if (( ld->ld_cache->lc_options &
+                               LDAP_CACHE_OPT_CACHEALLERRS ) != 0 ) {
+                               keep = 1;
+                       }
+
+                       if ( prev == NULLMSG ) {
+                               ld->ld_cache->lc_requests = req->lm_next;
+                       } else {
+                               prev->lm_next = req->lm_next;
+                       }
+
+                       if ( !keep ) {
+                               Debug( LDAP_DEBUG_TRACE,
+                                   "artc: not caching result with error %d\n",
+                                   err, 0, 0 );
+                               ldap_msgfree( req );
+                       } else {
+                               mp = &ld->ld_cache->lc_buckets[
+                                   cache_hash( req->lm_ber ) ];
+                               req->lm_next = *mp;
+                               *mp = req;
+                               req->lm_time = (long) time( NULL );
+                               ld->ld_cache->lc_memused += msg_size( req );
+                               check_cache_memused( ld->ld_cache );
+                               Debug( LDAP_DEBUG_TRACE,
+                                   "artc: cached result with error %d\n",
+                                   err, 0, 0 );
+                       }
+               }
+       } else {
+               Debug( LDAP_DEBUG_TRACE, "artc: msgid not in request list\n",
+                   0, 0, 0 );
+       }
+}
+
+
+/*
+ * look in the cache for this request
+ * return 0 if found, -1 if not
+ * if found, the corresponding result messages are added to the incoming
+ * queue with the correct (new) msgid so that subsequent ldap_result calls
+ * will find them.
+ */
+int
+check_cache( LDAP *ld, unsigned long msgtype, BerElement *request )
+{
+       LDAPMessage     *m, *new, *prev, *next;
+       BerElement      reqber;
+       int             first, hash;
+       unsigned long   validtime;
+
+       Debug( LDAP_DEBUG_TRACE, "check_cache\n", 0, 0, 0 );
+
+       if ( ld->ld_cache == NULLLDCACHE ||
+           ( ld->ld_cache->lc_enabled == 0 )) {
+               return( -1 );
+       }
+
+       reqber.ber_buf = reqber.ber_ptr = request->ber_buf;
+       reqber.ber_end = request->ber_ptr;
+
+       validtime = (long)time( NULL ) - ld->ld_cache->lc_timeout;
+
+       prev = NULLMSG;
+       hash = cache_hash( &reqber );
+       for ( m = ld->ld_cache->lc_buckets[ hash ]; m != NULLMSG; m = next ) {
+               Debug( LDAP_DEBUG_TRACE,"cc: examining id %d,type %d\n",
+                   m->lm_msgid, m->lm_msgtype, 0 );
+               if ( m->lm_time < validtime ) {
+                       /* delete expired message */
+                       next = m->lm_next;
+                       if ( prev == NULL ) {
+                               ld->ld_cache->lc_buckets[ hash ] = next;
+                       } else {
+                               prev->lm_next = next;
+                       }
+                       Debug( LDAP_DEBUG_TRACE, "cc: expired id %d\n",
+                           m->lm_msgid, 0, 0 );
+                       ld->ld_cache->lc_memused -= msg_size( m );
+                       ldap_msgfree( m );
+               } else {
+                   if ( m->lm_msgtype == (int)msgtype &&
+                       request_cmp( m->lm_ber, &reqber ) == 0 ) {
+                           break;
+                   }
+                   next = m->lm_next;
+                   prev = m;
+               }
+       }
+
+       if ( m == NULLMSG ) {
+               return( -1 );
+       }
+
+       /*
+        * add duplicates of responses to incoming queue
+        */
+       first = 1;
+       for ( m = m->lm_chain; m != NULLMSG; m = m->lm_chain ) {
+               if (( new = msg_dup( m )) == NULLMSG ) {
+                       return( -1 );
+               }
+
+               new->lm_msgid = ld->ld_msgid;
+               new->lm_chain = NULLMSG;
+               if ( first ) {
+                       new->lm_next = ld->ld_responses;
+                       ld->ld_responses = new;
+                       first = 0;
+               } else {
+                       prev->lm_chain = new;
+               }
+               prev = new;
+               Debug( LDAP_DEBUG_TRACE, "cc: added type %d\n",
+                   new->lm_msgtype, 0, 0 );
+       }
+
+       Debug( LDAP_DEBUG_TRACE, "cc: result returned from cache\n", 0, 0, 0 );
+       return( 0 );
+}
+
+
+static int
+cache_hash( BerElement *ber )
+{
+       BerElement      bercpy;
+       unsigned long   len;
+
+       /*
+         * just take the length of the packet and mod with # of buckets
+        */
+       bercpy = *ber;
+       if ( ber_skip_tag( &bercpy, &len ) == LBER_ERROR
+               || ber_scanf( &bercpy, "x" ) == LBER_ERROR ) {
+           len = 0;    /* punt: just return zero */
+       } else {
+           len = bercpy.ber_end - bercpy.ber_ptr;
+       }
+
+       Debug( LDAP_DEBUG_TRACE, "cache_hash: len is %ld, returning %ld\n",
+           len, len % LDAP_CACHE_BUCKETS, 0 );
+       return( (int) ( len % LDAP_CACHE_BUCKETS ));
+}
+
+
+static LDAPMessage *
+msg_dup( LDAPMessage *msg )
+{
+       LDAPMessage     *new;
+       long            len;
+
+       if (( new = (LDAPMessage *)malloc( sizeof(LDAPMessage))) != NULL ) {
+               *new = *msg;    /* struct copy */
+               if (( new->lm_ber = ber_dup( msg->lm_ber )) == NULLBER ) {
+                       free( (char *)new );
+                       return( NULLMSG );
+               }
+               len = msg->lm_ber->ber_end - msg->lm_ber->ber_buf;
+               if (( new->lm_ber->ber_buf = (char *) malloc(
+                   (size_t)len )) == NULL ) {
+                       ber_free( new->lm_ber, 0 );
+                       free( (char *)new );
+                       return( NULLMSG );
+               }
+               SAFEMEMCPY( new->lm_ber->ber_buf, msg->lm_ber->ber_buf,
+                   (size_t)len );
+               new->lm_ber->ber_ptr = new->lm_ber->ber_buf +
+                       ( msg->lm_ber->ber_ptr - msg->lm_ber->ber_buf );
+               new->lm_ber->ber_end = new->lm_ber->ber_buf + len;
+       }
+
+       return( new );
+}
+
+
+static int
+request_cmp( BerElement *req1, BerElement *req2 )
+{
+       unsigned long   len;
+       BerElement      r1, r2;
+
+       r1 = *req1;     /* struct copies */
+       r2 = *req2;
+
+       /*
+        * skip the enclosing tags (sequence markers) and the msg ids
+        */
+       if ( ber_skip_tag( &r1, &len ) == LBER_ERROR || ber_scanf( &r1, "x" )
+           == LBER_ERROR ) {
+           return( -1 );
+       }
+       if ( ber_skip_tag( &r2, &len ) == LBER_ERROR || ber_scanf( &r2, "x" ) 
+           == LBER_ERROR ) {
+           return( -1 );
+       }
+
+       /*
+        * check remaining length and bytes if necessary
+        */
+       if (( len = r1.ber_end - r1.ber_ptr ) != r2.ber_end - r2.ber_ptr ) {
+               return( -1 );   /* different lengths */
+       }
+       return( memcmp( r1.ber_ptr, r2.ber_ptr, (size_t)len ));
+}      
+
+
+static int
+chain_contains_dn( LDAPMessage *msg, char *dn )
+{
+       LDAPMessage     *m;
+       BerElement      ber;
+       long            msgid;
+       char            *s;
+       int             rc;
+
+
+       /*
+        * first check the base or dn of the request
+        */
+       ber = *msg->lm_ber;     /* struct copy */
+       if ( ber_scanf( &ber, "{i{a", &msgid, &s ) != LBER_ERROR ) {
+           rc = ( strcasecmp( dn, s ) == 0 ) ? 1 : 0;
+           free( s );
+           if ( rc != 0 ) {
+               return( rc );
+           }
+       }
+
+       if ( msg->lm_msgtype == LDAP_REQ_COMPARE ) {
+               return( 0 );
+       }
+
+       /*
+        * now check the dn of each search result
+        */
+       rc = 0;
+       for ( m = msg->lm_chain; m != NULLMSG && rc == 0 ; m = m->lm_chain ) {
+               if ( m->lm_msgtype != LDAP_RES_SEARCH_ENTRY ) {
+                       continue;
+               }
+               ber = *m->lm_ber;       /* struct copy */
+               if ( ber_scanf( &ber, "{a", &s ) != LBER_ERROR ) {
+                       rc = ( strcasecmp( dn, s ) == 0 ) ? 1 : 0;
+                       free( s );
+               }
+       }
+
+       return( rc );
+}
+
+
+static long
+msg_size( LDAPMessage *msg )
+{
+       LDAPMessage     *m;
+       long            size;
+
+       size = 0;
+       for ( m = msg; m != NULLMSG; m = m->lm_chain ) {
+               size += ( sizeof( LDAPMessage ) + m->lm_ber->ber_end -
+                   m->lm_ber->ber_buf );
+       }
+
+       return( size );
+}
+
+
+#define THRESHOLD_FACTOR       3 / 4
+#define SIZE_FACTOR            2 / 3
+
+static void
+check_cache_memused( LDAPCache *lc )
+{
+/*
+ * this routine is called to check if the cache is too big (lc_maxmem >
+ * minimum cache size and lc_memused > lc_maxmem).  If too big, it reduces
+ * the cache size to < SIZE_FACTOR * lc_maxmem. The algorithm is as follows:
+ *    remove_threshold = lc_timeout seconds;
+ *    do {
+ *        remove everything older than remove_threshold seconds;
+ *        remove_threshold = remove_threshold * THRESHOLD_FACTOR;
+ *    } while ( cache size is > SIZE_FACTOR * lc_maxmem )
+ */
+       int             i;
+       unsigned long   remove_threshold, validtime;
+       LDAPMessage     *m, *prev, *next;
+
+       Debug( LDAP_DEBUG_TRACE, "check_cache_memused: %ld bytes in use (%ld max)\n",
+           lc->lc_memused, lc->lc_maxmem, 0 );
+
+       if ( lc->lc_maxmem <= sizeof( LDAPCache )
+           || lc->lc_memused <= lc->lc_maxmem * SIZE_FACTOR ) {
+               return;
+       }
+
+       remove_threshold = lc->lc_timeout;
+       while ( lc->lc_memused > lc->lc_maxmem * SIZE_FACTOR ) {
+               validtime = (long)time( NULL ) - remove_threshold;
+               for ( i = 0; i < LDAP_CACHE_BUCKETS; ++i ) {
+                       prev = NULLMSG;
+                       for ( m = lc->lc_buckets[ i ]; m != NULLMSG;
+                           m = next ) {
+                               next = m->lm_next;
+                               if ( m->lm_time < validtime ) {
+                                       if ( prev == NULLMSG ) {
+                                               lc->lc_buckets[ i ] = next;
+                                       } else {
+                                               prev->lm_next = next;
+                                       }
+                                       lc->lc_memused -= msg_size( m );
+                                       Debug( LDAP_DEBUG_TRACE,
+                                           "ccm: removed %d\n",
+                                           m->lm_msgid, 0, 0 );
+                                       ldap_msgfree( m );
+                               } else {
+                                       prev = m;
+                               }
+                       }
+               }
+               remove_threshold *= THRESHOLD_FACTOR;
+       }
+
+       Debug( LDAP_DEBUG_TRACE, "ccm: reduced usage to %ld bytes\n",
+           lc->lc_memused, 0, 0 );
+}
+
+#endif /* !NO_CACHE */
diff --git a/libraries/libldap/charset.c b/libraries/libldap/charset.c
new file mode 100644 (file)
index 0000000..d5b7400
--- /dev/null
@@ -0,0 +1,1821 @@
+/*
+ *  Copyright (c) 1995 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  charset.c
+ */
+
+#if defined( DOS ) || defined( _WIN32 )
+/*
+ * This MUST precede "#ifdef STR_TRANSLATION"
+ * because STR_TRANSLATION and friends are defined in msdos.h.
+ */
+#include "msdos.h"
+#endif /* DOS */
+
+#ifdef STR_TRANSLATION
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1995 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef MACOS
+#include <stdlib.h>
+#include "macos.h"
+#endif /* MACOS */
+
+#if !defined(MACOS) && !defined(DOS) && !defined( _WIN32 ) && !defined(VMS)
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#endif
+#include "lber.h"
+#include "ldap.h"
+#include "ldap-int.h"
+
+
+void
+ldap_set_string_translators( LDAP *ld, BERTranslateProc encode_proc,
+       BERTranslateProc decode_proc )
+{
+       ld->ld_lber_encode_translate_proc = encode_proc;
+       ld->ld_lber_decode_translate_proc = decode_proc;
+}
+
+
+void
+ldap_enable_translation( LDAP *ld, LDAPMessage *entry, int enable )
+{
+       char    *optionsp;
+
+       optionsp = ( entry == NULLMSG ) ? &ld->ld_lberoptions :
+           &entry->lm_ber->ber_options;
+               
+       if ( enable ) {
+               *optionsp |= LBER_TRANSLATE_STRINGS;
+       } else {
+               *optionsp &= ~LBER_TRANSLATE_STRINGS;
+       }
+}
+
+
+int
+ldap_translate_from_t61( LDAP *ld, char **bufp, unsigned long *lenp,
+    int free_input )
+{
+       if ( ld->ld_lber_decode_translate_proc == NULL ) {
+               return( LDAP_SUCCESS );
+       }
+           
+       return( (*ld->ld_lber_decode_translate_proc)( bufp, lenp, free_input ));
+}
+
+
+int
+ldap_translate_to_t61( LDAP *ld, char **bufp, unsigned long *lenp,
+    int free_input )
+{
+       if ( ld->ld_lber_encode_translate_proc == NULL ) {
+               return( LDAP_SUCCESS );
+       }
+           
+       return( (*ld->ld_lber_encode_translate_proc)( bufp, lenp, free_input ));
+}
+
+
+/*
+ ** Character translation routine notes:
+ *
+ * On entry:  bufp points to a "string" to be converted (not necessarily
+ *  zero-terminated) and buflenp points to the length of the buffer.
+ *
+ * On exit:  bufp should point to a malloc'd result.  If free_input is
+ *  non-zero then the original bufp will be freed.  *buflenp should be
+ *  set to the new length.  Zero bytes in the input buffer must be left
+ *  as zero bytes.
+ *
+ * Return values: any ldap error code (LDAP_SUCCESS if all goes well).
+ */
+
+
+#ifdef LDAP_CHARSET_8859
+
+#if LDAP_CHARSET_8859 == 88591
+#define ISO_8859 1
+#elif LDAP_CHARSET_8859 == 88592
+#define ISO_8859 2
+#elif LDAP_CHARSET_8859 == 88593
+#define ISO_8859 3
+#elif LDAP_CHARSET_8859 == 88594
+#define ISO_8859 4
+#elif LDAP_CHARSET_8859 == 88595
+#define ISO_8859 5
+#elif LDAP_CHARSET_8859 == 88596
+#define ISO_8859 6
+#elif LDAP_CHARSET_8859 == 88597
+#define ISO_8859 7
+#elif LDAP_CHARSET_8859 == 88598
+#define ISO_8859 8
+#elif LDAP_CHARSET_8859 == 88599
+#define ISO_8859 9
+#elif LDAP_CHARSET_8859 == 885910
+#define ISO_8859 10
+#else
+#define ISO_8859 0
+#endif
+
+/*
+ * the following ISO_8859 to/afrom T.61 character set translation code is
+ * based on the code found in Enrique Silvestre Mora's iso-t61.c, found
+ * as part of this package:
+ *   ftp://pereiii.uji.es/pub/uji-ftp/unix/ldap/iso-t61.translation.tar.Z
+ * Enrique is now (10/95) at this address: enrique.silvestre@uv.es
+ *
+ * changes made by mcs@umich.edu 12 October 1995:
+ *   Change calling conventions of iso8859_t61() and t61_iso8859() to
+ *     match libldap conventions; rename to ldap_8859_to_t61() and
+ *     ldap_t61_to_8859().
+ *   Change conversion routines to deal with non-zero terminated strings.
+ *   ANSI-ize functions and include prototypes.
+ */
+
+/* iso-t61.c - ISO-T61 translation routines (version: 0.2.1, July-1994) */
+/*
+ * Copyright (c) 1994 Enrique Silvestre Mora, Universitat Jaume I, Spain.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the Universitat Jaume I. 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'' without express or implied warranty.
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Character set used: ISO 8859-1, ISO 8859-2, ISO 8859-3, ... */
+/* #define  ISO_8859      1 */
+
+#ifndef ISO_8859
+#  define ISO_8859     0
+#endif
+
+typedef unsigned char  Byte;
+typedef struct { Byte  a, b; } Couple;
+
+#ifdef NEEDPROTOS
+static Byte *c_to_hh( Byte *o, Byte c );
+static Byte *c_to_cc( Byte *o, Couple *cc, Byte c );
+static int hh_to_c( Byte *h );
+static Byte *cc_to_t61( Byte *o, Byte *s );
+#else /* NEEDPROTOS */
+static Byte *c_to_hh();
+static Byte *c_to_cc();
+static int hh_to_c();
+static Byte *cc_to_t61();
+#endif /* NEEDPROTOS */
+
+/*
+   Character choosed as base in diacritics alone: NO-BREAK SPACE.
+   (The standard say it must be a blank space, 0x20.)
+*/
+#define  ALONE  0xA0
+
+static Couple diacritic[16] = {
+#if (ISO_8859 == 1) || (ISO_8859 == 9)
+       {0,0},       {'`',0},     {0xb4,0},    {'^',0},
+       {'~',0},     {0xaf,0},    {'(',ALONE}, {'.',ALONE},
+       {0xa8,0},    {0,0},       {'0',ALONE}, {0xb8,0},
+       {0,0},       {'"',ALONE}, {';',ALONE}, {'<',ALONE},
+#elif (ISO_8859 == 2)
+       {0,0},       {'`',0},     {0xb4,0},    {'^',0},
+       {'~',0},     {'-',ALONE}, {0xa2,0},    {0xff,0},
+       {0xa8,0},    {0,0},       {'0',ALONE}, {0xb8,0},
+       {0,0},       {0xbd,0},    {0xb2,0},    {0xb7,0}
+#elif (ISO_8859 == 3)
+       {0,0},       {'`',0},     {0xb4,0},    {'^',0},
+       {'~',0},     {'-',ALONE}, {0xa2,0},    {0xff,0},
+       {0xa8,0},    {0,0},       {'0',ALONE}, {0xb8,0},
+       {0,0},       {'"',ALONE}, {';',ALONE}, {'<',ALONE}
+#elif (ISO_8859 == 4)
+       {0,0},       {'`',0},     {0xb4,0},    {'^',0},
+       {'~',0},     {0xaf,0},    {'(',ALONE}, {0xff,0},
+       {0xa8,0},    {0,0},       {'0',ALONE}, {0xb8,0},
+       {0,0},       {'"',ALONE}, {0xb2,0},    {0xb7,0}
+#else
+       {0,0},       {'`',0},     {'\'',ALONE}, {'^',0},
+       {'~',0},     {'-',ALONE}, {'(',ALONE},  {'.',ALONE},
+       {':',ALONE}, {0,0},       {'0',ALONE},  {',',ALONE},
+       {0,0},       {'"',ALONE}, {';',ALONE},  {'<',ALONE}
+#endif
+};
+
+/*
+   --- T.61 (T.51) letters with diacritics: conversion to ISO 8859-n -----
+       A,   C,   D,   E,   G,   H,   I,   J,   K,
+       L,   N,   O,   R,   S,   T,   U,   W,   Y,   Z.
+   -----------------------------------------------------------------------
+*/
+static int letter_w_diacritic[16][38] = {
+#if (ISO_8859 == 1)
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0xc0,0,   0,   0xc8,0,   0,   0xcc,0,   0,
+       0,   0,   0xd2,0,   0,   0,   0xd9,0,   0,   0,
+       0xe0,0,   0,   0xe8,0,   0,   0xec,0,   0,
+       0,   0,   0xf2,0,   0,   0,   0xf9,0,   0,   0,
+       0xc1,-1,  0,   0xc9,0,   0,   0xcd,0,   0,
+       -1,  -1,  0xd3,-1,  -1,  0,   0xda,0,   0xdd,-1,
+       0xe1,-1,  0,   0xe9,0,   0,   0xed,0,   0,
+       -1,  -1,  0xf3,-1,  -1,  0,   0xfa,0,   0xfd,-1,
+       0xc2,-1,  0,   0xca,-1,  -1,  0xce,-1,  0,
+       0,   0,   0xd4,0,   -1,  0,   0xdb,-1,  -1,  0,
+       0xe2,-1,  0,   0xea,-1,  -1,  0xee,-1,  0,
+       0,   0,   0xf4,0,   -1,  0,   0xfb,-1,  -1,  0,
+       0xc3,0,   0,   0,   0,   0,   -1,  0,   0,
+       0,   0xd1,0xd5,0,   0,   0,   -1,  0,   0,   0,
+       0xe3,0,   0,   0,   0,   0,   -1,  0,   0,
+       0,   0xf1,0xf5,0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   0,   -1,  0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   0,   -1,  0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       0,   -1,  0,   -1,  -1,  0,   -1,  0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   -1,
+       0,   -1,  0,   -1,  -1,  0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   -1,
+       0xc4,0,   0,   0xcb,0,   0,   0xcf,0,   0,
+       0,   0,   0xd6,0,   0,   0,   0xdc,0,   -1,  0,
+       0xe4,0,   0,   0xeb,0,   0,   0xef,0,   0,
+       0,   0,   0xf6,0,   0,   0,   0xfc,0,   0xff,0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0xc5,0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       0xe5,0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       0,   0xc7,0,   0,   -1,  0,   0,   0,   -1,
+       -1,  -1,  0,   -1,  -1,  -1,  0,   0,   0,   0,
+       0,   0xe7,0,   0,   -1,  0,   0,   0,   -1,
+       -1,  -1,  0,   -1,  -1,  -1,  0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       0,   -1,  -1,  -1,  0,   0,   0,   0,   0,
+       -1,  -1,  0,   -1,  -1,  -1,  0,   0,   0,   -1,
+       0,   -1,  -1,  -1,  0,   0,   0,   0,   0,
+       -1,  -1,  0,   -1,  -1,  -1,  0,   0,   0,   -1
+#elif (ISO_8859 == 2)
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       -1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+       0xc1,0xc6,0,   0xc9,0,   0,   0xcd,0,   0,
+       0xc5,0xd1,0xd3,0xc0,0xa6,0,   0xda,0,   0xdd,0xac,
+       0xe1,0xe6,0,   0xe9,0,   0,   0xed,0,   0,
+       0xe5,0xf1,0xf3,0xe0,0xb6,0,   0xfa,0,   0xfd,0xbc,
+       0xc2,-1,  0,   -1,  -1,  -1,  0xce,-1,  0,
+       0,   0,   0xd4,0,   -1,  0,   -1,  -1,  -1,  0,
+       0xe2,-1,  0,   -1,  -1,  -1,  0xee,-1,  0,
+       0,   0,   0xf4,0,   -1,  0,   -1,  -1,  -1,  0,
+       -1,  0,   0,   0,   0,   0,   -1,  0,   0,
+       0,   -1,  -1,  0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   0,   0,   0,   -1,  0,   0,
+       0,   -1,  -1,  0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+       0xc3,0,   0,   0,   -1,  0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       0xe3,0,   0,   0,   -1,  0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       0,   -1,  0,   -1,  -1,  0,   -1,  0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0xaf,
+       0,   -1,  0,   -1,  -1,  0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0xbf,
+       0xc4,0,   0,   0xcb,0,   0,   -1,  0,   0,
+       0,   0,   0xd6,0,   0,   0,   0xdc,0,   -1,  0,
+       0xe4,0,   0,   0xeb,0,   0,   -1,  0,   0,
+       0,   0,   0xf6,0,   0,   0,   0xfc,0,   -1,  0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       -1,  0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0xd9,0,   0,   0,
+       -1,  0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0xf9,0,   0,   0,
+       0,   0xc7,0,   0,   -1,  0,   0,   0,   -1,
+       -1,  -1,  0,   -1,  0xaa,0xde,0,   0,   0,   0,
+       0,   0xe7,0,   0,   -1,  0,   0,   0,   -1,
+       -1,  -1,  0,   -1,  0xba,0xfe,0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0xd5,0,   0,   0,   0xdb,0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0xf5,0,   0,   0,   0xfb,0,   0,   0,
+       0xa1,0,   0,   0xca,0,   0,   -1,  0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       0xb1,0,   0,   0xea,0,   0,   -1,  0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       0,   0xc8,0xcf,0xcc,0,   0,   0,   0,   0,
+       0xa5,0xd2,0,   0xd8,0xa9,0xab,0,   0,   0,   0xae,
+       0,   0xe8,0xef,0xec,0,   0,   0,   0,   0,
+       0xb5,0xf2,0,   0xf8,0xb9,0xbb,0,   0,   0,   0xbe
+#elif (ISO_8859 == 3)
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0xc0,0,   0,   0xc8,0,   0,   0xcc,0,   0,
+       0,   0,   0xd2,0,   0,   0,   0xd9,0,   0,   0,
+       0xe0,0,   0,   0xe8,0,   0,   0xec,0,   0,
+       0,   0,   0xf2,0,   0,   0,   0xf9,0,   0,   0,
+       0xc1,-1,  0,   0xc9,0,   0,   0xcd,0,   0,
+       -1,  -1,  0xd3,-1,  -1,  0,   0xda,0,   -1,  -1,
+       0xe1,-1,  0,   0xe9,0,   0,   0xed,0,   0,
+       -1,  -1,  0xf3,-1,  -1,  0,   0xfa,0,   -1,  -1,
+       0xc2,0xc6,0,   0xca,0xd8,0xa6,0xce,0xac,0,
+       0,   0,   0xd4,0,   0xde,0,   0xdb,-1,  -1,  0,
+       0xe2,0xe6,0,   0xea,0xf8,0xb6,0xee,0xbc,0,
+       0,   0,   0xf4,0,   0xfe,0,   0xfb,-1,  -1,  0,
+       -1,  0,   0,   0,   0,   0,   -1,  0,   0,
+       0,   0xd1,-1,  0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   0,   0,   0,   -1,  0,   0,
+       0,   0xf1,-1,  0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   0,   0xab,0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0xdd,0,   0,   0,
+       -1,  0,   0,   0,   0xbb,0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0xfd,0,   0,   0,
+       0,   0xc5,0,   -1,  0xd5,0,   0xa9,0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0xaf,
+       0,   0xe5,0,   -1,  0xf5,0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0xbf,
+       0xc4,0,   0,   0xcb,0,   0,   0xcf,0,   0,
+       0,   0,   0xd6,0,   0,   0,   0xdc,0,   -1,  0,
+       0xe4,0,   0,   0xeb,0,   0,   0xef,0,   0,
+       0,   0,   0xf6,0,   0,   0,   0xfc,0,   -1,  0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       -1,  0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       0,   0xc7,0,   0,   -1,  0,   0,   0,   -1,
+       -1,  -1,  0,   -1,  0xaa,-1,  0,   0,   0,   0,
+       0,   0xe7,0,   0,   -1,  0,   0,   0,   -1,
+       -1,  -1,  0,   -1,  0xba,-1,  0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       0,   -1,  -1,  -1,  0,   0,   0,   0,   0,
+       -1,  -1,  0,   -1,  -1,  -1,  0,   0,   0,   -1,
+       0,   -1,  -1,  -1,  0,   0,   0,   0,   0,
+       -1,  -1,  0,   -1,  -1,  -1,  0,   0,   0,   -1
+#elif (ISO_8859 == 4)
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       -1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+       0xc1,-1,  0,   0xc9,0,   0,   0xcd,0,   0,
+       -1,  -1,  -1,  -1,  -1,  0,   0xda,0,   -1,  -1,
+       0xe1,-1,  0,   0xe9,0,   0,   0xed,0,   0,
+       -1,  -1,  -1,  -1,  -1,  0,   0xfa,0,   -1,  -1,
+       0xc2,-1,  0,   -1,  -1,  -1,  0xce,-1,  0,
+       0,   0,   0xd4,0,   -1,  0,   0xdb,-1,  -1,  0,
+       0xe2,-1,  0,   -1,  -1,  -1,  0xee,-1,  0,
+       0,   0,   0xf4,0,   -1,  0,   0xfb,-1,  -1,  0,
+       0xc3,0,   0,   0,   0,   0,   0xa5,0,   0,
+       0,   -1,  0xd5,0,   0,   0,   0xdd,0,   0,   0,
+       0xe3,0,   0,   0,   0,   0,   0xb5,0,   0,
+       0,   -1,  0xf5,0,   0,   0,   0xfd,0,   0,   0,
+       0xc0,0,   0,   0xaa,0,   0,   0xcf,0,   0,
+       0,   0,   0xd2,0,   0,   0,   0xde,0,   0,   0,
+       0xe0,0,   0,   0xba,0,   0,   0xef,0,   0,
+       0,   0,   0xf2,0,   0,   0,   0xfe,0,   0,   0,
+       -1,  0,   0,   0,   -1,  0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   0,   -1,  0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       0,   -1,  0,   0xcc,-1,  0,   -1,  0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   -1,
+       0,   -1,  0,   0xec,-1,  0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   -1,
+       0xc4,0,   0,   0xcb,0,   0,   -1,  0,   0,
+       0,   0,   0xd6,0,   0,   0,   0xdc,0,   -1,  0,
+       0xe4,0,   0,   0xeb,0,   0,   -1,  0,   0,
+       0,   0,   0xf6,0,   0,   0,   0xfc,0,   -1,  0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0xc5,0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       0xe5,0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       0,   -1,  0,   0,   0xab,0,   0,   0,   0xd3,
+       0xa6,0xd1,0,   0xa3,-1,  -1,  0,   0,   0,   0,
+       0,   -1,  0,   0,   0xbb,0,   0,   0,   0xf3,
+       0xb6,0xf1,0,   0xb3,-1,  -1,  0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+       0xa1,0,   0,   0xca,0,   0,   0xc7,0,   0,
+       0,   0,   0,   0,   0,   0,   0xd9,0,   0,   0,
+       0xb1,0,   0,   0xea,0,   0,   0xe7,0,   0,
+       0,   0,   0,   0,   0,   0,   0xf9,0,   0,   0,
+       0,   0xc8,-1,  -1,  0,   0,   0,   0,   0,
+       -1,  -1,  0,   -1,  0xa9,-1,  0,   0,   0,   0xae,
+       0,   0xe8,-1,  -1,  0,   0,   0,   0,   0,
+       -1,  -1,  0,   -1,  0xb9,-1,  0,   0,   0,   0xbe
+#elif (ISO_8859 == 9)
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0xc0,0,   0,   0xc8,0,   0,   0xcc,0,   0,
+       0,   0,   0xd2,0,   0,   0,   0xd9,0,   0,   0,
+       0xe0,0,   0,   0xe8,0,   0,   -1,  0,   0,
+       0,   0,   0xf2,0,   0,   0,   0xf9,0,   0,   0,
+       0xc1,-1,  0,   0xc9,0,   0,   0xcd,0,   0,
+       -1,  -1,  0xd3,-1,  -1,  0,   0xda,0,   -1,  -1,
+       0xe1,-1,  0,   0xe9,0,   0,   0xed,0,   0,
+       -1,  -1,  0xf3,-1,  -1,  0,   0xfa,0,   -1,  -1,
+       0xc2,-1,  0,   0xca,-1,  -1,  0xce,-1,  0,
+       0,   0,   0xd4,0,   -1,  0,   0xdb,-1,  -1,  0,
+       0xe2,-1,  0,   -1,  -1,  -1,  0xee,-1,  0,
+       0,   0,   0xf4,0,   -1,  0,   0xfb,-1,  -1,  0,
+       0xc3,0,   0,   0,   0,   0,   -1,  0,   0,
+       0,   0xd1,0xd5,0,   0,   0,   -1,  0,   0,   0,
+       0xe3,0,   0,   0,   0,   0,   -1,  0,   0,
+       0,   0xf1,0xf5,0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   -1,  0,   0,   0xef,0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   0,   0xd0,0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   0,   0xf0,0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       0,   -1,  0,   -1,  -1,  0,   0xdd,0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   -1,
+       0,   -1,  0,   0xec,-1,  0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   -1,
+       0xc4,0,   0,   0xcb,0,   0,   0xcf,0,   0,
+       0,   0,   0xd6,0,   0,   0,   0xdc,0,   -1,  0,
+       0xe4,0,   0,   0xeb,0,   0,   -1,  0,   0,
+       0,   0,   0xf6,0,   0,   0,   0xfc,0,   0xff,0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0xc5,0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       0xe5,0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       0,   0xc7,0,   0,   -1,  0,   0,   0,   -1,
+       -1,  -1,  0,   -1,  0xde,-1,  0,   0,   0,   0,
+       0,   0xe7,0,   0,   -1,  0,   0,   0,   -1,
+       -1,  -1,  0,   -1,  0xfe,-1,  0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   0xea,0,   0,   -1,  0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       0,   -1,  -1,  -1,  0,   0,   0,   0,   0,
+       -1,  -1,  0,   -1,  -1,  -1,  0,   0,   0,   -1,
+       0,   -1,  -1,  -1,  0,   0,   0,   0,   0,
+       -1,  -1,  0,   -1,  -1,  -1,  0,   0,   0,   -1
+#elif (ISO_8859 == 10)
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       -1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+       0xc1,-1,  0,   0xc9,0,   0,   0xcd,0,   0,
+       -1,  -1,  0xd3,-1,  -1,  0,   0xda,0,   0xdd,-1,
+       0xe1,-1,  0,   0xe9,0,   0,   0xed,0,   0,
+       -1,  -1,  0xf3,-1,  -1,  0,   0xfa,0,   0xfd,-1,
+       0xc2,-1,  0,   -1,  -1,  -1,  0xce,-1,  0,
+       0,   0,   0xd4,0,   -1,  0,   0xdb,-1,  -1,  0,
+       0xe2,-1,  0,   -1,  -1,  -1,  0xee,-1,  0,
+       0,   0,   0xf4,0,   -1,  0,   0xfb,-1,  -1,  0,
+       0xc3,0,   0,   0,   0,   0,   0xa5,0,   0,
+       0,   -1,  0xd5,0,   0,   0,   0xd7,0,   0,   0,
+       0xe3,0,   0,   0,   0,   0,   0xb5,0,   0,
+       0,   -1,  0xf5,0,   0,   0,   0xf7,0,   0,   0,
+       0xc0,0,   0,   0xa2,0,   0,   0xa4,0,   0,
+       0,   0,   0xd2,0,   0,   0,   0xae,0,   0,   0,
+       0xe0,0,   0,   0xb2,0,   0,   0xb4,0,   0,
+       0,   0,   0xf2,0,   0,   0,   0xbe,0,   0,   0,
+       -1,  0,   0,   0,   -1,  0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   0,   -1,  0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       0,   -1,  0,   0xcc,-1,  0,   -1,  0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   -1,
+       0,   -1,  0,   0xec,-1,  0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   -1,
+       0xc4,0,   0,   0xcb,0,   0,   0xcf,0,   0,
+       0,   0,   0xd6,0,   0,   0,   0xdc,0,   -1,  0,
+       0xe4,0,   0,   0xeb,0,   0,   0xef,0,   0,
+       0,   0,   0xf6,0,   0,   0,   0xfc,0,   -1,  0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0xc5,0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       0xe5,0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       0,   -1,  0,   0,   0xa3,0,   0,   0,   0xa6,
+       0xa8,0xd1,0,   -1,  -1,  -1,  0,   0,   0,   0,
+       0,   -1,  0,   0,   0xb3,0,   0,   0,   0xb6,
+       0xb8,0xf1,0,   -1,  -1,  -1,  0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+       0xa1,0,   0,   0xca,0,   0,   0xc7,0,   0,
+       0,   0,   0,   0,   0,   0,   0xd9,0,   0,   0,
+       0xb1,0,   0,   0xea,0,   0,   0xe7,0,   0,
+       0,   0,   0,   0,   0,   0,   0xf9,0,   0,   0,
+       0,   0xc8,-1,  -1,  0,   0,   0,   0,   0,
+       -1,  -1,  0,   -1,  0xaa,-1,  0,   0,   0,   0xac,
+       0,   0xe8,-1,  -1,  0,   0,   0,   0,   0,
+       -1,  -1,  0,   -1,  0xba,-1,  0,   0,   0,   0xbc
+#else
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       -1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+       -1,  -1,  0,   -1,  0,   0,   -1,  0,   0,
+       -1,  -1,  -1,  -1,  -1,  0,   -1,  0,   -1,  -1,
+       -1,  -1,  0,   -1,  0,   0,   -1,  0,   0,
+       -1,  -1,  -1,  -1,  -1,  0,   -1,  0,   -1,  -1,
+       -1,  -1,  0,   -1,  -1,  -1,  -1,  -1,  0,
+       0,   0,   -1,  0,   -1,  0,   -1,  -1,  -1,  0,
+       -1,  -1,  0,   -1,  -1,  -1,  -1,  -1,  0,
+       0,   0,   -1,  0,   -1,  0,   -1,  -1,  -1,  0,
+       -1,  0,   0,   0,   0,   0,   -1,  0,   0,
+       0,   -1,  -1,  0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   0,   0,   0,   -1,  0,   0,
+       0,   -1,  -1,  0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   0,   -1,  0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   0,   -1,  0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       0,   -1,  0,   -1,  -1,  0,   -1,  0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   -1,
+       0,   -1,  0,   -1,  -1,  0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   -1,
+       -1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   -1,  0,
+       -1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   -1,  0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       -1,  0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       0,   -1,  0,   0,   -1,  0,   0,   0,   -1,
+       -1,  -1,  0,   -1,  -1,  -1,  0,   0,   0,   0,
+       0,   -1,  0,   0,   -1,  0,   0,   0,   -1,
+       -1,  -1,  0,   -1,  -1,  -1,  0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+       0,   0,   0,   0,   0,   0,   0,   0,   0,
+       0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       -1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+       0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+       0,   -1,  -1,  -1,  0,   0,   0,   0,   0,
+       -1,  -1,  0,   -1,  -1,  -1,  0,   0,   0,   -1,
+       0,   -1,  -1,  -1,  0,   0,   0,   0,   0,
+       -1,  -1,  0,   -1,  -1,  -1,  0,   0,   0,   -1
+#endif
+};
+
+/*
+--- T.61 characters [0xA0 .. 0xBF] -----------------
+*/
+static Couple trans_t61a_iso8859[32] = {
+#if (ISO_8859 == 1) || (ISO_8859 == 9)
+       {'N','S'}, {0xa1,0},  {0xa2,0},  {0xa3,0},
+       {'D','O'}, {0xa5,0},  {'C','u'}, {0xa7,0},
+       {0xa4,0},  {'\'','6'},{'"','6'}, {0xab,0},
+       {'<','-'}, {'-','!'}, {'-','>'}, {'-','v'},
+       {0xb0,0},  {0xb1,0},  {0xb2,0},  {0xb3,0},
+       {0xd7,0},  {0xb5,0},  {0xb6,0},  {0xb7,0},
+       {0xf7,0},  {'\'','9'},{'"','9'}, {0xbb,0},
+       {0xbc,0},  {0xbd,0},  {0xbe,0},  {0xbf,0}
+#elif (ISO_8859 == 2) || (ISO_8859 == 4)
+       {'N','S'}, {'!','I'}, {'C','t'}, {'P','d'},
+       {'D','O'}, {'Y','e'}, {'C','u'}, {0xa7,0},
+       {0xa4,0},  {'\'','6'},{'"','6'}, {'<','<'},
+       {'<','-'}, {'-','!'}, {'-','>'}, {'-','v'},
+       {0xb0,0},  {'+','-'}, {'2','S'}, {'3','S'},
+       {0xd7,0},  {'M','y'}, {'P','I'}, {'.','M'},
+       {0xf7,0},  {'\'','9'},{'"','9'}, {'>','>'},
+       {'1','4'}, {'1','2'}, {'3','4'}, {'?','I'},
+#elif (ISO_8859 == 3)
+       {'N','S'}, {'!','I'}, {'C','t'}, {0xa3,0},
+       {'D','O'}, {'Y','e'}, {'C','u'}, {0xa7,0},
+       {0xa4,0},  {'\'','6'},{'"','6'}, {'<','<'},
+       {'<','-'}, {'-','!'}, {'-','>'}, {'-','v'},
+       {0xb0,0},  {'+','-'}, {0xb2,0},  {0xb3,0},
+       {0xd7,0},  {0xb5,0},  {'P','I'}, {0xb7,0},
+       {0xf7,0},  {'\'','9'},{'"','9'}, {'>','>'},
+       {'1','4'}, {0xbd,0},  {'3','4'}, {'?','I'}
+#elif (ISO_8859 == 10)
+       {'N','S'}, {'!','I'}, {'C','t'}, {'P','d'},
+       {'D','O'}, {'Y','e'}, {'C','u'}, {0xa7,0},
+       {'C','u'}, {'\'','6'},{'"','6'}, {'<','<'},
+       {'<','-'}, {'-','!'}, {'-','>'}, {'-','v'},
+       {0xb0,0},  {'+','-'}, {'2','S'}, {'3','S'},
+       {'*','X'}, {'M','y'}, {'P','I'}, {0xb7,0},
+       {'-',':'}, {'\'','9'},{'"','9'}, {'>','>'},
+       {'1','4'}, {'1','2'}, {'3','4'}, {'?','I'}
+#else
+       {'N','S'}, {'!','I'}, {'C','t'}, {'P','d'},
+       {'D','O'}, {'Y','e'}, {'C','u'}, {'S','E'},
+       {'X','O'}, {'\'','6'},{'"','6'}, {'<','<'},
+       {'<','-'}, {'-','!'}, {'-','>'}, {'-','v'},
+       {'D','G'}, {'+','-'}, {'2','S'}, {'3','S'},
+       {'*','X'}, {'M','y'}, {'P','I'}, {'.','M'},
+       {'-',':'}, {'\'','9'},{'"','9'}, {'>','>'},
+       {'1','4'}, {'1','2'}, {'3','4'}, {'?','I'}
+#endif
+};
+
+/*
+--- T.61 characters [0xE0 .. 0xFF] -----------------
+*/
+static Couple trans_t61b_iso8859[48] = {
+#if (ISO_8859 == 1)
+       {'-','M'}, {0xb9,0},  {0xae,0},  {0xa9,0},
+       {'T','M'}, {'M','8'}, {0xac,0},  {0xa6,0},
+       {0,0},     {0,0},     {0,0},     {0,0},
+       {'1','8'}, {'3','8'}, {'5','8'}, {'7','8'},
+       {'O','m'}, {0xc6,0},  {0xd0,0},  {0xaa,0},
+       {'H','/'}, {0,0},     {'I','J'}, {'L','.'},
+       {'L','/'}, {0xd8,0},  {'O','E'}, {0xba,0},
+       {0xde,0},  {'T','/'}, {'N','G'}, {'\'','n'},
+       {'k','k'}, {0xe6,0},  {'d','/'}, {0xf0,0},
+       {'h','/'}, {'i','.'}, {'i','j'}, {'l','.'},
+       {'l','/'}, {0xf8,0},  {'o','e'}, {0xdf,0},
+       {0xfe,0},  {'t','/'}, {'n','g'}, {'-','-'}
+#elif (ISO_8859 == 2)
+       {'-','M'}, {'1','S'}, {'R','g'}, {'C','o'},
+       {'T','M'}, {'M','8'}, {'N','O'}, {'B','B'},
+       {0,0},     {0,0},     {0,0},     {0,0},
+       {'1','8'}, {'3','8'}, {'5','8'}, {'7','8'},
+       {'O','m'}, {'A','E'}, {0xd0,0},  {'-','a'},
+       {'H','/'}, {0,0},     {'I','J'}, {'L','.'},
+       {0xa3,0},  {'O','/'}, {'O','E'}, {'-','o'},
+       {'T','H'}, {'T','/'}, {'N','G'}, {'\'','n'},
+       {'k','k'}, {'a','e'}, {0xf0,0},  {'d','-'},
+       {'h','/'}, {'i','.'}, {'i','j'}, {'l','.'},
+       {0xb3,0},  {'o','/'}, {'o','e'}, {0xdf,0},
+       {'t','h'}, {'t','/'}, {'n','g'}, {'-','-'}
+#elif (ISO_8859 == 3)
+       {'-','M'}, {'1','S'}, {'R','g'}, {'C','o'},
+       {'T','M'}, {'M','8'}, {'N','O'}, {'B','B'},
+       {0,0},     {0,0},     {0,0},     {0,0},
+       {'1','8'}, {'3','8'}, {'5','8'}, {'7','8'},
+       {'O','m'}, {'A','E'}, {'D','/'}, {'-','a'},
+       {0xa1,0},  {0,0},     {'I','J'}, {'L','.'},
+       {'L','/'}, {'O','/'}, {'O','E'}, {'-','o'},
+       {'T','H'}, {'T','/'}, {'N','G'}, {'\'','n'},
+       {'k','k'}, {'a','e'}, {'d','/'}, {'d','-'},
+       {0xb1,0},  {0xb9,0},  {'i','j'}, {'l','.'},
+       {'l','/'}, {'o','/'}, {'o','e'}, {0xdf,0},
+       {'t','h'}, {'t','/'}, {'n','g'}, {'-','-'}
+#elif (ISO_8859 == 4)
+       {'-','M'}, {'1','S'}, {'R','g'}, {'C','o'},
+       {'T','M'}, {'M','8'}, {'N','O'}, {'B','B'},
+       {0,0},     {0,0},     {0,0},     {0,0},
+       {'1','8'}, {'3','8'}, {'5','8'}, {'7','8'},
+       {'O','m'}, {0xc6,0},  {0xd0,0},  {'-','a'},
+       {'H','/'}, {0,0},     {'I','J'}, {'L','.'},
+       {'L','/'}, {0xd8,0},  {'O','E'}, {'-','o'},
+       {'T','H'}, {0xac,0},  {0xbd,0},  {'\'','n'},
+       {0xa2,0},  {0xe6,0},  {0xf0,0},  {'d','-'},
+       {'h','/'}, {'i','.'}, {'i','j'}, {'l','.'},
+       {'l','/'}, {0xf8,0},  {'o','e'}, {0xdf,0},
+       {'t','h'}, {0xbc,0},  {0xbf,0},  {'-','-'}
+#elif (ISO_8859 == 9)
+       {'-','M'}, {0xb9,0},  {0xae,0},  {0xa9,0},
+       {'T','M'}, {'M','8'}, {0xac,0},  {0xa6,0},
+       {0,0},     {0,0},     {0,0},     {0,0},
+       {'1','8'}, {'3','8'}, {'5','8'}, {'7','8'},
+       {'O','m'}, {0xc6,0},  {'D','/'}, {0xaa,0},
+       {'H','/'}, {0,0},     {'I','J'}, {'L','.'},
+       {'L','/'}, {0xd8,0},  {'O','E'}, {0xba,0},
+       {'T','H'}, {'T','/'}, {'N','G'}, {'\'','n'},
+       {'k','k'}, {0xe6,0},  {'d','/'}, {'d','-'},
+       {'h','/'}, {0xfd,0},  {'i','j'}, {'l','.'},
+       {'l','/'}, {0xf8,0},  {'o','e'}, {0xdf,0},
+       {'t','h'}, {'t','/'}, {'n','g'}, {'-','-'}
+#elif (ISO_8859 == 10)
+       {0xbd,0},  {'1','S'}, {'R','g'}, {'C','o'},
+       {'T','M'}, {'M','8'}, {'N','O'}, {'B','B'},
+       {0,0},     {0,0},     {0,0},     {0,0},
+       {'1','8'}, {'3','8'}, {'5','8'}, {'7','8'},
+       {'O','m'}, {0xc6,0},  {0xa9,0},  {'-','a'},
+       {'H','/'}, {0,0},     {'I','J'}, {'L','.'},
+       {'L','/'}, {0xd8,0},  {'O','E'}, {'-','o'},
+       {0xde,0},  {0xab,0},  {0xaf,0},  {'\'','n'},
+       {0xff,0},  {0xe6,0},  {0xb9,0},  {0xf0,0},
+       {'h','/'}, {'i','.'}, {'i','j'}, {'l','.'},
+       {'l','/'}, {0xf8,0},  {'o','e'}, {0xdf,0},
+       {0xfe,0},  {0xbb,0},  {0xbf,0},  {'-','-'}
+#else
+       {'-','M'}, {'1','S'}, {'R','g'}, {'C','o'},
+       {'T','M'}, {'M','8'}, {'N','O'}, {'B','B'},
+       {0,0},     {0,0},     {0,0},     {0,0},
+       {'1','8'}, {'3','8'}, {'5','8'}, {'7','8'},
+       {'O','m'}, {'A','E'}, {'D','/'}, {'-','a'},
+       {'H','/'}, {0,0},     {'I','J'}, {'L','.'},
+       {'L','/'}, {'O','/'}, {'O','E'}, {'-','o'},
+       {'T','H'}, {'T','/'}, {'N','G'}, {'\'','n'},
+       {'k','k'}, {'a','e'}, {'d','/'}, {'d','-'},
+       {'h','/'}, {'i','.'}, {'i','j'}, {'l','.'},
+       {'l','/'}, {'o','/'}, {'o','e'}, {'s','s'},
+       {'t','h'}, {'t','-'}, {'n','g'}, {'-','-'}
+#endif
+};
+
+/*
+--- ISO 8859-n characters <0xA0 .. 0xFF> -------------------
+*/
+#if (ISO_8859 == 1)
+static Couple trans_iso8859_t61[96] = {
+       {0xa0,0},     {0xa1,0},     {0xa2,0},     {0xa3,0},
+       {0xa8,0},     {0xa5,0},     {0xd7,0},     {0xa7,0},
+       {0xc8,ALONE}, {0xd3,0},     {0xe3,0},     {0xab,0},
+       {0xd6,0},     {0xff,0},     {0xd2,0},     {0xc5,ALONE},
+       {0xb0,0},     {0xb1,0},     {0xb2,0},     {0xb3,0},
+       {0xc2,ALONE}, {0xb5,0},     {0xb6,0},     {0xb7,0},
+       {0xcb,ALONE}, {0xd1,0},     {0xeb,0},     {0xbb,0},
+       {0xbc,0},     {0xbd,0},     {0xbe,0},     {0xbf,0},
+       {0xc1,'A'},   {0xc2,'A'},   {0xc3,'A'},   {0xc4,'A'},
+       {0xc8,'A'},   {0xca,'A'},   {0xe1,0},     {0xcb,'C'},
+       {0xc1,'E'},   {0xc2,'E'},   {0xc3,'E'},   {0xc8,'E'},
+       {0xc1,'I'},   {0xc2,'I'},   {0xc3,'I'},   {0xc8,'I'},
+       {0xe2,0},     {0xc4,'N'},   {0xc1,'O'},   {0xc2,'O'},
+       {0xc3,'O'},   {0xc4,'O'},   {0xc8,'O'},   {0xb4,0},
+       {0xe9,0},     {0xc1,'U'},   {0xc2,'U'},   {0xc3,'U'},
+       {0xc8,'U'},   {0xc2,'Y'},   {0xec,0},     {0xfb,0},
+       {0xc1,'a'},   {0xc2,'a'},   {0xc3,'a'},   {0xc4,'a'},
+       {0xc8,'a'},   {0xca,'a'},   {0xf1,0},     {0xcb,'c'},
+       {0xc1,'e'},   {0xc2,'e'},   {0xc3,'e'},   {0xc8,'e'},
+       {0xc1,'i'},   {0xc2,'i'},   {0xc3,'i'},   {0xc8,'i'},
+       {0xf3,0},     {0xc4,'n'},   {0xc1,'o'},   {0xc2,'o'},
+       {0xc3,'o'},   {0xc4,'o'},   {0xc8,'o'},   {0xb8,0},
+       {0xf9,0},     {0xc1,'u'},   {0xc2,'u'},   {0xc3,'u'},
+       {0xc8,'u'},   {0xc2,'y'},   {0xfc,0},     {0xc8,'y'}
+};
+#elif (ISO_8859 == 2)
+static Couple trans_iso8859_t61[96] = {
+       {0xa0,0},     {0xce,'A'},   {0xc6,ALONE}, {0xe8,0},
+       {0xa8,0},     {0xcf,'L'},   {0xc2,'S'},   {0xa7,0},
+       {0xc8,ALONE}, {0xcf,'S'},   {0xcb,'S'},   {0xcf,'T'},
+       {0xc2,'Z'},   {0xff,0},     {0xcf,'Z'},   {0xc7,'Z'},
+       {0xb0,0},     {0xce,'a'},   {0xce,ALONE}, {0xf8,0},
+       {0xc2,ALONE}, {0xcf,'l'},   {0xc2,'s'},   {0xcf,ALONE},
+       {0xcb,ALONE}, {0xcf,'s'},   {0xcb,'s'},   {0xcf,'t'},
+       {0xc2,'z'},   {0xcd,ALONE}, {0xcf,'z'},   {0xc7,'z'},
+       {0xc2,'R'},   {0xc2,'A'},   {0xc3,'A'},   {0xc6,'A'},
+       {0xc8,'A'},   {0xc2,'L'},   {0xc2,'C'},   {0xcb,'C'},
+       {0xcf,'C'},   {0xc2,'E'},   {0xce,'E'},   {0xc8,'E'},
+       {0xcf,'E'},   {0xc2,'I'},   {0xc3,'I'},   {0xcf,'D'},
+       {0xe2,0},     {0xc2,'N'},   {0xcf,'N'},   {0xc2,'O'},
+       {0xc3,'O'},   {0xcd,'O'},   {0xc8,'O'},   {0xb4,0},
+       {0xcf,'R'},   {0xca,'U'},   {0xc2,'U'},   {0xcd,'U'},
+       {0xc8,'U'},   {0xc2,'Y'},   {0xcb,'T'},   {0xfb,0},
+       {0xc2,'r'},   {0xc2,'a'},   {0xc3,'a'},   {0xc6,'a'},
+       {0xc8,'a'},   {0xc2,'l'},   {0xc2,'c'},   {0xcb,'c'},
+       {0xcf,'c'},   {0xc2,'e'},   {0xce,'e'},   {0xc8,'e'},
+       {0xcf,'e'},   {0xc2,'i'},   {0xc3,'i'},   {0xcf,'d'},
+       {0xf2,0},     {0xc2,'n'},   {0xcf,'n'},   {0xc2,'o'},
+       {0xc3,'o'},   {0xcd,'o'},   {0xc8,'o'},   {0xb8,0},
+       {0xcf,'r'},   {0xca,'u'},   {0xc2,'u'},   {0xcd,'u'},
+       {0xc8,'u'},   {0xc2,'y'},   {0xcb,'t'},   {0xc7,ALONE}
+};
+#elif (ISO_8859 == 3)
+static Couple trans_iso8859_t61[96] = {
+       {0xa0,0},     {0xe4,0},     {0xc6,ALONE}, {0xa3,0},
+       {0xa8,0},     {0,0},        {0xc3,'H'},   {0xa7,0},
+       {0xc8,ALONE}, {0xc7,'I'},   {0xcb,'S'},   {0xc6,'G'},
+       {0xc3,'J'},   {0xff,0},     {0,0},        {0xc7,'Z'},
+       {0xb0,0},     {0xf4,0},     {0xb2,0},     {0xb3,0},
+       {0xc2,ALONE}, {0xb5,0},     {0xc3,'h'},   {0xb7,0},
+       {0xcb,ALONE}, {0xf5,0},     {0xcb,'s'},   {0xc6,'g'},
+       {0xc3,'j'},   {0xbd,0},     {0,0},        {0xc7,'z'},
+       {0xc1,'A'},   {0xc2,'A'},   {0xc3,'A'},   {0,0},
+       {0xc8,'A'},   {0xc7,'C'},   {0xc3,'C'},   {0xcb,'C'},
+       {0xc1,'E'},   {0xc2,'E'},   {0xc3,'E'},   {0xc8,'E'},
+       {0xc1,'I'},   {0xc2,'I'},   {0xc3,'I'},   {0xc8,'I'},
+       {0,0},        {0xc4,'N'},   {0xc1,'O'},   {0xc2,'O'},
+       {0xc3,'O'},   {0xc7,'G'},   {0xc8,'O'},   {0xb4,0},
+       {0xc3,'G'},   {0xc1,'U'},   {0xc2,'U'},   {0xc3,'U'},
+       {0xc8,'U'},   {0xc6,'U'},   {0xc3,'S'},   {0xfb,0},
+       {0xc1,'a'},   {0xc2,'a'},   {0xc3,'a'},   {0,0},
+       {0xc8,'a'},   {0xc7,'c'},   {0xc3,'c'},   {0xcb,'c'},
+       {0xc1,'e'},   {0xc2,'e'},   {0xc3,'e'},   {0xc8,'e'},
+       {0xc1,'i'},   {0xc2,'i'},   {0xc3,'i'},   {0xc8,'i'},
+       {0,0},        {0xc4,'n'},   {0xc1,'o'},   {0xc2,'o'},
+       {0xc3,'o'},   {0xc7,'g'},   {0xc8,'o'},   {0xb8,0},
+       {0xc3,'g'},   {0xc1,'u'},   {0xc2,'u'},   {0xc3,'u'},
+       {0xc8,'u'},   {0xc6,'u'},   {0xc3,'s'},   {0xc7,ALONE}
+};
+#elif (ISO_8859 == 4)
+static Couple trans_iso8859_t61[96] = {
+       {0xa0,0},     {0xce,'A'},   {0xf0,0},     {0xcb,'R'},
+       {0xa8,0},     {0xc4,'I'},   {0xcb,'L'},   {0xa7,0},
+       {0xc8,ALONE}, {0xcf,'S'},   {0xc5,'E'},   {0xcb,'G'},
+       {0xed,0},     {0xff,0},     {0xcf,'Z'},   {0xc5,ALONE},
+       {0xb0,0},     {0xce,'a'},   {0xce,ALONE}, {0xcb,'r'},
+       {0xc2,ALONE}, {0xc4,'i'},   {0xcb,'l'},   {0xcf,ALONE},
+       {0xcb,ALONE}, {0xcf,'s'},   {0xc5,'e'},   {0xcb,'g'},
+       {0xfd,0},     {0xee,0},     {0xcf,'z'},   {0xfe,0},
+       {0xc5,'A'},   {0xc2,'A'},   {0xc3,'A'},   {0xc4,'A'},
+       {0xc8,'A'},   {0xca,'A'},   {0xe1,0},     {0xce,'I'},
+       {0xcf,'C'},   {0xc2,'E'},   {0xce,'E'},   {0xc8,'E'},
+       {0xc7,'E'},   {0xc2,'I'},   {0xc3,'I'},   {0xc5,'I'},
+       {0xe2,0},     {0xcb,'N'},   {0xc5,'O'},   {0xcb,'K'},
+       {0xc3,'O'},   {0xc4,'O'},   {0xc8,'O'},   {0xb4,0},
+       {0xe9,0},     {0xce,'U'},   {0xc2,'U'},   {0xc3,'U'},
+       {0xc8,'U'},   {0xc4,'U'},   {0xc5,'U'},   {0xfb,0},
+       {0xc5,'a'},   {0xc2,'a'},   {0xc3,'a'},   {0xc4,'a'},
+       {0xc8,'a'},   {0xca,'a'},   {0xf1,0},     {0xce,'i'},
+       {0xcf,'c'},   {0xc2,'e'},   {0xce,'e'},   {0xc8,'e'},
+       {0xc7,'e'},   {0xc2,'i'},   {0xc3,'i'},   {0xc5,'i'},
+       {0xf2,0},     {0xcb,'n'},   {0xc5,'o'},   {0xcb,'k'},
+       {0xc3,'o'},   {0xc4,'o'},   {0xc8,'o'},   {0xb8,0},
+       {0xf9,0},     {0xce,'u'},   {0xc2,'u'},   {0xc3,'u'},
+       {0xc8,'u'},   {0xc4,'u'},   {0xc5,'u'},   {0xc7,ALONE}
+};
+#elif (ISO_8859 == 9)
+static Couple trans_iso8859_t61[96] = {
+       {0xa0,0},     {0xa1,0},     {0xa2,0},     {0xa3,0},
+       {0xa8,0},     {0xa5,0},     {0xd7,0},     {0xa7,0},
+       {0xc8,ALONE}, {0xd3,0},     {0xe3,0},     {0xab,0},
+       {0xd6,0},     {0xff,0},     {0xd2,0},     {0xc5,ALONE},
+       {0xb0,0},     {0xb1,0},     {0xb2,0},     {0xb3,0},
+       {0xc2,ALONE}, {0xb5,0},     {0xb6,0},     {0xb7,0},
+       {0xcb,ALONE}, {0xd1,0},     {0xeb,0},     {0xbb,0},
+       {0xbc,0},     {0xbd,0},     {0xbe,0},     {0xbf,0},
+       {0xc1,'A'},   {0xc2,'A'},   {0xc3,'A'},   {0xc4,'A'},
+       {0xc8,'A'},   {0xca,'A'},   {0xe1,0},     {0xcb,'C'},
+       {0xc1,'E'},   {0xc2,'E'},   {0xc3,'E'},   {0xc8,'E'},
+       {0xc1,'I'},   {0xc2,'I'},   {0xc3,'I'},   {0xc8,'I'},
+       {0xc6,'G'},   {0xc4,'N'},   {0xc1,'O'},   {0xc2,'O'},
+       {0xc3,'O'},   {0xc4,'O'},   {0xc8,'O'},   {0xb4,0},
+       {0xe9,0},     {0xc1,'U'},   {0xc2,'U'},   {0xc3,'U'},
+       {0xc8,'U'},   {0xc7,'I'},   {0xcb,'S'},   {0xfb,0},
+       {0xc1,'a'},   {0xc2,'a'},   {0xc3,'a'},   {0xc4,'a'},
+       {0xc8,'a'},   {0xca,'a'},   {0xf1,0},     {0xcb,'c'},
+       {0xc1,'e'},   {0xc2,'e'},   {0xce,'e'},   {0xc8,'e'},
+       {0xc7,'e'},   {0xc2,'i'},   {0xc3,'i'},   {0xc5,'i'},
+       {0xc6,'g'},   {0xc4,'n'},   {0xc1,'o'},   {0xc2,'o'},
+       {0xc3,'o'},   {0xc4,'o'},   {0xc8,'o'},   {0xb8,0},
+       {0xf9,0},     {0xc1,'u'},   {0xc2,'u'},   {0xc3,'u'},
+       {0xc8,'u'},   {0xf5,0},     {0xcb,'s'},   {0xc8,'y'}
+};
+#elif (ISO_8859 == 10)
+static Couple trans_iso8859_t61[96] = {
+       {0xa0,0},     {0xce,'A'},   {0xc5,'E'},   {0xcb,'G'},
+       {0xc5,'I'},   {0xc4,'I'},   {0xcb,'K'},   {0xa7,0},
+       {0xcb,'L'},   {0xe2,0},     {0xcf,'S'},   {0xed,0},
+       {0xcf,'Z'},   {0xff,0},     {0xc5,'U'},   {0xee,0},
+       {0xb0,0},     {0xce,'a'},   {0xc5,'e'},   {0xcb,'g'},
+       {0xc5,'i'},   {0xc4,'i'},   {0xcb,'k'},   {0xb7,0},
+       {0xcb,'l'},   {0xf2,0},     {0xcf,'s'},   {0xfd,0},
+       {0xcf,'z'},   {0xd0,0},     {0xc5,'u'},   {0xfe,0},
+       {0xc5,'A'},   {0xc2,'A'},   {0xc3,'A'},   {0xc4,'A'},
+       {0xc8,'A'},   {0xca,'A'},   {0xe1,0},     {0xce,'I'},
+       {0xcf,'C'},   {0xc2,'E'},   {0xce,'E'},   {0xc8,'E'},
+       {0xc7,'E'},   {0xc2,'I'},   {0xc3,'I'},   {0xc8,'I'},
+       {0,0},        {0xcb,'N'},   {0xc5,'O'},   {0xc2,'O'},
+       {0xc3,'O'},   {0xc4,'O'},   {0xc8,'O'},   {0xc4,'U'},
+       {0xe9,0},     {0xce,'U'},   {0xc2,'U'},   {0xc3,'U'},
+       {0xc8,'U'},   {0xc2,'Y'},   {0xec,0},     {0xfb,0},
+       {0xc5,'a'},   {0xc2,'a'},   {0xc3,'a'},   {0xc4,'a'},
+       {0xc8,'a'},   {0xca,'a'},   {0xf1,0},     {0xce,'i'},
+       {0xcf,'c'},   {0xc2,'e'},   {0xce,'e'},   {0xc8,'e'},
+       {0xc7,'e'},   {0xc2,'i'},   {0xc3,'i'},   {0xc8,'i'},
+       {0xf3,0},     {0xcb,'n'},   {0xc5,'o'},   {0xc2,'o'},
+       {0xc3,'o'},   {0xc4,'o'},   {0xc8,'o'},   {0xc4,'u'},
+       {0xf9,0},     {0xce,'u'},   {0xc2,'u'},   {0xc3,'u'},
+       {0xc8,'u'},   {0xc2,'y'},   {0xfc,0},     {0xf0,0}
+};
+#endif
+
+
+static Byte *
+c_to_hh( Byte *o, Byte c )
+{
+  Byte n;
+
+  *o++ = '{'; *o++ = 'x';
+  n = c >> 4;
+  *o++ = ((n < 0xA) ? '0' : 'A' - 0xA) + n;
+  n = c & 0x0F;
+  *o++ = ((n < 0xA) ? '0' : 'A' - 0xA) + n;
+  *o++ = '}';
+  return o;
+}
+
+
+static Byte *
+c_to_cc( Byte *o, Couple *cc, Byte c )
+{
+  if ( (*cc).a != 0 ) {
+    if ( (*cc).b == 0 )
+      *o++ = (*cc).a;
+    else {
+      *o++ = '{';
+      *o++ = (*cc).a;
+      *o++ = (*cc).b;
+      *o++ = '}';
+    }
+    return o;
+  }
+  else
+    return c_to_hh( o, c );
+}
+
+/* --- routine to convert from T.61 to ISO 8859-n --- */
+
+int
+ldap_t61_to_8859( char **bufp, unsigned long *buflenp, int free_input )
+{
+  Byte         *s, *oo, *o;
+  unsigned int  n;
+  int           c;
+  unsigned long len;
+  Couple        *cc;
+
+  Debug( LDAP_DEBUG_TRACE, "ldap_t61_to_8859 input length: %ld\n",
+       *buflenp, 0, 0 );
+
+  len = *buflenp;
+  s = (Byte *) *bufp;
+
+  if ( (o = oo = (Byte *)malloc( 2 * len + 64 )) == NULL ) {
+        return( 1 );
+  }
+
+  while ( (char *)s - *(char **)bufp < len ) {
+    switch ( *s >> 4 ) {
+
+    case 0xA: case 0xB:
+      o = c_to_cc( o, &trans_t61a_iso8859[ *s - 0xA0 ], *s );
+      s++;
+      break;
+
+    case 0xD: case 0xE: case 0xF:
+      o = c_to_cc( o, &trans_t61b_iso8859[ *s - 0xD0 ], *s );
+      s++;
+      break;
+
+    case 0xC:
+      if ( (*s == 0xC0) || (*s == 0xC9) || (*s == 0xCC) ) {
+        o = c_to_hh( o, *s++ );
+        break;
+      }
+
+      n = (*s++) - 0xC0;
+      switch ( *s ) {
+
+      case 'A':  c = letter_w_diacritic[n][0]; break;
+      case 'C':  c = letter_w_diacritic[n][1]; break;
+      case 'D':  c = letter_w_diacritic[n][2]; break;
+      case 'E':  c = letter_w_diacritic[n][3]; break;
+      case 'G':  c = letter_w_diacritic[n][4]; break;
+      case 'H':  c = letter_w_diacritic[n][5]; break;
+      case 'I':  c = letter_w_diacritic[n][6]; break;
+      case 'J':  c = letter_w_diacritic[n][7]; break;
+      case 'K':  c = letter_w_diacritic[n][8]; break;
+      case 'L':  c = letter_w_diacritic[n][9]; break;
+      case 'N':  c = letter_w_diacritic[n][10]; break;
+      case 'O':  c = letter_w_diacritic[n][11]; break;
+      case 'R':  c = letter_w_diacritic[n][12]; break;
+      case 'S':  c = letter_w_diacritic[n][13]; break;
+      case 'T':  c = letter_w_diacritic[n][14]; break;
+      case 'U':  c = letter_w_diacritic[n][15]; break;
+      case 'W':  c = letter_w_diacritic[n][16]; break;
+      case 'Y':  c = letter_w_diacritic[n][17]; break;
+      case 'Z':  c = letter_w_diacritic[n][18]; break;
+
+      case 'a':  c = letter_w_diacritic[n][19]; break;
+      case 'c':  c = letter_w_diacritic[n][20]; break;
+      case 'd':  c = letter_w_diacritic[n][21]; break;
+      case 'e':  c = letter_w_diacritic[n][22]; break;
+      case 'g':  c = letter_w_diacritic[n][23]; break;
+      case 'h':  c = letter_w_diacritic[n][24]; break;
+      case 'i':  c = letter_w_diacritic[n][25]; break;
+      case 'j':  c = letter_w_diacritic[n][26]; break;
+      case 'k':  c = letter_w_diacritic[n][27]; break;
+      case 'l':  c = letter_w_diacritic[n][28]; break;
+      case 'n':  c = letter_w_diacritic[n][29]; break;
+      case 'o':  c = letter_w_diacritic[n][30]; break;
+      case 'r':  c = letter_w_diacritic[n][31]; break;
+      case 's':  c = letter_w_diacritic[n][32]; break;
+      case 't':  c = letter_w_diacritic[n][33]; break;
+      case 'u':  c = letter_w_diacritic[n][34]; break;
+      case 'w':  c = letter_w_diacritic[n][35]; break;
+      case 'y':  c = letter_w_diacritic[n][36]; break;
+      case 'z':  c = letter_w_diacritic[n][37]; break;
+
+      case ALONE:  c = (( !diacritic[n].b ) ? diacritic[n].a : -1);
+                   break;
+
+      default:   c = 0;
+      }
+
+      if ( c > 0 ) {
+        *o++ = c;  s++;
+      } else {
+        *o++ = '{';
+        if ( c == -1 ) {
+          *o++ = ( ( *s == ALONE ) ? ' ' : *s );
+          s++;
+        } else {
+          *o++ = '"';
+        }
+        *o++ = diacritic[n].a;
+        *o++ = '}';
+      }
+      break;
+
+#if (ISO_8859 == 0)
+    case 0x8: case 0x9:
+      *o++ = 0x1B; /* <ESC> */
+      *o++ = *s++ - 0x40;
+      break;
+#endif
+
+      default:
+        *o++ = *s++;
+    }
+  }
+
+  len = o - oo;
+  o = oo;
+
+  if ( (oo = (Byte *)realloc( o, len )) == NULL ) {
+    free( o );
+    return( 1 );
+  }
+
+  if ( free_input ) {
+    free( *bufp );
+  }
+  *bufp = (char *) oo;
+  *buflenp = len;
+  return( 0 );
+}
+
+
+static int
+hh_to_c( Byte *h )
+{
+  Byte c;
+
+  if ( (*h >= '0') && (*h <= '9') )      c = *h++ - '0';
+  else if ( (*h >= 'A') && (*h <= 'F') ) c = *h++ - 'A' + 10;
+  else if ( (*h >= 'a') && (*h <= 'f') ) c = *h++ - 'a' + 10;
+  else return -1;
+
+  c <<= 4;
+
+  if ( (*h >= '0') && (*h <= '9') )      c |= *h - '0';
+  else if ( (*h >= 'A') && (*h <= 'F') ) c |= *h - 'A' + 10;
+  else if ( (*h >= 'a') && (*h <= 'f') ) c |= *h - 'a' + 10;
+  else return -1;
+
+  return c;
+}
+
+
+static Byte *
+cc_to_t61( Byte *o, Byte *s )
+{
+  int n, c = 0;
+
+  switch ( *(s + 1) ) {
+
+  case '`':  c = -1;   break;    /* <grave-accent> */
+
+  case '!':
+    switch ( *s ) {
+    case '!':  c = 0x7C;  break;  /* <vertical-line> */
+    case '(':  c = 0x7B;  break;  /* <left-curly-bracket> */
+    case '-':  c = 0xAD;  break;  /* <upwards-arrow> */
+    default:   c = -1;            /* <grave-accent> */
+    }
+    break;
+
+#if (ISO_8859 == 1) || (ISO_8859 == 2) || (ISO_8859 == 3) || \
+    (ISO_8859 == 4) || (ISO_8859 == 9)
+  case 0xB4:
+#endif
+  case '\'': c = -2;  break;    /* <acute-accent> */
+
+  case '^':  c = -3;  break;    /* <circumflex-acent> */
+
+  case '>':
+    switch ( *s ) {
+    case ')':  c = 0x5D;  break;  /* <right-square-bracket> */
+    case '>':  c = 0xBB;  break;  /* <right-angle-quotation> */
+    case '-':  c = 0xAE;  break;  /* <rightwards-arrow> */
+    default:   c = -3;            /* <circumflex-acent> */
+    }
+    break;
+
+  case '~':
+  case '?':  c = -4;  break;        /* <tilde> */
+
+#if (ISO_8859 == 1) || (ISO_8859 == 4) || (ISO_8859 == 9)
+  case 0xAF:  c = -5;  break;       /* <macron> */
+#endif
+
+  case '-':
+    switch ( *s ) {
+    case '-':  c = 0xFF; break; /* <soft-hyphen> */
+    case '<':  c = 0xAC; break; /* <leftwards arrow> */
+    case '+':  c = 0xB1; break; /* <plus-minus> */
+    case 'd':  c = 0xF3; break; /* <eth> */
+    default:   c = -5;          /* <macron> */
+    }
+    break;
+
+#if (ISO_8859 == 2) || (ISO_8859 == 3)
+  case 0xA2:  c = -6;  break;            /* <breve> */
+#endif
+
+  case '(':
+    if ( *s == '<' ) c = 0x5B;  /* <left-square-bracket> */
+    else             c = -6;    /* <breve> */
+    break;
+
+#if (ISO_8859 == 2) || (ISO_8859 == 3) || (ISO_8859 == 4)
+  case 0xFF:  c = -7;  break;    /* <dot-accent> */
+#endif
+
+  case '.':
+    switch ( *s ) {
+    case 'i':  c = 0xF5; break; /* <dotless-i> */
+    case 'L':  c = 0xE7; break; /* <L-middle-dot> */
+    case 'l':  c = 0xF7; break; /* <l-middle-dot> */
+    default:   c = -7;          /* <dot-accent> */
+    }
+    break;
+
+#if (ISO_8859 == 1) || (ISO_8859 == 2) || (ISO_8859 == 3) || \
+    (ISO_8859 == 4) || (ISO_8859 == 9)
+  case 0xA8:  c = -8; break; /* <diaeresis> */
+#endif
+
+  case ':':
+    if ( *s == '-')  c = 0xB8; /* <division-sign> */
+    else             c = -8;   /* <diaeresis> */
+    break;
+
+#if (ISO_8859 == 1) || (ISO_8859 == 2) || (ISO_8859 == 3) || \
+    (ISO_8859 == 4) || (ISO_8859 == 9) || (ISO_8859 == 10)
+  case 0xB0:
+#endif
+  case '0':  c = -10;  break;  /* <ring-above> */
+
+#if (ISO_8859 == 1) || (ISO_8859 == 2) || (ISO_8859 == 3) || \
+    (ISO_8859 == 4) || (ISO_8859 == 9)
+  case 0xB8:
+#endif
+  case ',':  c = -11; break; /* <cedilla> */
+
+#if (ISO_8859 == 2)
+  case 0xBD:
+#endif
+  case '"':  c = -13; break; /* <double-acute-accent> */
+
+#if (ISO_8859 == 2) || (ISO_8859 == 4)
+  case 0xB2:
+#endif
+  case ';':  c = -14; break; /* <ogonek> */
+
+#if (ISO_8859 == 2) || (ISO_8859 == 4)
+  case 0xB7:  c = -15;  break;  /* <caron> */
+#endif
+
+  case ')':
+    if ( *s == '!' )  c = 0x7D;  /* <left-curly-bracket> */
+    break;
+
+  case '<':
+    if ( *s == '<' )  c = 0xAB;  /* <left-angle-quotation> */
+    else              c = -15;   /* <caron> */
+    break;
+
+  case '/':
+    switch ( *s ) {
+    case '/':  c = 0x5C; break; /* <reverse-solidus> */
+    case 'D':  c = 0xE2; break; /* <D-stroke> */
+    case 'd':  c = 0xF2; break; /* <d-stroke> */
+    case 'H':  c = 0xE4; break; /* <H-stroke> */
+    case 'h':  c = 0xF4; break; /* <h-stroke> */
+    case 'L':  c = 0xE8; break; /* <L-stroke> */
+    case 'l':  c = 0xF8; break; /* <l-stroke> */
+    case 'O':  c = 0xE9; break; /* <O-stroke> */
+    case 'o':  c = 0xF9; break; /* <o-stroke> */
+    case 'T':  c = 0xED; break; /* <T-stroke> */
+    case 't':  c = 0xFD; break; /* <t-stroke> */
+    }
+    break;
+
+  case '2':
+    if ( *s == '1' )  c = 0xBD;    /* <one-half> */
+    break;
+
+  case '4':
+    switch ( *s ) {
+    case '1':  c = 0xBC; break; /* <one-quarter> */
+    case '3':  c = 0xBE; break; /* <three-quarters> */
+    }
+    break;
+
+  case '6':
+    switch ( *s ) {
+    case '\'': c = 0xA9; break; /* <left-single-quotation> */
+    case '"':  c = 0xAA; break; /* <left-double-quotation> */
+    }
+    break;
+
+  case '8':
+    switch ( *s ) {
+    case '1':  c = 0xDC; break; /* <one-eighth> */
+    case '3':  c = 0xDD; break; /* <three-eighths> */
+    case '5':  c = 0xDE; break; /* <five-eighths> */
+    case '7':  c = 0xDF; break; /* <seven-eighths> */
+    case 'M':  c = 0xD5; break; /* <eighth-note> */
+    }
+    break;
+
+  case '9':
+    switch ( *s ) {
+    case '\'': c = 0xB9; break; /* <right-single-quotation> */
+    case '"':  c = 0xBA; break; /* <right-double-quotation> */
+    }
+    break;
+
+  case 'A':
+    if ( *s == 'A' )  c = -10;  /* <ring-above> + <A> */
+    break;
+
+  case 'a':
+    switch ( *s ) {
+    case '-':  c = 0xE3; break; /* <femenine-ordinal-a> */
+    case 'a':  c = -10;  break; /* <ring-above> + <a> */
+    }
+    break;
+
+  case 'B':
+    if ( *s == 'B' )  c = 0xD7; /* <broken-bar> */
+    break;
+
+  case 'b':
+    if ( *s == 'N' )  c = 0xA6;  /* <number-sign> */
+    break;
+
+  case 'd':
+    if ( *s == 'P' )  c = 0xA3;  /* <pound-sign> */
+    break;
+
+  case 'E':
+    switch ( *s ) {
+    case 'S':  c = 0xA7; break; /* <section-sign> */
+    case 'A':  c = 0xE1; break; /* <AE> */
+    case 'O':  c = 0xEA; break; /* <OE> */
+    }
+    break;
+
+  case 'e':
+    switch ( *s ) {
+    case 'a':  c = 0xF1; break; /* <ae> */
+    case 'o':  c = 0xFA; break; /* <oe> */
+    case 'Y':  c = 0xA5;  break;  /* <yen-sign> */
+    }
+    break;
+
+  case 'G':
+    switch ( *s ) {
+    case 'D':  c = 0xB0; break; /* <degree-sign> */
+    case 'N':  c = 0xEE; break; /* <Eng> */
+    }
+    break;
+
+  case 'g':
+    switch ( *s ) {
+    case 'R':  c = 0xD2; break;  /* <registered-sign> */
+    case 'n':  c = 0xFE; break; /* <eng> */
+    }
+    break;
+
+  case 'H':
+    if ( *s == 'T' )  c = 0xEC;  /* <Thorn> */
+    break;
+
+  case 'h':
+    if ( *s == 't' )  c = 0xFC; /* <thorn> */
+    break;
+
+  case 'I':
+    switch ( *s ) {
+    case 'P':  c = 0xB6; break;  /* <pilcrow-sign> */
+    case '!':  c = 0xA1; break; /* <inverted-exclamation> */
+    case '?':  c = 0xBF; break; /* <inverted-question> */
+    }
+    break;
+
+  case 'J':
+    if ( *s == 'I' )  c = 0xE6; /* <IJ> */
+    break;
+
+  case 'j':
+    if ( *s == 'i' )  c = 0xF6;  /* <ij> */
+    break;
+
+  case 'k':
+    if ( *s == 'k' )  c = 0xF0; /* <kra> */
+    break;
+
+  case 'M':
+    switch ( *s ) {
+    case '.':  c = 0xB7; break; /* <middle-dot> */
+    case '-':  c = 0xD0; break; /* <em-dash> */
+    case 'T':  c = 0xD4; break; /* <trade-mark-sign> */
+    }
+    break;
+
+  case 'm':
+    switch ( *s ) {
+    case '\'':                  /* <macron> RFC 1345 */
+    case ' ':  c = -5;   break; /* <macron> */
+    case 'O':  c = 0xE0; break; /* <Ohm sign> */
+    }
+    break;
+
+  case 'n':
+    if ( *s == '\'' )  c = 0xEF; /* <n-preceded-by-apostrophe> */
+    break;
+
+  case 'O':
+    switch ( *s ) {
+    case 'D':  c = 0xA4; break; /* <dollar-sign> */
+    case 'N':  c = 0xD6; break; /* <not-sign> */
+    }
+    break;
+
+  case 'o':
+    switch ( *s ) {
+    case 'C':  c = 0xD3; break; /* <copyright-sign> */
+    case '-':  c = 0xEB; break; /* <masculine-ordinal-o> */
+    }
+    break;
+
+  case 'S':
+    switch ( *s ) {
+    case '1':  c = 0xD1; break; /* <superscript-1> */
+    case '2':  c = 0xB2; break; /* <superscript-2> */
+    case '3':  c = 0xB3; break; /* <superscript-3> */
+    case 'N':  c = 0xA0; break; /* <no-break-space> */
+    }
+    break;
+
+  case 's':
+    if ( *s == 's' )  c = 0xFB; /* <sharp-s> */
+    break;
+
+  case 't':
+    if ( *s == 'C' )  c = 0xA2; /* <cent-sign> */
+    break;
+
+  case 'u':
+    if ( *s == 'C' )  c = 0xA8; /* <currency-sign> */
+    break;
+
+  case 'v':
+    if ( *s == '-' )  c = 0xAF; /* <downwards-arrow> */
+    break;
+
+  case 'X':
+    if ( *s == '*' )  c = 0xB4; /* <multiplication-sign> */
+    break;
+
+  case 'y':
+    if ( *s == 'M' )  c = 0xB5; /* <micro-sign> */
+    break;
+  }
+
+  if ( c > 0 ) {
+    *o++ = c;
+    return o;
+  } else if ( !c )
+    return NULL;
+
+  /* else: c < 0 */
+  n = -c;
+  switch ( *s ) {
+
+  case 'A':  c = letter_w_diacritic[n][0]; break;
+  case 'C':  c = letter_w_diacritic[n][1]; break;
+  case 'D':  c = letter_w_diacritic[n][2]; break;
+  case 'E':  c = letter_w_diacritic[n][3]; break;
+  case 'G':  c = letter_w_diacritic[n][4]; break;
+  case 'H':  c = letter_w_diacritic[n][5]; break;
+  case 'I':  c = letter_w_diacritic[n][6]; break;
+  case 'J':  c = letter_w_diacritic[n][7]; break;
+  case 'K':  c = letter_w_diacritic[n][8]; break;
+  case 'L':  c = letter_w_diacritic[n][9]; break;
+  case 'N':  c = letter_w_diacritic[n][10]; break;
+  case 'O':  c = letter_w_diacritic[n][11]; break;
+  case 'R':  c = letter_w_diacritic[n][12]; break;
+  case 'S':  c = letter_w_diacritic[n][13]; break;
+  case 'T':  c = letter_w_diacritic[n][14]; break;
+  case 'U':  c = letter_w_diacritic[n][15]; break;
+  case 'W':  c = letter_w_diacritic[n][16]; break;
+  case 'Y':  c = letter_w_diacritic[n][17]; break;
+  case 'Z':  c = letter_w_diacritic[n][18]; break;
+
+  case 'a':  c = letter_w_diacritic[n][19]; break;
+  case 'c':  c = letter_w_diacritic[n][20]; break;
+  case 'd':  c = letter_w_diacritic[n][21]; break;
+  case 'e':  c = letter_w_diacritic[n][22]; break;
+  case 'g':  c = letter_w_diacritic[n][23]; break;
+  case 'h':  c = letter_w_diacritic[n][24]; break;
+  case 'i':  c = letter_w_diacritic[n][25]; break;
+  case 'j':  c = letter_w_diacritic[n][26]; break;
+  case 'k':  c = letter_w_diacritic[n][27]; break;
+  case 'l':  c = letter_w_diacritic[n][28]; break;
+  case 'n':  c = letter_w_diacritic[n][29]; break;
+  case 'o':  c = letter_w_diacritic[n][30]; break;
+  case 'r':  c = letter_w_diacritic[n][31]; break;
+  case 's':  c = letter_w_diacritic[n][32]; break;
+  case 't':  c = letter_w_diacritic[n][33]; break;
+  case 'u':  c = letter_w_diacritic[n][34]; break;
+  case 'w':  c = letter_w_diacritic[n][35]; break;
+  case 'y':  c = letter_w_diacritic[n][36]; break;
+  case 'z':  c = letter_w_diacritic[n][37]; break;
+
+  case '\'':
+  case ' ':  c = -1; break;
+
+  default:   c = 0;
+  }
+
+  if ( !c )
+    return NULL;
+
+  *o++ = n + 0xC0;
+  *o++ = ( ( (*s == ' ') || (*s == '\'') ) ? ALONE : *s );
+  return o;
+}
+
+
+/* --- routine to convert from ISO 8859-n to T.61 --- */
+
+int
+ldap_8859_to_t61( char **bufp, unsigned long *buflenp, int free_input )
+{
+  Byte         *s, *oo, *o, *aux;
+  int          c;
+  unsigned long len; 
+  Couple       *cc;
+
+  Debug( LDAP_DEBUG_TRACE, "ldap_8859_to_t61 input length: %ld\n",
+       *buflenp, 0, 0 );
+
+  len = *buflenp;
+  s = (Byte *) *bufp;
+
+  if ( (o = oo = (Byte *)malloc( 2 * len + 64 )) == NULL ) {
+        return( 1 );
+  }
+
+  while ( (char *)s - *(char **)bufp < len ) {
+    switch( *s >> 5 ) {
+
+    case 2:
+      switch ( *s ) {
+
+      case '^':  *o++ = 0xC3; *o++ = ALONE; s++; break;
+
+      case '\\':
+        s++;
+        if ( (c = hh_to_c( s )) != -1 ) {
+          *o++ = c;
+          s += 2;
+        } else
+          *o++ = '\\';
+        break;
+
+      default:  *o++ = *s++;
+      }
+      break;
+
+    case 3:
+      switch ( *s ) {
+
+      case '`':  *o++ = 0xC1; *o++ = ALONE; s++; break;
+      case '~':  *o++ = 0xC4; *o++ = ALONE; s++; break;
+
+      case '{':
+        s++;
+        if ( *(s + 2) == '}' ) {
+          if ( (aux = cc_to_t61( o, s )) != NULL ) {
+            o = aux;
+            s += 3;
+          } else {
+            *o++ = '{';
+          }
+        } else if ( (*(s + 3) == '}') && ( (*s == 'x') || (*s == 'X') ) &&
+                    ( (c = hh_to_c( s + 1 )) != -1 ) ) {
+          *o++ = c;
+          s += 4;
+        } else {
+          *o++ = '{';
+        }
+        break;
+
+      default:
+        *o++ = *s++;
+      }
+      break;
+
+#if (ISO_8859 == 0)
+    case 4: case 5: case 6: case 7:
+      s++;
+      break;
+#else
+    case 5: case 6: case 7:
+# if (ISO_8859 == 1) || (ISO_8859 == 2) || (ISO_8859 == 3) || \
+     (ISO_8859 == 4) || (ISO_8859 == 9) || (ISO_8859 == 10)
+      if ( (*(cc = &trans_iso8859_t61[ *s - 0xA0 ])).a ) {
+       *o++ = (*cc).a;
+       if ( (*cc).b )  *o++ = (*cc).b;
+      }
+# endif
+      s++;
+      break;
+#endif
+
+    default:
+      *o++ = *s++;
+    }
+  }
+
+  len = o - oo;
+  o = oo;
+
+  if ( (oo = (Byte *)realloc( o, len )) == NULL ) {
+    free( o );
+    return( 1 );
+  }
+
+  if ( free_input ) {
+    free( *bufp );
+  }
+  *bufp = (char *) oo;
+  *buflenp = len;
+  return( 0 );
+}
+
+
+#ifdef NOT_NEEDED_IN_LIBLDAP   /* mcs@umich.edu 12 Oct 1995 */
+/* --- routine to convert "escaped" (\hh) characters to 8bits --- */
+
+void convert_escaped_to_8bit( s )
+char   *s;
+{
+  char *o = s;
+  int  c;
+
+  while ( *s ) {
+    if ( *s == '\\' ) {
+      if ( (c = hh_to_c( ++s )) != -1 ) {
+       *o++ = c;
+       s += 2;
+      } else
+        *o++ = '\\';
+    } else
+      *o++ = *s++;
+  }
+  *o = '\0';
+}
+
+/* --- routine to convert 8bits characters to the "escaped" (\hh) form --- */
+
+char *convert_8bit_to_escaped( s )
+Byte  *s;
+{
+  Byte *o, *oo;
+  Byte n;
+
+  if ( (o = oo = (Byte *)malloc( 2 * strlen( s ) + 64 )) == NULL ) {
+        return( NULL );
+  }
+
+  while ( *s ) {
+    if ( *s < 0x80 )
+      *o++ = *s++;
+    else {
+      *o++ = '\\';
+      n = *s >> 4;
+      *o++ = ((n < 0xA) ? '0' : 'A' - 0xA) + n;
+      n = *s++ & 0x0F;
+      *o++ = ((n < 0xA) ? '0' : 'A' - 0xA) + n;
+    }
+  }
+  *o = '\0';
+
+  o = oo;
+
+  if ( (oo = (Byte *)realloc( o, strlen( o ) + 1 )) == NULL ) {
+    free( o );
+    return( NULL );
+  }
+
+  return( (char *)oo );
+}
+
+/* --- routine to convert from T.61 to printable characters --- */
+
+/*
+   printable characters [RFC 1488]: 'A'..'Z', 'a'..'z', '0'..'9',
+       '\'', '(', ')', '+', ',', '-', '.', '/', ':', '?, ' '.
+
+   that conversion is language dependent.
+*/
+
+static Couple last_t61_printabled[32] = {
+       {0,0},     {'A','E'}, {'D',0},   {0,0},
+       {'H',0},   {0,0},     {'I','J'}, {'L',0},
+       {'L',0},   {'O',0},   {'O','E'}, {0,0},
+       {'T','H'}, {'T',0},   {'N','G'}, {'n',0},
+       {'k',0},   {'a','e'}, {'d',0},   {'d',0},
+       {'h',0},   {'i',0},   {'i','j'}, {'l',0},
+       {'l',0},   {'o',0},   {'o','e'}, {'s','s'},
+       {'t','h'}, {'t',0},   {'n','g'}, {0,0}
+};
+
+char *t61_printable( s )
+Byte  *s;
+{
+  Byte   *o, *oo;
+  Byte   n;
+  Couple *cc;
+
+  if ( (o = oo = (Byte *)malloc( 2 * strlen( s ) + 64 )) == NULL ) {
+        return( NULL );
+  }
+
+  while ( *s ) {
+    if ( ( (*s >= 'A') && (*s <= 'Z') ) ||
+         ( (*s >= 'a') && (*s <= 'z') ) ||
+         ( (*s >= '0') && (*s <= '9') ) ||
+         ( (*s >= '\'') && (*s <= ')') ) ||
+         ( (*s >= '+') && (*s <= '/') ) ||
+         ( *s == '?' ) || ( *s == ' ' ) )
+      *o++ = *s++;
+    else {
+      if ( *s >= 0xE0 ) {
+       if ( (*(cc = &last_t61_printabled[ *s - 0xE0 ])).a ) {
+          *o++ = (*cc).a;
+          if ( (*cc).b )  *o++ = (*cc).b;
+        }
+      }
+      else if ( (*s >> 4) == 0xC ) {
+        switch ( *s ) {
+       case 0xCA:                      /* ring */
+         switch ( *(s + 1) ) {
+         case 'A':  *o++ = 'A'; *o++ = 'A'; s++; break; /* Swedish */
+         case 'a':  *o++ = 'a'; *o++ = 'a'; s++; break; /* Swedish */
+         }
+         break;
+
+       case 0xC8:                      /* diaeresis */
+         switch ( *(s + 1) ) {
+         case 'Y':  *o++ = 'I'; *o++ = 'J'; s++; break; /* Dutch */
+         case 'y':  *o++ = 'i'; *o++ = 'j'; s++; break; /* Dutch */
+          }
+         break;
+        }
+      }
+      s++;
+    }
+  }
+  *o = '\0';
+
+  o = oo;
+
+  if ( (oo = (Byte *)realloc( o, strlen( o ) + 1 )) == NULL ) {
+    free( o );
+    return( NULL );
+  }
+
+  return( (char *)oo );
+}
+#endif /* NOT_NEEDED_IN_LIBLDAP */     /* mcs@umich.edu 12 Oct 1995 */
+
+#endif /* LDAP_CHARSET_8859 */
+#endif /* STR_TRANSLATION */
diff --git a/libraries/libldap/cldap.c b/libraries/libldap/cldap.c
new file mode 100644 (file)
index 0000000..19782f7
--- /dev/null
@@ -0,0 +1,537 @@
+/*
+ *  Copyright (c) 1990, 1994 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  cldap.c - synchronous, retrying interface to the cldap protocol
+ */
+
+
+#ifdef CLDAP
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990, 1994 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#ifdef MACOS
+#include <stdlib.h>
+#include "macos.h"
+#else /* MACOS */
+#ifdef DOS
+#include "msdos.h"
+#else /* DOS */
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#endif /* DOS */
+#endif /* MACOS */
+
+#include "lber.h"
+#include "ldap.h"
+#include "ldap-int.h"
+
+#define DEF_CLDAP_TIMEOUT      3
+#define DEF_CLDAP_TRIES                4
+
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK        ((unsigned long) 0x7f000001)
+#endif
+
+
+struct cldap_retinfo {
+       int             cri_maxtries;
+       int             cri_try;
+       int             cri_useaddr;
+       long            cri_timeout;
+};
+
+#ifdef NEEDPROTOS
+static int add_addr( LDAP *ld, struct sockaddr *sap );
+static int cldap_result( LDAP *ld, int msgid, LDAPMessage **res,
+       struct cldap_retinfo *crip, char *base );
+static int cldap_parsemsg( LDAP *ld, int msgid, BerElement *ber,
+       LDAPMessage **res, char *base );
+#else /* NEEDPROTOS */
+static int add_addr();
+static int cldap_result();
+static int cldap_parsemsg();
+#endif /* NEEDPROTOS */
+
+/*
+ * cldap_open - initialize and connect to an ldap server.  A magic cookie to
+ * be used for future communication is returned on success, NULL on failure.
+ *
+ * Example:
+ *     LDAP    *ld;
+ *     ld = cldap_open( hostname, port );
+ */
+
+LDAP *
+cldap_open( char *host, int port )
+{
+    int                s;
+    unsigned long      address;
+    struct sockaddr_in         sock;
+    struct hostent     *hp;
+    LDAP               *ld;
+    char               *p;
+    int                        i;
+
+    Debug( LDAP_DEBUG_TRACE, "ldap_open\n", 0, 0, 0 );
+
+    if ( port == 0 ) {
+           port = LDAP_PORT;
+    }
+
+    if ( (s = socket( AF_INET, SOCK_DGRAM, 0 )) < 0 ) {
+       return( NULL );
+    }
+
+    sock.sin_addr.s_addr = 0;
+    sock.sin_family = AF_INET;
+    sock.sin_port = 0;
+    if ( bind(s, (struct sockaddr *) &sock, sizeof(sock)) < 0)  {
+       close( s );
+       return( NULL );
+    }
+
+    if (( ld = ldap_init( host, port )) == NULL ) {
+       close( s );
+       return( NULL );
+    }
+    if ( (ld->ld_sb.sb_fromaddr = (void *) calloc( 1,
+           sizeof( struct sockaddr ))) == NULL ) {
+       free( ld );
+       close( s );
+       return( NULL );
+    }  
+    ld->ld_sb.sb_sd = s;
+    ld->ld_sb.sb_naddr = 0;
+    ld->ld_version = LDAP_VERSION;
+
+    sock.sin_family = AF_INET;
+    sock.sin_port = htons( port );
+
+    /*
+     * 'host' may be a space-separated list.
+     */
+    if ( host != NULL ) {
+       for ( ; host != NULL; host = p ) {
+           if (( p = strchr( host, ' ' )) != NULL ) {
+               for (*p++ = '\0'; *p == ' '; p++) {
+                   ;
+               }
+           }
+
+           if ( (address = inet_addr( host )) == -1 ) {
+               if ( (hp = gethostbyname( host )) == NULL ) {
+                   errno = EHOSTUNREACH;
+                   continue;
+               }
+
+               for ( i = 0; hp->h_addr_list[ i ] != 0; ++i ) {
+                   SAFEMEMCPY( (char *)&sock.sin_addr.s_addr,
+                           (char *)hp->h_addr_list[ i ],
+                           sizeof(sock.sin_addr.s_addr));
+                   if ( add_addr( ld, (struct sockaddr *)&sock ) < 0 ) {
+                       close( s );
+                       free( ld );
+                       return( NULL );
+                   }
+               }
+
+           } else {
+               sock.sin_addr.s_addr = address;
+               if ( add_addr( ld, (struct sockaddr *)&sock ) < 0 ) {
+                   close( s );
+                   free( ld );
+                   return( NULL );
+               }
+           }
+
+           if ( ld->ld_host == NULL ) {
+                   ld->ld_host = strdup( host );
+           }
+       }
+
+    } else {
+       address = INADDR_LOOPBACK;
+       sock.sin_addr.s_addr = htonl( address );
+       if ( add_addr( ld, (struct sockaddr *)&sock ) < 0 ) {
+           close( s );
+           free( ld );
+           return( NULL );
+       }
+    }
+
+    if ( ld->ld_sb.sb_addrs == NULL
+#ifdef LDAP_REFERRALS
+           || ( ld->ld_defconn = new_connection( ld, NULL, 1,0,0 )) == NULL
+#endif /* LDAP_REFERRALS */
+           ) {
+       free( ld );
+       return( NULL );
+    }
+
+    ld->ld_sb.sb_useaddr = ld->ld_sb.sb_addrs[ 0 ];
+    cldap_setretryinfo( ld, 0, 0 );
+
+#ifdef LDAP_DEBUG
+    putchar( '\n' );
+    for ( i = 0; i < ld->ld_sb.sb_naddr; ++i ) {
+       Debug( LDAP_DEBUG_TRACE, "end of cldap_open address %d is %s\n",
+               i, inet_ntoa( ((struct sockaddr_in *)
+               ld->ld_sb.sb_addrs[ i ])->sin_addr ), 0 );
+    }
+#endif
+
+    return( ld );
+}
+
+
+
+void
+cldap_close( LDAP *ld )
+{
+       ldap_ld_free( ld, 0 );
+}
+
+
+void
+cldap_setretryinfo( LDAP *ld, int tries, int timeout )
+{
+    ld->ld_cldaptries = ( tries <= 0 ) ? DEF_CLDAP_TRIES : tries;
+    ld->ld_cldaptimeout = ( timeout <= 0 ) ? DEF_CLDAP_TIMEOUT : timeout;
+}
+
+
+int
+cldap_search_s( LDAP *ld, char *base, int scope, char *filter, char **attrs,
+       int attrsonly, LDAPMessage **res, char *logdn )
+{
+    int                                ret, msgid;
+    struct cldap_retinfo       cri;
+
+    *res = NULLMSG;
+
+    (void) memset( &cri, 0, sizeof( cri ));
+
+    if ( logdn != NULL ) {
+       ld->ld_cldapdn = logdn;
+    } else if ( ld->ld_cldapdn == NULL ) {
+       ld->ld_cldapdn = "";
+    }
+
+    do {
+       if ( cri.cri_try != 0 ) {
+               --ld->ld_msgid; /* use same id as before */
+       }
+       ld->ld_sb.sb_useaddr = ld->ld_sb.sb_addrs[ cri.cri_useaddr ];
+
+       Debug( LDAP_DEBUG_TRACE, "cldap_search_s try %d (to %s)\n",
+           cri.cri_try, inet_ntoa( ((struct sockaddr_in *)
+           ld->ld_sb.sb_useaddr)->sin_addr ), 0 );
+
+           if ( (msgid = ldap_search( ld, base, scope, filter, attrs,
+               attrsonly )) == -1 ) {
+                   return( ld->ld_errno );
+           }
+#ifndef NO_CACHE
+           if ( ld->ld_cache != NULL && ld->ld_responses != NULL ) {
+               Debug( LDAP_DEBUG_TRACE, "cldap_search_s res from cache\n",
+                       0, 0, 0 );
+               *res = ld->ld_responses;
+               ld->ld_responses = ld->ld_responses->lm_next;
+               return( ldap_result2error( ld, *res, 0 ));
+           }
+#endif /* NO_CACHE */
+           ret = cldap_result( ld, msgid, res, &cri, base );
+       } while (ret == -1);
+
+       return( ret );
+}
+
+
+static int
+add_addr( LDAP *ld, struct sockaddr *sap )
+{
+    struct sockaddr    *newsap, **addrs;
+
+    if (( newsap = (struct sockaddr *)malloc( sizeof( struct sockaddr )))
+           == NULL ) {
+       ld->ld_errno = LDAP_NO_MEMORY;
+       return( -1 );
+    }
+
+    if ( ld->ld_sb.sb_naddr == 0 ) {
+       addrs = (struct sockaddr **)malloc( sizeof(struct sockaddr *));
+    } else {
+       addrs = (struct sockaddr **)realloc( ld->ld_sb.sb_addrs,
+               ( ld->ld_sb.sb_naddr + 1 ) * sizeof(struct sockaddr *));
+    }
+
+    if ( addrs == NULL ) {
+       free( newsap );
+       ld->ld_errno = LDAP_NO_MEMORY;
+       return( -1 );
+    }
+
+    SAFEMEMCPY( (char *)newsap, (char *)sap, sizeof( struct sockaddr ));
+    addrs[ ld->ld_sb.sb_naddr++ ] = newsap;
+    ld->ld_sb.sb_addrs = (void **)addrs;
+    return( 0 );
+}
+
+
+static int
+cldap_result( LDAP *ld, int msgid, LDAPMessage **res,
+       struct cldap_retinfo *crip, char *base )
+{
+    Sockbuf            *sb = &ld->ld_sb;
+    BerElement         ber;
+    char               *logdn;
+    int                        ret, id, fromaddr, i;
+    struct timeval     tv;
+
+    fromaddr = -1;
+
+    if ( crip->cri_try == 0 ) {
+       crip->cri_maxtries = ld->ld_cldaptries * sb->sb_naddr;
+       crip->cri_timeout = ld->ld_cldaptimeout;
+       crip->cri_useaddr = 0;
+       Debug( LDAP_DEBUG_TRACE, "cldap_result tries %d timeout %d\n",
+               ld->ld_cldaptries, ld->ld_cldaptimeout, 0 );
+    }
+
+    if ((tv.tv_sec = crip->cri_timeout / sb->sb_naddr) < 1 ) {
+       tv.tv_sec = 1;
+    }
+    tv.tv_usec = 0;
+
+    Debug( LDAP_DEBUG_TRACE,
+           "cldap_result waiting up to %d seconds for a response\n",
+           tv.tv_sec, 0, 0 );
+    ber_init( &ber, 0 );
+    set_ber_options( ld, &ber );
+
+    if ( cldap_getmsg( ld, &tv, &ber ) == -1 ) {
+       ret = ld->ld_errno;
+       Debug( LDAP_DEBUG_TRACE, "cldap_getmsg returned -1 (%d)\n",
+               ret, 0, 0 );
+    } else if ( ld->ld_errno == LDAP_TIMEOUT ) {
+       Debug( LDAP_DEBUG_TRACE,
+           "cldap_result timed out\n", 0, 0, 0 );
+       /*
+        * It timed out; is it time to give up?
+        */
+       if ( ++crip->cri_try >= crip->cri_maxtries ) {
+           ret = LDAP_TIMEOUT;
+           --crip->cri_try;
+       } else {
+           if ( ++crip->cri_useaddr >= sb->sb_naddr ) {
+               /*
+                * new round: reset address to first one and
+                * double the timeout
+                */
+               crip->cri_useaddr = 0;
+               crip->cri_timeout <<= 1;
+           }
+           ret = -1;
+       }
+
+    } else {
+       /*
+        * Got a response.  It should look like:
+        * { msgid, logdn, { searchresponse...}}
+        */
+       logdn = NULL;
+
+       if ( ber_scanf( &ber, "ia", &id, &logdn ) == LBER_ERROR ) {
+           free( ber.ber_buf );        /* gack! */
+           ret = LDAP_DECODING_ERROR;
+           Debug( LDAP_DEBUG_TRACE,
+                   "cldap_result: ber_scanf returned LBER_ERROR (%d)\n",
+                   ret, 0, 0 );
+       } else if ( id != msgid ) {
+           free( ber.ber_buf );        /* gack! */
+           Debug( LDAP_DEBUG_TRACE,
+                   "cldap_result: looking for msgid %d; got %d\n",
+                   msgid, id, 0 );
+           ret = -1;   /* ignore and keep looking */
+       } else {
+           /*
+            * got a result: determine which server it came from
+            * decode into ldap message chain
+            */
+           for ( fromaddr = 0; fromaddr < sb->sb_naddr; ++fromaddr ) {
+                   if ( memcmp( &((struct sockaddr_in *)
+                           sb->sb_addrs[ fromaddr ])->sin_addr,
+                           &((struct sockaddr_in *)sb->sb_fromaddr)->sin_addr,
+                           sizeof( struct in_addr )) == 0 ) {
+                       break;
+                   }
+           }
+           ret = cldap_parsemsg( ld, msgid, &ber, res, base );
+           free( ber.ber_buf );        /* gack! */
+           Debug( LDAP_DEBUG_TRACE,
+               "cldap_result got result (%d)\n", ret, 0, 0 );
+       }
+
+       if ( logdn != NULL ) {
+               free( logdn );
+       }
+    }
+    
+
+    /*
+     * If we are giving up (successfully or otherwise) then 
+     * abandon any outstanding requests.
+     */
+    if ( ret != -1 ) {
+       i = crip->cri_try;
+       if ( i >= sb->sb_naddr ) {
+           i = sb->sb_naddr - 1;
+       }
+
+       for ( ; i >= 0; --i ) {
+           if ( i == fromaddr ) {
+               continue;
+           }
+           sb->sb_useaddr = sb->sb_addrs[ i ];
+           Debug( LDAP_DEBUG_TRACE, "cldap_result abandoning id %d (to %s)\n",
+               msgid, inet_ntoa( ((struct sockaddr_in *)
+               sb->sb_useaddr)->sin_addr ), 0 );
+           (void) ldap_abandon( ld, msgid );
+       }
+    }
+
+    return( ld->ld_errno = ret );
+}
+
+
+static int
+cldap_parsemsg( LDAP *ld, int msgid, BerElement *ber,
+       LDAPMessage **res, char *base )
+{
+    unsigned long      tag, len;
+    int                        baselen, slen, rc;
+    char               *dn, *p, *cookie;
+    LDAPMessage                *chain, *prev, *ldm;
+    struct berval      *bv;
+
+    rc = LDAP_DECODING_ERROR;  /* pessimistic */
+    ldm = chain = prev = NULLMSG;
+    baselen = ( base == NULL ) ? 0 : strlen( base );
+    bv = NULL;
+
+    for ( tag = ber_first_element( ber, &len, &cookie );
+           tag != LBER_DEFAULT && rc != LDAP_SUCCESS;
+           tag = ber_next_element( ber, &len, cookie )) {
+       if (( ldm = (LDAPMessage *)calloc( 1, sizeof(LDAPMessage)))
+               == NULL || ( ldm->lm_ber = alloc_ber_with_options( ld ))
+               == NULLBER ) {
+           rc = LDAP_NO_MEMORY;
+           break;      /* return w/error*/
+       }
+       ldm->lm_msgid = msgid;
+       ldm->lm_msgtype = tag;
+
+       if ( tag == LDAP_RES_SEARCH_RESULT ) {
+           Debug( LDAP_DEBUG_TRACE, "cldap_parsemsg got search result\n",
+                   0, 0, 0 );
+
+           if ( ber_get_stringal( ber, &bv ) == LBER_DEFAULT ) {
+               break;  /* return w/error */
+           }
+
+           if ( ber_printf( ldm->lm_ber, "to", tag, bv->bv_val,
+                   bv->bv_len ) == -1 ) {
+               break;  /* return w/error */
+           }
+           ber_bvfree( bv );
+           bv = NULL;
+           rc = LDAP_SUCCESS;
+
+       } else if ( tag == LDAP_RES_SEARCH_ENTRY ) {
+           if ( ber_scanf( ber, "{aO", &dn, &bv ) == LBER_ERROR ) {
+               break;  /* return w/error */
+           }
+           Debug( LDAP_DEBUG_TRACE, "cldap_parsemsg entry %s\n", dn, 0, 0 );
+           if ( dn != NULL && *(dn + ( slen = strlen(dn)) - 1) == '*' &&
+                   baselen > 0 ) {
+               /*
+                * substitute original searchbase for trailing '*'
+                */
+               if (( p = (char *)malloc( slen + baselen )) == NULL ) {
+                   rc = LDAP_NO_MEMORY;
+                   free( dn );
+                   break;      /* return w/error */
+               }
+               strcpy( p, dn );
+               strcpy( p + slen - 1, base );
+               free( dn );
+               dn = p;
+           }
+
+           if ( ber_printf( ldm->lm_ber, "t{so}", tag, dn, bv->bv_val,
+                   bv->bv_len ) == -1 ) {
+               break;  /* return w/error */
+           }
+           free( dn );
+           ber_bvfree( bv );
+           bv = NULL;
+               
+       } else {
+           Debug( LDAP_DEBUG_TRACE, "cldap_parsemsg got unknown tag %d\n",
+                   tag, 0, 0 );
+           rc = LDAP_PROTOCOL_ERROR;
+           break;      /* return w/error */
+       }
+
+       /* Reset message ber so we can read from it later.  Gack! */
+       ldm->lm_ber->ber_end = ldm->lm_ber->ber_ptr;
+       ldm->lm_ber->ber_ptr = ldm->lm_ber->ber_buf;
+
+#ifdef LDAP_DEBUG
+       if ( ldap_debug & LDAP_DEBUG_PACKETS ) {
+           fprintf( stderr, "cldap_parsemsg add message id %d type %d:\n",
+                   ldm->lm_msgid, ldm->lm_msgtype  );
+           ber_dump( ldm->lm_ber, 1 );
+       }
+#endif /* LDAP_DEBUG */
+
+#ifndef NO_CACHE
+           if ( ld->ld_cache != NULL ) {
+               add_result_to_cache( ld, ldm );
+           }
+#endif /* NO_CACHE */
+
+       if ( chain == NULL ) {
+           chain = ldm;
+       } else {
+           prev->lm_chain = ldm;
+       }
+       prev = ldm;
+       ldm = NULL;
+    }
+
+    /* dispose of any leftovers */
+    if ( ldm != NULL ) {
+       if ( ldm->lm_ber != NULLBER ) {
+           ber_free( ldm->lm_ber, 1 );
+       }
+       free( ldm );
+    }
+    if ( bv != NULL ) {
+       ber_bvfree( bv );
+    }
+
+    /* return chain, calling result2error if we got anything at all */
+    *res = chain;
+    return(( *res == NULLMSG ) ? rc : ldap_result2error( ld, *res, 0 ));
+}
+#endif /* CLDAP */
diff --git a/libraries/libldap/compare.c b/libraries/libldap/compare.c
new file mode 100644 (file)
index 0000000..74388f1
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  compare.c
+ */
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef MACOS
+#include "macos.h"
+#endif /* MACOS */
+
+#if !defined( MACOS ) && !defined( DOS )
+#include <sys/types.h>
+#include <sys/socket.h>
+#endif
+
+#include "lber.h"
+#include "ldap.h"
+#include "ldap-int.h"
+
+/*
+ * ldap_compare - perform an ldap (and X.500) compare operation.  The dn
+ * of the entry to compare to and the attribute and value to compare (in
+ * attr and value) are supplied.  The msgid of the response is returned.
+ *
+ * Example:
+ *     ldap_compare( ld, "c=us@cn=bob", "userPassword", "secret" )
+ */
+int
+ldap_compare( LDAP *ld, char *dn, char *attr, char *value )
+{
+       BerElement      *ber;
+
+       /* The compare request looks like this:
+        *      CompareRequest ::= SEQUENCE {
+        *              entry   DistinguishedName,
+        *              ava     SEQUENCE {
+        *                      type    AttributeType,
+        *                      value   AttributeValue
+        *              }
+        *      }
+        * and must be wrapped in an LDAPMessage.
+        */
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_compare\n", 0, 0, 0 );
+
+       /* create a message to send */
+       if ( (ber = alloc_ber_with_options( ld )) == NULLBER ) {
+               return( -1 );
+       }
+
+       if ( ber_printf( ber, "{it{s{ss}}}", ++ld->ld_msgid, LDAP_REQ_COMPARE,
+           dn, attr, value ) == -1 ) {
+               ld->ld_errno = LDAP_ENCODING_ERROR;
+               ber_free( ber, 1 );
+               return( -1 );
+       }
+
+#ifndef NO_CACHE
+       if ( ld->ld_cache != NULL ) {
+               if ( check_cache( ld, LDAP_REQ_COMPARE, ber ) == 0 ) {
+                       ber_free( ber, 1 );
+                       ld->ld_errno = LDAP_SUCCESS;
+                       return( ld->ld_msgid );
+               }
+               add_request_to_cache( ld, LDAP_REQ_COMPARE, ber );
+       }
+#endif /* NO_CACHE */
+
+       /* send the message */
+       return ( send_initial_request( ld, LDAP_REQ_COMPARE, dn, ber ));
+}
+
+int
+ldap_compare_s( LDAP *ld, char *dn, char *attr, char *value )
+{
+       int             msgid;
+       LDAPMessage     *res;
+
+       if ( (msgid = ldap_compare( ld, dn, attr, value )) == -1 )
+               return( ld->ld_errno );
+
+       if ( ldap_result( ld, msgid, 1, (struct timeval *) NULL, &res ) == -1 )
+               return( ld->ld_errno );
+
+       return( ldap_result2error( ld, res, 1 ) );
+}
diff --git a/libraries/libldap/delete.c b/libraries/libldap/delete.c
new file mode 100644 (file)
index 0000000..47e240e
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  delete.c
+ */
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef MACOS
+#include "macos.h"
+#endif /* MACOS */
+
+#if defined( DOS ) || defined( _WIN32 )
+#include "msdos.h"
+#endif /* DOS */
+
+#if !defined( MACOS ) && !defined( DOS )
+#include <sys/types.h>
+#include <sys/socket.h>
+#endif
+
+#include "lber.h"
+#include "ldap.h"
+#include "ldap-int.h"
+
+/*
+ * ldap_delete - initiate an ldap (and X.500) delete operation. Parameters:
+ *
+ *     ld              LDAP descriptor
+ *     dn              DN of the object to delete
+ *
+ * Example:
+ *     msgid = ldap_delete( ld, dn );
+ */
+int
+ldap_delete( LDAP *ld, char *dn )
+{
+       BerElement      *ber;
+
+       /*
+        * A delete request looks like this:
+        *      DelRequet ::= DistinguishedName,
+        */
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_delete\n", 0, 0, 0 );
+
+       /* create a message to send */
+       if ( (ber = alloc_ber_with_options( ld )) == NULLBER ) {
+               return( -1 );
+       }
+
+       if ( ber_printf( ber, "{its}", ++ld->ld_msgid, LDAP_REQ_DELETE, dn )
+           == -1 ) {
+               ld->ld_errno = LDAP_ENCODING_ERROR;
+               ber_free( ber, 1 );
+               return( -1 );
+       }
+
+       /* send the message */
+       return ( send_initial_request( ld, LDAP_REQ_DELETE, dn, ber ));
+}
+
+
+int
+ldap_delete_s( LDAP *ld, char *dn )
+{
+       int             msgid;
+       LDAPMessage     *res;
+
+       if ( (msgid = ldap_delete( ld, dn )) == -1 )
+               return( ld->ld_errno );
+
+       if ( ldap_result( ld, msgid, 1, (struct timeval *) NULL, &res ) == -1 )
+               return( ld->ld_errno );
+
+       return( ldap_result2error( ld, res, 1 ) );
+}
diff --git a/libraries/libldap/disptmpl.c b/libraries/libldap/disptmpl.c
new file mode 100644 (file)
index 0000000..be41830
--- /dev/null
@@ -0,0 +1,725 @@
+/*
+ * Copyright (c) 1993, 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ *
+ * disptmpl.c:  display template library routines for LDAP clients
+ * 7 March 1994 by Mark C Smith
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#ifdef MACOS
+#include "macos.h"
+#else /* MACOS */
+#ifdef DOS
+#include <malloc.h>
+#include "msdos.h"
+#else /* DOS */
+#include <sys/types.h>
+#include <sys/file.h>
+#ifndef VMS
+#include <unistd.h>
+#endif /* VMS */
+#endif /* DOS */
+#endif /* MACOS */
+
+#include "lber.h"
+#include "ldap.h"
+#include "disptmpl.h"
+
+#ifndef NEEDPROTOS
+static void free_disptmpl();
+static int read_next_tmpl();
+int next_line_tokens();
+void free_strarray();
+#else /* !NEEDPROTOS */
+static void free_disptmpl( struct ldap_disptmpl *tmpl );
+static int read_next_tmpl( char **bufp, long *blenp,
+       struct ldap_disptmpl **tmplp, int dtversion );
+int next_line_tokens( char **bufp, long *blenp, char ***toksp );
+void free_strarray( char **sap );
+#endif /* !NEEDPROTOS */
+
+static char            *tmploptions[] = {
+    "addable", "modrdn",
+    "altview",
+    NULL
+};
+
+
+static unsigned long   tmploptvals[] = {
+    LDAP_DTMPL_OPT_ADDABLE, LDAP_DTMPL_OPT_ALLOWMODRDN,
+    LDAP_DTMPL_OPT_ALTVIEW,
+};
+
+
+static char            *itemtypes[] = {
+    "cis",                     "mls",                  "dn",
+    "bool",                    "jpeg",                 "jpegbtn",
+    "fax",                     "faxbtn",               "audiobtn",
+    "time",                    "date",                 "url",
+    "searchact",               "linkact",              "adddnact",
+    "addact",                  "verifyact",            "mail",
+    NULL
+};
+
+static unsigned long   itemsynids[] = {
+    LDAP_SYN_CASEIGNORESTR,    LDAP_SYN_MULTILINESTR,  LDAP_SYN_DN,
+    LDAP_SYN_BOOLEAN,          LDAP_SYN_JPEGIMAGE,     LDAP_SYN_JPEGBUTTON,
+    LDAP_SYN_FAXIMAGE,         LDAP_SYN_FAXBUTTON,     LDAP_SYN_AUDIOBUTTON,
+    LDAP_SYN_TIME,             LDAP_SYN_DATE,          LDAP_SYN_LABELEDURL,
+    LDAP_SYN_SEARCHACTION,     LDAP_SYN_LINKACTION,    LDAP_SYN_ADDDNACTION,
+    LDAP_SYN_ADDDNACTION,      LDAP_SYN_VERIFYDNACTION,LDAP_SYN_RFC822ADDR,
+};
+
+
+static char            *itemoptions[] = {
+    "ro",                              "sort",
+    "1val",                            "hide",
+    "required",                                "hideiffalse",
+    NULL
+};
+
+
+static unsigned long   itemoptvals[] = {
+    LDAP_DITEM_OPT_READONLY,           LDAP_DITEM_OPT_SORTVALUES,
+    LDAP_DITEM_OPT_SINGLEVALUED,       LDAP_DITEM_OPT_HIDEIFEMPTY,
+    LDAP_DITEM_OPT_VALUEREQUIRED,      LDAP_DITEM_OPT_HIDEIFFALSE,
+};
+
+
+#define ADDEF_CONSTANT "constant"
+#define ADDEF_ADDERSDN "addersdn"
+
+
+int
+ldap_init_templates( char *file, struct ldap_disptmpl **tmpllistp )
+{
+    FILE       *fp;
+    char       *buf;
+    long       rlen, len;
+    int                rc, eof;
+
+    *tmpllistp = NULLDISPTMPL;
+
+    if (( fp = fopen( file, "r" )) == NULL ) {
+       return( LDAP_TMPL_ERR_FILE );
+    }
+
+    if ( fseek( fp, 0L, SEEK_END ) != 0 ) {    /* move to end to get len */
+       fclose( fp );
+       return( LDAP_TMPL_ERR_FILE );
+    }
+
+    len = ftell( fp );
+
+    if ( fseek( fp, 0L, SEEK_SET ) != 0 ) {    /* back to start of file */
+       fclose( fp );
+       return( LDAP_TMPL_ERR_FILE );
+    }
+
+    if (( buf = malloc( (size_t)len )) == NULL ) {
+       fclose( fp );
+       return( LDAP_TMPL_ERR_MEM );
+    }
+
+    rlen = fread( buf, 1, (size_t)len, fp );
+    eof = feof( fp );
+    fclose( fp );
+
+    if ( rlen != len && !eof ) {       /* error:  didn't get the whole file */
+       free( buf );
+       return( LDAP_TMPL_ERR_FILE );
+    }
+
+    rc = ldap_init_templates_buf( buf, rlen, tmpllistp );
+    free( buf );
+
+    return( rc );
+}
+
+
+int
+ldap_init_templates_buf( char *buf, long buflen,
+       struct ldap_disptmpl **tmpllistp )
+{
+    int                                rc, version;
+    char                       **toks;
+    struct ldap_disptmpl       *prevtmpl, *tmpl;
+
+    *tmpllistp = prevtmpl = NULLDISPTMPL;
+
+    if ( next_line_tokens( &buf, &buflen, &toks ) != 2 ||
+           strcasecmp( toks[ 0 ], "version" ) != 0 ) {
+       free_strarray( toks );
+       return( LDAP_TMPL_ERR_SYNTAX );
+    }
+    version = atoi( toks[ 1 ] );
+    free_strarray( toks );
+    if ( version != LDAP_TEMPLATE_VERSION ) {
+       return( LDAP_TMPL_ERR_VERSION );
+    }
+
+    while ( buflen > 0 && ( rc = read_next_tmpl( &buf, &buflen, &tmpl,
+           version )) == 0 && tmpl != NULLDISPTMPL ) {
+       if ( prevtmpl == NULLDISPTMPL ) {
+           *tmpllistp = tmpl;
+       } else {
+           prevtmpl->dt_next = tmpl;
+       }
+       prevtmpl = tmpl;
+    }
+
+    if ( rc != 0 ) {
+       ldap_free_templates( *tmpllistp );
+    }
+
+    return( rc );
+}
+           
+
+
+void
+ldap_free_templates( struct ldap_disptmpl *tmpllist )
+{
+    struct ldap_disptmpl       *tp, *nexttp;
+
+    if ( tmpllist != NULL ) {
+       for ( tp = tmpllist; tp != NULL; tp = nexttp ) {
+           nexttp = tp->dt_next;
+           free_disptmpl( tp );
+       }
+    }
+}
+
+
+static void
+free_disptmpl( struct ldap_disptmpl *tmpl )
+{
+    if ( tmpl != NULL ) {
+       if ( tmpl->dt_name != NULL ) {
+           free(  tmpl->dt_name );
+       }
+
+       if ( tmpl->dt_pluralname != NULL ) {
+           free( tmpl->dt_pluralname );
+       }
+
+       if ( tmpl->dt_iconname != NULL ) {
+           free( tmpl->dt_iconname );
+       }
+
+       if ( tmpl->dt_authattrname != NULL ) {
+           free( tmpl->dt_authattrname );
+       }
+
+       if ( tmpl->dt_defrdnattrname != NULL ) {
+           free( tmpl->dt_defrdnattrname );
+       }
+
+       if ( tmpl->dt_defaddlocation != NULL ) {
+           free( tmpl->dt_defaddlocation );
+       }
+
+       if (  tmpl->dt_oclist != NULL ) {
+           struct ldap_oclist  *ocp, *nextocp;
+
+           for ( ocp = tmpl->dt_oclist; ocp != NULL; ocp = nextocp ) {
+               nextocp = ocp->oc_next;
+               free_strarray( ocp->oc_objclasses );
+               free( ocp );
+           }
+       }
+
+       if (  tmpl->dt_adddeflist != NULL ) {
+           struct ldap_adddeflist      *adp, *nextadp;
+
+           for ( adp = tmpl->dt_adddeflist; adp != NULL; adp = nextadp ) {
+               nextadp = adp->ad_next;
+               if( adp->ad_attrname != NULL ) {
+                   free( adp->ad_attrname );
+               }
+               if( adp->ad_value != NULL ) {
+                   free( adp->ad_value );
+               }
+               free( adp );
+           }
+       }
+
+       if (  tmpl->dt_items != NULL ) {
+           struct ldap_tmplitem        *rowp, *nextrowp, *colp, *nextcolp;
+
+           for ( rowp = tmpl->dt_items; rowp != NULL; rowp = nextrowp ) {
+               nextrowp = rowp->ti_next_in_col;
+               for ( colp = rowp; colp != NULL; colp = nextcolp ) {
+                   nextcolp = colp->ti_next_in_row;
+                   if ( colp->ti_attrname != NULL ) {
+                       free( colp->ti_attrname );
+                   }
+                   if ( colp->ti_label != NULL ) {
+                       free( colp->ti_label );
+                   }
+                   if ( colp->ti_args != NULL ) {
+                       free_strarray( colp->ti_args );
+                   }
+                   free( colp );
+               }
+           }
+       }
+
+       free( tmpl );
+    }
+}
+
+
+struct ldap_disptmpl *
+ldap_first_disptmpl( struct ldap_disptmpl *tmpllist )
+{
+    return( tmpllist );
+}
+
+
+struct ldap_disptmpl *
+ldap_next_disptmpl( struct ldap_disptmpl *tmpllist,
+       struct ldap_disptmpl *tmpl )
+{
+    return( tmpl == NULLDISPTMPL ? tmpl : tmpl->dt_next );
+}
+
+
+struct ldap_disptmpl *
+ldap_name2template( char *name, struct ldap_disptmpl *tmpllist )
+{
+    struct ldap_disptmpl       *dtp;
+
+    for ( dtp = ldap_first_disptmpl( tmpllist ); dtp != NULLDISPTMPL;
+           dtp = ldap_next_disptmpl( tmpllist, dtp )) {
+       if ( strcasecmp( name, dtp->dt_name ) == 0 ) {
+           return( dtp );
+       }
+    }
+
+    return( NULLDISPTMPL );
+}
+
+
+struct ldap_disptmpl *
+ldap_oc2template( char **oclist, struct ldap_disptmpl *tmpllist )
+{
+    struct ldap_disptmpl       *dtp;
+    struct ldap_oclist         *oclp;
+    int                                i, j, needcnt, matchcnt;
+
+    if ( tmpllist == NULL || oclist == NULL || oclist[ 0 ] == NULL ) {
+       return( NULLDISPTMPL );
+    }
+
+    for ( dtp = ldap_first_disptmpl( tmpllist ); dtp != NULLDISPTMPL;
+               dtp = ldap_next_disptmpl( tmpllist, dtp )) {
+       for ( oclp = dtp->dt_oclist; oclp != NULLOCLIST;
+               oclp = oclp->oc_next ) {
+           needcnt = matchcnt = 0;
+           for ( i = 0; oclp->oc_objclasses[ i ] != NULL; ++i ) {
+               for ( j = 0; oclist[ j ] != NULL; ++j ) {
+                   if ( strcasecmp( oclist[ j ], oclp->oc_objclasses[ i ] )
+                           == 0 ) {
+                       ++matchcnt;
+                   }
+               }
+               ++needcnt;
+           }
+
+           if ( matchcnt == needcnt ) {
+               return( dtp );
+           }
+       }
+    }
+
+    return( NULLDISPTMPL );
+}
+
+
+struct ldap_tmplitem *
+ldap_first_tmplrow( struct ldap_disptmpl *tmpl )
+{
+    return( tmpl->dt_items );
+}
+
+
+struct ldap_tmplitem *
+ldap_next_tmplrow( struct ldap_disptmpl *tmpl, struct ldap_tmplitem *row )
+{
+    return( row == NULLTMPLITEM ? row : row->ti_next_in_col );
+}
+
+
+struct ldap_tmplitem *
+ldap_first_tmplcol( struct ldap_disptmpl *tmpl, struct ldap_tmplitem *row )
+{
+    return( row );
+}
+
+
+struct ldap_tmplitem *
+ldap_next_tmplcol( struct ldap_disptmpl *tmpl, struct ldap_tmplitem *row,
+       struct ldap_tmplitem *col )
+{
+    return( col == NULLTMPLITEM ? col : col->ti_next_in_row );
+}
+
+
+char **
+ldap_tmplattrs( struct ldap_disptmpl *tmpl, char **includeattrs,
+       int exclude, unsigned long syntaxmask )
+{
+/*
+ * this routine should filter out duplicate attributes...
+ */
+    struct ldap_tmplitem       *tirowp, *ticolp;
+    int                        i, attrcnt, memerr;
+    char               **attrs;
+
+    attrcnt = 0;
+    memerr = 0;
+
+    if (( attrs = (char **)malloc( sizeof( char * ))) == NULL ) {
+       return( NULL );
+    }
+
+    if ( includeattrs != NULL ) {
+       for ( i = 0; !memerr && includeattrs[ i ] != NULL; ++i ) {
+           if (( attrs = (char **)realloc( attrs, ( attrcnt + 2 ) *
+                   sizeof( char * ))) == NULL || ( attrs[ attrcnt++ ] =
+                   strdup( includeattrs[ i ] )) == NULL ) {
+               memerr = 1;
+           } else {
+               attrs[ attrcnt ] = NULL;
+           }
+       }
+    }
+
+    for ( tirowp = ldap_first_tmplrow( tmpl );
+           !memerr && tirowp != NULLTMPLITEM;
+           tirowp = ldap_next_tmplrow( tmpl, tirowp )) {
+       for ( ticolp = ldap_first_tmplcol( tmpl, tirowp );
+               ticolp != NULLTMPLITEM;
+               ticolp = ldap_next_tmplcol( tmpl, tirowp, ticolp )) {
+
+           if ( syntaxmask != 0 ) {
+               if (( exclude &&
+                       ( syntaxmask & ticolp->ti_syntaxid ) != 0 ) ||
+                       ( !exclude &&
+                       ( syntaxmask & ticolp->ti_syntaxid ) == 0 )) {
+                   continue;
+               }
+           }
+
+           if ( ticolp->ti_attrname != NULL ) {
+               if (( attrs = (char **)realloc( attrs, ( attrcnt + 2 ) *
+                       sizeof( char * ))) == NULL || ( attrs[ attrcnt++ ] =
+                       strdup( ticolp->ti_attrname )) == NULL ) {
+                   memerr = 1;
+               } else {
+                   attrs[ attrcnt ] = NULL;
+               }
+           }
+       }
+    }
+
+    if ( memerr || attrcnt == 0 ) {
+       for ( i = 0; i < attrcnt; ++i ) {
+           if ( attrs[ i ] != NULL ) {
+               free( attrs[ i ] );
+           }
+       }
+
+       free( (char *)attrs );
+       return( NULL );
+    }
+
+    return( attrs );
+}
+
+
+static int
+read_next_tmpl( char **bufp, long *blenp, struct ldap_disptmpl **tmplp,
+       int dtversion )
+{
+    int                                i, j, tokcnt, samerow, adsource;
+    char                       **toks, *itemopts;
+    struct ldap_disptmpl       *tmpl;
+    struct ldap_oclist         *ocp, *prevocp;
+    struct ldap_adddeflist     *adp, *prevadp;
+    struct ldap_tmplitem       *rowp, *ip, *previp;
+
+    *tmplp = NULL;
+
+    /*
+     * template name comes first
+     */
+    if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+       free_strarray( toks );
+       return( tokcnt == 0 ? 0 : LDAP_TMPL_ERR_SYNTAX );
+    }
+
+    if (( tmpl = (struct ldap_disptmpl *)calloc( 1,
+           sizeof( struct ldap_disptmpl ))) == NULL ) {
+       free_strarray( toks );
+       return(  LDAP_TMPL_ERR_MEM );
+    }
+    tmpl->dt_name = toks[ 0 ];
+    free( (char *)toks );
+
+    /*
+     * template plural name comes next
+     */
+    if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+       free_strarray( toks );
+       free_disptmpl( tmpl );
+       return( LDAP_TMPL_ERR_SYNTAX );
+    }
+    tmpl->dt_pluralname = toks[ 0 ];
+    free( (char *)toks );
+
+    /*
+     * template icon name is next
+     */
+    if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+       free_strarray( toks );
+       free_disptmpl( tmpl );
+       return( LDAP_TMPL_ERR_SYNTAX );
+    }
+    tmpl->dt_iconname = toks[ 0 ];
+    free( (char *)toks );
+
+    /*
+     * template options come next
+     */
+    if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) < 1 ) {
+       free_strarray( toks );
+       free_disptmpl( tmpl );
+       return( LDAP_TMPL_ERR_SYNTAX );
+    }
+    for ( i = 0; toks[ i ] != NULL; ++i ) {
+       for ( j = 0; tmploptions[ j ] != NULL; ++j ) {
+           if ( strcasecmp( toks[ i ], tmploptions[ j ] ) == 0 ) {
+               tmpl->dt_options |= tmploptvals[ j ];
+           }
+       }
+    }
+    free_strarray( toks );
+
+    /*
+     * object class list is next
+     */
+    while (( tokcnt = next_line_tokens( bufp, blenp, &toks )) > 0 ) {
+       if (( ocp = (struct ldap_oclist *)calloc( 1,
+               sizeof( struct ldap_oclist ))) == NULL ) {
+           free_strarray( toks );
+           free_disptmpl( tmpl );
+           return( LDAP_TMPL_ERR_MEM );
+       }
+       ocp->oc_objclasses = toks;
+       if ( tmpl->dt_oclist == NULL ) {
+           tmpl->dt_oclist = ocp;
+       } else {
+           prevocp->oc_next = ocp;
+       }
+       prevocp = ocp;
+    }
+    if ( tokcnt < 0 ) {
+       free_disptmpl( tmpl );
+       return( LDAP_TMPL_ERR_SYNTAX );
+    }
+
+    /*
+     * read name of attribute to authenticate as
+     */
+    if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+       free_strarray( toks );
+       free_disptmpl( tmpl );
+       return( LDAP_TMPL_ERR_SYNTAX );
+    }
+    if ( toks[ 0 ][ 0 ] != '\0' ) {
+       tmpl->dt_authattrname = toks[ 0 ];
+    } else {
+       free( toks[ 0 ] );
+    }
+    free( (char *)toks );
+
+    /*
+     * read default attribute to use for RDN
+     */
+    if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+       free_strarray( toks );
+       free_disptmpl( tmpl );
+       return( LDAP_TMPL_ERR_SYNTAX );
+    }
+    tmpl->dt_defrdnattrname = toks[ 0 ];
+    free( (char *)toks );
+
+    /*
+     * read default location for new entries
+     */
+    if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+       free_strarray( toks );
+       free_disptmpl( tmpl );
+       return( LDAP_TMPL_ERR_SYNTAX );
+    }
+    if ( toks[ 0 ][ 0 ] != '\0' ) {
+       tmpl->dt_defaddlocation = toks[ 0 ];
+    } else {
+       free( toks[ 0 ] );
+    }
+    free( (char *)toks );
+
+    /*
+     * read list of rules used to define default values for new entries
+     */
+    while (( tokcnt = next_line_tokens( bufp, blenp, &toks )) > 0 ) {
+       if ( strcasecmp( ADDEF_CONSTANT, toks[ 0 ] ) == 0 ) {
+           adsource = LDAP_ADSRC_CONSTANTVALUE;
+       } else if ( strcasecmp( ADDEF_ADDERSDN, toks[ 0 ] ) == 0 ) {
+           adsource = LDAP_ADSRC_ADDERSDN;
+       } else {
+           adsource = 0;
+       }
+       if ( adsource == 0 || tokcnt < 2 ||
+               ( adsource == LDAP_ADSRC_CONSTANTVALUE && tokcnt != 3 ) ||
+               ( adsource == LDAP_ADSRC_ADDERSDN && tokcnt != 2 )) {
+           free_strarray( toks );
+           free_disptmpl( tmpl );
+           return( LDAP_TMPL_ERR_SYNTAX );
+       }
+               
+       if (( adp = (struct ldap_adddeflist *)calloc( 1,
+               sizeof( struct ldap_adddeflist ))) == NULL ) {
+           free_strarray( toks );
+           free_disptmpl( tmpl );
+           return( LDAP_TMPL_ERR_MEM );
+       }
+       adp->ad_source = adsource;
+       adp->ad_attrname = toks[ 1 ];
+       if ( adsource == LDAP_ADSRC_CONSTANTVALUE ) {
+           adp->ad_value = toks[ 2 ];
+       }
+       free( toks[ 0 ] );
+       free( (char *)toks );
+
+       if ( tmpl->dt_adddeflist == NULL ) {
+           tmpl->dt_adddeflist = adp;
+       } else {
+           prevadp->ad_next = adp;
+       }
+       prevadp = adp;
+    }
+
+    /*
+     * item list is next
+     */
+    samerow = 0;
+    while (( tokcnt = next_line_tokens( bufp, blenp, &toks )) > 0 ) {
+       if ( strcasecmp( toks[ 0 ], "item" ) == 0 ) {
+           if ( tokcnt < 4 ) {
+               free_strarray( toks );
+               free_disptmpl( tmpl );
+               return( LDAP_TMPL_ERR_SYNTAX );
+           }
+
+           if (( ip = (struct ldap_tmplitem *)calloc( 1,
+                   sizeof( struct ldap_tmplitem ))) == NULL ) {
+               free_strarray( toks );
+               free_disptmpl( tmpl );
+               return( LDAP_TMPL_ERR_MEM );
+           }
+
+           /*
+            * find syntaxid from config file string
+            */
+           while (( itemopts = strrchr( toks[ 1 ], ',' )) != NULL ) {
+               *itemopts++ = '\0';
+               for ( i = 0; itemoptions[ i ] != NULL; ++i ) {
+                   if ( strcasecmp( itemopts, itemoptions[ i ] ) == 0 ) {
+                       break;
+                   }
+               }
+               if ( itemoptions[ i ] == NULL ) {
+                   free_strarray( toks );
+                   free_disptmpl( tmpl );
+                   return( LDAP_TMPL_ERR_SYNTAX );
+               }
+               ip->ti_options |= itemoptvals[ i ];
+           }
+
+           for ( i = 0; itemtypes[ i ] != NULL; ++i ) {
+               if ( strcasecmp( toks[ 1 ], itemtypes[ i ] ) == 0 ) {
+                   break;
+               }
+           }
+           if ( itemtypes[ i ] == NULL ) {
+               free_strarray( toks );
+               free_disptmpl( tmpl );
+               return( LDAP_TMPL_ERR_SYNTAX );
+           }
+
+           free( toks[ 0 ] );
+           free( toks[ 1 ] );
+           ip->ti_syntaxid = itemsynids[ i ];
+           ip->ti_label = toks[ 2 ];
+           if ( toks[ 3 ][ 0 ] == '\0' ) {
+               ip->ti_attrname = NULL;
+               free( toks[ 3 ] );
+           } else {
+               ip->ti_attrname = toks[ 3 ];
+           }
+           if ( toks[ 4 ] != NULL ) {  /* extra args. */
+               for ( i = 0; toks[ i + 4 ] != NULL; ++i ) {
+                   ;
+               }
+               if (( ip->ti_args = (char **) calloc( i + 1, sizeof( char * )))
+                       == NULL ) {
+                   free_disptmpl( tmpl );
+                   return( LDAP_TMPL_ERR_MEM );
+               }
+               for ( i = 0; toks[ i + 4 ] != NULL; ++i ) {
+                   ip->ti_args[ i ] = toks[ i + 4 ];
+               }
+           }
+           free( (char *)toks );
+
+           if ( tmpl->dt_items == NULL ) {
+               tmpl->dt_items = rowp = ip;
+           } else if ( samerow ) {
+               previp->ti_next_in_row = ip;
+           } else {
+               rowp->ti_next_in_col = ip;
+               rowp = ip;
+           }
+           previp = ip;
+           samerow = 0;
+       } else if ( strcasecmp( toks[ 0 ], "samerow" ) == 0 ) {
+           free_strarray( toks );
+           samerow = 1;
+       } else {
+           free_strarray( toks );
+           free_disptmpl( tmpl );
+           return( LDAP_TMPL_ERR_SYNTAX );
+       }
+    }
+    if ( tokcnt < 0 ) {
+       free_disptmpl( tmpl );
+       return( LDAP_TMPL_ERR_SYNTAX );
+    }
+
+    *tmplp = tmpl;
+    return( 0 );
+}
diff --git a/libraries/libldap/dsparse.c b/libraries/libldap/dsparse.c
new file mode 100644 (file)
index 0000000..1771d72
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 1993, 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ *
+ * dsparse.c:  parsing routines used by display template and search 
+ * preference file library routines for LDAP clients.
+ *
+ * 7 March 1994 by Mark C Smith
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#ifdef MACOS
+#include <stdlib.h>
+#include "macos.h"
+#else /* MACOS */
+#ifdef DOS
+#include <malloc.h>
+#include "msdos.h"
+#else /* DOS */
+#include <sys/types.h>
+#include <sys/file.h>
+#include <stdlib.h>
+#endif /* DOS */
+#endif /* MACOS */
+
+#include "lber.h"
+#include "ldap.h"
+
+#ifndef NEEDPROTOS
+int next_line_tokens();
+void free_strarray();
+static int next_line();
+static char *next_token();
+#else /* !NEEDPROTOS */
+int next_line_tokens( char **bufp, long *blenp, char ***toksp );
+void free_strarray( char **sap );
+static int next_line( char **bufp, long *blenp, char **linep );
+static char *next_token( char ** sp );
+#endif /* !NEEDPROTOS */
+
+
+
+int
+next_line_tokens( char **bufp, long *blenp, char ***toksp )
+{
+    char       *p, *line, *token, **toks;
+    int                rc, tokcnt;
+
+    *toksp = NULL;
+
+    if (( rc = next_line( bufp, blenp, &line )) <= 0 ) {
+       return( rc );
+    }
+
+    if (( toks = (char **)calloc( 1, sizeof( char * ))) == NULL ) {
+       free( line );
+       return( -1 );
+    }
+    tokcnt = 0;
+
+    p = line;
+    while (( token = next_token( &p )) != NULL ) {
+       if (( toks = (char **)realloc( toks, ( tokcnt + 2 ) *
+               sizeof( char * ))) == NULL ) {
+           free( (char *)toks );
+           free( line );
+           return( -1 );
+       }
+       toks[ tokcnt ] = token;
+       toks[ ++tokcnt ] = NULL;
+    }
+
+    if ( tokcnt == 1 && strcasecmp( toks[ 0 ], "END" ) == 0 ) {
+       tokcnt = 0;
+       free_strarray( toks );
+       toks = NULL;
+    }
+
+    free( line );
+
+    if ( tokcnt == 0 ) {
+       if ( toks != NULL ) {
+           free( (char *)toks );
+       }
+    } else {
+       *toksp = toks;
+    }
+
+    return( tokcnt );
+}
+
+
+static int
+next_line( char **bufp, long *blenp, char **linep )
+{
+    char       *linestart, *line, *p;
+    long       plen;
+
+    linestart = *bufp;
+    p = *bufp;
+    plen = *blenp;
+
+    do {
+       for ( linestart = p; plen > 0; ++p, --plen ) {
+           if ( *p == '\r' ) {
+               if ( plen > 1 && *(p+1) == '\n' ) {
+                   ++p;
+                   --plen;
+               }
+               break;
+           }
+
+           if ( *p == '\n' ) {
+               if ( plen > 1 && *(p+1) == '\r' ) {
+                   ++p;
+                   --plen;
+               }
+               break;
+           }
+       }
+       ++p;
+       --plen;
+    } while ( plen > 0 && ( *linestart == '#' || linestart + 1 == p ));
+
+
+    *bufp = p;
+    *blenp = plen;
+
+
+    if ( plen <= 0 ) {
+       *linep = NULL;
+       return( 0 );    /* end of file */
+    }
+
+    if (( line = malloc( p - linestart )) == NULL ) {
+       *linep = NULL;
+       return( -1 );   /* fatal error */
+    }
+
+    (void) memcpy( line, linestart, p - linestart );
+    line[ p - linestart - 1 ] = '\0';
+    *linep = line;
+    return( strlen( line ));
+}
+
+
+static char *
+next_token( char **sp )
+{
+    int                in_quote = 0;
+    char       *p, *tokstart, *t;
+
+    if ( **sp == '\0' ) {
+       return( NULL );
+    }
+
+    p = *sp;
+
+    while ( isspace( *p )) {           /* skip leading white space */
+       ++p;
+    }
+
+    if ( *p == '\0' ) {
+       return( NULL );
+    }
+
+    if ( *p == '\"' ) {
+       in_quote = 1;
+       ++p;
+    }
+    t = tokstart = p;
+
+    for ( ;; ) {
+       if ( *p == '\0' || ( isspace( *p ) && !in_quote )) {
+           if ( *p != '\0' ) {
+               ++p;
+           }
+           *t++ = '\0';                /* end of token */
+           break;
+       }
+
+       if ( *p == '\"' ) {
+           in_quote = !in_quote;
+           ++p;
+       } else {
+           *t++ = *p++;
+       }
+    }
+
+    *sp = p;
+
+    if ( t == tokstart ) {
+       return( NULL );
+    }
+
+    return( strdup( tokstart ));
+}
+
+
+void
+free_strarray( char **sap )
+{
+    int                i;
+
+    if ( sap != NULL ) {
+       for ( i = 0; sap[ i ] != NULL; ++i ) {
+           free( sap[ i ] );
+       }
+       free( (char *)sap );
+    }
+}
diff --git a/libraries/libldap/error.c b/libraries/libldap/error.c
new file mode 100644 (file)
index 0000000..b59563e
--- /dev/null
@@ -0,0 +1,171 @@
+#include <stdio.h>
+#include <string.h>
+#ifdef MACOS
+#include <stdlib.h>
+#else /* MACOS */
+#if defined( DOS ) || defined( _WIN32 )
+#include <malloc.h>
+#include "msdos.h"
+#else /* DOS */
+#include <sys/types.h>
+#include <sys/socket.h>
+#endif /* DOS */
+#endif /* MACOS */
+#include "lber.h"
+#include "ldap.h"
+
+struct ldaperror {
+       int     e_code;
+       char    *e_reason;
+};
+
+static struct ldaperror ldap_errlist[] = {
+       LDAP_SUCCESS,                   "Success",
+       LDAP_OPERATIONS_ERROR,          "Operations error",
+       LDAP_PROTOCOL_ERROR,            "Protocol error",
+       LDAP_TIMELIMIT_EXCEEDED,        "Timelimit exceeded",
+       LDAP_SIZELIMIT_EXCEEDED,        "Sizelimit exceeded",
+       LDAP_COMPARE_FALSE,             "Compare false",
+       LDAP_COMPARE_TRUE,              "Compare true",
+       LDAP_STRONG_AUTH_NOT_SUPPORTED, "Strong authentication not supported",
+       LDAP_STRONG_AUTH_REQUIRED,      "Strong authentication required",
+       LDAP_PARTIAL_RESULTS,           "Partial results and referral received",
+       LDAP_NO_SUCH_ATTRIBUTE,         "No such attribute",
+       LDAP_UNDEFINED_TYPE,            "Undefined attribute type",
+       LDAP_INAPPROPRIATE_MATCHING,    "Inappropriate matching",
+       LDAP_CONSTRAINT_VIOLATION,      "Constraint violation",
+       LDAP_TYPE_OR_VALUE_EXISTS,      "Type or value exists",
+       LDAP_INVALID_SYNTAX,            "Invalid syntax",
+       LDAP_NO_SUCH_OBJECT,            "No such object",
+       LDAP_ALIAS_PROBLEM,             "Alias problem",
+       LDAP_INVALID_DN_SYNTAX,         "Invalid DN syntax",
+       LDAP_IS_LEAF,                   "Object is a leaf",
+       LDAP_ALIAS_DEREF_PROBLEM,       "Alias dereferencing problem",
+       LDAP_INAPPROPRIATE_AUTH,        "Inappropriate authentication",
+       LDAP_INVALID_CREDENTIALS,       "Invalid credentials",
+       LDAP_INSUFFICIENT_ACCESS,       "Insufficient access",
+       LDAP_BUSY,                      "DSA is busy",
+       LDAP_UNAVAILABLE,               "DSA is unavailable",
+       LDAP_UNWILLING_TO_PERFORM,      "DSA is unwilling to perform",
+       LDAP_LOOP_DETECT,               "Loop detected",
+       LDAP_NAMING_VIOLATION,          "Naming violation",
+       LDAP_OBJECT_CLASS_VIOLATION,    "Object class violation",
+       LDAP_NOT_ALLOWED_ON_NONLEAF,    "Operation not allowed on nonleaf",
+       LDAP_NOT_ALLOWED_ON_RDN,        "Operation not allowed on RDN",
+       LDAP_ALREADY_EXISTS,            "Already exists",
+       LDAP_NO_OBJECT_CLASS_MODS,      "Cannot modify object class",
+       LDAP_RESULTS_TOO_LARGE,         "Results too large",
+       LDAP_OTHER,                     "Unknown error",
+       LDAP_SERVER_DOWN,               "Can't contact LDAP server",
+       LDAP_LOCAL_ERROR,               "Local error",
+       LDAP_ENCODING_ERROR,            "Encoding error",
+       LDAP_DECODING_ERROR,            "Decoding error",
+       LDAP_TIMEOUT,                   "Timed out",
+       LDAP_AUTH_UNKNOWN,              "Unknown authentication method",
+       LDAP_FILTER_ERROR,              "Bad search filter",
+       LDAP_USER_CANCELLED,            "User cancelled operation",
+       LDAP_PARAM_ERROR,               "Bad parameter to an ldap routine",
+       LDAP_NO_MEMORY,                 "Out of memory",
+       -1, 0
+};
+
+char *
+ldap_err2string( int err )
+{
+       int     i;
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_err2string\n", 0, 0, 0 );
+
+       for ( i = 0; ldap_errlist[i].e_code != -1; i++ ) {
+               if ( err == ldap_errlist[i].e_code )
+                       return( ldap_errlist[i].e_reason );
+       }
+
+       return( "Unknown error" );
+}
+
+#ifndef NO_USERINTERFACE
+void
+ldap_perror( LDAP *ld, char *s )
+{
+       int     i;
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_perror\n", 0, 0, 0 );
+
+       if ( ld == NULL ) {
+               perror( s );
+               return;
+       }
+
+       for ( i = 0; ldap_errlist[i].e_code != -1; i++ ) {
+               if ( ld->ld_errno == ldap_errlist[i].e_code ) {
+                       fprintf( stderr, "%s: %s\n", s,
+                           ldap_errlist[i].e_reason );
+                       if ( ld->ld_matched != NULL && *ld->ld_matched != '\0' )
+                               fprintf( stderr, "%s: matched: %s\n", s,
+                                   ld->ld_matched );
+                       if ( ld->ld_error != NULL && *ld->ld_error != '\0' )
+                               fprintf( stderr, "%s: additional info: %s\n",
+                                   s, ld->ld_error );
+                       fflush( stderr );
+                       return;
+               }
+       }
+
+       fprintf( stderr, "%s: Not an LDAP errno %d\n", s, ld->ld_errno );
+       fflush( stderr );
+}
+
+#else
+
+void
+ldap_perror( LDAP *ld, char *s )
+{
+}
+
+#endif /* NO_USERINTERFACE */
+
+
+int
+ldap_result2error( LDAP *ld, LDAPMessage *r, int freeit )
+{
+       LDAPMessage     *lm;
+       BerElement      ber;
+       long            along;
+       int             rc;
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_result2error\n", 0, 0, 0 );
+
+       if ( r == NULLMSG )
+               return( LDAP_PARAM_ERROR );
+
+       for ( lm = r; lm->lm_chain != NULL; lm = lm->lm_chain )
+               ;       /* NULL */
+
+       if ( ld->ld_error ) {
+               free( ld->ld_error );
+               ld->ld_error = NULL;
+       }
+       if ( ld->ld_matched ) {
+               free( ld->ld_matched );
+               ld->ld_matched = NULL;
+       }
+
+       ber = *(lm->lm_ber);
+       if ( ld->ld_version == LDAP_VERSION2 ) {
+               rc = ber_scanf( &ber, "{iaa}", &along, &ld->ld_matched,
+                   &ld->ld_error );
+       } else {
+               rc = ber_scanf( &ber, "{ia}", &along, &ld->ld_error );
+       }
+       if ( rc == LBER_ERROR ) {
+               ld->ld_errno = LDAP_DECODING_ERROR;
+       } else {
+               ld->ld_errno = (int) along;
+       }
+
+       if ( freeit )
+               ldap_msgfree( r );
+
+       return( ld->ld_errno );
+}
diff --git a/libraries/libldap/free.c b/libraries/libldap/free.c
new file mode 100644 (file)
index 0000000..d7a1322
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ *  Copyright (c) 1994 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  free.c - some free routines are included here to avoid having to
+ *           link in lots of extra code when not using certain features
+ */
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1994 The Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef MACOS
+#include <stdlib.h>
+#include "macos.h"
+#else /* MACOS */
+#ifdef DOS
+#include <malloc.h>
+#include "msdos.h"
+#else /* DOS */
+#include <sys/types.h>
+#include <stdlib.h>
+#endif /* DOS */
+#endif /* MACOS */
+
+#include "lber.h"
+#include "ldap.h"
+
+void
+ldap_getfilter_free( LDAPFiltDesc *lfdp )
+{
+    LDAPFiltList       *flp, *nextflp;
+    LDAPFiltInfo       *fip, *nextfip;
+
+    for ( flp = lfdp->lfd_filtlist; flp != NULL; flp = nextflp ) {
+       for ( fip = flp->lfl_ilist; fip != NULL; fip = nextfip ) {
+           nextfip = fip->lfi_next;
+           free( fip->lfi_filter );
+           free( fip->lfi_desc );
+           free( fip );
+       }
+       nextflp = flp->lfl_next;
+       free( flp->lfl_pattern );
+       free( flp->lfl_delims );
+       free( flp->lfl_tag );
+       free( flp );
+    }
+
+    if ( lfdp->lfd_curvalcopy != NULL ) {
+       free( lfdp->lfd_curvalcopy );
+    }
+    if ( lfdp->lfd_curvalwords != NULL ) {
+       free( lfdp->lfd_curvalwords );
+    }
+    if ( lfdp->lfd_filtprefix != NULL ) {
+       free( lfdp->lfd_filtprefix );
+    }
+    if ( lfdp->lfd_filtsuffix != NULL ) {
+       free( lfdp->lfd_filtsuffix );
+    }
+
+    free( lfdp );
+}
+
+/*
+ * free a null-terminated array of pointers to mod structures. the
+ * structures are freed, not the array itself, unless the freemods
+ * flag is set.
+ */
+
+void
+ldap_mods_free( LDAPMod **mods, int freemods )
+{
+       int     i;
+
+       if ( mods == NULL )
+               return;
+
+       for ( i = 0; mods[i] != NULL; i++ ) {
+               if ( mods[i]->mod_op & LDAP_MOD_BVALUES ) {
+                       ber_bvecfree( mods[i]->mod_bvalues );
+               } else {
+                       ldap_value_free( mods[i]->mod_values );
+               }
+               free( (char *) mods[i] );
+       }
+
+       if ( freemods )
+               free( (char *) mods );
+}
diff --git a/libraries/libldap/friendly.c b/libraries/libldap/friendly.c
new file mode 100644 (file)
index 0000000..5d77f0b
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  friendly.c
+ */
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1993 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#ifdef MACOS
+#include <stdlib.h>
+#include "macos.h"
+#endif /* MACOS */
+
+#if defined( DOS ) || defined( _WIN32 )
+#include <malloc.h>
+#include "msdos.h"
+#endif /* DOS */
+
+#if !defined( MACOS ) && !defined( DOS )
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#endif
+
+#include "lber.h"
+#include "ldap.h"
+
+char *
+ldap_friendly_name( char *filename, char *uname, FriendlyMap **map )
+{
+       int     i, entries;
+       FILE    *fp;
+       char    *s;
+       char    buf[BUFSIZ];
+
+       if ( map == NULL ) {
+#if !defined( MACOS ) && !defined( DOS )
+               errno = EINVAL;
+#endif
+               return( uname );
+       }
+
+       if ( *map == NULL ) {
+               if ( (fp = fopen( filename, "r" )) == NULL )
+                       return( uname );
+
+               entries = 0;
+               while ( fgets( buf, sizeof(buf), fp ) != NULL ) {
+                       if ( buf[0] != '#' )
+                               entries++;
+               }
+               rewind( fp );
+
+               if ( (*map = (FriendlyMap *) malloc( (entries + 1) *
+                   sizeof(FriendlyMap) )) == NULL ) {
+                       fclose( fp );
+                       return( uname );
+               }
+
+               i = 0;
+               while ( fgets( buf, sizeof(buf), fp ) != NULL && i < entries ) {
+                       if ( buf[0] == '#' )
+                               continue;
+
+                       if ( (s = strchr( buf, '\n' )) != NULL )
+                               *s = '\0';
+
+                       if ( (s = strchr( buf, '\t' )) == NULL )
+                               continue;
+                       *s++ = '\0';
+
+                       if ( *s == '"' ) {
+                               int     esc = 0, found = 0;
+
+                               for ( ++s; *s && !found; s++ ) {
+                                       switch ( *s ) {
+                                       case '\\':
+                                               esc = 1;
+                                               break;
+                                       case '"':
+                                               if ( !esc )
+                                                       found = 1;
+                                               /* FALL */
+                                       default:
+                                               esc = 0;
+                                               break;
+                                       }
+                               }
+                       }
+
+                       (*map)[i].f_unfriendly = strdup( buf );
+                       (*map)[i].f_friendly = strdup( s );
+                       i++;
+               }
+
+               fclose( fp );
+               (*map)[i].f_unfriendly = NULL;
+       }
+
+       for ( i = 0; (*map)[i].f_unfriendly != NULL; i++ ) {
+               if ( strcasecmp( uname, (*map)[i].f_unfriendly ) == 0 )
+                       return( (*map)[i].f_friendly );
+       }
+       return( uname );
+}
+
+
+void
+ldap_free_friendlymap( FriendlyMap **map )
+{
+       struct friendly* pF = *map;
+
+       if ( pF == NULL )
+               return;
+
+       while ( pF->f_unfriendly )
+       {
+               free( pF->f_unfriendly );
+               free( pF->f_friendly );
+               pF++;
+       }
+       free( *map );
+       *map = NULL;
+}
diff --git a/libraries/libldap/getattr.c b/libraries/libldap/getattr.c
new file mode 100644 (file)
index 0000000..50caa77
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  getattr.c
+ */
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#ifdef MACOS
+#include <stdlib.h>
+#include "macos.h"
+#else /* MACOS */
+#if defined( DOS ) || defined( _WIN32 )
+#include <malloc.h>
+#include "msdos.h"
+#else /* DOS */
+#include <sys/types.h>
+#include <sys/socket.h>
+#endif /* DOS */
+#endif /* MACOS */
+
+#include "lber.h"
+#include "ldap.h"
+#include "ldap-int.h"
+
+char *
+ldap_first_attribute( LDAP *ld, LDAPMessage *entry, BerElement **ber )
+{
+       long    len;
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_first_attribute\n", 0, 0, 0 );
+
+       if ( (*ber = alloc_ber_with_options( ld )) == NULLBER ) {
+               return( NULL );
+       }
+
+       **ber = *entry->lm_ber;
+
+       /* 
+        * Skip past the sequence, dn, sequence of sequence, snarf the
+        * attribute type, and skip the set of values, leaving us
+        * positioned right before the next attribute type/value sequence.
+        */
+
+       len = LDAP_MAX_ATTR_LEN;
+       if ( ber_scanf( *ber, "{x{{sx}", ld->ld_attrbuffer, &len )
+           == LBER_ERROR ) {
+               ld->ld_errno = LDAP_DECODING_ERROR;
+               ber_free( *ber, 0 );
+               return( NULL );
+       }
+
+       return( ld->ld_attrbuffer );
+}
+
+/* ARGSUSED */
+char *
+ldap_next_attribute( LDAP *ld, LDAPMessage *entry, BerElement *ber )
+{
+       long    len;
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_next_attribute\n", 0, 0, 0 );
+
+       /* skip sequence, snarf attribute type, skip values */
+       len = LDAP_MAX_ATTR_LEN;
+       if ( ber_scanf( ber, "{sx}", ld->ld_attrbuffer, &len ) 
+           == LBER_ERROR ) {
+               ld->ld_errno = LDAP_DECODING_ERROR;
+               ber_free( ber, 0 );
+               return( NULL );
+       }
+
+       return( ld->ld_attrbuffer );
+}
diff --git a/libraries/libldap/getdn.c b/libraries/libldap/getdn.c
new file mode 100644 (file)
index 0000000..2ea0d03
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ *  Copyright (c) 1994 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  getdn.c
+ */
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#ifdef MACOS
+#include <stdlib.h>
+#include "macos.h"
+#else /* MACOS */
+#if defined( DOS ) || defined( _WIN32 )
+#include <malloc.h>
+#include "msdos.h"
+#else /* DOS */
+#include <sys/types.h>
+#include <sys/socket.h>
+#endif /* DOS */
+#endif /* MACOS */
+
+#include "lber.h"
+#include "ldap.h"
+
+char *
+ldap_get_dn( LDAP *ld, LDAPMessage *entry )
+{
+       char            *dn;
+       BerElement      tmp;
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_get_dn\n", 0, 0, 0 );
+
+       if ( entry == NULL ) {
+               ld->ld_errno = LDAP_PARAM_ERROR;
+               return( NULL );
+       }
+
+       tmp = *entry->lm_ber;   /* struct copy */
+       if ( ber_scanf( &tmp, "{a", &dn ) == LBER_ERROR ) {
+               ld->ld_errno = LDAP_DECODING_ERROR;
+               return( NULL );
+       }
+
+       return( dn );
+}
+
+char *
+ldap_dn2ufn( char *dn )
+{
+       char    *p, *ufn, *r;
+       int     state;
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 );
+
+       if ( ldap_is_dns_dn( dn ) || ( p = strchr( dn, '=' )) == NULL )
+               return( strdup( dn ));
+
+       ufn = strdup( ++p );
+
+#define INQUOTE                1
+#define OUTQUOTE       2
+       state = OUTQUOTE;
+       for ( p = ufn, r = ufn; *p; p++ ) {
+               switch ( *p ) {
+               case '\\':
+                       if ( *++p == '\0' )
+                               p--;
+                       else {
+                               *r++ = '\\';
+                               *r++ = *p;
+                       }
+                       break;
+               case '"':
+                       if ( state == INQUOTE )
+                               state = OUTQUOTE;
+                       else
+                               state = INQUOTE;
+                       *r++ = *p;
+                       break;
+               case ';':
+               case ',':
+                       if ( state == OUTQUOTE )
+                               *r++ = ',';
+                       else
+                               *r++ = *p;
+                       break;
+               case '=':
+                       if ( state == INQUOTE )
+                               *r++ = *p;
+                       else {
+                               char    *rsave = r;
+
+                               *r-- = '\0';
+                               while ( !isspace( *r ) && *r != ';'
+                                   && *r != ',' && r > ufn )
+                                       r--;
+                               r++;
+
+                               if ( strcasecmp( r, "c" )
+                                   && strcasecmp( r, "o" )
+                                   && strcasecmp( r, "ou" )
+                                   && strcasecmp( r, "st" )
+                                   && strcasecmp( r, "l" )
+                                   && strcasecmp( r, "cn" ) ) {
+                                       r = rsave;
+                                       *r++ = '=';
+                               }
+                       }
+                       break;
+               default:
+                       *r++ = *p;
+                       break;
+               }
+       }
+       *r = '\0';
+
+       return( ufn );
+}
+
+char **
+ldap_explode_dns( char *dn )
+{
+       int     ncomps, maxcomps;
+       char    *s;
+       char    **rdns;
+
+       if ( (rdns = (char **) malloc( 8 * sizeof(char *) )) == NULL ) {
+               return( NULL );
+       }
+
+       maxcomps = 8;
+       ncomps = 0;
+       for ( s = strtok( dn, "@." ); s != NULL; s = strtok( NULL, "@." ) ) {
+               if ( ncomps == maxcomps ) {
+                       maxcomps *= 2;
+                       if ( (rdns = (char **) realloc( rdns, maxcomps *
+                           sizeof(char *) )) == NULL ) {
+                               return( NULL );
+                       }
+               }
+               rdns[ncomps++] = strdup( s );
+       }
+       rdns[ncomps] = NULL;
+
+       return( rdns );
+}
+
+char **
+ldap_explode_dn( char *dn, int notypes )
+{
+       char    *p, *q, *rdnstart, **rdns = NULL;
+       int     state, count = 0, endquote, len;
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_explode_dn\n", 0, 0, 0 );
+
+       if ( ldap_is_dns_dn( dn ) ) {
+               return( ldap_explode_dns( dn ) );
+       }
+
+       rdnstart = dn;
+       p = dn-1;
+       state = OUTQUOTE;
+
+       do {
+
+               ++p;
+               switch ( *p ) {
+               case '\\':
+                       if ( *++p == '\0' )
+                               p--;
+                       break;
+               case '"':
+                       if ( state == INQUOTE )
+                               state = OUTQUOTE;
+                       else
+                               state = INQUOTE;
+                       break;
+               case ';':
+               case ',':
+               case '\0':
+                       if ( state == OUTQUOTE ) {
+                               ++count;
+                               if ( rdns == NULL ) {
+                                       if (( rdns = (char **)malloc( 8
+                                                * sizeof( char *))) == NULL )
+                                               return( NULL );
+                               } else if ( count >= 8 ) {
+                                       if (( rdns = (char **)realloc( rdns,
+                                               (count+1) * sizeof( char *)))
+                                               == NULL )
+                                               return( NULL );
+                               }
+                               rdns[ count ] = NULL;
+                               endquote = 0;
+                               if ( notypes ) {
+                                       for ( q = rdnstart;
+                                           q < p && *q != '='; ++q ) {
+                                               ;
+                                       }
+                                       if ( q < p ) {
+                                               rdnstart = ++q;
+                                       }
+                                       if ( *rdnstart == '"' ) {
+                                               ++rdnstart;
+                                       }
+                                       
+                                       if ( *(p-1) == '"' ) {
+                                               endquote = 1;
+                                               --p;
+                                       }
+                               }
+
+                               len = p - rdnstart;
+                               if (( rdns[ count-1 ] = (char *)calloc( 1,
+                                   len + 1 )) != NULL ) {
+                                       SAFEMEMCPY( rdns[ count-1 ], rdnstart,
+                                           len );
+                                       rdns[ count-1 ][ len ] = '\0';
+                               }
+
+                               /*
+                                *  Don't forget to increment 'p' back to where
+                                *  it should be.  If we don't, then we will
+                                *  never get past an "end quote."
+                                */
+                               if ( endquote == 1 )
+                                       p++;
+
+                               rdnstart = *p ? p + 1 : p;
+                               while ( isspace( *rdnstart ))
+                                       ++rdnstart;
+                       }
+                       break;
+               }
+       } while ( *p );
+
+       return( rdns );
+}
+
+
+int
+ldap_is_dns_dn( char *dn )
+{
+       return( dn[ 0 ] != '\0' && strchr( dn, '=' ) == NULL &&
+           strchr( dn, ',' ) == NULL );
+}
+
+
+#if defined( ultrix ) || defined( NeXT )
+
+char *strdup( char *s )
+{
+       char    *p;
+
+       if ( (p = (char *) malloc( strlen( s ) + 1 )) == NULL )
+               return( NULL );
+
+       strcpy( p, s );
+
+       return( p );
+}
+
+#endif /* ultrix */
diff --git a/libraries/libldap/getdxbyname.c b/libraries/libldap/getdxbyname.c
new file mode 100644 (file)
index 0000000..50683f6
--- /dev/null
@@ -0,0 +1,218 @@
+#ifdef LDAP_DNS
+/*
+ *  Copyright (c) 1995 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ * getdxbyname - retrieve DX records from the DNS (from TXT records for now)
+ */
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef MACOS
+#include <stdlib.h>
+#include "macos.h"
+#endif /* MACOS */
+
+#if !defined(MACOS) && !defined(DOS) && !defined( _WIN32 )
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <resolv.h>
+#endif
+#include "lber.h"
+#include "ldap.h"
+#include "ldap-int.h"
+
+#if defined( DOS ) || defined( _WIN32 )
+#include "msdos.h"
+#endif /* DOS */
+
+
+#ifdef NEEDPROTOS
+static char ** decode_answer( unsigned char *answer, int len );
+#else /* NEEDPROTOS */
+static char **decode_answer();
+#endif /* NEEDPROTOS */
+
+extern int h_errno;
+extern char *h_errlist[];
+
+
+#define MAX_TO_SORT    32
+
+
+/*
+ * getdxbyname - lookup DNS DX records for domain and return an ordered
+ *     array.
+ */
+char **
+getdxbyname( char *domain )
+{
+    unsigned char      buf[ PACKETSZ ];
+    char               **dxs;
+    int                        rc;
+
+    Debug( LDAP_DEBUG_TRACE, "getdxbyname( %s )\n", domain, 0, 0 );
+
+    memset( buf, 0, sizeof( buf ));
+
+    if (( rc = res_search( domain, C_IN, T_TXT, buf, sizeof( buf ))) < 0
+               || ( dxs = decode_answer( buf, rc )) == NULL ) {
+       /*
+        * punt:  return list conisting of the original domain name only
+        */
+       if (( dxs = (char **)malloc( 2 * sizeof( char * ))) == NULL ||
+               ( dxs[ 0 ] = strdup( domain )) == NULL ) {
+           if ( dxs != NULL ) {
+               free( dxs );
+           }
+           dxs = NULL;
+       } else {
+           dxs[ 1 ] = NULL;
+       }
+    }
+
+    return( dxs );
+}
+
+
+static char **
+decode_answer( unsigned char *answer, int len )
+{
+    HEADER             *hp;
+    char               buf[ 256 ], **dxs;
+    unsigned char      *eom, *p;
+    int                        ancount, err, rc, type, class, dx_count, rr_len;
+    int                        dx_pref[ MAX_TO_SORT ];
+
+#ifdef LDAP_DEBUG
+    if ( ldap_debug & LDAP_DEBUG_PACKETS ) {
+/*     __p_query( answer );    /* */
+    }
+#endif /* LDAP_DEBUG */
+
+    dxs = NULL;
+    hp = (HEADER *)answer;
+    eom = answer + len;
+
+    if ( ntohs( hp->qdcount ) != 1 ) {
+       h_errno = NO_RECOVERY;
+       return( NULL );
+    }
+
+    ancount = ntohs( hp->ancount );
+    if ( ancount < 1 ) {
+       h_errno = NO_DATA;
+       return( NULL );
+    }
+
+    /*
+     * skip over the query
+     */
+    p = answer + HFIXEDSZ;
+    if (( rc = dn_expand( answer, eom, p, buf, sizeof( buf ))) < 0 ) {
+       h_errno = NO_RECOVERY;
+       return( NULL );
+    }
+    p += ( rc + QFIXEDSZ );
+
+    /*
+     * pull out the answers we are interested in
+     */
+    err = dx_count = 0;
+    while ( ancount > 0 && err == 0 && p < eom ) {
+       if (( rc = dn_expand( answer, eom, p, buf, sizeof( buf ))) < 0 ) {
+           err = NO_RECOVERY;
+           continue;
+       }
+       p += rc;        /* skip over name */
+       type = _getshort( p );
+       p += INT16SZ;
+       class = _getshort( p );
+       p += INT16SZ;
+       p += INT32SZ;           /* skip over TTL */
+       rr_len = _getshort( p );
+       p += INT16SZ;
+       if ( class == C_IN && type == T_TXT ) {
+           int         i, n, pref, txt_len;
+           char        *q, *r;
+
+           q = (char *)p;
+           while ( q < (char *)p + rr_len && err == 0 ) {
+               if ( *q >= 3 && strncasecmp( q + 1, "dx:", 3 ) == 0 ) {
+                   txt_len = *q - 3;
+                   r = q + 4;
+                   while ( isspace( *r )) { 
+                       ++r;
+                       --txt_len;
+                   }
+                   pref = 0;
+                   while ( isdigit( *r )) {
+                       pref *= 10;
+                       pref += ( *r - '0' );
+                       ++r;
+                       --txt_len;
+                   }
+                   if ( dx_count < MAX_TO_SORT - 1 ) {
+                       dx_pref[ dx_count ] = pref;
+                   }
+                   while ( isspace( *r )) { 
+                       ++r;
+                       --txt_len;
+                   }
+                   if ( dx_count == 0 ) {
+                       dxs = (char **)malloc( 2 * sizeof( char * ));
+                   } else {
+                       dxs = (char **)realloc( dxs,
+                               ( dx_count + 2 ) * sizeof( char * ));
+                   }
+                   if ( dxs == NULL || ( dxs[ dx_count ] =
+                               (char *)calloc( 1, txt_len + 1 )) == NULL ) {
+                       err = NO_RECOVERY;
+                       continue;
+                   }
+                   memcpy( dxs[ dx_count ], r, txt_len );
+                   dxs[ ++dx_count ] = NULL;
+               }
+               q += ( *q + 1 );        /* move past last TXT record */
+           }
+       }
+       p += rr_len;
+    }
+
+    if ( err == 0 ) {
+       if ( dx_count == 0 ) {
+           err = NO_DATA;
+       } else {
+           /*
+            * sort records based on associated preference value
+            */
+           int         i, j, sort_count, tmp_pref;
+           char        *tmp_dx;
+
+           sort_count = ( dx_count < MAX_TO_SORT ) ? dx_count : MAX_TO_SORT;
+           for ( i = 0; i < sort_count; ++i ) {
+               for ( j = i + 1; j < sort_count; ++j ) {
+                   if ( dx_pref[ i ] > dx_pref[ j ] ) {
+                       tmp_pref = dx_pref[ i ];
+                       dx_pref[ i ] = dx_pref[ j ];
+                       dx_pref[ j ] = tmp_pref;
+                       tmp_dx = dxs[ i ];
+                       dxs[ i ] = dxs[ j ];
+                       dxs[ j ] = tmp_dx;
+                   }
+               }
+           }
+       }
+    }
+
+    h_errno = err;
+    return( dxs );
+}
+
+#endif /* LDAP_DNS */
diff --git a/libraries/libldap/getentry.c b/libraries/libldap/getentry.c
new file mode 100644 (file)
index 0000000..f3f896e
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  getentry.c
+ */
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#ifdef MACOS
+#include <stdlib.h>
+#include "macos.h"
+#else /* MACOS */
+#if defined( DOS ) || defined( _WIN32 )
+#include <malloc.h>
+#include "msdos.h"
+#else /* DOS */
+#include <sys/types.h>
+#include <sys/socket.h>
+#endif /* DOS */
+#endif /* MACOS */
+
+#include "lber.h"
+#include "ldap.h"
+
+/* ARGSUSED */
+LDAPMessage *
+ldap_first_entry( LDAP *ld, LDAPMessage *chain )
+{
+       return( chain == NULLMSG || chain->lm_msgtype == LDAP_RES_SEARCH_RESULT
+           ? NULLMSG : chain );
+}
+
+/* ARGSUSED */
+LDAPMessage *ldap_next_entry( LDAP *ld, LDAPMessage *entry )
+{
+       if ( entry == NULLMSG || entry->lm_chain == NULLMSG
+           || entry->lm_chain->lm_msgtype == LDAP_RES_SEARCH_RESULT )
+               return( NULLMSG );
+
+       return( entry->lm_chain );
+}
+
+/* ARGSUSED */
+int
+ldap_count_entries( LDAP *ld, LDAPMessage *chain )
+{
+       int     i;
+
+       for ( i = 0; chain != NULL && chain->lm_msgtype
+           != LDAP_RES_SEARCH_RESULT; chain = chain->lm_chain )
+               i++;
+
+       return( i );
+}
diff --git a/libraries/libldap/getfilter.c b/libraries/libldap/getfilter.c
new file mode 100644 (file)
index 0000000..e9ebc6a
--- /dev/null
@@ -0,0 +1,432 @@
+/*
+ *  Copyright (c) 1993 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  getfilter.c -- optional add-on to libldap
+ */
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1993 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#if defined(NeXT)
+#include <regex.h>
+#endif
+#ifdef MACOS
+#include <stdlib.h>
+#include "macos.h"
+#else /* MACOS */
+#ifdef DOS
+#include <malloc.h>
+#include "msdos.h"
+#else /* DOS */
+#include <sys/types.h>
+#include <sys/file.h>
+#include <stdlib.h>
+#include <sys/errno.h>
+#ifndef VMS
+#include <unistd.h>
+#endif /* VMS */
+#endif /* DOS */
+#endif /* MACOS */
+
+#include "lber.h"
+#include "ldap.h"
+#include "regex.h"
+
+#ifdef NEEDPROTOS
+static int break_into_words( char *str, char *delims, char ***wordsp );
+int next_line_tokens( char **bufp, long *blenp, char ***toksp );
+void free_strarray( char **sap );
+#else /* NEEDPROTOS */
+static int break_into_words();
+int next_line_tokens();
+void free_strarray();
+#endif /* NEEDPROTOS */
+
+#if !defined( MACOS ) && !defined( DOS )
+extern int     errno;
+extern char    *re_comp();
+#endif
+
+#define FILT_MAX_LINE_LEN      1024
+
+LDAPFiltDesc *
+ldap_init_getfilter( char *fname )
+{
+    FILE               *fp;
+    char               *buf;
+    long               rlen, len;
+    int                eof;
+    LDAPFiltDesc       *lfdp;
+
+    if (( fp = fopen( fname, "r" )) == NULL ) {
+       return( NULL );
+    }
+
+    if ( fseek( fp, 0L, SEEK_END ) != 0 ) {    /* move to end to get len */
+       fclose( fp );
+       return( NULL );
+    }
+
+    len = ftell( fp );
+
+    if ( fseek( fp, 0L, SEEK_SET ) != 0 ) {    /* back to start of file */
+       fclose( fp );
+       return( NULL );
+    }
+
+    if (( buf = malloc( (size_t)len )) == NULL ) {
+       fclose( fp );
+       return( NULL );
+    }
+
+    rlen = fread( buf, 1, (size_t)len, fp );
+    eof = feof( fp );
+    fclose( fp );
+
+    if ( rlen != len && !eof ) {       /* error:  didn't get the whole file */
+       free( buf );
+       return( NULL );
+    }
+
+
+    lfdp = ldap_init_getfilter_buf( buf, rlen );
+    free( buf );
+
+    return( lfdp );
+}
+
+
+LDAPFiltDesc *
+ldap_init_getfilter_buf( char *buf, long buflen )
+{
+    LDAPFiltDesc       *lfdp;
+    LDAPFiltList       *flp, *nextflp;
+    LDAPFiltInfo       *fip, *nextfip;
+    char               *tag, **tok;
+    int                        tokcnt, i;
+
+    if (( lfdp = (LDAPFiltDesc *)calloc( 1, sizeof( LDAPFiltDesc))) == NULL ) {
+       return( NULL );
+    }
+
+    flp = nextflp = NULL;
+    fip = NULL;
+    tag = NULL;
+
+    while ( buflen > 0 && ( tokcnt = next_line_tokens( &buf, &buflen, &tok ))
+           > 0 ) {
+
+       switch( tokcnt ) {
+       case 1:         /* tag line */
+           if ( tag != NULL ) {
+               free( tag );
+           }
+           tag = tok[ 0 ];
+           free( tok );
+           break;
+       case 4:
+       case 5:         /* start of filter info. list */
+           if (( nextflp = (LDAPFiltList *)calloc( 1, sizeof( LDAPFiltList )))
+                   == NULL ) {
+               ldap_getfilter_free( lfdp );
+               return( NULL );
+           }
+           nextflp->lfl_tag = strdup( tag );
+           nextflp->lfl_pattern = tok[ 0 ];
+           if ( re_comp( nextflp->lfl_pattern ) != NULL ) {
+#ifndef NO_USERINTERFACE
+               ldap_getfilter_free( lfdp );
+               fprintf( stderr, "bad regular expresssion %s\n",
+                       nextflp->lfl_pattern );
+#if !defined( MACOS ) && !defined( DOS )
+               errno = EINVAL;
+#endif
+#endif /* NO_USERINTERFACE */
+               free_strarray( tok );
+               return( NULL );
+           }
+               
+           nextflp->lfl_delims = tok[ 1 ];
+           nextflp->lfl_ilist = NULL;
+           nextflp->lfl_next = NULL;
+           if ( flp == NULL ) {        /* first one */
+               lfdp->lfd_filtlist = nextflp;
+           } else {
+               flp->lfl_next = nextflp;
+           }
+           flp = nextflp;
+           fip = NULL;
+           for ( i = 2; i < 5; ++i ) {
+               tok[ i - 2 ] = tok[ i ];
+           }
+           /* fall through */
+
+       case 2:
+       case 3:         /* filter, desc, and optional search scope */
+           if ( nextflp != NULL ) { /* add to info list */
+               if (( nextfip = (LDAPFiltInfo *)calloc( 1,
+                       sizeof( LDAPFiltInfo ))) == NULL ) {
+                   ldap_getfilter_free( lfdp );
+                   free_strarray( tok );
+                   return( NULL );
+               }
+               if ( fip == NULL ) {    /* first one */
+                   nextflp->lfl_ilist = nextfip;
+               } else {
+                   fip->lfi_next = nextfip;
+               }
+               fip = nextfip;
+               nextfip->lfi_next = NULL;
+               nextfip->lfi_filter = tok[ 0 ];
+               nextfip->lfi_desc = tok[ 1 ];
+               if ( tok[ 2 ] != NULL ) {
+                   if ( strcasecmp( tok[ 2 ], "subtree" ) == 0 ) {
+                       nextfip->lfi_scope = LDAP_SCOPE_SUBTREE;
+                   } else if ( strcasecmp( tok[ 2 ], "onelevel" ) == 0 ) {
+                       nextfip->lfi_scope = LDAP_SCOPE_ONELEVEL;
+                   } else if ( strcasecmp( tok[ 2 ], "base" ) == 0 ) {
+                       nextfip->lfi_scope = LDAP_SCOPE_BASE;
+                   } else {
+                       free_strarray( tok );
+                       ldap_getfilter_free( lfdp );
+#if !defined( MACOS ) && !defined( DOS )
+                       errno = EINVAL;
+#endif
+                       return( NULL );
+                   }
+                   free( tok[ 2 ] );
+                   tok[ 2 ] = NULL;
+               } else {
+                   nextfip->lfi_scope = LDAP_SCOPE_SUBTREE;    /* default */
+               }
+               nextfip->lfi_isexact = ( strchr( tok[ 0 ], '*' ) == NULL &&
+                       strchr( tok[ 0 ], '~' ) == NULL );
+               free( tok );
+           }
+           break;
+
+       default:
+           free_strarray( tok );
+           ldap_getfilter_free( lfdp );
+#if !defined( MACOS ) && !defined( DOS )
+           errno = EINVAL;
+#endif
+           return( NULL );
+       }
+    }
+
+    if ( tag != NULL ) {
+       free( tag );
+    }
+
+    return( lfdp );
+}
+
+
+void
+ldap_setfilteraffixes( LDAPFiltDesc *lfdp, char *prefix, char *suffix )
+{
+    if ( lfdp->lfd_filtprefix != NULL ) {
+       free( lfdp->lfd_filtprefix );
+    }
+    lfdp->lfd_filtprefix = ( prefix == NULL ) ? NULL : strdup( prefix );
+
+    if ( lfdp->lfd_filtsuffix != NULL ) {
+       free( lfdp->lfd_filtsuffix );
+    }
+    lfdp->lfd_filtsuffix = ( suffix == NULL ) ? NULL : strdup( suffix );
+}
+
+
+LDAPFiltInfo *
+ldap_getfirstfilter( LDAPFiltDesc *lfdp, char *tagpat, char *value )
+{
+    LDAPFiltList       *flp;
+
+    if ( lfdp->lfd_curvalcopy != NULL ) {
+       free( lfdp->lfd_curvalcopy );
+       free( lfdp->lfd_curvalwords );
+    }
+
+    lfdp->lfd_curval = value;
+    lfdp->lfd_curfip = NULL;
+
+    for ( flp = lfdp->lfd_filtlist; flp != NULL; flp = flp->lfl_next ) {
+       if ( re_comp( tagpat ) == NULL && re_exec( flp->lfl_tag ) == 1
+               && re_comp( flp->lfl_pattern ) == NULL
+               && re_exec( lfdp->lfd_curval ) == 1 ) {
+           lfdp->lfd_curfip = flp->lfl_ilist;
+           break;
+       }
+    }
+
+    if ( lfdp->lfd_curfip == NULL ) {
+       return( NULL );
+    }
+
+    if (( lfdp->lfd_curvalcopy = strdup( value )) == NULL ) {
+       return( NULL );
+    }
+
+    if ( break_into_words( lfdp->lfd_curvalcopy, flp->lfl_delims,
+               &lfdp->lfd_curvalwords ) < 0 ) {
+       free( lfdp->lfd_curvalcopy );
+       lfdp->lfd_curvalcopy = NULL;
+       return( NULL );
+    }
+
+    return( ldap_getnextfilter( lfdp ));
+}
+
+
+LDAPFiltInfo *
+ldap_getnextfilter( LDAPFiltDesc *lfdp )
+{
+    LDAPFiltInfo       *fip;
+
+    fip = lfdp->lfd_curfip;
+
+    if ( fip == NULL ) {
+       return( NULL );
+    }
+
+    lfdp->lfd_curfip = fip->lfi_next;
+
+    ldap_build_filter( lfdp->lfd_filter, LDAP_FILT_MAXSIZ, fip->lfi_filter,
+           lfdp->lfd_filtprefix, lfdp->lfd_filtsuffix, NULL,
+           lfdp->lfd_curval, lfdp->lfd_curvalwords );
+    lfdp->lfd_retfi.lfi_filter = lfdp->lfd_filter;
+    lfdp->lfd_retfi.lfi_desc = fip->lfi_desc;
+    lfdp->lfd_retfi.lfi_scope = fip->lfi_scope;
+    lfdp->lfd_retfi.lfi_isexact = fip->lfi_isexact;
+
+    return( &lfdp->lfd_retfi );
+}
+
+
+void
+ldap_build_filter( char *filtbuf, unsigned long buflen, char *pattern,
+       char *prefix, char *suffix, char *attr, char *value, char **valwords )
+{
+       char    *p, *f;
+       size_t  slen;
+       int     i, wordcount, wordnum, endwordnum;
+       
+       if ( valwords == NULL ) {
+           wordcount = 0;
+       } else {
+           for ( wordcount = 0; valwords[ wordcount ] != NULL; ++wordcount ) {
+               ;
+           }
+       }
+
+       f = filtbuf;
+
+       if ( prefix != NULL ) {
+           strcpy( f, prefix );
+           f += strlen( prefix );
+       }
+
+       for ( p = pattern; *p != '\0'; ++p ) {
+           if ( *p == '%' ) {
+               ++p;
+               if ( *p == 'v' ) {
+                   if ( isdigit( *(p+1))) {
+                       ++p;
+                       wordnum = *p - '1';
+                       if ( *(p+1) == '-' ) {
+                           ++p;
+                           if ( isdigit( *(p+1))) {
+                               ++p;
+                               endwordnum = *p - '1';  /* e.g., "%v2-4" */
+                               if ( endwordnum > wordcount - 1 ) {
+                                   endwordnum = wordcount - 1;
+                               }
+                           } else {
+                               endwordnum = wordcount - 1;  /* e.g., "%v2-" */
+                           }
+                       } else {
+                           endwordnum = wordnum;       /* e.g., "%v2" */
+                       }
+
+                       if ( wordcount > 0 ) {
+                           for ( i = wordnum; i <= endwordnum; ++i ) {
+                               if ( i > wordnum ) {  /* add blank btw words */
+                                   *f++ = ' ';
+                               }
+                               slen = strlen( valwords[ i ] );
+                               SAFEMEMCPY( f, valwords[ i ], slen );
+                               f += slen;
+                           }
+                       }
+                   } else if ( *(p+1) == '$' ) {
+                       ++p;
+                       if ( wordcount > 0 ) {
+                           wordnum = wordcount - 1;
+                           slen = strlen( valwords[ wordnum ] );
+                           SAFEMEMCPY( f, valwords[ wordnum ], slen );
+                           f += slen;
+                       }
+                   } else if ( value != NULL ) {
+                       slen = strlen( value );
+                       SAFEMEMCPY( f, value, slen );
+                       f += slen;
+                   }
+               } else if ( *p == 'a' && attr != NULL ) {
+                   slen = strlen( attr );
+                   SAFEMEMCPY( f, attr, slen );
+                   f += slen;
+               } else {
+                   *f++ = *p;
+               }
+           } else {
+               *f++ = *p;
+           }
+               
+           if ( f - filtbuf > buflen ) {
+               /* sanity check */
+               --f;
+               break;
+           }
+       }
+
+       if ( suffix != NULL && ( f - filtbuf ) < buflen ) {
+           strcpy( f, suffix );
+       } else {
+           *f = '\0';
+       }
+}
+
+
+static int
+break_into_words( char *str, char *delims, char ***wordsp )
+{
+    char       *word, **words;
+    int                count;
+       
+    if (( words = (char **)calloc( 1, sizeof( char * ))) == NULL ) {
+       return( -1 );
+    }
+    count = 0;
+    words[ count ] = NULL;
+
+    word = strtok( str, delims );
+    while ( word != NULL ) {
+       if (( words = (char **)realloc( words,
+               ( count + 2 ) * sizeof( char * ))) == NULL ) {
+           return( -1 );
+       }
+
+       words[ count ] = word;
+       words[ ++count ] = NULL;
+       word = strtok( NULL, delims );
+    }
+       
+    *wordsp = words;
+    return( count );
+}
diff --git a/libraries/libldap/getvalues.c b/libraries/libldap/getvalues.c
new file mode 100644 (file)
index 0000000..55102be
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  getvalues.c
+ */
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#ifdef MACOS
+#include <stdlib.h>
+#include "macos.h"
+#else /* MACOS */
+#if defined( DOS ) || defined( _WIN32 )
+#include <malloc.h>
+#include "msdos.h"
+#else /* DOS */
+#include <sys/types.h>
+#include <sys/socket.h>
+#endif /* DOS */
+#endif /* MACOS */
+
+#include "lber.h"
+#include "ldap.h"
+
+char **
+ldap_get_values( LDAP *ld, LDAPMessage *entry, char *target )
+{
+       BerElement      ber;
+       char            attr[LDAP_MAX_ATTR_LEN];
+       int             found = 0;
+       long            len;
+       char            **vals;
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_get_values\n", 0, 0, 0 );
+
+       ber = *entry->lm_ber;
+
+       /* skip sequence, dn, sequence of, and snag the first attr */
+       len = sizeof(attr);
+       if ( ber_scanf( &ber, "{x{{s", attr, &len ) == LBER_ERROR ) {
+               ld->ld_errno = LDAP_DECODING_ERROR;
+               return( NULL );
+       }
+
+       if ( strcasecmp( target, attr ) == 0 )
+               found = 1;
+
+       /* break out on success, return out on error */
+       while ( ! found ) {
+               len = sizeof(attr);
+               if ( ber_scanf( &ber, "x}{s", attr, &len ) == LBER_ERROR ) {
+                       ld->ld_errno = LDAP_DECODING_ERROR;
+                       return( NULL );
+               }
+
+               if ( strcasecmp( target, attr ) == 0 )
+                       break;
+       }
+
+       /* 
+        * if we get this far, we've found the attribute and are sitting
+        * just before the set of values.
+        */
+
+       if ( ber_scanf( &ber, "[v]", &vals ) == LBER_ERROR ) {
+               ld->ld_errno = LDAP_DECODING_ERROR;
+               return( NULL );
+       }
+
+       return( vals );
+}
+
+struct berval **
+ldap_get_values_len( LDAP *ld, LDAPMessage *entry, char *target )
+{
+       BerElement      ber;
+       char            attr[LDAP_MAX_ATTR_LEN];
+       int             found = 0;
+       long            len;
+       struct berval   **vals;
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_get_values_len\n", 0, 0, 0 );
+
+       ber = *entry->lm_ber;
+
+       /* skip sequence, dn, sequence of, and snag the first attr */
+       len = sizeof(attr);
+       if ( ber_scanf( &ber, "{x{{s", attr, &len ) == LBER_ERROR ) {
+               ld->ld_errno = LDAP_DECODING_ERROR;
+               return( NULL );
+       }
+
+       if ( strcasecmp( target, attr ) == 0 )
+               found = 1;
+
+       /* break out on success, return out on error */
+       while ( ! found ) {
+               len = sizeof(attr);
+               if ( ber_scanf( &ber, "x}{s", attr, &len ) == LBER_ERROR ) {
+                       ld->ld_errno = LDAP_DECODING_ERROR;
+                       return( NULL );
+               }
+
+               if ( strcasecmp( target, attr ) == 0 )
+                       break;
+       }
+
+       /* 
+        * if we get this far, we've found the attribute and are sitting
+        * just before the set of values.
+        */
+
+       if ( ber_scanf( &ber, "[V]", &vals ) == LBER_ERROR ) {
+               ld->ld_errno = LDAP_DECODING_ERROR;
+               return( NULL );
+       }
+
+       return( vals );
+}
+
+int
+ldap_count_values( char **vals )
+{
+       int     i;
+
+       if ( vals == NULL )
+               return( 0 );
+
+       for ( i = 0; vals[i] != NULL; i++ )
+               ;       /* NULL */
+
+       return( i );
+}
+
+int
+ldap_count_values_len( struct berval **vals )
+{
+       return( ldap_count_values( (char **) vals ) );
+}
+
+void
+ldap_value_free( char **vals )
+{
+       int     i;
+
+       if ( vals == NULL )
+               return;
+       for ( i = 0; vals[i] != NULL; i++ )
+               free( vals[i] );
+       free( (char *) vals );
+}
+
+void
+ldap_value_free_len( struct berval **vals )
+{
+       int     i;
+
+       if ( vals == NULL )
+               return;
+       for ( i = 0; vals[i] != NULL; i++ ) {
+               free( vals[i]->bv_val );
+               free( vals[i] );
+       }
+       free( (char *) vals );
+}
diff --git a/libraries/libldap/kbind.c b/libraries/libldap/kbind.c
new file mode 100644 (file)
index 0000000..ce4a8a7
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ *  Copyright (c) 1993 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  kbind.c
+ */
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1993 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#ifdef KERBEROS
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef MACOS
+#include <stdlib.h>
+#include "macos.h"
+#else /* MACOS */
+#ifdef DOS
+#include "msdos.h"
+#endif /* DOS */
+#include <krb.h>
+#include <stdlib.h>
+#if !defined(DOS) && !defined( _WIN32 )
+#include <sys/types.h>
+#endif /* !DOS && !_WIN32 */
+#include <sys/time.h>
+#include <sys/socket.h>
+#endif /* MACOS */
+
+#include "lber.h"
+#include "ldap.h"
+#include "ldap-int.h"
+
+
+
+/*
+ * ldap_kerberos_bind1 - initiate a bind to the ldap server using
+ * kerberos authentication.  The dn is supplied.  It is assumed the user
+ * already has a valid ticket granting ticket.  The msgid of the
+ * request is returned on success (suitable for passing to ldap_result()),
+ * -1 is returned if there's trouble.
+ *
+ * Example:
+ *     ldap_kerberos_bind1( ld, "cn=manager, o=university of michigan, c=us" )
+ */
+int
+ldap_kerberos_bind1( LDAP *ld, char *dn )
+{
+       BerElement      *ber;
+       char            *cred;
+       int             rc, credlen;
+       char            *get_kerberosv4_credentials();
+#ifdef STR_TRANSLATION
+       int             str_translation_on;
+#endif /* STR_TRANSLATION */
+
+       /*
+        * The bind request looks like this:
+        *      BindRequest ::= SEQUENCE {
+        *              version         INTEGER,
+        *              name            DistinguishedName,
+        *              authentication  CHOICE {
+        *                      krbv42ldap      [1] OCTET STRING
+        *                      krbv42dsa       [2] OCTET STRING
+        *              }
+        *      }
+        * all wrapped up in an LDAPMessage sequence.
+        */
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_kerberos_bind1\n", 0, 0, 0 );
+
+       if ( dn == NULL )
+               dn = "";
+
+       if ( (cred = get_kerberosv4_credentials( ld, dn, "ldapserver",
+           &credlen )) == NULL ) {
+               return( -1 );   /* ld_errno should already be set */
+       }
+
+       /* create a message to send */
+       if ( (ber = alloc_ber_with_options( ld )) == NULLBER ) {
+               free( cred );
+               return( -1 );
+       }
+
+#ifdef STR_TRANSLATION
+       if (( str_translation_on = (( ber->ber_options &
+           LBER_TRANSLATE_STRINGS ) != 0 ))) { /* turn translation off */
+               ber->ber_options &= ~LBER_TRANSLATE_STRINGS;
+       }
+#endif /* STR_TRANSLATION */
+
+       /* fill it in */
+       rc = ber_printf( ber, "{it{isto}}", ++ld->ld_msgid, LDAP_REQ_BIND,
+           ld->ld_version, dn, LDAP_AUTH_KRBV41, cred, credlen );
+
+#ifdef STR_TRANSLATION
+       if ( str_translation_on ) {     /* restore translation */
+               ber->ber_options |= LBER_TRANSLATE_STRINGS;
+       }
+#endif /* STR_TRANSLATION */
+
+       if ( rc == -1 ) {
+               free( cred );
+               ber_free( ber, 1 );
+               ld->ld_errno = LDAP_ENCODING_ERROR;
+               return( -1 );
+       }
+
+       free( cred );
+
+#ifndef NO_CACHE
+       if ( ld->ld_cache != NULL ) {
+               ldap_flush_cache( ld );
+       }
+#endif /* !NO_CACHE */
+
+       /* send the message */
+       return ( send_initial_request( ld, LDAP_REQ_BIND, dn, ber ));
+}
+
+int
+ldap_kerberos_bind1_s( LDAP *ld, char *dn )
+{
+       int             msgid;
+       LDAPMessage     *res;
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_kerberos_bind1_s\n", 0, 0, 0 );
+
+       /* initiate the bind */
+       if ( (msgid = ldap_kerberos_bind1( ld, dn )) == -1 )
+               return( ld->ld_errno );
+
+       /* wait for a result */
+       if ( ldap_result( ld, ld->ld_msgid, 1, (struct timeval *) 0, &res )
+           == -1 ) {
+               return( ld->ld_errno ); /* ldap_result sets ld_errno */
+       }
+
+       return( ldap_result2error( ld, res, 1 ) );
+}
+
+/*
+ * ldap_kerberos_bind2 - initiate a bind to the X.500 server using
+ * kerberos authentication.  The dn is supplied.  It is assumed the user
+ * already has a valid ticket granting ticket.  The msgid of the
+ * request is returned on success (suitable for passing to ldap_result()),
+ * -1 is returned if there's trouble.
+ *
+ * Example:
+ *     ldap_kerberos_bind2( ld, "cn=manager, o=university of michigan, c=us" )
+ */
+int
+ldap_kerberos_bind2( LDAP *ld, char *dn )
+{
+       BerElement      *ber;
+       char            *cred;
+       int             rc, credlen;
+       char            *get_kerberosv4_credentials();
+#ifdef STR_TRANSLATION
+       int             str_translation_on;
+#endif /* STR_TRANSLATION */
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_kerberos_bind2\n", 0, 0, 0 );
+
+       if ( dn == NULL )
+               dn = "";
+
+       if ( (cred = get_kerberosv4_credentials( ld, dn, "x500dsa", &credlen ))
+           == NULL ) {
+               return( -1 );   /* ld_errno should already be set */
+       }
+
+       /* create a message to send */
+       if ( (ber = alloc_ber_with_options( ld )) == NULLBER ) {
+               free( cred );
+               return( -1 );
+       }
+
+#ifdef STR_TRANSLATION
+       if (( str_translation_on = (( ber->ber_options &
+           LBER_TRANSLATE_STRINGS ) != 0 ))) { /* turn translation off */
+               ber->ber_options &= ~LBER_TRANSLATE_STRINGS;
+       }
+#endif /* STR_TRANSLATION */
+
+       /* fill it in */
+       rc = ber_printf( ber, "{it{isto}}", ++ld->ld_msgid, LDAP_REQ_BIND,
+           ld->ld_version, dn, LDAP_AUTH_KRBV42, cred, credlen );
+
+
+#ifdef STR_TRANSLATION
+       if ( str_translation_on ) {     /* restore translation */
+               ber->ber_options |= LBER_TRANSLATE_STRINGS;
+       }
+#endif /* STR_TRANSLATION */
+
+       free( cred );
+
+       if ( rc == -1 ) {
+               ber_free( ber, 1 );
+               ld->ld_errno = LDAP_ENCODING_ERROR;
+               return( -1 );
+       }
+
+       /* send the message */
+       return ( send_initial_request( ld, LDAP_REQ_BIND, dn, ber ));
+}
+
+/* synchronous bind to DSA using kerberos */
+int
+ldap_kerberos_bind2_s( LDAP *ld, char *dn )
+{
+       int             msgid;
+       LDAPMessage     *res;
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_kerberos_bind2_s\n", 0, 0, 0 );
+
+       /* initiate the bind */
+       if ( (msgid = ldap_kerberos_bind2( ld, dn )) == -1 )
+               return( ld->ld_errno );
+
+       /* wait for a result */
+       if ( ldap_result( ld, ld->ld_msgid, 1, (struct timeval *) 0, &res )
+           == -1 ) {
+               return( ld->ld_errno ); /* ldap_result sets ld_errno */
+       }
+
+       return( ldap_result2error( ld, res, 1 ) );
+}
+
+/* synchronous bind to ldap and DSA using kerberos */
+int
+ldap_kerberos_bind_s( LDAP *ld, char *dn )
+{
+       int     err;
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_kerberos_bind_s\n", 0, 0, 0 );
+
+       if ( (err = ldap_kerberos_bind1_s( ld, dn )) != LDAP_SUCCESS )
+               return( err );
+
+       return( ldap_kerberos_bind2_s( ld, dn ) );
+}
+
+
+#ifndef AUTHMAN
+/*
+ * get_kerberosv4_credentials - obtain kerberos v4 credentials for ldap.
+ * The dn of the entry to which to bind is supplied.  It's assumed the
+ * user already has a tgt.
+ */
+
+char *
+get_kerberosv4_credentials( LDAP *ld, char *who, char *service, int *len )
+{
+       KTEXT_ST        ktxt;
+       int             err;
+       char            realm[REALM_SZ], *cred, *krbinstance;
+
+       Debug( LDAP_DEBUG_TRACE, "get_kerberosv4_credentials\n", 0, 0, 0 );
+
+       if ( (err = krb_get_tf_realm( tkt_string(), realm )) != KSUCCESS ) {
+#ifndef NO_USERINTERFACE
+               fprintf( stderr, "krb_get_tf_realm failed (%s)\n",
+                   krb_err_txt[err] );
+#endif /* NO_USERINTERFACE */
+               ld->ld_errno = LDAP_INVALID_CREDENTIALS;
+               return( NULL );
+       }
+
+#ifdef LDAP_REFERRALS
+       krbinstance = ld->ld_defconn->lconn_krbinstance;
+#else /* LDAP_REFERRALS */
+       krbinstance = ld->ld_host;
+#endif /* LDAP_REFERRALS */
+
+       if ( (err = krb_mk_req( &ktxt, service, krbinstance, realm, 0 ))
+           != KSUCCESS ) {
+#ifndef NO_USERINTERFACE
+               fprintf( stderr, "krb_mk_req failed (%s)\n", krb_err_txt[err] );
+#endif /* NO_USERINTERFACE */
+               ld->ld_errno = LDAP_INVALID_CREDENTIALS;
+               return( NULL );
+       }
+
+       if ( ( cred = malloc( ktxt.length )) == NULL ) {
+               ld->ld_errno = LDAP_NO_MEMORY;
+               return( NULL );
+       }
+
+       *len = ktxt.length;
+       memcpy( cred, ktxt.dat, ktxt.length );
+
+       return( cred );
+}
+
+#endif /* !AUTHMAN */
+#endif /* KERBEROS */
diff --git a/libraries/libldap/ldap-int.h b/libraries/libldap/ldap-int.h
new file mode 100644 (file)
index 0000000..10adbe9
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ *  Copyright (c) 1995 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  ldap-int.h - defines & prototypes internal to the LDAP library
+ */
+
+
+#define LDAP_URL_PREFIX         "ldap://"
+#define LDAP_URL_PREFIX_LEN     7
+#define LDAP_URL_URLCOLON      "URL:"
+#define LDAP_URL_URLCOLON_LEN  4
+
+#ifdef LDAP_REFERRALS
+#define LDAP_REF_STR           "Referral:\n"
+#define LDAP_REF_STR_LEN       10
+#define LDAP_LDAP_REF_STR      LDAP_URL_PREFIX
+#define LDAP_LDAP_REF_STR_LEN  LDAP_URL_PREFIX_LEN
+#ifdef LDAP_DNS
+#define LDAP_DX_REF_STR                "dx://"
+#define LDAP_DX_REF_STR_LEN    5
+#endif /* LDAP_DNS */
+#endif /* LDAP_REFERRALS */
+
+
+/*
+ * in cache.c
+ */
+#ifdef NEEDPROTOS
+void add_request_to_cache( LDAP *ld, unsigned long msgtype,
+        BerElement *request );
+void add_result_to_cache( LDAP *ld, LDAPMessage *result );
+int check_cache( LDAP *ld, unsigned long msgtype, BerElement *request );
+#else /* NEEDPROTOS */
+void add_request_to_cache();
+void add_result_to_cache();
+int check_cache();
+#endif /* NEEDPROTOS */
+
+
+#ifdef KERBEROS
+/*
+ * in kerberos.c
+ */
+#ifdef NEEDPROTOS
+char *get_kerberosv4_credentials( LDAP *ld, char *who, char *service,
+        int *len );
+#else /* NEEDPROTOS */
+char *get_kerberosv4_credentials();
+#endif /* NEEDPROTOS */
+
+#endif /* KERBEROS */
+
+
+/*
+ * in open.c
+ */
+#ifdef NEEDPROTOS
+int open_ldap_connection( LDAP *ld, Sockbuf *sb, char *host, int defport,
+       char **krbinstancep, int async );
+#else /* NEEDPROTOS */
+int open_ldap_connection();
+#endif /* NEEDPROTOS */
+
+
+/*
+ * in os-ip.c
+ */
+#ifdef NEEDPROTOS
+int connect_to_host( Sockbuf *sb, char *host, unsigned long address, int port,
+       int async );
+void close_connection( Sockbuf *sb );
+#else /* NEEDPROTOS */
+int connect_to_host();
+void close_connection();
+#endif /* NEEDPROTOS */
+
+#ifdef KERBEROS
+#ifdef NEEDPROTOS
+char *host_connected_to( Sockbuf *sb );
+#else /* NEEDPROTOS */
+char *host_connected_to();
+#endif /* NEEDPROTOS */
+#endif /* KERBEROS */
+
+#ifdef LDAP_REFERRALS
+#ifdef NEEDPROTOS
+int do_ldap_select( LDAP *ld, struct timeval *timeout );
+void *new_select_info( void );
+void free_select_info( void *sip );
+void mark_select_write( LDAP *ld, Sockbuf *sb );
+void mark_select_read( LDAP *ld, Sockbuf *sb );
+void mark_select_clear( LDAP *ld, Sockbuf *sb );
+int is_read_ready( LDAP *ld, Sockbuf *sb );
+int is_write_ready( LDAP *ld, Sockbuf *sb );
+#else /* NEEDPROTOS */
+int do_ldap_select();
+void *new_select_info();
+void free_select_info();
+void mark_select_write();
+void mark_select_read();
+void mark_select_clear();
+int is_read_ready();
+int is_write_ready();
+#endif /* NEEDPROTOS */
+#endif /* LDAP_REFERRALS */
+
+
+/*
+ * in request.c
+ */
+#ifdef NEEDPROTOS
+int send_initial_request( LDAP *ld, unsigned long msgtype,
+       char *dn, BerElement *ber );
+BerElement *alloc_ber_with_options( LDAP *ld );
+void set_ber_options( LDAP *ld, BerElement *ber );
+#else /* NEEDPROTOS */
+int send_initial_request();
+BerElement *alloc_ber_with_options();
+void set_ber_options();
+#endif /* NEEDPROTOS */
+
+#if defined( LDAP_REFERRALS ) || defined( LDAP_DNS )
+#ifdef NEEDPROTOS
+int send_server_request( LDAP *ld, BerElement *ber, int msgid,
+       LDAPRequest *parentreq, LDAPServer *srvlist, LDAPConn *lc,
+       int bind );
+LDAPConn *new_connection( LDAP *ld, LDAPServer **srvlistp, int use_ldsb,
+       int connect, int bind );
+LDAPRequest *find_request_by_msgid( LDAP *ld, int msgid );
+void free_request( LDAP *ld, LDAPRequest *lr );
+void free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind );
+void dump_connection( LDAP *ld, LDAPConn *lconns, int all );
+void dump_requests_and_responses( LDAP *ld );
+#else /* NEEDPROTOS */
+int send_server_request();
+LDAPConn *new_connection();
+LDAPRequest *find_request_by_msgid();
+void free_request();
+void free_connection();
+void dump_connection();
+void dump_requests_and_responses();
+#endif /* NEEDPROTOS */
+#endif /* LDAP_REFERRALS || LDAP_DNS */
+
+#ifdef LDAP_REFERRALS
+#ifdef NEEDPROTOS
+int chase_referrals( LDAP *ld, LDAPRequest *lr, char **errstrp, int *hadrefp );
+int append_referral( LDAP *ld, char **referralsp, char *s );
+#else /* NEEDPROTOS */
+int chase_referrals();
+int append_referral();
+#endif /* NEEDPROTOS */
+#endif /* LDAP_REFERRALS */
+
+
+/*
+ * in search.c
+ */
+#ifdef NEEDPROTOS
+BerElement *ldap_build_search_req( LDAP *ld, char *base, int scope,
+       char *filter, char **attrs, int attrsonly );
+#else /* NEEDPROTOS */
+BerElement *ldap_build_search_req();
+#endif /* NEEDPROTOS */
+
+
+/*
+ * in unbind.c
+ */
+#ifdef NEEDPROTOS
+int ldap_ld_free( LDAP *ld, int close );
+int send_unbind( LDAP *ld, Sockbuf *sb );
+#else /* NEEDPROTOS */
+int ldap_ld_free();
+int send_unbind();
+#endif /* NEEDPROTOS */
+
+
+#ifdef LDAP_DNS
+/*
+ * in getdxbyname.c
+ */
+#ifdef NEEDPROTOS
+char **getdxbyname( char *domain );
+#else /* NEEDPROTOS */
+char **getdxbyname();
+#endif /* NEEDPROTOS */
+#endif /* LDAP_DNS */
diff --git a/libraries/libldap/ldapfilter.conf b/libraries/libldap/ldapfilter.conf
new file mode 100644 (file)
index 0000000..c602f7d
--- /dev/null
@@ -0,0 +1,105 @@
+# ldap filter file
+#
+# lines like this that start with # or empty lines are ignored
+# 
+# syntax:
+#
+# <tag>
+#   <pattern1> <delimiters>    <filter1-1>     <desc1-1>       [<scope>]
+#                              <filter1-2>     <desc1-2>       [<scope>]
+#
+#   <pattern2> <delimiters>    <filter2-1>     <desc2-1>       [<scope>] ...
+#
+# The "desc" should describe the filter and it should correctly complete
+# both of the following phrases:
+#
+#      One <desc> match was found for...
+#      Three <desc> matches were found for...
+#
+# The scope is optional, and should be one of:
+#      "base"
+#      "onelevel"
+#      "subtree"
+# if it is included.
+#
+
+"finger and ud and go500 and go500gw subtree and web500gw subtree and rp500 and rcpt500 and ufn last"
+    "="                " "     "%v"                            "arbitrary filter"
+
+    "^[0-9][0-9-]*$"   " "     "(telephoneNumber=*%v)" "phone number"
+
+    "@"                " "     "(mail=%v)"                     "email address"
+                       "(mail=%v*)"                    "start of email address"
+
+    "^.[. _].*"        ". _"   "(cn=%v1* %v2-)"                "first initial"
+
+    ".*[. _].$"        ". _"   "(cn=%v1-*)"                    "last initial"
+
+    "[. _]"    ". _"   "(|(sn=%v1-)(cn=%v1-))"         "exact"
+                       "(|(sn~=%v1-)(cn~=%v1-))"       "approximate"
+
+    ".*"       ". "    "(|(cn=%v1)(sn=%v1)(uid=%v1))"  "exact"
+                       "(|(cn~=%v1)(sn~=%v1))"         "approximate"
+
+"go500gw onelevel and web500gw onelevel and ufn first and ufn intermediate"
+    "="                " "     "%v"                            "arbitrary filter"
+
+    "^..$"     " "     "(|(o=%v)(c=%v)(l=%v)(co=%v))"          "exact"
+                       "(|(o~=%v)(c~=%v)(l~=%v)(co~=%v))"      "approximate"
+
+    " "                " "     "(|(o=%v)(l=%v)(co=%v)(ou=%v))"         "exact"
+                       "(|(o~=%v)(l~=%v)(co~=%v)(ou~=%v))"     "approximate"
+
+    "\."       " "     "(associatedDomain=%v)"                 "exact"
+
+    ".*"       " "     "(|(o=%v)(l=%v)(co=%v)(ou=%v))"         "exact"
+                       "(|(o~=%v)(l~=%v)(co~=%v)(ou~=%v))"     "approximate"
+
+
+#
+# xax500
+#
+
+"xax500"
+    "="                        " "     "(%v)"                  "arbitrary filter"
+
+    "^[0-9][0-9-]*$"   " "     "(telephoneNumber=*%v)" "phone number"
+
+    "@"                        " "     "(mail=%v)"             "email address"
+                               "(mail=%v*)"            "start of email address"
+
+    "^.[. _].*"                ". _"   "(cn=%v1* %v2-)"        "first initial"
+
+    ".*[. _].$"                ". _"   "(cn=%v1-*)"            "last initial"
+
+    "[. _]"            ". _"   "(|(sn=%v1-)(cn=%v1-))"         "exact"
+                               "(|(sn~=%v1-)(cn~=%v1-))"       "approximate"
+
+    ".*"               ". "    "(|(cn=%v1)(sn=%v1)(uid=%v1))"  "exact"
+                       "(|(cn=%v1)(sn~=%v1))"                  "approximate"
+
+
+"xax500-auth"
+    "="                        " "     "(%v)"                  "arbitrary filter"
+
+    "^[0-9][0-9-]*$"   " "     "(telephoneNumber=*%v)" "phone number"
+
+    "@"                        " "     "(mail=%v)"             "email address"
+                               "(mail=%v*)"            "start of email address"
+
+    "^.[. _].*"                ". _"   "(cn=%v1* %v2-)"        "first initial"
+
+    ".*[. _].$"                ". _"   "(cn=%v1-*)"            "last initial"
+
+    "[. _]"            ". _"   "(|(sn=%v1-)(cn=%v1-))" "exact"
+                       "(|(sn~=%v1-)(cn~=%v1-))"       "approximate"
+
+    ".*"               ". "    "(|(cn=%v1)(sn=%v1)(uid=%v1))"  "exact"
+                       "(|(cn=%v1)(sn~=%v1))"                  "approximate"
+
+"list500"
+    "[. _]"    ". _"   "(|(sn=%v1-)(cn=%v1-))"         "exact"
+                       "(|(sn~=%v1-)(cn~=%v1-))"       "approximate"
+
+    ".*"       ". "    "(|(cn=%v1)(sn=%v1)(uid=%v1))"  "exact"
+                       "(|(cn~=%v1)(sn~=%v1))"         "approximate"
diff --git a/libraries/libldap/ldapfriendly b/libraries/libldap/ldapfriendly
new file mode 100644 (file)
index 0000000..3605090
--- /dev/null
@@ -0,0 +1,242 @@
+AD     Andorra
+AE     United Arab Emirates
+AF     Afghanistan
+AG     Antigua and Barbuda
+AI     Anguilla
+AL     Albania
+AM     Armenia
+AN     Netherlands Antilles
+AO     Angola
+AQ     Antarctica
+AR     Argentina
+AS     American Samoa
+AT     Austria
+AU     Australia
+AW     Aruba
+AZ     Azerbaijan
+BA     Bosnia and Herzegowina
+BB     Barbados
+BD     Bangladesh
+BE     Belgium
+BF     Burkina Faso
+BG     Bulgaria
+BH     Bahrain
+BI     Burundi
+BJ     Benin
+BM     Bermuda
+BN     Brunei Darussalam
+BO     Bolivia
+BR     Brazil
+BS     Bahamas
+BT     Bhutan
+BV     Bouvet Island
+BW     Botswana
+BY     Belarus
+BZ     Belize
+CA     Canada
+CC     Cocos (Keeling) Islands
+CF     Central African Republic
+CG     Congo
+CH     Switzerland
+CI     Cote d'Ivoire
+CK     Cook Islands
+CL     Chile
+CM     Cameroon
+CN     China
+CO     Colombia
+CR     Costa Rica
+CS     Former Czechoslovakia
+CU     Cuba
+CV     Cape Verde
+CX     Christmas Island
+CY     Cyprus
+CZ     Czech Republic
+DE     Germany
+DJ     Djibouti
+DK     Denmark
+DM     Dominica
+DO     Dominican Republic
+DZ     Algeria
+EC     Ecuador
+EE     Estonia
+EG     Egypt
+EH     Western Sahara
+ER     Eritrea
+ES     Spain
+ET     Ethiopia
+FI     Finland
+FJ     Fiji
+FK     Falkland Islands (Malvinas)
+FM     Micronesia
+FO     Faroe Islands
+FR     France
+FX     France, Metropolitan
+GA     Gabon
+GB     United Kingdom
+GD     Grenada
+GE     Georgia
+GF     French Guiana
+GH     Ghana
+GI     Gibraltar
+GL     Greenland
+GM     Gambia
+GN     Guinea
+GP     Guadeloupe
+GQ     Equatorial Guinea
+GR     Greece
+GS     South Georgia and the South Sandwich Islands
+GT     Guatemala
+GU     Guam
+GW     Guinea-Bissau
+GY     Guyana
+HK     Hong Kong
+HM     Heard and McDonald Islands
+HN     Honduras
+HR     Croatia
+HT     Haiti
+HU     Hungary
+ID     Indonesia
+IE     Ireland
+IL     Israel
+IN     India
+IO     British Indian Ocean Territory
+IQ     Iraq
+IR     Iran
+IS     Iceland
+IT     Italy
+JM     Jamaica
+JO     Jordan
+JP     Japan
+KE     Kenya
+KG     Kyrgyzstan
+KH     Cambodia
+KI     Kiribati
+KM     Comoros
+KN     Saint Kitts and Nevis
+KP     Korea, Democratic People's Republic of
+KR     Korea, Republic of
+KW     Kuwait
+KY     Cayman Islands
+KZ     Kazakhstan
+LA     Laos
+LB     Lebanon
+LC     Saint Lucia
+LI     Liechtenstein
+LK     Sri Lanka
+LR     Liberia
+LS     Lesotho
+LT     Lithuania
+LU     Luxembourg
+LV     Latvia
+LY     Libya
+MA     Morocco
+MC     Monaco
+MD     Moldova
+MG     Madagascar
+MH     Marshall Islands
+MK     Macedonia
+ML     Mali
+MM     Myanmar
+MN     Mongolia
+MO     Macau
+MP     Northern Mariana Islands
+MQ     Martinique
+MR     Mauritania
+MS     Montserrat
+MT     Malta
+MU     Mauritius
+MV     Maldives
+MW     Malawi
+MX     Mexico
+MY     Malaysia
+MZ     Mozambique
+NA     Namibia
+NC     New Caledonia
+NE     Niger
+NF     Norfolk Island
+NG     Nigeria
+NI     Nicaragua
+NL     Netherlands
+NO     Norway
+NP     Nepal
+NR     Nauru
+NU     Niue
+NZ     New Zealand
+OM     Oman
+PA     Panama
+PE     Peru
+PF     French Polynesia
+PG     Papua New Guinea
+PH     Philippines
+PK     Pakistan
+PL     Poland
+PM     St. Pierre and Miquelon
+PN     Pitcairn
+PR     Puerto Rico
+PT     Portugal
+PW     Palau
+PY     Paraguay
+QA     Qatar
+RE     Reunion
+RO     Romania
+RU     Russian Federation
+RW     Rwanda
+SA     Saudi Arabia
+SB     Solomon Islands
+SC     Seychelles
+SD     Sudan
+SE     Sweden
+SG     Singapore
+SH     St. Helena
+SI     Slovenia
+SJ     Svalbard and Jan Mayen Islands
+SK     Slovakia (Slovak Republic)
+SL     Sierra Leone
+SM     San Marino
+SN     Senegal
+SO     Somalia
+SR     Suriname
+ST     Sao Tome and Principe
+SU     Former Soviet Union
+SV     El Salvador
+SY     Syria
+SZ     Swaziland
+TC     Turks and Caicos Islands
+TD     Chad
+TF     French Southern Territories
+TG     Togo
+TH     Thailand
+TJ     Tajikistan
+TK     Tokelau
+TM     Turkmenistan
+TN     Tunisia
+TO     Tonga
+TP     East Timor
+TR     Turkey
+TT     Trinidad and Tobago
+TV     Tuvalu
+TW     Taiwan
+TZ     Tanzania
+UA     Ukraine
+UG     Uganda
+UK     United Kingdom
+UM     United States Minor Outlying Islands
+US     United States of America
+UY     Uruguay
+UZ     Uzbekistan
+VA     Vatican City State (Holy See)
+VC     Saint Vincent and the Grenadines
+VE     Venezuela
+VG     Virgin Islands (British)
+VI     Virgin Islands (U.S.)
+VN     Viet Nam
+VU     Vanuatu
+WF     Wallis and Futuna Islands
+WS     Samoa
+YE     Yemen
+YT     Mayotte
+YU     Yugoslavia
+ZA     South Africa
+ZM     Zambia
+ZR     Zaire
+ZW     Zimbabwe
diff --git a/libraries/libldap/ldapsearchprefs.conf b/libraries/libldap/ldapsearchprefs.conf
new file mode 100644 (file)
index 0000000..74be091
--- /dev/null
@@ -0,0 +1,153 @@
+# Version should be 1 now
+Version 1
+#
+#
+# Name for this search object
+People
+# options (the only one supported right now is "internal" which means that
+#   this search object should not be presented directly to the user)
+#   use "" for none
+""
+# Label to place before text box user types in
+"Search For:"
+# Filter prefix to append to all "More Choices" searches
+"(&(objectClass=person)"
+# Tag to use for "Fewer Choices" searches - from ldapfilter.conf file
+"xax500"
+# If a search results in > 1 match, retrieve this attribute to help
+# user disambiguate the entries...
+title
+# ...and label it with this string:
+"Title"
+# Search scope to use when searching
+subtree
+# Follows a list of "More Choices" search options.  Format is:
+# Label, attribute, select-bitmap, extra attr display name, extra attr ldap name
+# If last two are null, "Fewer Choices" name/attributes used
+"Common Name"                   cn                 11111  ""  ""
+"Surname"                       sn                 11111  ""  ""
+"Business Phone"                "telephoneNumber"  11101  ""  ""
+"E-Mail Address"                "mail"             11111  ""  ""
+"Uniqname"                      "uid"              11111  ""  ""
+"Title"                         title              11111 "" ""
+END
+# Match types
+"exactly matches"               "(%a=%v))"
+"approximately matches"         "(%a~=%v))"
+"starts with"                   "(%a=%v*))"
+"ends with"                     "(%a=*%v))"
+"contains"                      "(%a=*%v*))"
+END
+#
+#
+#
+Groups
+""
+"Search For:"
+"(&(objectClass=rfc822MailGroup)"
+"xax500"
+multilineDescription
+"Description"
+subtree
+"Common Name"                   cn                    11111  ""       ""
+"Description"                   multilineDescription  11101  ""       ""
+"Owner"                         "owner"               00001  "owner"  "Owner"
+"X.500 Member"                  "member"              00001  ""       ""
+"E-Mail Member"                 "mail"                00101  ""       ""
+END
+"exactly matches"               "(%a=%v))"
+"approximately matches"         "(%a~=%v))"
+"starts with"                   "(%a=%v*))"
+"ends with"                     "(%a=*%v))"
+"contains"                      "(%a=*%v*))"
+END
+#
+#
+#
+"Joinable Groups"
+""
+"Search For:"
+"(&(&(objectClass=rfc822MailGroup)(joinable=TRUE))"
+"xax500"
+multilineDescription
+"Description"
+subtree
+"Common Name"                   cn                    11111  ""       ""
+"Description"                   multilineDescription  11101  ""       ""
+"Owner"                         "owner"               00001  "owner"  "Owner"
+"X.500 Member"                  "member"              00001  ""       ""
+"E-Mail Member"                 "mail"                00101  ""       ""
+END
+"exactly matches"               "(%a=%v))"
+"approximately matches"         "(%a~=%v))"
+"starts with"                   "(%a=%v*))"
+"ends with"                     "(%a=*%v))"
+"contains"                      "(%a=*%v*))"
+END
+#
+#
+#
+Services
+""
+"Search For:"
+"(&(objectClass=service)"
+"xax500"
+multilineDescription
+"Description"
+subtree
+"Common Name"                   cn                    11111  ""       ""
+"Description"                   multilineDescription  11101  ""       ""
+"Owner"                         "owner"               00001  "owner"  "Owner"
+"Keywords"                      "keywords"            11111  ""       ""
+"Hours"                         "hoursOfOperation"    11111  ""       ""
+END
+"exactly matches"               "(%a=%v))"
+"approximately matches"         "(%a~=%v))"
+"starts with"                   "(%a=%v*))"
+"ends with"                     "(%a=*%v))"
+"contains"                      "(%a=*%v*))"
+END
+#
+#
+#
+Organizations
+""
+"Search For:"
+"(&(objectClass=organization)"
+"xax500"
+multilineDescription
+"Description"
+subtree
+"Name"                          organizationName      01111  ""       ""
+"Location"                      localityName          11111  ""       ""
+"Phone Number"                  "telephoneNumber"     10111  ""       ""
+"Description"                   description           10111  ""       ""
+END
+"exactly matches"               "(%a=%v))"
+"approximately matches"         "(%a~=%v))"
+"starts with"                   "(%a=%v*))"
+"ends with"                     "(%a=*%v))"
+"contains"                      "(%a=*%v*))"
+END
+#
+#
+#
+Documents
+""
+"Search For:"
+"(&(objectClass=document)"
+"xax500"
+multilineDescription
+"Description"
+subtree
+"Document Title"                 cn                   11111  ""       ""
+"Keyword"                       "keywords"            11111  ""       ""
+"Category"                      "category"            11111  ""       ""
+"Document Number"               "documentIdentifier"  11111  ""       ""
+END
+"exactly matches"               "(%a=%v))"
+"approximately matches"         "(%a~=%v))"
+"starts with"                   "(%a=%v*))"
+"ends with"                     "(%a=*%v))"
+"contains"                      "(%a=*%v*))"
+END
diff --git a/libraries/libldap/ldaptemplates.conf b/libraries/libldap/ldaptemplates.conf
new file mode 100644 (file)
index 0000000..f08e3b2
--- /dev/null
@@ -0,0 +1,677 @@
+##########################################################################
+# LDAP display templates
+##########################################################################
+
+#
+# Version must be 1
+#
+Version 1
+
+##########################################################################
+# U-M Person template
+##########################################################################
+#
+# template name and plural name come first
+"U-M Person"
+"U-M People"
+
+# name of the icon that is associated with this template
+"person icon"
+
+# blank-separated list of template options ("" for none)
+#   addable    - end-user should be allowed to add these types of entries
+#   modrdn     - end-user can change the name of these entries
+#   altview    - this template is referred to in another template's
+#                      "linkact" item
+"addable"
+
+#
+# objectclass list
+umichPerson person
+END
+
+#
+# name of attribute to authenticate as ("" means auth as this entry)
+""
+
+#
+# default attribute name to use when forming RDN of a new entry
+#
+cn
+
+#
+# default location when adding new entries (DN; "" means no default)
+"o=University of Michigan, c=US"
+
+#
+# rules used to define default values for new entries
+END
+
+#
+#
+# list of items for display
+# each line is either:
+#    item (type) (attribute) (attr name) (extra args...)
+# to define an item or
+#    samerow
+# to keep the next item on the same row as the previous
+#
+# valid types are:
+#    cis       - case ignore string
+#    mls       - multiline string
+#    dn                - 
+#    mail      - case ignore string that contains an RFC822 mail address
+#    bool      - boolean value
+#    jpeg      - inlined JPEG image
+#    jpegbtn   - JPEG image button
+#    fax       - inlined Fax image
+#    faxbtn    - Fax image button
+#    audiobtn  - audio button
+#    time      - time value
+#    date      - time value displayed as a date only
+#    url       - labeled URL for links to items in WWW
+#    searchact  - search action
+#    linkact    - link to another template
+#
+# valid options (comma separated list appended to the type) are:
+#  ro          - attribute is read only; don't let user edit it
+#  sort                - order the values of this attribute
+#  1val                - disallow entry of multiple values
+#  required    - this attribute should have at least one value
+#  hide                - don't show this item if attribute has no values
+#  hideiffalse - hide item if value is FALSE (for type 'bool' only)
+#
+item jpegbtn   "View Photo"            jpegPhoto       "Next Photo"
+item audiobtn  "Play Sound"            audio
+item cis,ro,sort       "Also Known As"         cn
+item mail      "E-Mail Address"        mail
+item cis       "Work Phone"            telephoneNumber
+item cis       "Fax Number"            facsimileTelephoneNumber
+item cis       "Pager Number"          pager
+item mls       "Work Address"          postalAddress
+item cis,sort  "Title"                 title
+item cis,ro    "Uniqname"              uid
+item mls       "Description"           multiLineDescription
+item cis       "Home Phone"            homePhone
+item mls       "Home Address"          homePostalAddress
+item url       "More Info (URL)"       labeledURL
+item dn,sort   "See Also"              seeAlso
+item cis       "Favorite Beverage"     drink
+item cis       "Notice"                notice
+item bool,hideiffalse  "On Vacation"           onVacation
+item mls,1val  "Vacation Message"      vacationMessage
+item bool,hideiffalse  "Do Not Allow Updates"  noBatchUpdates
+item time,ro   "Last Modified"         lastModifiedTime
+item dn,ro     "Modified By"           lastModifiedBy
+item searchact  "Find Groups Added To"  ""      "-dnt" "(&(objectclass=rfc822mailgroup)(member=%v))" "multiLineDescription" "Description" ""
+item searchact "List Owned Groups"     ""      "-dnt" "(&(objectclass=rfc822mailgroup)(owner=%v))" "title" "Title" ""
+item linkact   "Other Addresses"       ""      "other addresses"
+END
+
+
+##########################################################################
+# Person template
+##########################################################################
+"Person"
+"People"
+"person icon"
+
+# template options
+addable
+#
+# objectclass list
+person
+END
+# name of attribute to authenticate as
+""
+
+# default attribute name to use when forming RDN of a new entry
+#
+cn
+
+# default location when adding new entries
+""
+
+#
+# rules used to define default values for new entries
+END
+
+#
+# list of items for display
+item jpegbtn   "View Photo"            jpegPhoto       "Next Photo"
+item audiobtn  "Play Sound"            audio
+item cis,sort  "Also Known As"         cn
+item cis,sort  "Title"                 title
+item mls       "Work Address"          postalAddress
+item cis       "Work Phone"            telephoneNumber
+item cis       "Fax Number"            facsimileTelephoneNumber
+item cis       "Pager Number"          pager
+item mls       "Home Address"          homePostalAddress
+item cis       "Home Phone"            homePhone
+item cis       "User ID"               uid
+item mail      "E-Mail Address"        mail
+item cis       "Description"           description
+item cis       "Favorite Beverage"     drink
+item dn,sort   "See Also"              seeAlso
+item time,ro   "Last Modified"         lastModifiedTime
+item dn,ro     "Modified By"           lastModifiedBy
+END
+
+
+##########################################################################
+# Group template
+##########################################################################
+"Group"
+"Groups"
+"group icon"
+
+# template options
+addable modrdn
+
+# objectclass list
+rfc822MailGroup
+END
+
+# name of attribute to authenticate as
+"owner"
+
+# default attribute name to use when forming RDN of a new entry
+#
+cn
+
+# default location when adding new entries
+"ou=User Groups, ou=Groups, o=University of Michigan, c=US"
+
+#
+# rules used to define default values for new entries
+constant       "associatedDomain"      "umich.edu"
+constant       "joinable"              "FALSE"
+addersdn       "owner"
+addersdn       "member"
+addersdn       "errorsTo"
+addersdn       "requestsTo"
+END
+
+#
+#
+# list of items for display
+# each line is either:
+#    item (type) (attribute) (attr name) (extra args...)
+# to define an item or
+#    samerow
+#
+# list of items for display
+item cis,sort  "Also Known As"         cn
+item mls       "Description"           multiLineDescription
+item cis       "Phone Number"          telephoneNumber
+item cis       "Fax Number"            facsimileTelephoneNumber
+item mls       "Address"               postalAddress
+item dn,required,sort  "Owner"         owner
+item url       "More Info (URL)"       labeledURL
+item dn,sort   "See Also"              seeAlso
+item dn,sort   "Errors To"             errorsTo
+item dn,sort   "Requests To"           requestsTo
+item cis       "Associated Domain"     associatedDomain
+item cis       "Moderator"             moderator
+item bool      "Suppress 'No E-Mail Address' Errors"   suppressNoEmailError
+item bool      "Others May Join"       joinable
+item dn,sort   "X.500 Members"         member
+item mail,sort "E-Mail Errors To"      rfc822ErrorsTo
+item mail,sort "E-Mail Requests To"    rfc822RequestsTo
+item mail,sort "E-Mail Members"        mail
+item cis       "Notice"                notice
+item time,ro   "Last Modified"         lastModifiedTime
+item dn,ro     "Modified By"           lastModifiedBy
+item searchact  "Subscribers"           "" "-dnt" "memberOfGroup=%v" "title" "Title" "joinable"
+item verifyact "Verify Members"        "member"        "mail" "E-Mail Address"
+END
+
+##########################################################################
+# Organization template
+##########################################################################
+"Organization"
+"Organizations"
+"organization icon"
+
+# template options
+""
+
+# objectclass list
+organization
+END
+
+# name of attribute to authenticate as
+""
+
+# default attribute name to use when forming RDN of a new entry
+o
+
+# default location when adding new entries
+""
+
+# rules used to define default values for new entries
+constant       "o"     "foo"
+END
+
+#
+#
+# list of items for display
+# each line is either:
+#    item (type) (attribute) (attr name) (extra args...)
+# to define an item or
+#    samerow
+#
+# list of items for display
+item cis,sort  "Name"                  o
+item cis       "Location"              l
+item mls       "Address"               postalAddress
+item cis       "Phone Number"          telephoneNumber
+item cis       "Fax Number"            facsimileTelephoneNumber
+item cis       "Description"           description
+item dn,sort   "See Also"              seeAlso
+item time,ro   "Last Modified"         lastModifiedTime
+item dn,ro     "Modified By"           lastModifiedBy
+END
+
+
+##########################################################################
+# Service template
+##########################################################################
+"Service"
+"Services"
+"service icon"
+
+# template options
+"addable"
+
+# objectclass list
+service
+END
+
+# name of attribute to authenticate as
+"owner"
+
+# default attribute name to use when forming RDN of a new entry
+cn
+
+# default location when adding new entries
+"ou=Services, o=University of Michigan, c=US"
+
+# rules used to define default values for new entries
+addersdn       "owner"
+END
+
+#
+#
+# list of items for display
+# each line is either:
+#    item (type) (attribute) (attr name) (extra args...)
+# to define an item or
+#    samerow
+#
+# list of items for display
+item jpegbtn   "View Photo"            jpegPhoto
+item cis,sort  "Name"                  cn
+item mls       "Description"           multilineDescription
+item cis       "Provider"              provider
+item cis,sort  "Service Area"          serviceArea
+item mail      "E-mail Address"        mail
+item cis       "Phone"                 telephoneNumber
+item cis       "Fax Number"            facsimileTelephoneNumber
+item mls       "Postal Address"        postalAddress
+item cis       "Hours"                 hoursOfOperation
+item url       "More Info (URL)"       labeledURL
+item dn,sort   "Depends On"            dependentUpon
+item dn,sort   "See Also"              seeAlso
+item cis,sort  "Platform"              platform
+item cis,sort  "Product"               product
+item cis,sort  "Keywords"              keywords
+item cis       "FCE Rating"            serviceRating
+item date      "Date Rated"            ratingTime
+item mls       "Rating Description"    ratingDescription
+item time,ro   "Last Modified"         lastModifiedTime
+item dn,ro     "Modified By"           lastModifiedBy
+item dn,required,sort  "Owner"         owner
+END
+
+
+##########################################################################
+# Organizational Role template
+##########################################################################
+"Organizational Role"
+"Organizational Roles"
+"person icon"
+
+# template options
+""
+
+# objectclass list
+organizationalRole
+END
+
+# name of attribute to authenticate as
+""
+
+# default attribute name to use when forming RDN of a new entry
+cn
+
+# default location when adding new entries
+""
+
+# rules used to define default values for new entries
+END
+
+#
+#
+# list of items for display
+# each line is either:
+#    item (type) (attribute) (attr name) (extra args...)
+# to define an item or
+#    samerow
+#
+# list of items for display
+item cis,sort  "Name"                  cn
+item cis       "Description"           description
+item dn                "Role Occupant"         roleOccupant
+item dn,sort   "See Also"              seeAlso
+item time,ro   "Last Modified"         lastModifiedTime
+item dn,ro     "Modified By"           lastModifiedBy
+END
+
+
+##########################################################################
+# Organizational Unit template
+##########################################################################
+"Organizational Unit"
+"Organizational Units"
+"organization icon"
+
+# template options
+""
+
+# objectclass list
+organizationalUnit
+END
+
+# name of attribute to authenticate as
+""
+
+# default attribute name to use when forming RDN of a new entry
+cn
+
+# default location when adding new entries
+""
+
+# rules used to define default values for new entries
+END
+
+# Item list
+item cis       "Organization Unit Name"        ou
+item cis       "Title"                         title
+item time,ro   "Last Modified"         lastModifiedTime
+item dn,ro     "Modified By"           lastModifiedBy
+END
+
+
+
+##########################################################################
+# Application Entity template
+##########################################################################
+"Application Entity"
+"Application Entities"
+"application icon"
+
+# template options
+""
+
+# objectclass list
+applicationEntity
+END
+
+# name of attribute to authenticate as
+""
+
+# default attribute name to use when forming RDN of a new entry
+cn
+
+# default location when adding new entries
+""
+
+# rules used to define default values for new entries
+END
+
+# Item list
+item cis,sort  "Name"                  cn
+item cis       "Location"              l
+item cis       "Description"           description
+item time,ro   "Last Modified"         lastModifiedTime
+item dn,ro     "Modified By"           lastModifiedBy
+END
+
+##########################################################################
+# Document template
+##########################################################################
+"Document"
+"Documents"
+"document icon"
+
+# template options
+""
+
+# objectclass list
+document
+umichDocument
+END
+
+# name of attribute to authenticate as
+""
+
+# default attribute name to use when forming RDN of a new entry
+cn
+
+# default location when adding new entries
+""
+
+# rules used to define default values for new entries
+END
+
+#
+# Item list
+item cis       "Document ID"           documentIdentifier
+item cis       "Title"                 documentTitle
+item cis       "Series Title"          documentSeriesTitle
+item cis       "Version"               documentVersion
+item cis,sort  "Service Area"          serviceArea
+item mls       "Abstract"              multiLineAbstract
+item url       "More Info (URL)"       labeledURL
+item dn,sort   "Availability"          documentAvailable
+item dn,sort   "See Also"              seeAlso
+item cis,sort  "Platform"              platform
+item cis,sort  "Product"               product
+item cis,sort  "Keyword"               keywords
+item dn,sort   "Author"                documentAuthor
+item time,ro   "Last Modified"         lastModifiedTime
+item dn,ro     "Modified By"           lastModifiedBy
+item dn,required       "Owner"         owner
+END
+
+##########################################################################
+# Document description template
+##########################################################################
+"DocumentDescription"
+"DocumentDescriptions"
+"document description icon"
+
+# template options
+""
+
+# objectclass list
+documentDescription
+END
+
+# name of attribute to authenticate as
+""
+
+# default attribute name to use when forming RDN of a new entry
+cn
+
+# default location when adding new entries
+""
+
+# rules used to define default values for new entries
+END
+
+#
+# Item list
+item mls       "Description"           multilineDescription
+item url       "More Info (URL)"       labeledURL
+item time,ro   "Last Modified"         lastModifiedTime
+item dn,ro     "Modified By"           lastModifiedBy
+item dn,required       "Owner"         owner
+END
+
+##########################################################################
+# Image template
+##########################################################################
+"Image"
+"Images"
+"image icon"
+
+# template options
+""
+
+# objectclass list
+image
+END
+
+# name of attribute to authenticate as
+""
+
+# default attribute name to use when forming RDN of a new entry
+cn
+
+# default location when adding new entries
+""
+
+# rules used to define default values for new entries
+END
+
+#
+# Item list
+item cis       "Name"                  cn
+item mls       "Description"           multilineDescription
+item jpegbtn   "View Photo(s)"         jpegPhoto
+item cis       "Citation"              citation
+item cis       "Copyright"             copyright
+item cis       "Keywords"              keywords
+item time,ro   "Last Modified"         lastModifiedTime
+item dn,ro     "Modified By"           lastModifiedBy
+item dn,required       "Owner"         owner
+END
+
+
+
+##########################################################################
+# Country template
+##########################################################################
+"Country"
+"Countries"
+"country icon"
+
+# template options
+""
+
+# objectclass list
+friendlyCountry
+END
+
+# name of attribute to authenticate as
+""
+
+# default attribute name to use when forming RDN of a new entry
+c
+
+# default location when adding new entries
+""
+
+# rules used to define default values for new entries
+END
+
+# Item list
+item cis       "Country Name"          co
+item cis       "Country Code"          c
+item cis       "Description"           description
+item time,ro   "Last Modified"         lastModifiedTime
+item dn,ro     "Modified By"           lastModifiedBy
+END
+
+##########################################################################
+# Locality template
+##########################################################################
+"Locality"
+"Localities"
+"locality icon"
+
+# template options
+""
+
+# objectclass list
+locality
+END
+
+# name of attribute to authenticate as
+""
+
+# default attribute name to use when forming RDN of a new entry
+l
+
+# default location when adding new entries
+""
+
+# rules used to define default values for new entries
+END
+
+#
+# Item list
+item cis       "Name"                  l
+item time,ro   "Last Modified"         lastModifiedTime
+item dn,ro     "Modified By"           lastModifiedBy
+END
+
+
+##########################################################################
+# "Other Addresses" template
+##########################################################################
+"Others Addresses"
+"Other Addresses"
+"other addr icon"
+
+# template options
+"altview"
+
+# objectclass list
+END
+
+# name of attribute to authenticate as
+""
+
+# default attribute name to use when forming RDN of a new entry
+""
+
+# default location when adding new entries
+""
+
+# rules used to define default values for new entries
+END
+
+# Item list
+item cis       "Street Address"        streetAddress
+item cis       "Locality"              l
+item cis       "State or Province"     st
+item cis       "Postal Code"           postalCode
+item cis,hide  "X.400 Address"         mhsORAddresses
+item cis,hide  "X.400 Address"         textEncodedORAddress
+Item cis       "Other Mailbox"         otherMailbox
+item time,ro   "Last Modified"         lastModifiedTime
+item dn,ro     "Modified By"           lastModifiedBy
+END
diff --git a/libraries/libldap/modify.c b/libraries/libldap/modify.c
new file mode 100644 (file)
index 0000000..316dde7
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  modify.c
+ */
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef MACOS
+#include "macos.h"
+#endif /* MACOS */
+
+#if !defined( MACOS ) && !defined( DOS )
+#include <sys/types.h>
+#include <sys/socket.h>
+#endif
+
+#include "lber.h"
+#include "ldap.h"
+#include "ldap-int.h"
+
+/*
+ * ldap_modify - initiate an ldap (and X.500) modify operation.  Parameters:
+ *
+ *     ld              LDAP descriptor
+ *     dn              DN of the object to modify
+ *     mods            List of modifications to make.  This is null-terminated
+ *                     array of struct ldapmod's, specifying the modifications
+ *                     to perform.
+ *
+ * Example:
+ *     LDAPMod *mods[] = { 
+ *                     { LDAP_MOD_ADD, "cn", { "babs jensen", "babs", 0 } },
+ *                     { LDAP_MOD_REPLACE, "sn", { "jensen", 0 } },
+ *                     0
+ *             }
+ *     msgid = ldap_modify( ld, dn, mods );
+ */
+int
+ldap_modify( LDAP *ld, char *dn, LDAPMod **mods )
+{
+       BerElement      *ber;
+       int             i, rc;
+
+       /*
+        * A modify request looks like this:
+        *      ModifyRequet ::= SEQUENCE {
+        *              object          DistinguishedName,
+        *              modifications   SEQUENCE OF SEQUENCE {
+        *                      operation       ENUMERATED {
+        *                              add     (0),
+        *                              delete  (1),
+        *                              replace (2)
+        *                      },
+        *                      modification    SEQUENCE {
+        *                              type    AttributeType,
+        *                              values  SET OF AttributeValue
+        *                      }
+        *              }
+        *      }
+        */
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_modify\n", 0, 0, 0 );
+
+       /* create a message to send */
+       if ( (ber = alloc_ber_with_options( ld )) == NULLBER ) {
+               return( -1 );
+       }
+
+       if ( ber_printf( ber, "{it{s{", ++ld->ld_msgid, LDAP_REQ_MODIFY, dn )
+           == -1 ) {
+               ld->ld_errno = LDAP_ENCODING_ERROR;
+               ber_free( ber, 1 );
+               return( -1 );
+       }
+
+       /* for each modification to be performed... */
+       for ( i = 0; mods[i] != NULL; i++ ) {
+               if (( mods[i]->mod_op & LDAP_MOD_BVALUES) != 0 ) {
+                       rc = ber_printf( ber, "{e{s[V]}}",
+                           mods[i]->mod_op & ~LDAP_MOD_BVALUES,
+                           mods[i]->mod_type, mods[i]->mod_bvalues );
+               } else {
+                       rc = ber_printf( ber, "{e{s[v]}}", mods[i]->mod_op,
+                           mods[i]->mod_type, mods[i]->mod_values );
+               }
+
+               if ( rc == -1 ) {
+                       ld->ld_errno = LDAP_ENCODING_ERROR;
+                       ber_free( ber, 1 );
+                       return( -1 );
+               }
+       }
+
+       if ( ber_printf( ber, "}}}" ) == -1 ) {
+               ld->ld_errno = LDAP_ENCODING_ERROR;
+               ber_free( ber, 1 );
+               return( -1 );
+       }
+
+       /* send the message */
+       return( send_initial_request( ld, LDAP_REQ_MODIFY, dn, ber ));
+}
+
+int
+ldap_modify_s( LDAP *ld, char *dn, LDAPMod **mods )
+{
+       int             msgid;
+       LDAPMessage     *res;
+
+       if ( (msgid = ldap_modify( ld, dn, mods )) == -1 )
+               return( ld->ld_errno );
+
+       if ( ldap_result( ld, msgid, 1, (struct timeval *) NULL, &res ) == -1 )
+               return( ld->ld_errno );
+
+       return( ldap_result2error( ld, res, 1 ) );
+}
+
diff --git a/libraries/libldap/modrdn.c b/libraries/libldap/modrdn.c
new file mode 100644 (file)
index 0000000..f4624a9
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  modrdn.c
+ */
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef MACOS
+#include "macos.h"
+#endif /* MACOS */
+
+#if !defined( MACOS ) && !defined( DOS )
+#include <sys/types.h>
+#include <sys/socket.h>
+#endif
+
+#include "lber.h"
+#include "ldap.h"
+#include "ldap-int.h"
+
+/*
+ * ldap_modrdn2 - initiate an ldap (and X.500) modifyRDN operation. Parameters:
+ *
+ *     ld              LDAP descriptor
+ *     dn              DN of the object to modify
+ *     newrdn          RDN to give the object
+ *     deleteoldrdn    nonzero means to delete old rdn values from the entry
+ *
+ * Example:
+ *     msgid = ldap_modrdn( ld, dn, newrdn );
+ */
+int
+ldap_modrdn2( LDAP *ld, char *dn, char *newrdn, int deleteoldrdn )
+{
+       BerElement      *ber;
+
+       /*
+        * A modify rdn request looks like this:
+        *      ModifyRDNRequest ::= SEQUENCE {
+        *              entry           DistinguishedName,
+        *              newrdn          RelativeDistinguishedName,
+        *              deleteoldrdn    BOOLEAN
+        *      }
+        */
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_modrdn\n", 0, 0, 0 );
+
+       /* create a message to send */
+       if ( (ber = alloc_ber_with_options( ld )) == NULLBER ) {
+               return( -1 );
+       }
+
+       if ( ber_printf( ber, "{it{ssb}}", ++ld->ld_msgid, LDAP_REQ_MODRDN, dn,
+           newrdn, deleteoldrdn ) == -1 ) {
+               ld->ld_errno = LDAP_ENCODING_ERROR;
+               ber_free( ber, 1 );
+               return( -1 );
+       }
+
+       /* send the message */
+       return ( send_initial_request( ld, LDAP_REQ_MODRDN, dn, ber ));
+}
+
+int
+ldap_modrdn( LDAP *ld, char *dn, char *newrdn )
+{
+       return( ldap_modrdn2( ld, dn, newrdn, 1 ) );
+}
+
+int
+ldap_modrdn2_s( LDAP *ld, char *dn, char *newrdn, int deleteoldrdn )
+{
+       int             msgid;
+       LDAPMessage     *res;
+
+       if ( (msgid = ldap_modrdn2( ld, dn, newrdn, deleteoldrdn )) == -1 )
+               return( ld->ld_errno );
+
+       if ( ldap_result( ld, msgid, 1, (struct timeval *) NULL, &res ) == -1 )
+               return( ld->ld_errno );
+
+       return( ldap_result2error( ld, res, 1 ) );
+}
+
+int
+ldap_modrdn_s( LDAP *ld, char *dn, char *newrdn )
+{
+       return( ldap_modrdn2_s( ld, dn, newrdn, 1 ) );
+}
diff --git a/libraries/libldap/open.c b/libraries/libldap/open.c
new file mode 100644 (file)
index 0000000..22cd98e
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ *  Copyright (c) 1995 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  open.c
+ */
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1995 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef MACOS
+#include <stdlib.h>
+#include "macos.h"
+#endif /* MACOS */
+
+#if defined( DOS ) || defined( _WIN32 )
+#include "msdos.h"
+#include <stdlib.h>
+#endif /* DOS */
+
+#if !defined(MACOS) && !defined(DOS) && !defined( _WIN32 )
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#ifndef VMS
+#include <sys/param.h>
+#endif
+#include <netinet/in.h>
+#endif
+#include "lber.h"
+#include "ldap.h"
+#include "ldap-int.h"
+
+#ifdef LDAP_DEBUG
+int    ldap_debug;
+#endif
+
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK        ((unsigned long) 0x7f000001)
+#endif
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN  64
+#endif
+
+
+/*
+ * ldap_open - initialize and connect to an ldap server.  A magic cookie to
+ * be used for future communication is returned on success, NULL on failure.
+ * "host" may be a space-separated list of hosts or IP addresses
+ *
+ * Example:
+ *     LDAP    *ld;
+ *     ld = ldap_open( hostname, port );
+ */
+
+LDAP *
+ldap_open( char *host, int port )
+{
+       LDAP            *ld;
+#ifdef LDAP_REFERRALS
+       LDAPServer      *srv;
+#endif /* LDAP_REFERRALS */
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_open\n", 0, 0, 0 );
+
+       if (( ld = ldap_init( host, port )) == NULL ) {
+               return( NULL );
+       }
+
+#ifdef LDAP_REFERRALS
+       if (( srv = (LDAPServer *)calloc( 1, sizeof( LDAPServer ))) ==
+           NULL || ( ld->ld_defhost != NULL && ( srv->lsrv_host =
+           strdup( ld->ld_defhost )) == NULL )) {
+               ldap_ld_free( ld, 0 );
+               return( NULL );
+       }
+       srv->lsrv_port = ld->ld_defport;
+
+       if (( ld->ld_defconn = new_connection( ld, &srv, 1,1,0 )) == NULL ) {
+               if ( ld->ld_defhost != NULL ) free( srv->lsrv_host );
+               free( (char *)srv );
+               ldap_ld_free( ld, 0 );
+               return( NULL );
+       }
+       ++ld->ld_defconn->lconn_refcnt; /* so it never gets closed/freed */
+
+#else /* LDAP_REFERRALS */
+       if ( open_ldap_connection( ld, &ld->ld_sb, ld->ld_defhost,
+           ld->ld_defport, &ld->ld_host, 0 ) < 0 ) {
+               ldap_ld_free( ld, 0 );
+               return( NULL );
+       }
+#endif /* LDAP_REFERRALS */
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_open successful, ld_host is %s\n",
+               ( ld->ld_host == NULL ) ? "(null)" : ld->ld_host, 0, 0 );
+
+       return( ld );
+}
+
+
+/*
+ * ldap_init - initialize the LDAP library.  A magic cookie to be used for
+ * future communication is returned on success, NULL on failure.
+ * "defhost" may be a space-separated list of hosts or IP addresses
+ *
+ * Example:
+ *     LDAP    *ld;
+ *     ld = ldap_open( default_hostname, default_port );
+ */
+LDAP *
+ldap_init( char *defhost, int defport )
+{
+       LDAP                    *ld;
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_init\n", 0, 0, 0 );
+
+
+       if ( (ld = (LDAP *) calloc( 1, sizeof(LDAP) )) == NULL ) {
+               return( NULL );
+       }
+
+#ifdef LDAP_REFERRALS
+       if (( ld->ld_selectinfo = new_select_info()) == NULL ) {
+               free( (char*)ld );
+               return( NULL );
+       }
+       ld->ld_options = LDAP_OPT_REFERRALS;
+#endif /* LDAP_REFERRALS */
+
+       if ( defhost != NULL &&
+           ( ld->ld_defhost = strdup( defhost )) == NULL ) {
+#ifdef LDAP_REFERRALS
+               free_select_info( ld->ld_selectinfo );
+#endif /* LDAP_REFERRALS */
+               free( (char*)ld );
+               return( NULL );
+       }
+
+
+       ld->ld_defport = ( defport == 0 ) ? LDAP_PORT : defport;
+       ld->ld_version = LDAP_VERSION;
+       ld->ld_lberoptions = LBER_USE_DER;
+       ld->ld_refhoplimit = LDAP_DEFAULT_REFHOPLIMIT;
+
+#if defined( STR_TRANSLATION ) && defined( LDAP_DEFAULT_CHARSET )
+       ld->ld_lberoptions |= LBER_TRANSLATE_STRINGS;
+#if LDAP_CHARSET_8859 == LDAP_DEFAULT_CHARSET
+       ldap_set_string_translators( ld, ldap_8859_to_t61, ldap_t61_to_8859 );
+#endif /* LDAP_CHARSET_8859 == LDAP_DEFAULT_CHARSET */
+#endif /* STR_TRANSLATION && LDAP_DEFAULT_CHARSET */
+
+       return( ld );
+}
+
+
+int
+open_ldap_connection( LDAP *ld, Sockbuf *sb, char *host, int defport,
+       char **krbinstancep, int async )
+{
+       int                     rc, port;
+       char                    *p, *q, *r;
+       char                    *curhost, hostname[ 2*MAXHOSTNAMELEN ];
+
+       Debug( LDAP_DEBUG_TRACE, "open_ldap_connection\n", 0, 0, 0 );
+
+       defport = htons( defport );
+
+       if ( host != NULL ) {
+               for ( p = host; p != NULL && *p != '\0'; p = q ) {
+                       if (( q = strchr( p, ' ' )) != NULL ) {
+                               strncpy( hostname, p, q - p );
+                               hostname[ q - p ] = '\0';
+                               curhost = hostname;
+                               while ( *q == ' ' ) {
+                                   ++q;
+                               }
+                       } else {
+                               curhost = p;    /* avoid copy if possible */
+                               q = NULL;
+                       }
+
+                       if (( r = strchr( curhost, ':' )) != NULL ) {
+                           if ( curhost != hostname ) {
+                               strcpy( hostname, curhost );    /* now copy */
+                               r = hostname + ( r - curhost );
+                               curhost = hostname;
+                           }
+                           *r++ = '\0';
+                           port = htons( (short)atoi( r ));
+                       } else {
+                           port = defport;   
+                       }
+
+                       if (( rc = connect_to_host( sb, curhost, 0L,
+                           port, async )) != -1 ) {
+                               break;
+                       }
+               }
+       } else {
+               rc = connect_to_host( sb, NULL, htonl( INADDR_LOOPBACK ),
+                   defport, async );
+       }
+
+       if ( rc == -1 ) {
+               return( rc );
+       }
+
+       if ( krbinstancep != NULL ) {
+#ifdef KERBEROS
+               if (( *krbinstancep = host_connected_to( sb )) != NULL &&
+                   ( p = strchr( *krbinstancep, '.' )) != NULL ) {
+                       *p = '\0';
+               }
+#else /* KERBEROS */
+               krbinstancep = NULL;
+#endif /* KERBEROS */
+       }
+
+       return( 0 );
+}
diff --git a/libraries/libldap/os-ip.c b/libraries/libldap/os-ip.c
new file mode 100644 (file)
index 0000000..ce1ab0e
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ *  Copyright (c) 1995 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  os-ip.c -- platform-specific TCP & UDP related code
+ */
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1995 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef _WIN32
+#include <io.h>
+#include "msdos.h"
+#else /* _WIN32 */
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#endif /* _WIN32 */
+#ifdef _AIX
+#include <sys/select.h>
+#endif /* _AIX */
+#ifdef VMS
+#include "ucx_select.h"
+#endif /* VMS */
+#include "portable.h"
+#include "lber.h"
+#include "ldap.h"
+
+#ifdef LDAP_REFERRALS
+#ifdef USE_SYSCONF
+#include <unistd.h>
+#endif /* USE_SYSCONF */
+#ifdef notyet
+#ifdef NEED_FILIO
+#include <sys/filio.h>
+#else /* NEED_FILIO */
+#include <sys/ioctl.h>
+#endif /* NEED_FILIO */
+#endif /* notyet */
+#endif /* LDAP_REFERRALS */
+
+#ifdef MACOS
+#define tcp_close( s )         tcpclose( s )
+#else /* MACOS */
+#ifdef DOS
+#ifdef PCNFS
+#define tcp_close( s )         close( s )
+#endif /* PCNFS */
+#ifdef NCSA
+#define tcp_close( s )         netclose( s ); netshut()
+#endif /* NCSA */
+#ifdef WINSOCK
+#define tcp_close( s )         closesocket( s ); WSACleanup();
+#endif /* WINSOCK */
+#else /* DOS */
+#define tcp_close( s )         close( s )
+#endif /* DOS */
+#endif /* MACOS */
+
+
+int
+connect_to_host( Sockbuf *sb, char *host, unsigned long address,
+       int port, int async )
+/*
+ * if host == NULL, connect using address
+ * "address" and "port" must be in network byte order
+ * zero is returned upon success, -1 if fatal error, -2 EINPROGRESS
+ * async is only used ifdef LDAP_REFERRALS (non-0 means don't wait for connect)
+ * XXX async is not used yet!
+ */
+{
+       int                     rc, i, s, connected, use_hp;
+       struct sockaddr_in      sin;
+       struct hostent          *hp;
+#ifdef notyet
+#ifdef LDAP_REFERRALS
+       int                     status; /* for ioctl call */
+#endif /* LDAP_REFERRALS */
+#endif /* notyet */
+
+       Debug( LDAP_DEBUG_TRACE, "connect_to_host: %s:%d\n",
+           ( host == NULL ) ? "(by address)" : host, ntohs( port ), 0 );
+
+       connected = use_hp = 0;
+
+       if ( host != NULL && ( address = inet_addr( host )) == -1 ) {
+               if ( (hp = gethostbyname( host )) == NULL ) {
+                       errno = EHOSTUNREACH;   /* not exactly right, but... */
+                       return( -1 );
+               }
+               use_hp = 1;
+       }
+
+       rc = -1;
+       for ( i = 0; !use_hp || ( hp->h_addr_list[ i ] != 0 ); i++ ) {
+               if (( s = socket( AF_INET, SOCK_STREAM, 0 )) < 0 ) {
+                       return( -1 );
+               }
+#ifdef notyet
+#ifdef LDAP_REFERRALS
+               status = 1;
+               if ( async && ioctl( s, FIONBIO, (caddr_t)&status ) == -1 ) {
+                       Debug( LDAP_DEBUG_ANY, "FIONBIO ioctl failed on %d\n",
+                           s, 0, 0 );
+               }
+#endif /* LDAP_REFERRALS */
+#endif /* notyet */
+               (void)memset( (char *)&sin, 0, sizeof( struct sockaddr_in ));
+               sin.sin_family = AF_INET;
+               sin.sin_port = port;
+               SAFEMEMCPY( (char *) &sin.sin_addr.s_addr,
+                   ( use_hp ? (char *) hp->h_addr_list[ i ] :
+                   (char *) &address ), sizeof( sin.sin_addr.s_addr) );
+
+               if ( connect( s, (struct sockaddr *)&sin,
+                   sizeof( struct sockaddr_in )) >= 0 ) {
+                       connected = 1;
+                       rc = 0;
+                       break;
+               } else {
+#ifdef notyet
+#ifdef LDAP_REFERRALS
+#ifdef EAGAIN
+                       if ( errno == EINPROGRESS || errno == EAGAIN ) {
+#else /* EAGAIN */
+                       if ( errno == EINPROGRESS ) {
+#endif /* EAGAIN */
+                               Debug( LDAP_DEBUG_TRACE,
+                                       "connect would block...\n", 0, 0, 0 );
+                               rc = -2;
+                               break;
+                       }
+#endif /* LDAP_REFERRALS */
+#endif /* notyet */
+
+#ifdef LDAP_DEBUG              
+                       if ( ldap_debug & LDAP_DEBUG_TRACE ) {
+                               perror( (char *)inet_ntoa( sin.sin_addr ));
+                       }
+#endif
+                       close( s );
+                       if ( !use_hp ) {
+                               break;
+                       }
+               }
+       }
+
+       sb->sb_sd = s;
+
+       if ( connected ) {
+#ifdef notyet
+#ifdef LDAP_REFERRALS
+               status = 0;
+               if ( !async && ioctl( s, FIONBIO, (caddr_t)&on ) == -1 ) {
+                       Debug( LDAP_DEBUG_ANY, "FIONBIO ioctl failed on %d\n",
+                           s, 0, 0 );
+               }
+#endif /* LDAP_REFERRALS */
+#endif /* notyet */
+
+               Debug( LDAP_DEBUG_TRACE, "sd %d connected to: %s\n",
+                   s, inet_ntoa( sin.sin_addr ), 0 );
+       }
+
+       return( rc );
+}
+
+
+void
+close_connection( Sockbuf *sb )
+{
+    tcp_close( sb->sb_sd );
+}
+
+
+#ifdef KERBEROS
+char *
+host_connected_to( Sockbuf *sb )
+{
+       struct hostent          *hp;
+       char                    *p;
+       int                     len;
+       struct sockaddr_in      sin;
+
+       (void)memset( (char *)&sin, 0, sizeof( struct sockaddr_in ));
+       len = sizeof( sin );
+       if ( getpeername( sb->sb_sd, (struct sockaddr *)&sin, &len ) == -1 ) {
+               return( NULL );
+       }
+
+       /*
+        * do a reverse lookup on the addr to get the official hostname.
+        * this is necessary for kerberos to work right, since the official
+        * hostname is used as the kerberos instance.
+        */
+       if (( hp = gethostbyaddr( (char *) &sin.sin_addr,
+           sizeof( sin.sin_addr ), AF_INET )) != NULL ) {
+               if ( hp->h_name != NULL ) {
+                       return( strdup( hp->h_name ));
+               }
+       }
+
+       return( NULL );
+}
+#endif /* KERBEROS */
+
+
+#ifdef LDAP_REFERRALS
+/* for UNIX */
+struct selectinfo {
+       fd_set  si_readfds;
+       fd_set  si_writefds;
+       fd_set  si_use_readfds;
+       fd_set  si_use_writefds;
+};
+
+
+void
+mark_select_write( LDAP *ld, Sockbuf *sb )
+{
+       struct selectinfo       *sip;
+
+       sip = (struct selectinfo *)ld->ld_selectinfo;
+
+       if ( !FD_ISSET( sb->sb_sd, &sip->si_writefds )) {
+               FD_SET( sb->sb_sd, &sip->si_writefds );
+       }
+}
+
+
+void
+mark_select_read( LDAP *ld, Sockbuf *sb )
+{
+       struct selectinfo       *sip;
+
+       sip = (struct selectinfo *)ld->ld_selectinfo;
+
+       if ( !FD_ISSET( sb->sb_sd, &sip->si_readfds )) {
+               FD_SET( sb->sb_sd, &sip->si_readfds );
+       }
+}
+
+
+void
+mark_select_clear( LDAP *ld, Sockbuf *sb )
+{
+       struct selectinfo       *sip;
+
+       sip = (struct selectinfo *)ld->ld_selectinfo;
+
+       FD_CLR( sb->sb_sd, &sip->si_writefds );
+       FD_CLR( sb->sb_sd, &sip->si_readfds );
+}
+
+
+int
+is_write_ready( LDAP *ld, Sockbuf *sb )
+{
+       struct selectinfo       *sip;
+
+       sip = (struct selectinfo *)ld->ld_selectinfo;
+
+       return( FD_ISSET( sb->sb_sd, &sip->si_use_writefds ));
+}
+
+
+int
+is_read_ready( LDAP *ld, Sockbuf *sb )
+{
+       struct selectinfo       *sip;
+
+       sip = (struct selectinfo *)ld->ld_selectinfo;
+
+       return( FD_ISSET( sb->sb_sd, &sip->si_use_readfds ));
+}
+
+
+void *
+new_select_info()
+{
+       struct selectinfo       *sip;
+
+       if (( sip = (struct selectinfo *)calloc( 1,
+           sizeof( struct selectinfo ))) != NULL ) {
+               FD_ZERO( &sip->si_readfds );
+               FD_ZERO( &sip->si_writefds );
+       }
+
+       return( (void *)sip );
+}
+
+
+void
+free_select_info( void *sip )
+{
+       free( sip );
+}
+
+
+int
+do_ldap_select( LDAP *ld, struct timeval *timeout )
+{
+       struct selectinfo       *sip;
+       static int              tblsize;
+
+       Debug( LDAP_DEBUG_TRACE, "do_ldap_select\n", 0, 0, 0 );
+
+       if ( tblsize == 0 ) {
+#ifdef USE_SYSCONF
+               tblsize = sysconf( _SC_OPEN_MAX );
+#else /* USE_SYSCONF */
+               tblsize = getdtablesize();
+#endif /* USE_SYSCONF */
+       }
+
+       sip = (struct selectinfo *)ld->ld_selectinfo;
+       sip->si_use_readfds = sip->si_readfds;
+       sip->si_use_writefds = sip->si_writefds;
+       
+       return( select( tblsize, &sip->si_use_readfds, &sip->si_use_writefds,
+           NULL, timeout ));
+}
+#endif /* LDAP_REFERRALS */
diff --git a/libraries/libldap/regex.c b/libraries/libldap/regex.c
new file mode 100644 (file)
index 0000000..4f309c5
--- /dev/null
@@ -0,0 +1,906 @@
+#include "portable.h"
+
+#if defined( MACOS ) || defined( DOS ) || defined( _WIN32 ) || defined( NEED_BSDREGEX )
+#include "regex.h"
+
+/*
+ * regex - Regular expression pattern matching  and replacement
+ *
+ * By:  Ozan S. Yigit (oz)
+ *      Dept. of Computer Science
+ *      York University
+ *
+ * These routines are the PUBLIC DOMAIN equivalents of regex
+ * routines as found in 4.nBSD UN*X, with minor extensions.
+ *
+ * These routines are derived from various implementations found
+ * in software tools books, and Conroy's grep. They are NOT derived
+ * from licensed/restricted software.
+ * For more interesting/academic/complicated implementations,
+ * see Henry Spencer's regexp routines, or GNU Emacs pattern
+ * matching module.
+ *
+ * Modification history:
+ *
+ * $Log: regex.c,v $
+ * Revision 1.12  1996/04/25  16:20:59  mcs
+ * make re_exec() match "" with ".*" and similar patterns
+ * hopefully this change doesn't break anything else!
+ *
+ * Revision 1.11  1994/12/14  21:33:45  mcs
+ * use new NEED_BSDREGEX
+ * fix pmatch() prototype
+ *
+ * Revision 1.10  1994/12/12  18:16:39  mcs
+ * use on NetBSD
+ *
+ * Revision 1.9  1994/11/15  19:16:35  mcs
+ * add (CHAR) cast to make VisualC++ happy
+ *
+ * Revision 1.8  1994/11/08  21:14:32  mcs
+ * WIN32 changes
+ *
+ * Revision 1.7  1994/07/23  19:51:24  mcs
+ * use ANSI-style inline function parameters
+ *
+ * Revision 1.6  1993/10/18  01:52:32  tim
+ * include for VMS
+ *
+ * Revision 1.5  1993/09/28  21:37:54  mcs
+ * HP/UX needs the regex we include (not in its libc)
+ *
+ * Revision 1.4  1993/08/27  15:59:52  mcs
+ * use CHAR for deftab
+ *
+ * Revision 1.3  1993/08/27  15:49:47  mcs
+ * added missing 0 to octal constants
+ * use unsigned char for CHAR under DOS
+ *
+ * Revision 1.2  1993/08/27  14:57:48  mcs
+ * add proto. for pmatch
+ *
+ * Revision 1.1  1993/08/18  21:20:02  mcs
+ * Initial revision
+ *
+ * Revision 1.4  1991/10/17  03:56:42  oz
+ * miscellaneous changes, small cleanups etc.
+ *
+ * Revision 1.3  1989/04/01  14:18:09  oz
+ * Change all references to a dfa: this is actually an nfa.
+ *
+ * Revision 1.2  88/08/28  15:36:04  oz
+ * Use a complement bitmap to represent NCL.
+ * This removes the need to have seperate 
+ * code in the pmatch case block - it is 
+ * just CCL code now.
+ * 
+ * Use the actual CCL code in the CLO
+ * section of pmatch. No need for a recursive
+ * pmatch call.
+ * 
+ * Use a bitmap table to set char bits in an
+ * 8-bit chunk.
+ * 
+ * Interfaces:
+ *      re_comp:        compile a regular expression into a NFA.
+ *
+ *                     char *re_comp(s)
+ *                     char *s;
+ *
+ *      re_exec:        execute the NFA to match a pattern.
+ *
+ *                     int re_exec(s)
+ *                     char *s;
+ *
+ *     re_modw         change re_exec's understanding of what a "word"
+ *                     looks like (for \< and \>) by adding into the
+ *                     hidden word-syntax table.
+ *
+ *                     void re_modw(s)
+ *                     char *s;
+ *
+ *      re_subs:       substitute the matched portions in a new string.
+ *
+ *                     int re_subs(src, dst)
+ *                     char *src;
+ *                     char *dst;
+ *
+ *     re_fail:        failure routine for re_exec.
+ *
+ *                     void re_fail(msg, op)
+ *                     char *msg;
+ *                     char op;
+ *  
+ * Regular Expressions:
+ *
+ *      [1]     char    matches itself, unless it is a special
+ *                      character (metachar): . \ [ ] * + ^ $
+ *
+ *      [2]     .       matches any character.
+ *
+ *      [3]     \       matches the character following it, except
+ *                     when followed by a left or right round bracket,
+ *                     a digit 1 to 9 or a left or right angle bracket. 
+ *                     (see [7], [8] and [9])
+ *                     It is used as an escape character for all 
+ *                     other meta-characters, and itself. When used
+ *                     in a set ([4]), it is treated as an ordinary
+ *                     character.
+ *
+ *      [4]     [set]   matches one of the characters in the set.
+ *                      If the first character in the set is "^",
+ *                      it matches a character NOT in the set, i.e. 
+ *                     complements the set. A shorthand S-E is 
+ *                     used to specify a set of characters S upto 
+ *                     E, inclusive. The special characters "]" and 
+ *                     "-" have no special meaning if they appear 
+ *                     as the first chars in the set.
+ *                      examples:        match:
+ *
+ *                              [a-z]    any lowercase alpha
+ *
+ *                              [^]-]    any char except ] and -
+ *
+ *                              [^A-Z]   any char except uppercase
+ *                                       alpha
+ *
+ *                              [a-zA-Z] any alpha
+ *
+ *      [5]     *       any regular expression form [1] to [4], followed by
+ *                      closure char (*) matches zero or more matches of
+ *                      that form.
+ *
+ *      [6]     +       same as [5], except it matches one or more.
+ *
+ *      [7]             a regular expression in the form [1] to [10], enclosed
+ *                      as \(form\) matches what form matches. The enclosure
+ *                      creates a set of tags, used for [8] and for
+ *                      pattern substution. The tagged forms are numbered
+ *                     starting from 1.
+ *
+ *      [8]             a \ followed by a digit 1 to 9 matches whatever a
+ *                      previously tagged regular expression ([7]) matched.
+ *
+ *     [9]     \<      a regular expression starting with a \< construct
+ *             \>      and/or ending with a \> construct, restricts the
+ *                     pattern matching to the beginning of a word, and/or
+ *                     the end of a word. A word is defined to be a character
+ *                     string beginning and/or ending with the characters
+ *                     A-Z a-z 0-9 and _. It must also be preceded and/or
+ *                     followed by any character outside those mentioned.
+ *
+ *      [10]            a composite regular expression xy where x and y
+ *                      are in the form [1] to [10] matches the longest
+ *                      match of x followed by a match for y.
+ *
+ *      [11]   ^       a regular expression starting with a ^ character
+ *             $       and/or ending with a $ character, restricts the
+ *                      pattern matching to the beginning of the line,
+ *                      or the end of line. [anchors] Elsewhere in the
+ *                     pattern, ^ and $ are treated as ordinary characters.
+ *
+ *
+ * Acknowledgements:
+ *
+ *     HCR's Hugh Redelmeier has been most helpful in various
+ *     stages of development. He convinced me to include BOW
+ *     and EOW constructs, originally invented by Rob Pike at
+ *     the University of Toronto.
+ *
+ * References:
+ *              Software tools                 Kernighan & Plauger
+ *              Software tools in Pascal        Kernighan & Plauger
+ *              Grep [rsx-11 C dist]            David Conroy
+ *             ed - text editor                Un*x Programmer's Manual
+ *             Advanced editing on Un*x        B. W. Kernighan
+ *             RegExp routines                 Henry Spencer
+ *
+ * Notes:
+ *
+ *     This implementation uses a bit-set representation for character
+ *     classes for speed and compactness. Each character is represented 
+ *     by one bit in a 128-bit block. Thus, CCL always takes a 
+ *     constant 16 bytes in the internal nfa, and re_exec does a single
+ *     bit comparison to locate the character in the set.
+ *
+ * Examples:
+ *
+ *     pattern:        foo*.*
+ *     compile:        CHR f CHR o CLO CHR o END CLO ANY END END
+ *     matches:        fo foo fooo foobar fobar foxx ...
+ *
+ *     pattern:        fo[ob]a[rz]     
+ *     compile:        CHR f CHR o CCL bitset CHR a CCL bitset END
+ *     matches:        fobar fooar fobaz fooaz
+ *
+ *     pattern:        foo\\+
+ *     compile:        CHR f CHR o CHR o CHR \ CLO CHR \ END END
+ *     matches:        foo\ foo\\ foo\\\  ...
+ *
+ *     pattern:        \(foo\)[1-3]\1  (same as foo[1-3]foo)
+ *     compile:        BOT 1 CHR f CHR o CHR o EOT 1 CCL bitset REF 1 END
+ *     matches:        foo1foo foo2foo foo3foo
+ *
+ *     pattern:        \(fo.*\)-\1
+ *     compile:        BOT 1 CHR f CHR o CLO ANY END EOT 1 CHR - REF 1 END
+ *     matches:        foo-foo fo-fo fob-fob foobar-foobar ...
+ */
+
+#define MAXNFA  1024
+#define MAXTAG  10
+
+#define OKP     1
+#define NOP     0
+
+#define CHR     1
+#define ANY     2
+#define CCL     3
+#define BOL     4
+#define EOL     5
+#define BOT     6
+#define EOT     7
+#define BOW    8
+#define EOW    9
+#define REF     10
+#define CLO     11
+
+#define END     0
+
+/*
+ * The following defines are not meant to be changeable.
+ * They are for readability only.
+ */
+#define MAXCHR 128
+#define CHRBIT 8
+#define BITBLK MAXCHR/CHRBIT
+#define BLKIND 0170
+#define BITIND 07
+
+#define ASCIIB 0177
+
+#if defined( DOS ) || defined( _WIN32 )
+typedef unsigned char CHAR;
+#else /* DOS */
+typedef /*unsigned*/ char CHAR;
+#endif /* DOS */
+
+static int  tagstk[MAXTAG];             /* subpat tag stack..*/
+static CHAR nfa[MAXNFA];               /* automaton..       */
+static int  sta = NOP;                 /* status of lastpat */
+
+static CHAR bittab[BITBLK];            /* bit table for CCL */
+                                       /* pre-set bits...   */
+static CHAR bitarr[] = {1,2,4,8,16,32,64,128};
+
+static void
+chset(CHAR c)
+{
+       bittab[((c) & BLKIND) >> 3] |= bitarr[(c) & BITIND];
+}
+
+#define badpat(x)      (*nfa = END, x)
+#define store(x)       *mp++ = x
+char *     
+re_comp( char *pat )
+{
+       register char *p;               /* pattern pointer   */
+       register CHAR *mp=nfa;          /* nfa pointer       */
+       register CHAR *lp;              /* saved pointer..   */
+       register CHAR *sp=nfa;          /* another one..     */
+
+       register int tagi = 0;          /* tag stack index   */
+       register int tagc = 1;          /* actual tag count  */
+
+       register int n;
+       register CHAR mask;             /* xor mask -CCL/NCL */
+       int c1, c2;
+               
+       if (!pat || !*pat)
+               if (sta)
+                       return 0;
+               else
+                       return badpat("No previous regular expression");
+       sta = NOP;
+
+       for (p = pat; *p; p++) {
+               lp = mp;
+               switch(*p) {
+
+               case '.':               /* match any char..  */
+                       store(ANY);
+                       break;
+
+               case '^':               /* match beginning.. */
+                       if (p == pat)
+                               store(BOL);
+                       else {
+                               store(CHR);
+                               store(*p);
+                       }
+                       break;
+
+               case '$':               /* match endofline.. */
+                       if (!*(p+1))
+                               store(EOL);
+                       else {
+                               store(CHR);
+                               store(*p);
+                       }
+                       break;
+
+               case '[':               /* match char class..*/
+                       store(CCL);
+
+                       if (*++p == '^') {
+                               mask = 0377;    
+                               p++;
+                       }
+                       else
+                               mask = 0;
+
+                       if (*p == '-')          /* real dash */
+                               chset(*p++);
+                       if (*p == ']')          /* real brac */
+                               chset(*p++);
+                       while (*p && *p != ']') {
+                               if (*p == '-' && *(p+1) && *(p+1) != ']') {
+                                       p++;
+                                       c1 = *(p-2) + 1;
+                                       c2 = *p++;
+                                       while (c1 <= c2)
+                                               chset((CHAR)c1++);
+                               }
+#ifdef EXTEND
+                               else if (*p == '\\' && *(p+1)) {
+                                       p++;
+                                       chset(*p++);
+                               }
+#endif
+                               else
+                                       chset(*p++);
+                       }
+                       if (!*p)
+                               return badpat("Missing ]");
+
+                       for (n = 0; n < BITBLK; bittab[n++] = (char) 0)
+                               store(mask ^ bittab[n]);
+       
+                       break;
+
+               case '*':               /* match 0 or more.. */
+               case '+':               /* match 1 or more.. */
+                       if (p == pat)
+                               return badpat("Empty closure");
+                       lp = sp;                /* previous opcode */
+                       if (*lp == CLO)         /* equivalence..   */
+                               break;
+                       switch(*lp) {
+
+                       case BOL:
+                       case BOT:
+                       case EOT:
+                       case BOW:
+                       case EOW:
+                       case REF:
+                               return badpat("Illegal closure");
+                       default:
+                               break;
+                       }
+
+                       if (*p == '+')
+                               for (sp = mp; lp < sp; lp++)
+                                       store(*lp);
+
+                       store(END);
+                       store(END);
+                       sp = mp;
+                       while (--mp > lp)
+                               *mp = mp[-1];
+                       store(CLO);
+                       mp = sp;
+                       break;
+
+               case '\\':              /* tags, backrefs .. */
+                       switch(*++p) {
+
+                       case '(':
+                               if (tagc < MAXTAG) {
+                                       tagstk[++tagi] = tagc;
+                                       store(BOT);
+                                       store(tagc++);
+                               }
+                               else
+                                       return badpat("Too many \\(\\) pairs");
+                               break;
+                       case ')':
+                               if (*sp == BOT)
+                                       return badpat("Null pattern inside \\(\\)");
+                               if (tagi > 0) {
+                                       store(EOT);
+                                       store(tagstk[tagi--]);
+                               }
+                               else
+                                       return badpat("Unmatched \\)");
+                               break;
+                       case '<':
+                               store(BOW);
+                               break;
+                       case '>':
+                               if (*sp == BOW)
+                                       return badpat("Null pattern inside \\<\\>");
+                               store(EOW);
+                               break;
+                       case '1':
+                       case '2':
+                       case '3':
+                       case '4':
+                       case '5':
+                       case '6':
+                       case '7':
+                       case '8':
+                       case '9':
+                               n = *p-'0';
+                               if (tagi > 0 && tagstk[tagi] == n)
+                                       return badpat("Cyclical reference");
+                               if (tagc > n) {
+                                       store(REF);
+                                       store(n);
+                               }
+                               else
+                                       return badpat("Undetermined reference");
+                               break;
+#ifdef EXTEND
+                       case 'b':
+                               store(CHR);
+                               store('\b');
+                               break;
+                       case 'n':
+                               store(CHR);
+                               store('\n');
+                               break;
+                       case 'f':
+                               store(CHR);
+                               store('\f');
+                               break;
+                       case 'r':
+                               store(CHR);
+                               store('\r');
+                               break;
+                       case 't':
+                               store(CHR);
+                               store('\t');
+                               break;
+#endif
+                       default:
+                               store(CHR);
+                               store(*p);
+                       }
+                       break;
+
+               default :               /* an ordinary char  */
+                       store(CHR);
+                       store(*p);
+                       break;
+               }
+               sp = lp;
+       }
+       if (tagi > 0)
+               return badpat("Unmatched \\(");
+       store(END);
+       sta = OKP;
+       return 0;
+}
+
+
+static char *bol;
+char *bopat[MAXTAG];
+char *eopat[MAXTAG];
+#ifdef NEEDPROTOS
+static char *pmatch( char *lp, CHAR *ap );
+#else /* NEEDPROTOS */
+static char *pmatch();
+#endif /* NEEDPROTOS */
+
+/*
+ * re_exec:
+ *     execute nfa to find a match.
+ *
+ *     special cases: (nfa[0]) 
+ *             BOL
+ *                     Match only once, starting from the
+ *                     beginning.
+ *             CHR
+ *                     First locate the character without
+ *                     calling pmatch, and if found, call
+ *                     pmatch for the remaining string.
+ *             END
+ *                     re_comp failed, poor luser did not
+ *                     check for it. Fail fast.
+ *
+ *     If a match is found, bopat[0] and eopat[0] are set
+ *     to the beginning and the end of the matched fragment,
+ *     respectively.
+ *
+ */
+
+int
+re_exec( char *lp )
+{
+       register char c;
+       register char *ep = 0;
+       register CHAR *ap = nfa;
+
+       bol = lp;
+
+       bopat[0] = 0;
+       bopat[1] = 0;
+       bopat[2] = 0;
+       bopat[3] = 0;
+       bopat[4] = 0;
+       bopat[5] = 0;
+       bopat[6] = 0;
+       bopat[7] = 0;
+       bopat[8] = 0;
+       bopat[9] = 0;
+
+       switch(*ap) {
+
+       case BOL:                       /* anchored: match from BOL only */
+               ep = pmatch(lp,ap);
+               break;
+       case CHR:                       /* ordinary char: locate it fast */
+               c = *(ap+1);
+               while (*lp && *lp != c)
+                       lp++;
+               if (!*lp)               /* if EOS, fail, else fall thru. */
+                       return 0;
+       default:                        /* regular matching all the way. */
+               do {
+                       if ((ep = pmatch(lp,ap)))
+                               break;
+                       lp++;
+               } while (*lp);
+
+               break;
+       case END:                       /* munged automaton. fail always */
+               return 0;
+       }
+       if (!ep)
+               return 0;
+
+       bopat[0] = lp;
+       eopat[0] = ep;
+       return 1;
+}
+
+/* 
+ * pmatch: internal routine for the hard part
+ *
+ *     This code is partly snarfed from an early grep written by
+ *     David Conroy. The backref and tag stuff, and various other
+ *     innovations are by oz.
+ *
+ *     special case optimizations: (nfa[n], nfa[n+1])
+ *             CLO ANY
+ *                     We KNOW .* will match everything upto the
+ *                     end of line. Thus, directly go to the end of
+ *                     line, without recursive pmatch calls. As in
+ *                     the other closure cases, the remaining pattern
+ *                     must be matched by moving backwards on the
+ *                     string recursively, to find a match for xy
+ *                     (x is ".*" and y is the remaining pattern)
+ *                     where the match satisfies the LONGEST match for
+ *                     x followed by a match for y.
+ *             CLO CHR
+ *                     We can again scan the string forward for the
+ *                     single char and at the point of failure, we
+ *                     execute the remaining nfa recursively, same as
+ *                     above.
+ *
+ *     At the end of a successful match, bopat[n] and eopat[n]
+ *     are set to the beginning and end of subpatterns matched
+ *     by tagged expressions (n = 1 to 9).     
+ *
+ */
+
+#ifndef re_fail
+extern void re_fail();
+#endif /* re_fail */
+
+/*
+ * character classification table for word boundary operators BOW
+ * and EOW. the reason for not using ctype macros is that we can
+ * let the user add into our own table. see re_modw. This table
+ * is not in the bitset form, since we may wish to extend it in the
+ * future for other character classifications. 
+ *
+ *     TRUE for 0-9 A-Z a-z _
+ */
+static char chrtyp[MAXCHR] = {
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 
+       0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 0, 0, 0, 0, 0
+       };
+
+#define inascii(x)     (0177&(x))
+#define iswordc(x)     chrtyp[inascii(x)]
+#define isinset(x,y)   ((x)[((y)&BLKIND)>>3] & bitarr[(y)&BITIND])
+
+/*
+ * skip values for CLO XXX to skip past the closure
+ */
+
+#define ANYSKIP        2       /* [CLO] ANY END ...         */
+#define CHRSKIP        3       /* [CLO] CHR chr END ...     */
+#define CCLSKIP 18     /* [CLO] CCL 16bytes END ... */
+
+static char *
+pmatch( char *lp, CHAR *ap)
+{
+       register int op, c, n;
+       register char *e;               /* extra pointer for CLO */
+       register char *bp;              /* beginning of subpat.. */
+       register char *ep;              /* ending of subpat..    */
+       char *are;                      /* to save the line ptr. */
+
+       while ((op = *ap++) != END)
+               switch(op) {
+
+               case CHR:
+                       if (*lp++ != *ap++)
+                               return 0;
+                       break;
+               case ANY:
+                       if (!*lp++)
+                               return 0;
+                       break;
+               case CCL:
+                       c = *lp++;
+                       if (!isinset(ap,c))
+                               return 0;
+                       ap += BITBLK;
+                       break;
+               case BOL:
+                       if (lp != bol)
+                               return 0;
+                       break;
+               case EOL:
+                       if (*lp)
+                               return 0;
+                       break;
+               case BOT:
+                       bopat[*ap++] = lp;
+                       break;
+               case EOT:
+                       eopat[*ap++] = lp;
+                       break;
+               case BOW:
+                       if (lp!=bol && iswordc(lp[-1]) || !iswordc(*lp))
+                               return 0;
+                       break;
+               case EOW:
+                       if (lp==bol || !iswordc(lp[-1]) || iswordc(*lp))
+                               return 0;
+                       break;
+               case REF:
+                       n = *ap++;
+                       bp = bopat[n];
+                       ep = eopat[n];
+                       while (bp < ep)
+                               if (*bp++ != *lp++)
+                                       return 0;
+                       break;
+               case CLO:
+                       are = lp;
+                       switch(*ap) {
+
+                       case ANY:
+                               while (*lp)
+                                       lp++;
+                               n = ANYSKIP;
+                               break;
+                       case CHR:
+                               c = *(ap+1);
+                               while (*lp && c == *lp)
+                                       lp++;
+                               n = CHRSKIP;
+                               break;
+                       case CCL:
+                               while ((c = *lp) && isinset(ap+1,c))
+                                       lp++;
+                               n = CCLSKIP;
+                               break;
+                       default:
+                               re_fail("closure: bad nfa.", *ap);
+                               return 0;
+                       }
+
+                       ap += n;
+
+                       while (lp >= are) {
+                               if (e = pmatch(lp, ap))
+                                       return e;
+                               --lp;
+                       }
+                       return 0;
+               default:
+                       re_fail("re_exec: bad nfa.", op);
+                       return 0;
+               }
+       return lp;
+}
+
+/*
+ * re_modw:
+ *     add new characters into the word table to change re_exec's
+ *     understanding of what a word should look like. Note that we
+ *     only accept additions into the word definition.
+ *
+ *     If the string parameter is 0 or null string, the table is
+ *     reset back to the default containing A-Z a-z 0-9 _. [We use
+ *     the compact bitset representation for the default table]
+ */
+
+static CHAR deftab[16] = {     
+       0, 0, 0, 0, 0, 0, 0377, 003, 0376, 0377, 0377, 0207,  
+       0376, 0377, 0377, 007 
+}; 
+
+void
+re_modw( char *s )
+{
+       register int i;
+
+       if (!s || !*s) {
+               for (i = 0; i < MAXCHR; i++)
+                       if (!isinset(deftab,i))
+                               iswordc(i) = 0;
+       }
+       else
+               while(*s)
+                       iswordc(*s++) = 1;
+}
+
+/*
+ * re_subs:
+ *     substitute the matched portions of the src in dst.
+ *
+ *     &       substitute the entire matched pattern.
+ *
+ *     \digit  substitute a subpattern, with the given tag number.
+ *             Tags are numbered from 1 to 9. If the particular
+ *             tagged subpattern does not exist, null is substituted.
+ */
+int
+re_subs( char *src, char *dst)
+{
+       register char c;
+       register int  pin;
+       register char *bp;
+       register char *ep;
+
+       if (!*src || !bopat[0])
+               return 0;
+
+       while (c = *src++) {
+               switch(c) {
+
+               case '&':
+                       pin = 0;
+                       break;
+
+               case '\\':
+                       c = *src++;
+                       if (c >= '0' && c <= '9') {
+                               pin = c - '0';
+                               break;
+                       }
+                       
+               default:
+                       *dst++ = c;
+                       continue;
+               }
+
+               if ((bp = bopat[pin]) && (ep = eopat[pin])) {
+                       while (*bp && bp < ep)
+                               *dst++ = *bp++;
+                       if (bp < ep)
+                               return 0;
+               }
+       }
+       *dst = (char) 0;
+       return 1;
+}
+                       
+#ifdef DEBUG
+/*
+ * symbolic - produce a symbolic dump of the nfa
+ */
+symbolic( char *s ) 
+{
+       printf("pattern: %s\n", s);
+       printf("nfacode:\n");
+       nfadump(nfa);
+}
+
+static 
+nfadump( CHAR *ap)
+{
+       register int n;
+
+       while (*ap != END)
+               switch(*ap++) {
+               case CLO:
+                       printf("CLOSURE");
+                       nfadump(ap);
+                       switch(*ap) {
+                       case CHR:
+                               n = CHRSKIP;
+                               break;
+                       case ANY:
+                               n = ANYSKIP;
+                               break;
+                       case CCL:
+                               n = CCLSKIP;
+                               break;
+                       }
+                       ap += n;
+                       break;
+               case CHR:
+                       printf("\tCHR %c\n",*ap++);
+                       break;
+               case ANY:
+                       printf("\tANY .\n");
+                       break;
+               case BOL:
+                       printf("\tBOL -\n");
+                       break;
+               case EOL:
+                       printf("\tEOL -\n");
+                       break;
+               case BOT:
+                       printf("BOT: %d\n",*ap++);
+                       break;
+               case EOT:
+                       printf("EOT: %d\n",*ap++);
+                       break;
+               case BOW:
+                       printf("BOW\n");
+                       break;
+               case EOW:
+                       printf("EOW\n");
+                       break;
+               case REF:
+                       printf("REF: %d\n",*ap++);
+                       break;
+               case CCL:
+                       printf("\tCCL [");
+                       for (n = 0; n < MAXCHR; n++)
+                               if (isinset(ap,(CHAR)n)) {
+                                       if (n < ' ')
+                                               printf("^%c", n ^ 0x040);
+                                       else
+                                               printf("%c", n);
+                               }
+                       printf("]\n");
+                       ap += BITBLK;
+                       break;
+               default:
+                       printf("bad nfa. opcode %o\n", ap[-1]);
+                       exit(1);
+                       break;
+               }
+}
+#endif
+#endif /* MACOS or DOS or NEED_BSDREGEX */
diff --git a/libraries/libldap/request.c b/libraries/libldap/request.c
new file mode 100644 (file)
index 0000000..b8b50ea
--- /dev/null
@@ -0,0 +1,965 @@
+/*
+ *  Copyright (c) 1995 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  request.c - sending of ldap requests; handling of referrals
+ */
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1995 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef MACOS
+#include <stdlib.h>
+#include <time.h>
+#include "macos.h"
+#else /* MACOS */
+#if defined( DOS ) || defined( _WIN32 )
+#include "msdos.h"
+#include <time.h>
+#include <stdlib.h>
+#ifdef PCNFS
+#include <tklib.h>
+#include <tk_errno.h>
+#include <bios.h>
+#endif /* PCNFS */
+#ifdef NCSA
+#include "externs.h"
+#endif /* NCSA */
+#else /* DOS */
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+#ifdef _AIX
+#include <sys/select.h>
+#endif /* _AIX */
+#include "portable.h"
+#endif /* DOS */
+#endif /* MACOS */
+#ifdef VMS
+#include "ucx_select.h"
+#endif
+#include "lber.h"
+#include "ldap.h"
+#include "ldap-int.h"
+
+#ifdef USE_SYSCONF
+#include <unistd.h>
+#endif /* USE_SYSCONF */
+
+
+#if defined( LDAP_REFERRALS ) || defined( LDAP_DNS )
+#ifdef NEEDPROTOS
+static LDAPConn *find_connection( LDAP *ld, LDAPServer *srv, int any );
+static void use_connection( LDAP *ld, LDAPConn *lc );
+static void free_servers( LDAPServer *srvlist );
+#else /* NEEDPROTOS */
+static LDAPConn *find_connection();
+static void use_connection();
+static void free_servers();
+#endif /* NEEDPROTOS */
+#endif /* LDAP_REFERRALS || LDAP_DNS */
+
+
+#ifdef LDAP_DNS
+#ifdef NEEDPROTOS
+static LDAPServer *dn2servers( LDAP *ld, char *dn );
+#else /* NEEDPROTOS */
+static LDAPServer *dn2servers();
+#endif /* NEEDPROTOS */
+#endif /* LDAP_DNS */
+
+#ifdef LDAP_REFERRALS
+#ifdef NEEDPROTOS
+static BerElement *re_encode_request( LDAP *ld, BerElement *origber,
+    int msgid, char **dnp );
+#else /* NEEDPROTOS */
+static BerElement *re_encode_request();
+#endif /* NEEDPROTOS */
+#endif /* LDAP_REFERRALS */
+
+
+BerElement *
+alloc_ber_with_options( LDAP *ld )
+{
+       BerElement      *ber;
+
+       if (( ber = ber_alloc_t( ld->ld_lberoptions )) == NULLBER ) {
+               ld->ld_errno = LDAP_NO_MEMORY;
+#ifdef STR_TRANSLATION
+       } else {
+               set_ber_options( ld, ber );
+#endif /* STR_TRANSLATION */
+       }
+
+       return( ber );
+}
+
+
+void
+set_ber_options( LDAP *ld, BerElement *ber )
+{
+       ber->ber_options = ld->ld_lberoptions;
+#ifdef STR_TRANSLATION
+       if (( ld->ld_lberoptions & LBER_TRANSLATE_STRINGS ) != 0 ) {
+               ber_set_string_translators( ber,
+                   ld->ld_lber_encode_translate_proc,
+                   ld->ld_lber_decode_translate_proc );
+       }
+#endif /* STR_TRANSLATION */
+}
+
+
+int
+send_initial_request( LDAP *ld, unsigned long msgtype, char *dn,
+       BerElement *ber )
+{
+#if defined( LDAP_REFERRALS ) || defined( LDAP_DNS )
+       LDAPServer      *servers;
+#endif /* LDAP_REFERRALS || LDAP_DNS */
+
+       Debug( LDAP_DEBUG_TRACE, "send_initial_request\n", 0, 0, 0 );
+
+#if !defined( LDAP_REFERRALS ) && !defined( LDAP_DNS )
+       if ( ber_flush( &ld->ld_sb, ber, 1 ) != 0 ) {
+               ld->ld_errno = LDAP_SERVER_DOWN;
+               return( -1 );
+       }
+
+       ld->ld_errno = LDAP_SUCCESS;
+       return( ld->ld_msgid );
+#else /* !LDAP_REFERRALS && !LDAP_DNS */
+
+#ifdef LDAP_DNS
+       if (( ld->ld_options & LDAP_OPT_DNS ) != 0 && ldap_is_dns_dn( dn )) {
+               if (( servers = dn2servers( ld, dn )) == NULL ) {
+                       ber_free( ber, 1 );
+                       return( -1 );
+               }
+
+#ifdef LDAP_DEBUG
+               if ( ldap_debug & LDAP_DEBUG_TRACE ) {
+                       LDAPServer      *srv;
+
+                       for ( srv = servers; srv != NULL;
+                           srv = srv->lsrv_next ) {
+                               fprintf( stderr,
+                                   "LDAP server %s:  dn %s, port %d\n",
+                                   srv->lsrv_host, ( srv->lsrv_dn == NULL ) ?
+                                   "(default)" : srv->lsrv_dn,
+                                   srv->lsrv_port );
+                       }
+               }
+#endif /* LDAP_DEBUG */
+       } else {
+#endif /* LDAP_DNS */
+               /*
+                * use of DNS is turned off or this is an X.500 DN...
+                * use our default connection
+                */
+               servers = NULL;
+#ifdef LDAP_DNS
+       }       
+#endif /* LDAP_DNS */
+
+       return( send_server_request( ld, ber, ld->ld_msgid, NULL, servers,
+           NULL, 0 ));
+#endif /* !LDAP_REFERRALS && !LDAP_DNS */
+}
+
+
+
+#if defined( LDAP_REFERRALS ) || defined( LDAP_DNS )
+int
+send_server_request( LDAP *ld, BerElement *ber, int msgid, LDAPRequest
+       *parentreq, LDAPServer *srvlist, LDAPConn *lc, int bind )
+{
+       LDAPRequest     *lr;
+
+       Debug( LDAP_DEBUG_TRACE, "send_server_request\n", 0, 0, 0 );
+
+       ld->ld_errno = LDAP_SUCCESS;    /* optimistic */
+
+       if ( lc == NULL ) {
+               if ( srvlist == NULL ) {
+                       lc = ld->ld_defconn;
+               } else {
+                       if (( lc = find_connection( ld, srvlist, 1 )) ==
+                           NULL ) {
+                               lc = new_connection( ld, &srvlist, 0, 1, bind );
+                       }
+                       free_servers( srvlist );
+               }
+       }
+
+       if ( lc == NULL || lc->lconn_status != LDAP_CONNST_CONNECTED ) {
+               ber_free( ber, 1 );
+               if ( ld->ld_errno == LDAP_SUCCESS ) {
+                       ld->ld_errno = LDAP_SERVER_DOWN;
+               }
+               return( -1 );
+       }
+
+       use_connection( ld, lc );
+       if (( lr = (LDAPRequest *)calloc( 1, sizeof( LDAPRequest ))) ==
+           NULL ) {
+               ld->ld_errno = LDAP_NO_MEMORY;
+               free_connection( ld, lc, 0, 0 );
+               ber_free( ber, 1 );
+               return( -1 );
+       } 
+       lr->lr_msgid = msgid;
+       lr->lr_status = LDAP_REQST_INPROGRESS;
+       lr->lr_res_errno = LDAP_SUCCESS;        /* optimistic */
+       lr->lr_ber = ber;
+       lr->lr_conn = lc;
+       if ( parentreq != NULL ) {      /* sub-request */
+               ++parentreq->lr_outrefcnt;
+               lr->lr_origid = parentreq->lr_origid;
+               lr->lr_parentcnt = parentreq->lr_parentcnt + 1;
+               lr->lr_parent = parentreq;
+               lr->lr_refnext = parentreq->lr_refnext;
+               parentreq->lr_refnext = lr;
+       } else {                        /* original request */
+               lr->lr_origid = lr->lr_msgid;
+       }
+
+       if (( lr->lr_next = ld->ld_requests ) != NULL ) {
+               lr->lr_next->lr_prev = lr;
+       }
+       ld->ld_requests = lr;
+       lr->lr_prev = NULL;
+
+       if ( ber_flush( lc->lconn_sb, ber, 0 ) != 0 ) {
+#ifdef notyet
+               extern int      errno;
+
+               if ( errno == EWOULDBLOCK ) {
+                       /* need to continue write later */
+                       lr->lr_status = LDAP_REQST_WRITING;
+                       mark_select_write( ld, lc->lconn_sb );
+               } else {
+#else /* notyet */
+                       ld->ld_errno = LDAP_SERVER_DOWN;
+                       free_request( ld, lr );
+                       free_connection( ld, lc, 0, 0 );
+                       return( -1 );
+#endif /* notyet */
+#ifdef notyet
+               }
+#endif /* notyet */
+       } else {
+               if ( parentreq == NULL ) {
+                       ber->ber_end = ber->ber_ptr;
+                       ber->ber_ptr = ber->ber_buf;
+               }
+
+               /* sent -- waiting for a response */
+               mark_select_read( ld, lc->lconn_sb );
+       }
+
+       ld->ld_errno = LDAP_SUCCESS;
+       return( msgid );
+}
+
+
+LDAPConn *
+new_connection( LDAP *ld, LDAPServer **srvlistp, int use_ldsb,
+       int connect, int bind )
+{
+       LDAPConn        *lc;
+       LDAPServer      *prevsrv, *srv;
+       Sockbuf         *sb;
+
+       /*
+        * make a new LDAP server connection
+        * XXX open connection synchronously for now
+        */
+       if (( lc = (LDAPConn *)calloc( 1, sizeof( LDAPConn ))) == NULL ||
+           ( !use_ldsb && ( sb = (Sockbuf *)calloc( 1, sizeof( Sockbuf )))
+           == NULL )) {
+               if ( lc != NULL ) {
+                       free( (char *)lc );
+               }
+               ld->ld_errno = LDAP_NO_MEMORY;
+               return( NULL );
+       }
+
+       lc->lconn_sb = ( use_ldsb ) ? &ld->ld_sb : sb;
+
+       if ( connect ) {
+               prevsrv = NULL;
+
+               for ( srv = *srvlistp; srv != NULL; srv = srv->lsrv_next ) {
+                       if ( open_ldap_connection( ld, lc->lconn_sb,
+                           srv->lsrv_host, srv->lsrv_port,
+                           &lc->lconn_krbinstance, 0 ) != -1 ) {
+                               break;
+                       }
+                       prevsrv = srv;
+               }
+
+               if ( srv == NULL ) {
+                   if ( !use_ldsb ) {
+                       free( (char *)lc->lconn_sb );
+                   }
+                   free( (char *)lc );
+                   ld->ld_errno = LDAP_SERVER_DOWN;
+                   return( NULL );
+               }
+
+               if ( prevsrv == NULL ) {
+                   *srvlistp = srv->lsrv_next;
+               } else {
+                   prevsrv->lsrv_next = srv->lsrv_next;
+               }
+               lc->lconn_server = srv;
+       }
+
+       lc->lconn_status = LDAP_CONNST_CONNECTED;
+       lc->lconn_next = ld->ld_conns;
+       ld->ld_conns = lc;
+
+       /*
+        * XXX for now, we always do a synchronous bind.  This will have
+        * to change in the long run...
+        */
+       if ( bind ) {
+               int             err, freepasswd, authmethod;
+               char            *binddn, *passwd;
+               LDAPConn        *savedefconn;
+
+               freepasswd = err = 0;
+
+               if ( ld->ld_rebindproc == NULL ) {
+                       binddn = passwd = "";
+                       authmethod = LDAP_AUTH_SIMPLE;
+               } else {
+                       if (( err = (*ld->ld_rebindproc)( ld, &binddn, &passwd,
+                           &authmethod, 0 )) == LDAP_SUCCESS ) {
+                               freepasswd = 1;
+                       } else {
+                               ld->ld_errno = err;
+                               err = -1;
+                       }
+               }
+
+
+               if ( err == 0 ) {
+                       savedefconn = ld->ld_defconn;
+                       ld->ld_defconn = lc;
+                       ++lc->lconn_refcnt;     /* avoid premature free */
+
+                       if ( ldap_bind_s( ld, binddn, passwd, authmethod ) !=
+                           LDAP_SUCCESS ) {
+                               err = -1;
+                       }
+                       --lc->lconn_refcnt;
+                       ld->ld_defconn = savedefconn;
+               }
+
+               if ( freepasswd ) {
+                       (*ld->ld_rebindproc)( ld, &binddn, &passwd,
+                               &authmethod, 1 );
+               }
+
+               if ( err != 0 ) {
+                       free_connection( ld, lc, 1, 0 );
+                       lc = NULL;
+               }
+       }
+
+       return( lc );
+}
+
+
+static LDAPConn *
+find_connection( LDAP *ld, LDAPServer *srv, int any )
+/*
+ * return an existing connection (if any) to the server srv
+ * if "any" is non-zero, check for any server in the "srv" chain
+ */
+{
+       LDAPConn        *lc;
+       LDAPServer      *ls;
+
+       for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
+               for ( ls = srv; ls != NULL; ls = ls->lsrv_next ) {
+                       if ( lc->lconn_server->lsrv_host != NULL &&
+                           ls->lsrv_host != NULL && strcasecmp(
+                           ls->lsrv_host, lc->lconn_server->lsrv_host ) == 0
+                           && ls->lsrv_port == lc->lconn_server->lsrv_port ) {
+                               return( lc );
+                       }
+                       if ( !any ) {
+                               break;
+                       }
+               }
+       }
+
+       return( NULL );
+}
+
+
+
+static void
+use_connection( LDAP *ld, LDAPConn *lc )
+{
+       ++lc->lconn_refcnt;
+       lc->lconn_lastused = time( 0 );
+}
+
+
+void
+free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind )
+{
+       LDAPConn        *tmplc, *prevlc;
+
+       Debug( LDAP_DEBUG_TRACE, "free_connection\n", 0, 0, 0 );
+
+       if ( force || --lc->lconn_refcnt <= 0 ) {
+               if ( lc->lconn_status == LDAP_CONNST_CONNECTED ) {
+                       mark_select_clear( ld, lc->lconn_sb );
+                       if ( unbind ) {
+                               send_unbind( ld, lc->lconn_sb );
+                       }
+                       close_connection( lc->lconn_sb );
+                       if ( lc->lconn_sb->sb_ber.ber_buf != NULL ) {
+                               free( lc->lconn_sb->sb_ber.ber_buf );
+                       }
+               }
+               prevlc = NULL;
+               for ( tmplc = ld->ld_conns; tmplc != NULL;
+                   tmplc = tmplc->lconn_next ) {
+                       if ( tmplc == lc ) {
+                               if ( prevlc == NULL ) {
+                                   ld->ld_conns = tmplc->lconn_next;
+                               } else {
+                                   prevlc->lconn_next = tmplc->lconn_next;
+                               }
+                               break;
+                       }
+               }
+               free_servers( lc->lconn_server );
+               if ( lc->lconn_krbinstance != NULL ) {
+                       free( lc->lconn_krbinstance );
+               }
+               if ( lc->lconn_sb != &ld->ld_sb ) {
+                       free( (char *)lc->lconn_sb );
+               }
+               free( lc );
+               Debug( LDAP_DEBUG_TRACE, "free_connection: actually freed\n",
+                   0, 0, 0 );
+       } else {
+               lc->lconn_lastused = time( 0 );
+               Debug( LDAP_DEBUG_TRACE, "free_connection: refcnt %d\n",
+                   lc->lconn_refcnt, 0, 0 );
+       }
+}
+
+
+#ifdef LDAP_DEBUG
+void
+dump_connection( LDAP *ld, LDAPConn *lconns, int all )
+{
+       LDAPConn        *lc;
+
+       fprintf( stderr, "** Connection%s:\n", all ? "s" : "" );
+       for ( lc = lconns; lc != NULL; lc = lc->lconn_next ) {
+               if ( lc->lconn_server != NULL ) {
+                       fprintf( stderr, "* host: %s  port: %d%s\n",
+                           ( lc->lconn_server->lsrv_host == NULL ) ? "(null)"
+                           : lc->lconn_server->lsrv_host,
+                           lc->lconn_server->lsrv_port, ( lc->lconn_sb ==
+                           &ld->ld_sb ) ? "  (default)" : "" );
+               }
+               fprintf( stderr, "  refcnt: %d  status: %s\n", lc->lconn_refcnt,
+                   ( lc->lconn_status == LDAP_CONNST_NEEDSOCKET ) ?
+                   "NeedSocket" : ( lc->lconn_status ==
+                   LDAP_CONNST_CONNECTING ) ? "Connecting" : "Connected" );
+               fprintf( stderr, "  last used: %s\n",
+                   ctime( &lc->lconn_lastused ));
+               if ( !all ) {
+                       break;
+               }
+       }
+}
+
+
+void
+dump_requests_and_responses( LDAP *ld )
+{
+       LDAPRequest     *lr;
+       LDAPMessage     *lm, *l;
+
+       fprintf( stderr, "** Outstanding Requests:\n" );
+       if (( lr = ld->ld_requests ) == NULL ) {
+               fprintf( stderr, "   Empty\n" );
+       }
+       for ( ; lr != NULL; lr = lr->lr_next ) {
+           fprintf( stderr, " * msgid %d,  origid %d, status %s\n",
+               lr->lr_msgid, lr->lr_origid, ( lr->lr_status ==
+               LDAP_REQST_INPROGRESS ) ? "InProgress" :
+               ( lr->lr_status == LDAP_REQST_CHASINGREFS ) ? "ChasingRefs" :
+               ( lr->lr_status == LDAP_REQST_NOTCONNECTED ) ? "NotConnected" :
+               "Writing" );
+           fprintf( stderr, "   outstanding referrals %d, parent count %d\n",
+                   lr->lr_outrefcnt, lr->lr_parentcnt );
+       }
+
+       fprintf( stderr, "** Response Queue:\n" );
+       if (( lm = ld->ld_responses ) == NULLMSG ) {
+               fprintf( stderr, "   Empty\n" );
+       }
+       for ( ; lm != NULLMSG; lm = lm->lm_next ) {
+               fprintf( stderr, " * msgid %d,  type %d\n",
+                   lm->lm_msgid, lm->lm_msgtype );
+               if (( l = lm->lm_chain ) != NULL ) {
+                       fprintf( stderr, "   chained responses:\n" );
+                       for ( ; l != NULLMSG; l = l->lm_chain ) {
+                               fprintf( stderr,
+                                   "  * msgid %d,  type %d\n",
+                                   l->lm_msgid, l->lm_msgtype );
+                       }
+               }
+       }
+}
+#endif /* LDAP_DEBUG */
+
+
+void
+free_request( LDAP *ld, LDAPRequest *lr )
+{
+       LDAPRequest     *tmplr, *nextlr;
+
+       Debug( LDAP_DEBUG_TRACE, "free_request (origid %d, msgid %d)\n",
+               lr->lr_origid, lr->lr_msgid, 0 );
+
+       if ( lr->lr_parent != NULL ) {
+               --lr->lr_parent->lr_outrefcnt;
+       } else {
+               /* free all referrals (child requests) */
+               for ( tmplr = lr->lr_refnext; tmplr != NULL; tmplr = nextlr ) {
+                       nextlr = tmplr->lr_refnext;
+                       free_request( ld, tmplr );
+               }
+       }
+
+       if ( lr->lr_prev == NULL ) {
+               ld->ld_requests = lr->lr_next;
+       } else {
+               lr->lr_prev->lr_next = lr->lr_next;
+       }
+
+       if ( lr->lr_next != NULL ) {
+               lr->lr_next->lr_prev = lr->lr_prev;
+       }
+
+       if ( lr->lr_ber != NULL ) {
+               ber_free( lr->lr_ber, 1 );
+       }
+
+       if ( lr->lr_res_error != NULL ) {
+               free( lr->lr_res_error );
+       }
+
+       if ( lr->lr_res_matched != NULL ) {
+               free( lr->lr_res_matched );
+       }
+
+       free( lr );
+}
+
+
+static void
+free_servers( LDAPServer *srvlist )
+{
+    LDAPServer *nextsrv;
+
+    while ( srvlist != NULL ) {
+       nextsrv = srvlist->lsrv_next;
+       if ( srvlist->lsrv_dn != NULL ) {
+               free( srvlist->lsrv_dn );
+       }
+       if ( srvlist->lsrv_host != NULL ) {
+               free( srvlist->lsrv_host );
+       }
+       free( srvlist );
+       srvlist = nextsrv;
+    }
+}
+#endif /* LDAP_REFERRALS || LDAP_DNS */
+
+
+#ifdef LDAP_REFERRALS
+/*
+ * XXX merging of errors in this routine needs to be improved
+ */
+int
+chase_referrals( LDAP *ld, LDAPRequest *lr, char **errstrp, int *hadrefp )
+{
+       int             rc, count, len, newdn;
+#ifdef LDAP_DNS
+       int             ldapref;
+#endif /* LDAP_DNS */
+       char            *p, *ports, *ref, *tmpref, *refdn, *unfollowed;
+       LDAPRequest     *origreq;
+       LDAPServer      *srv;
+       BerElement      *ber;
+
+       Debug( LDAP_DEBUG_TRACE, "chase_referrals\n", 0, 0, 0 );
+
+       ld->ld_errno = LDAP_SUCCESS;    /* optimistic */
+       *hadrefp = 0;
+
+       if ( *errstrp == NULL ) {
+               return( 0 );
+       }
+
+       len = strlen( *errstrp );
+       for ( p = *errstrp; len >= LDAP_REF_STR_LEN; ++p, --len ) {
+               if (( *p == 'R' || *p == 'r' ) && strncasecmp( p,
+                   LDAP_REF_STR, LDAP_REF_STR_LEN ) == 0 ) {
+                       *p = '\0';
+                       p += LDAP_REF_STR_LEN;
+                       break;
+               }
+       }
+
+       if ( len < LDAP_REF_STR_LEN ) {
+               return( 0 );
+       }
+
+       if ( lr->lr_parentcnt >= ld->ld_refhoplimit ) {
+               Debug( LDAP_DEBUG_ANY,
+                   "more than %d referral hops (dropping)\n",
+                   ld->ld_refhoplimit, 0, 0 );
+                   /* XXX report as error in ld->ld_errno? */
+                   return( 0 );
+       }
+
+       /* find original request */
+       for ( origreq = lr; origreq->lr_parent != NULL;
+            origreq = origreq->lr_parent ) {
+               ;
+       }
+
+       unfollowed = NULL;
+       rc = count = 0;
+
+       /* parse out & follow referrals */
+       for ( ref = p; rc == 0 && ref != NULL; ref = p ) {
+#ifdef LDAP_DNS
+               ldapref = 0;
+#endif /* LDAP_DNS */
+
+               if (( p = strchr( ref, '\n' )) != NULL ) {
+                       *p++ = '\0';
+               } else {
+                       p = NULL;
+               }
+
+               len = strlen( ref );
+               if ( len > LDAP_LDAP_REF_STR_LEN && strncasecmp( ref,
+                   LDAP_LDAP_REF_STR, LDAP_LDAP_REF_STR_LEN ) == 0 ) {
+                       Debug( LDAP_DEBUG_TRACE,
+                           "chasing LDAP referral: <%s>\n", ref, 0, 0 );
+#ifdef LDAP_DNS
+                       ldapref = 1;
+#endif /* LDAP_DNS */
+                       tmpref = ref + LDAP_LDAP_REF_STR_LEN;
+#ifdef LDAP_DNS
+               } else if ( len > LDAP_DX_REF_STR_LEN && strncasecmp( ref,
+                   LDAP_DX_REF_STR, LDAP_DX_REF_STR_LEN ) == 0 ) {
+                       Debug( LDAP_DEBUG_TRACE,
+                           "chasing DX referral: <%s>\n", ref, 0, 0 );
+                       tmpref = ref + LDAP_DX_REF_STR_LEN;
+#endif /* LDAP_DNS */
+               } else {
+                       Debug( LDAP_DEBUG_TRACE,
+                           "ignoring unknown referral <%s>\n", ref, 0, 0 );
+                       rc = append_referral( ld, &unfollowed, ref );
+                       *hadrefp = 1;
+                       continue;
+               }
+
+               *hadrefp = 1;
+               if (( refdn = strchr( tmpref, '/' )) != NULL ) {
+                       *refdn++ = '\0';
+                       newdn = 1;
+               } else {
+                       newdn = 0;
+               }
+
+               if (( ber = re_encode_request( ld, origreq->lr_ber,
+                   ++ld->ld_msgid, &refdn )) == NULL ) {
+                       return( -1 );
+               }
+
+#ifdef LDAP_DNS
+               if ( ldapref ) {
+#endif /* LDAP_DNS */
+                       if (( srv = (LDAPServer *)calloc( 1,
+                           sizeof( LDAPServer ))) == NULL ) {
+                               ber_free( ber, 1 );
+                               ld->ld_errno = LDAP_NO_MEMORY;
+                               return( -1 );
+                       }
+
+                       if (( srv->lsrv_host = strdup( tmpref )) == NULL ) {
+                               free( (char *)srv );
+                               ber_free( ber, 1 );
+                               ld->ld_errno = LDAP_NO_MEMORY;
+                               return( -1 );
+                       }
+
+                       if (( ports = strchr( srv->lsrv_host, ':' )) != NULL ) {
+                               *ports++ = '\0';
+                               srv->lsrv_port = atoi( ports );
+                       } else {
+                               srv->lsrv_port = LDAP_PORT;
+                       }
+#ifdef LDAP_DNS
+               } else {
+                       srv = dn2servers( ld, tmpref );
+               }
+#endif /* LDAP_DNS */
+
+               if ( srv != NULL && send_server_request( ld, ber, ld->ld_msgid,
+                   lr, srv, NULL, 1 ) >= 0 ) {
+                       ++count;
+               } else {
+                       Debug( LDAP_DEBUG_ANY,
+                           "Unable to chase referral (%s)\n", 
+                           ldap_err2string( ld->ld_errno ), 0, 0 );
+                       rc = append_referral( ld, &unfollowed, ref );
+               }
+
+               if ( !newdn && refdn != NULL ) {
+                       free( refdn );
+               }
+       }
+
+       free( *errstrp );
+       *errstrp = unfollowed;
+
+       return(( rc == 0 ) ? count : rc );
+}
+
+
+int
+append_referral( LDAP *ld, char **referralsp, char *s )
+{
+       int     first;
+
+       if ( *referralsp == NULL ) {
+               first = 1;
+               *referralsp = (char *)malloc( strlen( s ) + LDAP_REF_STR_LEN
+                   + 1 );
+       } else {
+               first = 0;
+               *referralsp = (char *)realloc( *referralsp,
+                   strlen( *referralsp ) + strlen( s ) + 2 );
+       }
+
+       if ( *referralsp == NULL ) {
+               ld->ld_errno = LDAP_NO_MEMORY;
+               return( -1 );
+       }
+
+       if ( first ) {
+               strcpy( *referralsp, LDAP_REF_STR );
+       } else {
+               strcat( *referralsp, "\n" );
+       }
+       strcat( *referralsp, s );
+
+       return( 0 );
+}
+
+
+
+static BerElement *
+re_encode_request( LDAP *ld, BerElement *origber, int msgid, char **dnp )
+{
+/*
+ * XXX this routine knows way too much about how the lber library works!
+ */
+       unsigned long   along, tag;
+       long            ver;
+       int             rc;
+       BerElement      tmpber, *ber;
+       char            *orig_dn;
+
+       Debug( LDAP_DEBUG_TRACE,
+           "re_encode_request: new msgid %d, new dn <%s>\n",
+           msgid, ( *dnp == NULL ) ? "NONE" : *dnp, 0 );
+
+       tmpber = *origber;
+
+       /*
+        * all LDAP requests are sequences that start with a message id,
+        * followed by a sequence that is tagged with the operation code
+        */
+       if ( ber_scanf( &tmpber, "{i", &along ) != LDAP_TAG_MSGID ||
+           ( tag = ber_skip_tag( &tmpber, &along )) == LBER_DEFAULT ) {
+                ld->ld_errno = LDAP_DECODING_ERROR;
+               return( NULL );
+       }
+
+        if (( ber = alloc_ber_with_options( ld )) == NULLBER ) {
+                return( NULL );
+        }
+
+       /* bind requests have a version number before the DN & other stuff */
+       if ( tag == LDAP_REQ_BIND && ber_get_int( &tmpber, (long *)&ver ) ==
+           LBER_DEFAULT ) {
+                ld->ld_errno = LDAP_DECODING_ERROR;
+               ber_free( ber, 1 );
+               return( NULL );
+       }
+
+       /* the rest of the request is the DN followed by other stuff */
+       if ( ber_get_stringa( &tmpber, &orig_dn ) == LBER_DEFAULT ) {
+               ber_free( ber, 1 );
+               return( NULL );
+       }
+
+       if ( *dnp == NULL ) {
+               *dnp = orig_dn;
+       } else {
+               free( orig_dn );
+       }
+
+       if ( tag == LDAP_REQ_BIND ) {
+               rc = ber_printf( ber, "{it{is", msgid, tag, ver, *dnp );
+       } else {
+               rc = ber_printf( ber, "{it{s", msgid, tag, *dnp );
+       }
+
+       if ( rc == -1 ) {
+               ber_free( ber, 1 );
+               return( NULL );
+       }
+
+       if ( ber_write( ber, tmpber.ber_ptr, ( tmpber.ber_end -
+           tmpber.ber_ptr ), 0 ) != ( tmpber.ber_end - tmpber.ber_ptr ) ||
+           ber_printf( ber, "}}" ) == -1 ) {
+               ld->ld_errno = LDAP_ENCODING_ERROR;
+               ber_free( ber, 1 );
+               return( NULL );
+       }
+
+#ifdef LDAP_DEBUG
+       if ( ldap_debug & LDAP_DEBUG_PACKETS ) {
+               Debug( LDAP_DEBUG_ANY, "re_encode_request new request is:\n",
+                   0, 0, 0 );
+               ber_dump( ber, 0 );
+       }
+#endif /* LDAP_DEBUG */
+
+       return( ber );
+}
+
+
+LDAPRequest *
+find_request_by_msgid( LDAP *ld, int msgid )
+{
+       LDAPRequest     *lr;
+
+       for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) {
+               if ( msgid == lr->lr_msgid ) {
+                       break;
+               }
+       }
+
+       return( lr );
+}
+#endif /* LDAP_REFERRALS */
+
+
+#ifdef LDAP_DNS
+static LDAPServer *
+dn2servers( LDAP *ld, char *dn )       /* dn can also be a domain.... */
+{
+       char            *p, *domain, *host, *server_dn, **dxs;
+       int             i, port;
+       LDAPServer      *srvlist, *prevsrv, *srv;
+
+       if (( domain = strrchr( dn, '@' )) != NULL ) {
+               ++domain;
+       } else {
+               domain = dn;
+       }
+
+       if (( dxs = getdxbyname( domain )) == NULL ) {
+               ld->ld_errno = LDAP_NO_MEMORY;
+               return( NULL );
+       }
+
+       srvlist = NULL;
+
+       for ( i = 0; dxs[ i ] != NULL; ++i ) {
+               port = LDAP_PORT;
+               server_dn = NULL;
+               if ( strchr( dxs[ i ], ':' ) == NULL ) {
+                       host = dxs[ i ];
+               } else if ( strlen( dxs[ i ] ) >= 7 &&
+                   strncmp( dxs[ i ], "ldap://", 7 ) == 0 ) {
+                       host = dxs[ i ] + 7;
+                       if (( p = strchr( host, ':' )) == NULL ) {
+                               p = host;
+                       } else {
+                               *p++ = '\0';
+                               port = atoi( p );
+                       }
+                       if (( p = strchr( p, '/' )) != NULL ) {
+                               server_dn = ++p;
+                               if ( *server_dn == '\0' ) {
+                                       server_dn = NULL;
+                               }
+                       }
+               } else {
+                       host = NULL;
+               }
+
+               if ( host != NULL ) {   /* found a server we can use */
+                       if (( srv = (LDAPServer *)calloc( 1,
+                           sizeof( LDAPServer ))) == NULL ) {
+                               free_servers( srvlist );
+                               srvlist = NULL;
+                               break;          /* exit loop & return */
+                       }
+
+                       /* add to end of list of servers */
+                       if ( srvlist == NULL ) {
+                               srvlist = srv;
+                       } else {
+                               prevsrv->lsrv_next = srv;
+                       }
+                       prevsrv = srv;
+                       
+                       /* copy in info. */
+                       if (( srv->lsrv_host = strdup( host )) == NULL ||
+                           ( server_dn != NULL && ( srv->lsrv_dn =
+                           strdup( server_dn )) == NULL )) {
+                               free_servers( srvlist );
+                               srvlist = NULL;
+                               break;          /* exit loop & return */
+                       }
+                       srv->lsrv_port = port;
+               }
+       }
+
+       ldap_value_free( dxs );
+
+       if ( srvlist == NULL ) {
+               ld->ld_errno = LDAP_SERVER_DOWN;
+       }
+
+       return( srvlist );
+}
+#endif /* LDAP_DNS */
diff --git a/libraries/libldap/result.c b/libraries/libldap/result.c
new file mode 100644 (file)
index 0000000..3f8408d
--- /dev/null
@@ -0,0 +1,836 @@
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  result.c - wait for an ldap result
+ */
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef MACOS
+#include <stdlib.h>
+#include <time.h>
+#include "macos.h"
+#else /* MACOS */
+#if defined( DOS ) || defined( _WIN32 )
+#include <time.h>
+#include "msdos.h"
+#ifdef PCNFS
+#include <tklib.h>
+#include <tk_errno.h>
+#include <bios.h>
+#endif /* PCNFS */
+#ifdef NCSA
+#include "externs.h"
+#endif /* NCSA */
+#else /* DOS */
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#ifdef _AIX
+#include <sys/select.h>
+#endif /* _AIX */
+#include "portable.h"
+#endif /* DOS */
+#endif /* MACOS */
+#ifdef VMS
+#include "ucx_select.h"
+#endif
+#include "lber.h"
+#include "ldap.h"
+#include "ldap-int.h"
+
+#ifdef USE_SYSCONF
+#include <unistd.h>
+#endif /* USE_SYSCONF */
+
+#ifdef NEEDPROTOS
+static int ldap_abandoned( LDAP *ld, int msgid );
+static int ldap_mark_abandoned( LDAP *ld, int msgid );
+static int wait4msg( LDAP *ld, int msgid, int all, struct timeval *timeout,
+       LDAPMessage **result );
+#ifdef LDAP_REFERRALS
+static int read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb, LDAPConn *lc,
+       LDAPMessage **result );
+static int build_result_ber( LDAP *ld, BerElement *ber, LDAPRequest *lr );
+static void merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr );
+#else /* LDAP_REFERRALS */
+static int read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb,
+       LDAPMessage **result );
+#endif /* LDAP_REFERRALS */
+#if defined( CLDAP ) || !defined( LDAP_REFERRALS )
+static int ldap_select1( LDAP *ld, struct timeval *timeout );
+#endif
+#else /* NEEDPROTOS */
+static int ldap_abandoned();
+static int ldap_mark_abandoned();
+static int wait4msg();
+static int read1msg();
+#ifdef LDAP_REFERRALS
+static int build_result_ber();
+static void merge_error_info();
+#endif /* LDAP_REFERRALS */
+#if defined( CLDAP ) || !defined( LDAP_REFERRALS )
+static int ldap_select1();
+#endif
+#endif /* NEEDPROTOS */
+
+#if !defined( MACOS ) && !defined( DOS )
+extern int     errno;
+#endif
+
+
+/*
+ * ldap_result - wait for an ldap result response to a message from the
+ * ldap server.  If msgid is -1, any message will be accepted, otherwise
+ * ldap_result will wait for a response with msgid.  If all is 0 the
+ * first message with id msgid will be accepted, otherwise, ldap_result
+ * will wait for all responses with id msgid and then return a pointer to
+ * the entire list of messages.  This is only useful for search responses,
+ * which can be of two message types (zero or more entries, followed by an
+ * ldap result).  The type of the first message received is returned.
+ * When waiting, any messages that have been abandoned are discarded.
+ *
+ * Example:
+ *     ldap_result( s, msgid, all, timeout, result )
+ */
+int
+ldap_result( LDAP *ld, int msgid, int all, struct timeval *timeout,
+       LDAPMessage **result )
+{
+       LDAPMessage     *lm, *lastlm, *nextlm;
+
+       /*
+        * First, look through the list of responses we have received on
+        * this association and see if the response we're interested in
+        * is there.  If it is, return it.  If not, call wait4msg() to
+        * wait until it arrives or timeout occurs.
+        */
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_result\n", 0, 0, 0 );
+
+       *result = NULLMSG;
+       lastlm = NULLMSG;
+       for ( lm = ld->ld_responses; lm != NULLMSG; lm = nextlm ) {
+               nextlm = lm->lm_next;
+
+               if ( ldap_abandoned( ld, lm->lm_msgid ) ) {
+                       ldap_mark_abandoned( ld, lm->lm_msgid );
+
+                       if ( lastlm == NULLMSG ) {
+                               ld->ld_responses = lm->lm_next;
+                       } else {
+                               lastlm->lm_next = nextlm;
+                       }
+
+                       ldap_msgfree( lm );
+
+                       continue;
+               }
+
+               if ( msgid == LDAP_RES_ANY || lm->lm_msgid == msgid ) {
+                       LDAPMessage     *tmp;
+
+                       if ( all == 0
+                           || (lm->lm_msgtype != LDAP_RES_SEARCH_RESULT
+                           && lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY) )
+                               break;
+
+                       for ( tmp = lm; tmp != NULLMSG; tmp = tmp->lm_chain ) {
+                               if ( tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT )
+                                       break;
+                       }
+
+                       if ( tmp == NULLMSG ) {
+                               return( wait4msg( ld, msgid, all, timeout,
+                                   result ) );
+                       }
+
+                       break;
+               }
+               lastlm = lm;
+       }
+       if ( lm == NULLMSG ) {
+               return( wait4msg( ld, msgid, all, timeout, result ) );
+       }
+
+       if ( lastlm == NULLMSG ) {
+               ld->ld_responses = (all == 0 && lm->lm_chain != NULLMSG
+                   ? lm->lm_chain : lm->lm_next);
+       } else {
+               lastlm->lm_next = (all == 0 && lm->lm_chain != NULLMSG
+                   ? lm->lm_chain : lm->lm_next);
+       }
+       if ( all == 0 )
+               lm->lm_chain = NULLMSG;
+       lm->lm_next = NULLMSG;
+
+       *result = lm;
+       ld->ld_errno = LDAP_SUCCESS;
+       return( lm->lm_msgtype );
+}
+
+static int
+wait4msg( LDAP *ld, int msgid, int all, struct timeval *timeout,
+       LDAPMessage **result )
+{
+       int             rc;
+       struct timeval  tv, *tvp;
+       long            start_time, tmp_time;
+#ifdef LDAP_REFERRALS
+       LDAPConn        *lc, *nextlc;
+#endif /* LDAP_REFERRALS */
+
+#ifdef LDAP_DEBUG
+       if ( timeout == NULL ) {
+               Debug( LDAP_DEBUG_TRACE, "wait4msg (infinite timeout)\n",
+                   0, 0, 0 );
+       } else {
+               Debug( LDAP_DEBUG_TRACE, "wait4msg (timeout %ld sec, %ld usec)\n",
+                   timeout->tv_sec, timeout->tv_usec, 0 );
+       }
+#endif /* LDAP_DEBUG */
+
+       if ( timeout == NULL ) {
+               tvp = NULL;
+       } else {
+               tv = *timeout;
+               tvp = &tv;
+               start_time = (long)time( NULL );
+       }
+                   
+       rc = -2;
+       while ( rc == -2 ) {
+#ifndef LDAP_REFERRALS
+               /* hack attack */
+               if ( ld->ld_sb.sb_ber.ber_ptr >= ld->ld_sb.sb_ber.ber_end ) {
+                       rc = ldap_select1( ld, tvp );
+
+#if !defined( MACOS ) && !defined( DOS )
+                       if ( rc == 0 || ( rc == -1 && (( ld->ld_options &
+                           LDAP_OPT_RESTART ) == 0 || errno != EINTR ))) {
+#else
+                       if ( rc == -1 || rc == 0 ) {
+#endif
+                               ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN :
+                                   LDAP_TIMEOUT);
+                               return( rc );
+                       }
+
+               }
+               if ( rc == -1 ) {
+                       rc = -2;        /* select interrupted: loop */
+               } else {
+                       rc = read1msg( ld, msgid, all, &ld->ld_sb, result );
+               }
+#else /* !LDAP_REFERRALS */
+#ifdef LDAP_DEBUG
+               if ( ldap_debug & LDAP_DEBUG_TRACE ) {
+                       dump_connection( ld, ld->ld_conns, 1 );
+                       dump_requests_and_responses( ld );
+               }
+#endif /* LDAP_DEBUG */
+               for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
+                       if ( lc->lconn_sb->sb_ber.ber_ptr <
+                           lc->lconn_sb->sb_ber.ber_end ) {
+                               rc = read1msg( ld, msgid, all, lc->lconn_sb,
+                                   lc, result );
+                               break;
+                       }
+               }
+
+               if ( lc == NULL ) {
+                       rc = do_ldap_select( ld, tvp );
+
+
+#if defined( LDAP_DEBUG ) && !defined( MACOS ) && !defined( DOS )
+                       if ( rc == -1 ) {
+                           Debug( LDAP_DEBUG_TRACE,
+                                   "do_ldap_select returned -1: errno %d\n",
+                                   errno, 0, 0 );
+                       }
+#endif
+
+#if !defined( MACOS ) && !defined( DOS )
+                       if ( rc == 0 || ( rc == -1 && (( ld->ld_options &
+                           LDAP_OPT_RESTART ) == 0 || errno != EINTR ))) {
+#else
+                       if ( rc == -1 || rc == 0 ) {
+#endif
+                               ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN :
+                                   LDAP_TIMEOUT);
+                               return( rc );
+                       }
+
+                       if ( rc == -1 ) {
+                               rc = -2;        /* select interrupted: loop */
+                       } else {
+                               rc = -2;
+                               for ( lc = ld->ld_conns; rc == -2 && lc != NULL;
+                                   lc = nextlc ) {
+                                       nextlc = lc->lconn_next;
+                                       if ( lc->lconn_status ==
+                                           LDAP_CONNST_CONNECTED &&
+                                           is_read_ready( ld,
+                                           lc->lconn_sb )) {
+                                               rc = read1msg( ld, msgid, all,
+                                                   lc->lconn_sb, lc, result );
+                                       }
+                               }
+                       }
+               }
+#endif /* !LDAP_REFERRALS */
+
+               if ( rc == -2 && tvp != NULL ) {
+                       tmp_time = (long)time( NULL );
+                       if (( tv.tv_sec -=  ( tmp_time - start_time )) <= 0 ) {
+                               rc = 0; /* timed out */
+                               ld->ld_errno = LDAP_TIMEOUT;
+                               break;
+                       }
+
+                       Debug( LDAP_DEBUG_TRACE, "wait4msg:  %ld secs to go\n",
+                               tv.tv_sec, 0, 0 );
+                       start_time = tmp_time;
+               }
+       }
+
+       return( rc );
+}
+
+
+static int
+read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb,
+#ifdef LDAP_REFERRALS
+    LDAPConn *lc,
+#endif /* LDAP_REFERRALS */
+    LDAPMessage **result )
+{
+       BerElement      ber;
+       LDAPMessage     *new, *l, *prev, *tmp;
+       long            id;
+       unsigned long   tag, len;
+       int             foundit = 0;
+#ifdef LDAP_REFERRALS
+       LDAPRequest     *lr;
+       BerElement      tmpber;
+       int             rc, refer_cnt, hadref, simple_request;
+       unsigned long   lderr;
+#endif /* LDAP_REFERRALS */
+
+       Debug( LDAP_DEBUG_TRACE, "read1msg\n", 0, 0, 0 );
+
+       ber_init( &ber, 0 );
+       set_ber_options( ld, &ber );
+
+       /* get the next message */
+       if ( (tag = ber_get_next( sb, &len, &ber ))
+           != LDAP_TAG_MESSAGE ) {
+               ld->ld_errno = (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN :
+                   LDAP_LOCAL_ERROR);
+               return( -1 );
+       }
+
+       /* message id */
+       if ( ber_get_int( &ber, &id ) == LBER_ERROR ) {
+               ld->ld_errno = LDAP_DECODING_ERROR;
+               return( -1 );
+       }
+
+       /* if it's been abandoned, toss it */
+       if ( ldap_abandoned( ld, (int)id ) ) {
+               free( ber.ber_buf );    /* gack! */
+               return( -2 );   /* continue looking */
+       }
+
+#ifdef LDAP_REFERRALS
+       if (( lr = find_request_by_msgid( ld, id )) == NULL ) {
+               Debug( LDAP_DEBUG_ANY,
+                   "no request for response with msgid %ld (tossing)\n",
+                   id, 0, 0 );
+               free( ber.ber_buf );    /* gack! */
+               return( -2 );   /* continue looking */
+       }
+       Debug( LDAP_DEBUG_TRACE, "got %s msgid %ld, original id %d\n",
+           ( tag == LDAP_RES_SEARCH_ENTRY ) ? "entry" : "result", id,
+           lr->lr_origid );
+       id = lr->lr_origid;
+#endif /* LDAP_REFERRALS */
+
+       /* the message type */
+       if ( (tag = ber_peek_tag( &ber, &len )) == LBER_ERROR ) {
+               ld->ld_errno = LDAP_DECODING_ERROR;
+               return( -1 );
+       }
+
+#ifdef LDAP_REFERRALS
+       refer_cnt = 0;
+       hadref = simple_request = 0;
+       rc = -2;        /* default is to keep looking (no response found) */
+       lr->lr_res_msgtype = tag;
+
+       if ( tag != LDAP_RES_SEARCH_ENTRY ) {
+               if ( ld->ld_version >= LDAP_VERSION2 &&
+                           ( lr->lr_parent != NULL ||
+                           ( ld->ld_options & LDAP_OPT_REFERRALS ) != 0 )) {
+                       tmpber = ber;   /* struct copy */
+                       if ( ber_scanf( &tmpber, "{iaa}", &lderr,
+                           &lr->lr_res_matched, &lr->lr_res_error )
+                           != LBER_ERROR ) {
+                               if ( lderr != LDAP_SUCCESS ) {
+                                       /* referrals are in error string */
+                                       refer_cnt = chase_referrals( ld, lr,
+                                           &lr->lr_res_error, &hadref );
+                               }
+
+                               /* save errno, message, and matched string */
+                               if ( !hadref || lr->lr_res_error == NULL ) {
+                                       lr->lr_res_errno = ( lderr ==
+                                       LDAP_PARTIAL_RESULTS ) ? LDAP_SUCCESS
+                                       : lderr;
+                               } else if ( ld->ld_errno != LDAP_SUCCESS ) {
+                                       lr->lr_res_errno = ld->ld_errno;
+                               } else {
+                                       lr->lr_res_errno = LDAP_PARTIAL_RESULTS;
+                               }
+Debug( LDAP_DEBUG_TRACE,
+    "new result:  res_errno: %d, res_error: <%s>, res_matched: <%s>\n",
+    lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "",
+    lr->lr_res_matched ? lr->lr_res_matched : "" );
+                       }
+               }
+
+               Debug( LDAP_DEBUG_TRACE,
+                   "read1msg:  %d new referrals\n", refer_cnt, 0, 0 );
+
+               if ( refer_cnt != 0 ) { /* chasing referrals */
+                       free( ber.ber_buf );    /* gack! */
+                       ber.ber_buf = NULL;
+                       if ( refer_cnt < 0 ) {
+                               return( -1 );   /* fatal error */
+                       }
+                       lr->lr_status = LDAP_REQST_CHASINGREFS;
+               } else {
+                       if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL ) {
+                               /* request without any referrals */
+                               simple_request = ( hadref ? 0 : 1 );
+                       } else {
+                               /* request with referrals or child request */
+                               free( ber.ber_buf );    /* gack! */
+                               ber.ber_buf = NULL;
+                       }
+
+                       while ( lr->lr_parent != NULL ) {
+                               merge_error_info( ld, lr->lr_parent, lr );
+
+                               lr = lr->lr_parent;
+                               if ( --lr->lr_outrefcnt > 0 ) {
+                                       break;  /* not completely done yet */
+                               }
+                       }
+
+                       if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL ) {
+                               id = lr->lr_msgid;
+                               tag = lr->lr_res_msgtype;
+                               Debug( LDAP_DEBUG_ANY, "request %ld done\n",
+                                   id, 0, 0 );
+Debug( LDAP_DEBUG_TRACE,
+"res_errno: %d, res_error: <%s>, res_matched: <%s>\n",
+lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "",
+lr->lr_res_matched ? lr->lr_res_matched : "" );
+                               if ( !simple_request ) {
+                                       if ( ber.ber_buf != NULL ) {
+                                               free( ber.ber_buf ); /* gack! */
+                                               ber.ber_buf = NULL;
+                                       }
+                                       if ( build_result_ber( ld, &ber, lr )
+                                           == LBER_ERROR ) {
+                                               ld->ld_errno = LDAP_NO_MEMORY;
+                                               rc = -1; /* fatal error */
+                                       }
+                               }
+
+                               free_request( ld, lr );
+                       }
+
+                       if ( lc != NULL ) {
+                               free_connection( ld, lc, 0, 1 );
+                       }
+               }
+       }
+
+       if ( ber.ber_buf == NULL ) {
+               return( rc );
+       }
+
+#endif /* LDAP_REFERRALS */
+       /* make a new ldap message */
+       if ( (new = (LDAPMessage *) calloc( 1, sizeof(LDAPMessage) ))
+           == NULL ) {
+               ld->ld_errno = LDAP_NO_MEMORY;
+               return( -1 );
+       }
+       new->lm_msgid = (int)id;
+       new->lm_msgtype = tag;
+       new->lm_ber = ber_dup( &ber );
+
+#ifndef NO_CACHE
+               if ( ld->ld_cache != NULL ) {
+                       add_result_to_cache( ld, new );
+               }
+#endif /* NO_CACHE */
+
+       /* is this the one we're looking for? */
+       if ( msgid == LDAP_RES_ANY || id == msgid ) {
+               if ( all == 0
+                   || (new->lm_msgtype != LDAP_RES_SEARCH_RESULT
+                   && new->lm_msgtype != LDAP_RES_SEARCH_ENTRY) ) {
+                       *result = new;
+                       ld->ld_errno = LDAP_SUCCESS;
+                       return( tag );
+               } else if ( new->lm_msgtype == LDAP_RES_SEARCH_RESULT) {
+                       foundit = 1;    /* return the chain later */
+               }
+       }
+
+       /* 
+        * if not, we must add it to the list of responses.  if
+        * the msgid is already there, it must be part of an existing
+        * search response.
+        */
+
+       prev = NULLMSG;
+       for ( l = ld->ld_responses; l != NULLMSG; l = l->lm_next ) {
+               if ( l->lm_msgid == new->lm_msgid )
+                       break;
+               prev = l;
+       }
+
+       /* not part of an existing search response */
+       if ( l == NULLMSG ) {
+               if ( foundit ) {
+                       *result = new;
+                       ld->ld_errno = LDAP_SUCCESS;
+                       return( tag );
+               }
+
+               new->lm_next = ld->ld_responses;
+               ld->ld_responses = new;
+               return( -2 );   /* continue looking */
+       }
+
+       Debug( LDAP_DEBUG_TRACE, "adding response id %d type %d:\n",
+           new->lm_msgid, new->lm_msgtype, 0 );
+
+       /* part of a search response - add to end of list of entries */
+       for ( tmp = l; tmp->lm_chain != NULLMSG &&
+           tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_ENTRY;
+           tmp = tmp->lm_chain )
+               ;       /* NULL */
+       tmp->lm_chain = new;
+
+       /* return the whole chain if that's what we were looking for */
+       if ( foundit ) {
+               if ( prev == NULLMSG )
+                       ld->ld_responses = l->lm_next;
+               else
+                       prev->lm_next = l->lm_next;
+               *result = l;
+               ld->ld_errno = LDAP_SUCCESS;
+               return( tag );
+       }
+
+       return( -2 );   /* continue looking */
+}
+
+
+#ifdef LDAP_REFERRALS
+static int
+build_result_ber( LDAP *ld, BerElement *ber, LDAPRequest *lr )
+{
+       unsigned long   len;
+       long            along;
+
+       ber_init( ber, 0 );
+       set_ber_options( ld, ber );
+       if ( ber_printf( ber, "{it{ess}}", lr->lr_msgid,
+           (long)lr->lr_res_msgtype, lr->lr_res_errno,
+           lr->lr_res_matched ? lr->lr_res_matched : "",
+           lr->lr_res_error ? lr->lr_res_error : "" ) == LBER_ERROR ) {
+               return( LBER_ERROR );
+       }
+
+       ber_reset( ber, 1 );
+       if ( ber_skip_tag( ber, &len ) == LBER_ERROR ) {
+               return( LBER_ERROR );
+       }
+
+       if ( ber_get_int( ber, &along ) == LBER_ERROR ) {
+               return( LBER_ERROR );
+       }
+
+       return( ber_peek_tag( ber, &len ));
+}
+
+
+static void
+merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr )
+{
+/*
+ * Merge error information in "lr" with "parentr" error code and string.
+ */
+       if ( lr->lr_res_errno == LDAP_PARTIAL_RESULTS ) {
+               parentr->lr_res_errno = lr->lr_res_errno;
+               if ( lr->lr_res_error != NULL ) {
+                       (void)append_referral( ld, &parentr->lr_res_error,
+                           lr->lr_res_error );
+               }
+       } else if ( lr->lr_res_errno != LDAP_SUCCESS &&
+           parentr->lr_res_errno == LDAP_SUCCESS ) {
+               parentr->lr_res_errno = lr->lr_res_errno;
+               if ( parentr->lr_res_error != NULL ) {
+                       free( parentr->lr_res_error );
+               }
+               parentr->lr_res_error = lr->lr_res_error;
+               lr->lr_res_error = NULL;
+               if ( NAME_ERROR( lr->lr_res_errno )) {
+                       if ( parentr->lr_res_matched != NULL ) {
+                               free( parentr->lr_res_matched );
+                       }
+                       parentr->lr_res_matched = lr->lr_res_matched;
+                       lr->lr_res_matched = NULL;
+               }
+       }
+
+       Debug( LDAP_DEBUG_TRACE, "merged parent (id %d) error info:  ",
+           parentr->lr_msgid, 0, 0 );
+       Debug( LDAP_DEBUG_TRACE, "result errno %d, error <%s>, matched <%s>\n",
+           parentr->lr_res_errno, parentr->lr_res_error ?
+           parentr->lr_res_error : "", parentr->lr_res_matched ?
+           parentr->lr_res_matched : "" );
+}
+#endif /* LDAP_REFERRALS */
+
+
+
+#if defined( CLDAP ) || !defined( LDAP_REFERRALS )
+#if !defined( MACOS ) && !defined( DOS ) && !defined( _WIN32 )
+static int
+ldap_select1( LDAP *ld, struct timeval *timeout )
+{
+       fd_set          readfds;
+       static int      tblsize;
+
+       if ( tblsize == 0 ) {
+#ifdef USE_SYSCONF
+               tblsize = sysconf( _SC_OPEN_MAX );
+#else /* USE_SYSCONF */
+               tblsize = getdtablesize();
+#endif /* USE_SYSCONF */
+       }
+
+       FD_ZERO( &readfds );
+       FD_SET( ld->ld_sb.sb_sd, &readfds );
+
+       return( select( tblsize, &readfds, 0, 0, timeout ) );
+}
+#endif /* !MACOS */
+
+
+#ifdef MACOS
+static int
+ldap_select1( LDAP *ld, struct timeval *timeout )
+{
+       return( tcpselect( ld->ld_sb.sb_sd, timeout ));
+}
+#endif /* MACOS */
+
+
+#if ( defined( DOS ) && defined( WINSOCK )) || defined( _WIN32 )
+static int
+ldap_select1( LDAP *ld, struct timeval *timeout )
+{
+    fd_set          readfds;
+    int             rc;
+
+    FD_ZERO( &readfds );
+    FD_SET( ld->ld_sb.sb_sd, &readfds );
+
+    rc = select( 1, &readfds, 0, 0, timeout );
+    return( rc == SOCKET_ERROR ? -1 : rc );
+}
+#endif /* WINSOCK || _WIN32 */
+
+
+#ifdef DOS
+#ifdef PCNFS
+static int
+ldap_select1( LDAP *ld, struct timeval *timeout )
+{
+       fd_set  readfds;
+       int     res;
+
+       FD_ZERO( &readfds );
+       FD_SET( ld->ld_sb.sb_sd, &readfds );
+
+       res = select( FD_SETSIZE, &readfds, NULL, NULL, timeout );
+       if ( res == -1 && errno == EINTR) {
+               /* We've been CTRL-C'ed at this point.  It'd be nice to
+                  carry on but PC-NFS currently won't let us! */
+               printf("\n*** CTRL-C ***\n");
+               exit(-1);
+       }
+       return( res );
+}
+#endif /* PCNFS */
+
+#ifdef NCSA
+static int
+ldap_select1( LDAP *ld, struct timeval *timeout )
+{
+       int rc;
+       clock_t endtime;
+
+       if ( timeout != NULL ) {
+               endtime = timeout->tv_sec * CLK_TCK +
+                       timeout->tv_usec * CLK_TCK / 1000000 + clock();
+       }
+
+       do {
+               Stask();
+               rc = netqlen( ld->ld_sb.sb_sd );
+       } while ( rc <= 0 && ( timeout == NULL || clock() < endtime ));
+
+       return( rc > 0 ? 1 : 0 );
+}
+#endif /* NCSA */
+#endif /* DOS */
+#endif /* !LDAP_REFERRALS */
+
+
+int
+ldap_msgfree( LDAPMessage *lm )
+{
+       LDAPMessage     *next;
+       int             type = 0;
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_msgfree\n", 0, 0, 0 );
+
+       for ( ; lm != NULLMSG; lm = next ) {
+               next = lm->lm_chain;
+               type = lm->lm_msgtype;
+               ber_free( lm->lm_ber, 1 );
+               free( (char *) lm );
+       }
+
+       return( type );
+}
+
+/*
+ * ldap_msgdelete - delete a message.  It returns:
+ *     0       if the entire message was deleted
+ *     -1      if the message was not found, or only part of it was found
+ */
+int
+ldap_msgdelete( LDAP *ld, int msgid )
+{
+       LDAPMessage     *lm, *prev;
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_msgdelete\n", 0, 0, 0 );
+
+       prev = NULLMSG;
+       for ( lm = ld->ld_responses; lm != NULLMSG; lm = lm->lm_next ) {
+               if ( lm->lm_msgid == msgid )
+                       break;
+               prev = lm;
+       }
+
+       if ( lm == NULLMSG )
+               return( -1 );
+
+       if ( prev == NULLMSG )
+               ld->ld_responses = lm->lm_next;
+       else
+               prev->lm_next = lm->lm_next;
+
+       if ( ldap_msgfree( lm ) == LDAP_RES_SEARCH_ENTRY )
+               return( -1 );
+
+       return( 0 );
+}
+
+
+/*
+ * return 1 if message msgid is waiting to be abandoned, 0 otherwise
+ */
+static int
+ldap_abandoned( LDAP *ld, int msgid )
+{
+       int     i;
+
+       if ( ld->ld_abandoned == NULL )
+               return( 0 );
+
+       for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
+               if ( ld->ld_abandoned[i] == msgid )
+                       return( 1 );
+
+       return( 0 );
+}
+
+
+static int
+ldap_mark_abandoned( LDAP *ld, int msgid )
+{
+       int     i;
+
+       if ( ld->ld_abandoned == NULL )
+               return( -1 );
+
+       for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
+               if ( ld->ld_abandoned[i] == msgid )
+                       break;
+
+       if ( ld->ld_abandoned[i] == -1 )
+               return( -1 );
+
+       for ( ; ld->ld_abandoned[i] != -1; i++ ) {
+               ld->ld_abandoned[i] = ld->ld_abandoned[i + 1];
+       }
+
+       return( 0 );
+}
+
+
+#ifdef CLDAP
+int
+cldap_getmsg( LDAP *ld, struct timeval *timeout, BerElement *ber )
+{
+       int             rc;
+       unsigned long   tag, len;
+
+       if ( ld->ld_sb.sb_ber.ber_ptr >= ld->ld_sb.sb_ber.ber_end ) {
+               rc = ldap_select1( ld, timeout );
+               if ( rc == -1 || rc == 0 ) {
+                       ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN :
+                           LDAP_TIMEOUT);
+                       return( rc );
+               }
+       }
+
+       /* get the next message */
+       if ( (tag = ber_get_next( &ld->ld_sb, &len, ber ))
+           != LDAP_TAG_MESSAGE ) {
+               ld->ld_errno = (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN :
+                   LDAP_LOCAL_ERROR);
+               return( -1 );
+       }
+
+       return( tag );
+}
+#endif /* CLDAP */
diff --git a/libraries/libldap/sbind.c b/libraries/libldap/sbind.c
new file mode 100644 (file)
index 0000000..656c722
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ *  Copyright (c) 1993 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  sbind.c
+ */
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1993 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef MACOS
+#include "macos.h"
+#endif /* MACOS */
+
+#if !defined( MACOS ) && !defined( DOS )
+#include <sys/types.h>
+#include <sys/socket.h>
+#endif
+
+#include "lber.h"
+#include "ldap.h"
+#include "ldap-int.h"
+
+
+/*
+ * ldap_simple_bind - bind to the ldap server (and X.500).  The dn and
+ * password of the entry to which to bind are supplied.  The message id
+ * of the request initiated is returned.
+ *
+ * Example:
+ *     ldap_simple_bind( ld, "cn=manager, o=university of michigan, c=us",
+ *         "secret" )
+ */
+
+int
+ldap_simple_bind( LDAP *ld, char *dn, char *passwd )
+{
+       BerElement      *ber;
+
+       /*
+        * The bind request looks like this:
+        *      BindRequest ::= SEQUENCE {
+        *              version         INTEGER,
+        *              name            DistinguishedName,       -- who
+        *              authentication  CHOICE {
+        *                      simple          [0] OCTET STRING -- passwd
+        *              }
+        *      }
+        * all wrapped up in an LDAPMessage sequence.
+        */
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_simple_bind\n", 0, 0, 0 );
+
+       if ( dn == NULL )
+               dn = "";
+       if ( passwd == NULL )
+               passwd = "";
+
+       /* create a message to send */
+       if ( (ber = alloc_ber_with_options( ld )) == NULLBER ) {
+               return( -1 );
+       }
+
+       /* fill it in */
+       if ( ber_printf( ber, "{it{ists}}", ++ld->ld_msgid, LDAP_REQ_BIND,
+           ld->ld_version, dn, LDAP_AUTH_SIMPLE, passwd ) == -1 ) {
+               ld->ld_errno = LDAP_ENCODING_ERROR;
+               ber_free( ber, 1 );
+               return( -1 );
+       }
+
+#ifndef NO_CACHE
+       if ( ld->ld_cache != NULL ) {
+               ldap_flush_cache( ld );
+       }
+#endif /* !NO_CACHE */
+
+       /* send the message */
+       return( send_initial_request( ld, LDAP_REQ_BIND, dn, ber ));
+}
+
+/*
+ * ldap_simple_bind - bind to the ldap server (and X.500) using simple
+ * authentication.  The dn and password of the entry to which to bind are
+ * supplied.  LDAP_SUCCESS is returned upon success, the ldap error code
+ * otherwise.
+ *
+ * Example:
+ *     ldap_simple_bind_s( ld, "cn=manager, o=university of michigan, c=us",
+ *         "secret" )
+ */
+
+int
+ldap_simple_bind_s( LDAP *ld, char *dn, char *passwd )
+{
+       int             msgid;
+       LDAPMessage     *result;
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_simple_bind_s\n", 0, 0, 0 );
+
+       if ( (msgid = ldap_simple_bind( ld, dn, passwd )) == -1 )
+               return( ld->ld_errno );
+
+       if ( ldap_result( ld, msgid, 1, (struct timeval *) 0, &result ) == -1 )
+               return( ld->ld_errno ); /* ldap_result sets ld_errno */
+
+       return( ldap_result2error( ld, result, 1 ) );
+}
diff --git a/libraries/libldap/search.c b/libraries/libldap/search.c
new file mode 100644 (file)
index 0000000..2b73ddd
--- /dev/null
@@ -0,0 +1,571 @@
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  search.c
+ */
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef MACOS
+#include <stdlib.h>
+#include "macos.h"
+#endif /* MACOS */
+
+#if defined( DOS ) || defined( _WIN32 )
+#include "msdos.h"
+#endif /* DOS */
+
+#if !defined(MACOS) && !defined(DOS) && !defined( _WIN32 )
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#endif
+#include "lber.h"
+#include "ldap.h"
+#include "ldap-int.h"
+
+#ifdef NEEDPROTOS
+static char *find_right_paren( char *s );
+static char *put_complex_filter( BerElement *ber, char *str,
+       unsigned long tag, int not );
+static int put_filter( BerElement *ber, char *str );
+static int put_simple_filter( BerElement *ber, char *str );
+static int put_substring_filter( BerElement *ber, char *type, char *str );
+static int put_filter_list( BerElement *ber, char *str );
+#else
+static char *find_right_paren();
+static char *put_complex_filter();
+static int put_filter();
+static int put_simple_filter();
+static int put_substring_filter();
+static int put_filter_list();
+#endif /* NEEDPROTOS */
+
+/*
+ * ldap_search - initiate an ldap (and X.500) search operation.  Parameters:
+ *
+ *     ld              LDAP descriptor
+ *     base            DN of the base object
+ *     scope           the search scope - one of LDAP_SCOPE_BASE,
+ *                         LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBTREE
+ *     filter          a string containing the search filter
+ *                     (e.g., "(|(cn=bob)(sn=bob))")
+ *     attrs           list of attribute types to return for matches
+ *     attrsonly       1 => attributes only 0 => attributes and values
+ *
+ * Example:
+ *     char    *attrs[] = { "mail", "title", 0 };
+ *     msgid = ldap_search( ld, "c=us@o=UM", LDAP_SCOPE_SUBTREE, "cn~=bob",
+ *         attrs, attrsonly );
+ */
+int
+ldap_search( LDAP *ld, char *base, int scope, char *filter,
+       char **attrs, int attrsonly )
+{
+       BerElement      *ber;
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_search\n", 0, 0, 0 );
+
+       if (( ber = ldap_build_search_req( ld, base, scope, filter, attrs,
+           attrsonly )) == NULLBER ) {
+               return( -1 );
+       }
+
+#ifndef NO_CACHE
+       if ( ld->ld_cache != NULL ) {
+               if ( check_cache( ld, LDAP_REQ_SEARCH, ber ) == 0 ) {
+                       ber_free( ber, 1 );
+                       ld->ld_errno = LDAP_SUCCESS;
+                       return( ld->ld_msgid );
+               }
+               add_request_to_cache( ld, LDAP_REQ_SEARCH, ber );
+       }
+#endif /* NO_CACHE */
+
+       /* send the message */
+       return ( send_initial_request( ld, LDAP_REQ_SEARCH, base, ber ));
+}
+
+
+BerElement *
+ldap_build_search_req( LDAP *ld, char *base, int scope, char *filter,
+       char **attrs, int attrsonly )
+{
+       BerElement      *ber;
+       int             err;
+
+       /*
+        * Create the search request.  It looks like this:
+        *      SearchRequest := [APPLICATION 3] SEQUENCE {
+        *              baseObject      DistinguishedName,
+        *              scope           ENUMERATED {
+        *                      baseObject      (0),
+        *                      singleLevel     (1),
+        *                      wholeSubtree    (2)
+        *              },
+        *              derefAliases    ENUMERATED {
+        *                      neverDerefaliases       (0),
+        *                      derefInSearching        (1),
+        *                      derefFindingBaseObj     (2),
+        *                      alwaysDerefAliases      (3)
+        *              },
+        *              sizelimit       INTEGER (0 .. 65535),
+        *              timelimit       INTEGER (0 .. 65535),
+        *              attrsOnly       BOOLEAN,
+        *              filter          Filter,
+        *              attributes      SEQUENCE OF AttributeType
+        *      }
+        * wrapped in an ldap message.
+        */
+
+       /* create a message to send */
+       if ( (ber = alloc_ber_with_options( ld )) == NULLBER ) {
+               return( NULLBER );
+       }
+
+       if ( base == NULL ) {
+           base = "";
+       }
+
+#ifdef CLDAP
+       if ( ld->ld_sb.sb_naddr > 0 ) {
+           err = ber_printf( ber, "{ist{seeiib", ++ld->ld_msgid,
+               ld->ld_cldapdn, LDAP_REQ_SEARCH, base, scope, ld->ld_deref,
+               ld->ld_sizelimit, ld->ld_timelimit, attrsonly );
+       } else {
+#endif /* CLDAP */
+               err = ber_printf( ber, "{it{seeiib", ++ld->ld_msgid,
+                   LDAP_REQ_SEARCH, base, scope, ld->ld_deref,
+                   ld->ld_sizelimit, ld->ld_timelimit, attrsonly );
+#ifdef CLDAP
+       }
+#endif /* CLDAP */
+
+       if ( err == -1 ) {
+               ld->ld_errno = LDAP_ENCODING_ERROR;
+               ber_free( ber, 1 );
+               return( NULLBER );
+       }
+
+       filter = strdup( filter );
+       err = put_filter( ber, filter );
+       free( filter );
+
+       if ( err  == -1 ) {
+               ld->ld_errno = LDAP_FILTER_ERROR;
+               ber_free( ber, 1 );
+               return( NULLBER );
+       }
+
+       if ( ber_printf( ber, "{v}}}", attrs ) == -1 ) {
+               ld->ld_errno = LDAP_ENCODING_ERROR;
+               ber_free( ber, 1 );
+               return( NULLBER );
+       }
+
+       return( ber );
+}
+
+static char *
+find_right_paren( char *s )
+{
+       int     balance, escape;
+
+       balance = 1;
+       escape = 0;
+       while ( *s && balance ) {
+               if ( escape == 0 ) {
+                       if ( *s == '(' )
+                               balance++;
+                       else if ( *s == ')' )
+                               balance--;
+               }
+               if ( *s == '\\' && ! escape )
+                       escape = 1;
+               else
+                       escape = 0;
+               if ( balance )
+                       s++;
+       }
+
+       return( *s ? s : NULL );
+}
+
+static char *
+put_complex_filter( BerElement *ber, char *str, unsigned long tag, int not )
+{
+       char    *next;
+
+       /*
+        * We have (x(filter)...) with str sitting on
+        * the x.  We have to find the paren matching
+        * the one before the x and put the intervening
+        * filters by calling put_filter_list().
+        */
+
+       /* put explicit tag */
+       if ( ber_printf( ber, "t{", tag ) == -1 )
+               return( NULL );
+/*
+       if ( !not && ber_printf( ber, "{" ) == -1 )
+               return( NULL );
+*/
+
+       str++;
+       if ( (next = find_right_paren( str )) == NULL )
+               return( NULL );
+
+       *next = '\0';
+       if ( put_filter_list( ber, str ) == -1 )
+               return( NULL );
+       *next++ = ')';
+
+       /* flush explicit tagged thang */
+       if ( ber_printf( ber, "}" ) == -1 )
+               return( NULL );
+/*
+       if ( !not && ber_printf( ber, "}" ) == -1 )
+               return( NULL );
+*/
+
+       return( next );
+}
+
+static int
+put_filter( BerElement *ber, char *str )
+{
+       char    *next, *tmp, *s, *d;
+       int     parens, balance, escape, gotescape;
+
+       /*
+        * A Filter looks like this:
+        *      Filter ::= CHOICE {
+        *              and             [0]     SET OF Filter,
+        *              or              [1]     SET OF Filter,
+        *              not             [2]     Filter,
+        *              equalityMatch   [3]     AttributeValueAssertion,
+        *              substrings      [4]     SubstringFilter,
+        *              greaterOrEqual  [5]     AttributeValueAssertion,
+        *              lessOrEqual     [6]     AttributeValueAssertion,
+        *              present         [7]     AttributeType,,
+        *              approxMatch     [8]     AttributeValueAssertion
+        *      }
+        *
+        *      SubstringFilter ::= SEQUENCE {
+        *              type               AttributeType,
+        *              SEQUENCE OF CHOICE {
+        *                      initial          [0] IA5String,
+        *                      any              [1] IA5String,
+        *                      final            [2] IA5String
+        *              }
+        *      }
+        * Note: tags in a choice are always explicit
+        */
+
+       Debug( LDAP_DEBUG_TRACE, "put_filter \"%s\"\n", str, 0, 0 );
+
+       gotescape = parens = 0;
+       while ( *str ) {
+               switch ( *str ) {
+               case '(':
+                       str++;
+                       parens++;
+                       switch ( *str ) {
+                       case '&':
+                               Debug( LDAP_DEBUG_TRACE, "put_filter: AND\n",
+                                   0, 0, 0 );
+
+                               if ( (str = put_complex_filter( ber, str,
+                                   LDAP_FILTER_AND, 0 )) == NULL )
+                                       return( -1 );
+
+                               parens--;
+                               break;
+
+                       case '|':
+                               Debug( LDAP_DEBUG_TRACE, "put_filter: OR\n",
+                                   0, 0, 0 );
+
+                               if ( (str = put_complex_filter( ber, str,
+                                   LDAP_FILTER_OR, 0 )) == NULL )
+                                       return( -1 );
+
+                               parens--;
+                               break;
+
+                       case '!':
+                               Debug( LDAP_DEBUG_TRACE, "put_filter: NOT\n",
+                                   0, 0, 0 );
+
+                               if ( (str = put_complex_filter( ber, str,
+                                   LDAP_FILTER_NOT, 1 )) == NULL )
+                                       return( -1 );
+
+                               parens--;
+                               break;
+
+                       default:
+                               Debug( LDAP_DEBUG_TRACE, "put_filter: simple\n",
+                                   0, 0, 0 );
+
+                               balance = 1;
+                               escape = 0;
+                               next = str;
+                               while ( *next && balance ) {
+                                       if ( escape == 0 ) {
+                                               if ( *next == '(' )
+                                                       balance++;
+                                               else if ( *next == ')' )
+                                                       balance--;
+                                       }
+                                       if ( *next == '\\' && ! escape )
+                                               gotescape = escape = 1;
+                                       else
+                                               escape = 0;
+                                       if ( balance )
+                                               next++;
+                               }
+                               if ( balance != 0 )
+                                       return( -1 );
+
+                               *next = '\0';
+                               tmp = strdup( str );
+                               if ( gotescape ) {
+                                       escape = 0;
+                                       for ( s = d = tmp; *s; s++ ) {
+                                               if ( *s != '\\' || escape ) {
+                                                       *d++ = *s;
+                                                       escape = 0;
+                                               } else {
+                                                       escape = 1;
+                                               }
+                                       }
+                                       *d = '\0';
+                               }
+                               if ( put_simple_filter( ber, tmp ) == -1 ) {
+                                       free( tmp );
+                                       return( -1 );
+                               }
+                               free( tmp );
+                               *next++ = ')';
+                               str = next;
+                               parens--;
+                               break;
+                       }
+                       break;
+
+               case ')':
+                       Debug( LDAP_DEBUG_TRACE, "put_filter: end\n", 0, 0,
+                           0 );
+                       if ( ber_printf( ber, "]" ) == -1 )
+                               return( -1 );
+                       str++;
+                       parens--;
+                       break;
+
+               case ' ':
+                       str++;
+                       break;
+
+               default:        /* assume it's a simple type=value filter */
+                       Debug( LDAP_DEBUG_TRACE, "put_filter: default\n", 0, 0,
+                           0 );
+                       next = strchr( str, '\0' );
+                       tmp = strdup( str );
+                       if ( strchr( tmp, '\\' ) != NULL ) {
+                               escape = 0;
+                               for ( s = d = tmp; *s; s++ ) {
+                                       if ( *s != '\\' || escape ) {
+                                               *d++ = *s;
+                                               escape = 0;
+                                       } else {
+                                               escape = 1;
+                                       }
+                               }
+                               *d = '\0';
+                       }
+                       if ( put_simple_filter( ber, tmp ) == -1 ) {
+                               free( tmp );
+                               return( -1 );
+                       }
+                       free( tmp );
+                       str = next;
+                       break;
+               }
+       }
+
+       return( parens ? -1 : 0 );
+}
+
+/*
+ * Put a list of filters like this "(filter1)(filter2)..."
+ */
+
+static int
+put_filter_list( BerElement *ber, char *str )
+{
+       char    *next;
+       char    save;
+
+       Debug( LDAP_DEBUG_TRACE, "put_filter_list \"%s\"\n", str, 0, 0 );
+
+       while ( *str ) {
+               while ( *str && isspace( *str ) )
+                       str++;
+               if ( *str == '\0' )
+                       break;
+
+               if ( (next = find_right_paren( str + 1 )) == NULL )
+                       return( -1 );
+               save = *++next;
+
+               /* now we have "(filter)" with str pointing to it */
+               *next = '\0';
+               if ( put_filter( ber, str ) == -1 )
+                       return( -1 );
+               *next = save;
+
+               str = next;
+       }
+
+       return( 0 );
+}
+
+static int
+put_simple_filter( BerElement *ber, char *str )
+{
+       char            *s;
+       char            *value, savechar;
+       unsigned long   ftype;
+       int             rc;
+
+       Debug( LDAP_DEBUG_TRACE, "put_simple_filter \"%s\"\n", str, 0, 0 );
+
+       if ( (s = strchr( str, '=' )) == NULL )
+               return( -1 );
+       value = s + 1;
+       *s-- = '\0';
+       savechar = *s;
+
+       switch ( *s ) {
+       case '<':
+               ftype = LDAP_FILTER_LE;
+               *s = '\0';
+               break;
+       case '>':
+               ftype = LDAP_FILTER_GE;
+               *s = '\0';
+               break;
+       case '~':
+               ftype = LDAP_FILTER_APPROX;
+               *s = '\0';
+               break;
+       default:
+               if ( strchr( value, '*' ) == NULL ) {
+                       ftype = LDAP_FILTER_EQUALITY;
+               } else if ( strcmp( value, "*" ) == 0 ) {
+                       ftype = LDAP_FILTER_PRESENT;
+               } else {
+                       rc = put_substring_filter( ber, str, value );
+                       *(value-1) = '=';
+                       return( rc );
+               }
+               break;
+       }
+
+       if ( ftype == LDAP_FILTER_PRESENT ) {
+               rc = ber_printf( ber, "ts", ftype, str );
+       } else {
+               rc = ber_printf( ber, "t{ss}", ftype, str, value );
+       }
+
+       *s = savechar;
+       *(value-1) = '=';
+       return( rc == -1 ? rc : 0 );
+}
+
+static int
+put_substring_filter( BerElement *ber, char *type, char *val )
+{
+       char            *nextstar, gotstar = 0;
+       unsigned long   ftype;
+
+       Debug( LDAP_DEBUG_TRACE, "put_substring_filter \"%s=%s\"\n", type,
+           val, 0 );
+
+       if ( ber_printf( ber, "t{s{", LDAP_FILTER_SUBSTRINGS, type ) == -1 )
+               return( -1 );
+
+       while ( val != NULL ) {
+               if ( (nextstar = strchr( val, '*' )) != NULL )
+                       *nextstar++ = '\0';
+
+               if ( gotstar == 0 ) {
+                       ftype = LDAP_SUBSTRING_INITIAL;
+               } else if ( nextstar == NULL ) {
+                       ftype = LDAP_SUBSTRING_FINAL;
+               } else {
+                       ftype = LDAP_SUBSTRING_ANY;
+               }
+               if ( *val != '\0' ) {
+                       if ( ber_printf( ber, "ts", ftype, val ) == -1 )
+                               return( -1 );
+               }
+
+               gotstar = 1;
+               if ( nextstar != NULL )
+                       *(nextstar-1) = '*';
+               val = nextstar;
+       }
+
+       if ( ber_printf( ber, "}}" ) == -1 )
+               return( -1 );
+
+       return( 0 );
+}
+
+int
+ldap_search_st( LDAP *ld, char *base, int scope, char *filter, char **attrs,
+       int attrsonly, struct timeval *timeout, LDAPMessage **res )
+{
+       int     msgid;
+
+       if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
+           == -1 )
+               return( ld->ld_errno );
+
+       if ( ldap_result( ld, msgid, 1, timeout, res ) == -1 )
+               return( ld->ld_errno );
+
+       if ( ld->ld_errno == LDAP_TIMEOUT ) {
+               (void) ldap_abandon( ld, msgid );
+               ld->ld_errno = LDAP_TIMEOUT;
+               return( ld->ld_errno );
+       }
+
+       return( ldap_result2error( ld, *res, 0 ) );
+}
+
+int
+ldap_search_s( LDAP *ld, char *base, int scope, char *filter, char **attrs,
+       int attrsonly, LDAPMessage **res )
+{
+       int     msgid;
+
+       if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
+           == -1 )
+               return( ld->ld_errno );
+
+       if ( ldap_result( ld, msgid, 1, (struct timeval *) NULL, res ) == -1 )
+               return( ld->ld_errno );
+
+       return( ldap_result2error( ld, *res, 0 ) );
+}
+
diff --git a/libraries/libldap/sort.c b/libraries/libldap/sort.c
new file mode 100644 (file)
index 0000000..ee5d549
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ *
+ * sort.c:  LDAP library entry and value sort routines
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#ifdef MACOS
+#include "macos.h"
+#else /* MACOS */
+#ifdef DOS
+#include <malloc.h>
+#include "msdos.h"
+#endif /* DOS */
+#endif /* MACOS */
+
+#include "lber.h"
+#include "ldap.h"
+
+struct entrything {
+       char            **et_vals;
+       LDAPMessage     *et_msg;
+};
+
+#ifndef NEEDPROTOS
+static int     (*et_cmp_fn)();
+static int     et_cmp();
+#else /* !NEEDPROTOS */
+static int     (*et_cmp_fn)( char *a, char *b );
+static int     et_cmp( void *aa, void *bb);
+#endif /* !NEEDPROTOS */
+
+int
+ldap_sort_strcasecmp(
+    char       **a,
+    char       **b
+)
+{
+       return( strcasecmp( *a, *b ) );
+}
+
+static int
+et_cmp(
+       void    *aa,
+       void    *bb
+)
+{
+       int                     i, rc;
+       struct entrything       *a = (struct entrything *)aa;
+       struct entrything       *b = (struct entrything *)bb;
+
+       if ( a->et_vals == NULL && b->et_vals == NULL )
+               return( 0 );
+       if ( a->et_vals == NULL )
+               return( -1 );
+       if ( b->et_vals == NULL )
+               return( 1 );
+
+       for ( i = 0; a->et_vals[i] && b->et_vals[i]; i++ ) {
+               if ( (rc = (*et_cmp_fn)( a->et_vals[i], b->et_vals[i] ))
+                   != 0 ) {
+                       return( rc );
+               }
+       }
+
+       if ( a->et_vals[i] == NULL && b->et_vals[i] == NULL )
+               return( 0 );
+       if ( a->et_vals[i] == NULL )
+               return( -1 );
+       return( 1 );
+}
+
+int
+ldap_sort_entries(
+    LDAP       *ld,
+    LDAPMessage        **chain,
+    char       *attr,          /* NULL => sort by DN */
+    int                (*cmp)()
+)
+{
+       int                     i, count;
+       struct entrything       *et;
+       LDAPMessage             *e, *last;
+       LDAPMessage             **ep;
+
+       count = ldap_count_entries( ld, *chain );
+
+       if ( (et = (struct entrything *) malloc( count *
+           sizeof(struct entrything) )) == NULL ) {
+               ld->ld_errno = LDAP_NO_MEMORY;
+               return( -1 );
+       }
+
+       e = *chain;
+       for ( i = 0; i < count; i++ ) {
+               et[i].et_msg = e;
+               if ( attr == NULL ) {
+                       char    *dn;
+
+                       dn = ldap_get_dn( ld, e );
+                       et[i].et_vals = ldap_explode_dn( dn, 1 );
+                       free( dn );
+               } else {
+                       et[i].et_vals = ldap_get_values( ld, e, attr );
+               }
+
+               e = e->lm_chain;
+       }
+       last = e;
+
+       et_cmp_fn = cmp;
+       qsort( et, count, sizeof(struct entrything), (void *) et_cmp );
+
+       ep = chain;
+       for ( i = 0; i < count; i++ ) {
+               *ep = et[i].et_msg;
+               ep = &(*ep)->lm_chain;
+
+               ldap_value_free( et[i].et_vals );
+       }
+       *ep = last;
+       free( (char *) et );
+
+       return( 0 );
+}
+
+int
+ldap_sort_values(
+    LDAP       *ld,
+    char       **vals,
+    int                (*cmp)()
+)
+{
+       int     nel;
+
+       for ( nel = 0; vals[nel] != NULL; nel++ )
+               ;       /* NULL */
+
+       qsort( vals, nel, sizeof(char *), cmp );
+
+       return( 0 );
+}
diff --git a/libraries/libldap/srchpref.c b/libraries/libldap/srchpref.c
new file mode 100644 (file)
index 0000000..88c094c
--- /dev/null
@@ -0,0 +1,421 @@
+/*
+ * Copyright (c) 1993, 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ *
+ * searchpref.c:  search preferences library routines for LDAP clients
+ * 17 May 1994 by Gordon Good
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#ifdef MACOS
+#include "macos.h"
+#else /* MACOS */
+#ifdef DOS
+#include <malloc.h>
+#include "msdos.h"
+#else /* DOS */
+#include <sys/types.h>
+#include <sys/file.h>
+#ifndef VMS
+#include <unistd.h>
+#endif /* VMS */
+#endif /* DOS */
+#endif /* MACOS */
+
+#include "lber.h"
+#include "ldap.h"
+#include "srchpref.h"
+
+#ifndef NEEDPROTOS
+int next_line_tokens();
+void free_strarray();
+static void free_searchobj();
+static int read_next_searchobj();
+#else /* !NEEDPROTOS */
+int next_line_tokens( char **bufp, long *blenp, char ***toksp );
+void free_strarray( char **sap );
+static void free_searchobj( struct ldap_searchobj *so );
+static int read_next_searchobj( char **bufp, long *blenp,
+       struct ldap_searchobj **sop, int soversion );
+#endif /* !NEEDPROTOS */
+
+
+static char            *sobjoptions[] = {
+    "internal",
+    NULL
+};
+
+
+static unsigned long   sobjoptvals[] = {
+    LDAP_SEARCHOBJ_OPT_INTERNAL,
+};
+
+
+int
+ldap_init_searchprefs( char *file, struct ldap_searchobj **solistp )
+{
+    FILE       *fp;
+    char       *buf;
+    long       rlen, len;
+    int                rc, eof;
+
+    if (( fp = fopen( file, "r" )) == NULL ) {
+       return( LDAP_SEARCHPREF_ERR_FILE );
+    }
+
+    if ( fseek( fp, 0L, SEEK_END ) != 0 ) {    /* move to end to get len */
+       fclose( fp );
+       return( LDAP_SEARCHPREF_ERR_FILE );
+    }
+
+    len = ftell( fp );
+
+    if ( fseek( fp, 0L, SEEK_SET ) != 0 ) {    /* back to start of file */
+       fclose( fp );
+       return( LDAP_SEARCHPREF_ERR_FILE );
+    }
+
+    if (( buf = malloc( (size_t)len )) == NULL ) {
+       fclose( fp );
+       return( LDAP_SEARCHPREF_ERR_MEM );
+    }
+
+    rlen = fread( buf, 1, (size_t)len, fp );
+    eof = feof( fp );
+    fclose( fp );
+
+    if ( rlen != len && !eof ) {       /* error:  didn't get the whole file */
+       free( buf );
+       return( LDAP_SEARCHPREF_ERR_FILE );
+    }
+
+    rc = ldap_init_searchprefs_buf( buf, rlen, solistp );
+    free( buf );
+
+    return( rc );
+}
+
+
+int
+ldap_init_searchprefs_buf( char *buf, long buflen,
+       struct ldap_searchobj **solistp )
+{
+    int                                rc, version;
+    char                       **toks;
+    struct ldap_searchobj      *prevso, *so;
+
+    *solistp = prevso = NULLSEARCHOBJ;
+
+    if ( next_line_tokens( &buf, &buflen, &toks ) != 2 ||
+           strcasecmp( toks[ 0 ], "version" ) != 0 ) {
+       free_strarray( toks );
+       return( LDAP_SEARCHPREF_ERR_SYNTAX );
+    }
+    version = atoi( toks[ 1 ] );
+    free_strarray( toks );
+    if ( version != LDAP_SEARCHPREF_VERSION &&
+           version != LDAP_SEARCHPREF_VERSION_ZERO ) {
+       return( LDAP_SEARCHPREF_ERR_VERSION );
+    }
+
+    while ( buflen > 0 && ( rc = read_next_searchobj( &buf, &buflen, &so,
+           version )) == 0 && so != NULLSEARCHOBJ ) {
+       if ( prevso == NULLSEARCHOBJ ) {
+           *solistp = so;
+       } else {
+           prevso->so_next = so;
+       }
+       prevso = so;
+    }
+
+    if ( rc != 0 ) {
+       ldap_free_searchprefs( *solistp );
+    }
+
+    return( rc );
+}
+           
+
+
+void
+ldap_free_searchprefs( struct ldap_searchobj *solist )
+{
+    struct ldap_searchobj      *so, *nextso;
+
+    if ( solist != NULL ) {
+       for ( so = solist; so != NULL; so = nextso ) {
+           nextso = so->so_next;
+           free_searchobj( so );
+       }
+    }
+    /* XXX XXX need to do some work here */
+}
+
+
+static void
+free_searchobj( struct ldap_searchobj *so )
+{
+    if ( so != NULL ) {
+       if ( so->so_objtypeprompt != NULL ) {
+           free(  so->so_objtypeprompt );
+       }
+       if ( so->so_prompt != NULL ) {
+           free(  so->so_prompt );
+       }
+       if ( so->so_filterprefix != NULL ) {
+           free(  so->so_filterprefix );
+       }
+       if ( so->so_filtertag != NULL ) {
+           free(  so->so_filtertag );
+       }
+       if ( so->so_defaultselectattr != NULL ) {
+           free(  so->so_defaultselectattr );
+       }
+       if ( so->so_defaultselecttext != NULL ) {
+           free(  so->so_defaultselecttext );
+       }
+       if ( so->so_salist != NULL ) {
+           struct ldap_searchattr *sa, *nextsa;
+           for ( sa = so->so_salist; sa != NULL; sa = nextsa ) {
+               nextsa = sa->sa_next;
+               if ( sa->sa_attrlabel != NULL ) {
+                   free( sa->sa_attrlabel );
+               }
+               if ( sa->sa_attr != NULL ) {
+                   free( sa->sa_attr );
+               }
+               if ( sa->sa_selectattr != NULL ) {
+                   free( sa->sa_selectattr );
+               }
+               if ( sa->sa_selecttext != NULL ) {
+                   free( sa->sa_selecttext );
+               }
+               free( sa );
+           }
+       }
+       if ( so->so_smlist != NULL ) {
+           struct ldap_searchmatch *sm, *nextsm;
+           for ( sm = so->so_smlist; sm != NULL; sm = nextsm ) {
+               nextsm = sm->sm_next;
+               if ( sm->sm_matchprompt != NULL ) {
+                   free( sm->sm_matchprompt );
+               }
+               if ( sm->sm_filter != NULL ) {
+                   free( sm->sm_filter );
+               }
+               free( sm );
+           }
+       }
+       free( so );
+    }
+}
+
+
+
+struct ldap_searchobj *
+ldap_first_searchobj( struct ldap_searchobj *solist )
+{
+    return( solist );
+}
+
+
+struct ldap_searchobj *
+ldap_next_searchobj( struct ldap_searchobj *solist, struct ldap_searchobj *so )
+{
+    return( so == NULLSEARCHOBJ ? so : so->so_next );
+}
+
+
+
+static int
+read_next_searchobj( char **bufp, long *blenp, struct ldap_searchobj **sop,
+       int soversion )
+{
+    int                                i, j, tokcnt;
+    char                       **toks;
+    struct ldap_searchobj      *so;
+    struct ldap_searchattr     **sa;
+    struct ldap_searchmatch    **sm;
+
+    *sop = NULL;
+
+    /*
+     * Object type prompt comes first
+     */
+    if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+       free_strarray( toks );
+       return( tokcnt == 0 ? 0 : LDAP_SEARCHPREF_ERR_SYNTAX );
+    }
+
+    if (( so = (struct ldap_searchobj *)calloc( 1,
+           sizeof( struct ldap_searchobj ))) == NULL ) {
+       free_strarray( toks );
+       return(  LDAP_SEARCHPREF_ERR_MEM );
+    }
+    so->so_objtypeprompt = toks[ 0 ];
+    free( (char *)toks );
+
+    /*
+     * if this is post-version zero, options come next
+     */
+    if ( soversion > LDAP_SEARCHPREF_VERSION_ZERO ) {
+       if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) < 1 ) {
+           free_strarray( toks );
+           ldap_free_searchprefs( so );
+           return( LDAP_SEARCHPREF_ERR_SYNTAX );
+       }
+       for ( i = 0; toks[ i ] != NULL; ++i ) {
+           for ( j = 0; sobjoptions[ j ] != NULL; ++j ) {
+               if ( strcasecmp( toks[ i ], sobjoptions[ j ] ) == 0 ) {
+                   so->so_options |= sobjoptvals[ j ];
+               }
+           }
+       }
+       free_strarray( toks );
+    }
+
+    /*
+     * "Fewer choices" prompt is next
+     */
+    if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+       free_strarray( toks );
+       ldap_free_searchprefs( so );
+       return( LDAP_SEARCHPREF_ERR_SYNTAX );
+    }
+    so->so_prompt = toks[ 0 ];
+    free( (char *)toks );
+
+    /*
+     * Filter prefix for "More Choices" searching is next
+     */
+    if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+       free_strarray( toks );
+       ldap_free_searchprefs( so );
+       return( LDAP_SEARCHPREF_ERR_SYNTAX );
+    }
+    so->so_filterprefix = toks[ 0 ];
+    free( (char *)toks );
+
+    /*
+     * "Fewer Choices" filter tag comes next
+     */
+    if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+       free_strarray( toks );
+       ldap_free_searchprefs( so );
+       return( LDAP_SEARCHPREF_ERR_SYNTAX );
+    }
+    so->so_filtertag = toks[ 0 ];
+    free( (char *)toks );
+
+    /*
+     * Selection (disambiguation) attribute comes next
+     */
+    if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+       free_strarray( toks );
+       ldap_free_searchprefs( so );
+       return( LDAP_SEARCHPREF_ERR_SYNTAX );
+    }
+    so->so_defaultselectattr = toks[ 0 ];
+    free( (char *)toks );
+
+    /*
+     * Label for selection (disambiguation) attribute
+     */
+    if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+       free_strarray( toks );
+       ldap_free_searchprefs( so );
+       return( LDAP_SEARCHPREF_ERR_SYNTAX );
+    }
+    so->so_defaultselecttext = toks[ 0 ];
+    free( (char *)toks );
+
+    /*
+     * Search scope is next
+     */
+    if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+       free_strarray( toks );
+       ldap_free_searchprefs( so );
+       return( LDAP_SEARCHPREF_ERR_SYNTAX );
+    }
+    if ( !strcasecmp(toks[ 0 ], "subtree" )) {
+       so->so_defaultscope = LDAP_SCOPE_SUBTREE;
+    } else if ( !strcasecmp(toks[ 0 ], "onelevel" )) {
+       so->so_defaultscope = LDAP_SCOPE_ONELEVEL;
+    } else if ( !strcasecmp(toks[ 0 ], "base" )) {
+       so->so_defaultscope = LDAP_SCOPE_BASE;
+    } else {
+       ldap_free_searchprefs( so );
+       return( LDAP_SEARCHPREF_ERR_SYNTAX );
+    }
+    free_strarray( toks );
+
+
+    /*
+     * "More Choices" search option list comes next
+     */
+    sa = &( so->so_salist );
+    while (( tokcnt = next_line_tokens( bufp, blenp, &toks )) > 0 ) {
+       if ( tokcnt < 5 ) {
+           free_strarray( toks );
+           ldap_free_searchprefs( so );
+           return( LDAP_SEARCHPREF_ERR_SYNTAX );
+       }
+       if (( *sa = ( struct ldap_searchattr * ) calloc( 1,
+               sizeof( struct ldap_searchattr ))) == NULL ) {
+           free_strarray( toks );
+           ldap_free_searchprefs( so );
+           return(  LDAP_SEARCHPREF_ERR_MEM );
+       }
+       ( *sa )->sa_attrlabel = toks[ 0 ];
+       ( *sa )->sa_attr = toks[ 1 ];
+       ( *sa )->sa_selectattr = toks[ 3 ];
+       ( *sa )->sa_selecttext = toks[ 4 ];
+       /* Deal with bitmap */
+       ( *sa )->sa_matchtypebitmap = 0;
+       for ( i = strlen( toks[ 2 ] ) - 1, j = 0; i >= 0; i--, j++ ) {
+           if ( toks[ 2 ][ i ] == '1' ) {
+               ( *sa )->sa_matchtypebitmap |= (1 << j);
+           }
+       }
+       free( toks[ 2 ] );
+       free( ( char * ) toks );
+       sa = &(( *sa )->sa_next);
+    }
+    *sa = NULL;
+
+    /*
+     * Match types are last
+     */
+    sm = &( so->so_smlist );
+    while (( tokcnt = next_line_tokens( bufp, blenp, &toks )) > 0 ) {
+       if ( tokcnt < 2 ) {
+           free_strarray( toks );
+           ldap_free_searchprefs( so );
+           return( LDAP_SEARCHPREF_ERR_SYNTAX );
+       }
+       if (( *sm = ( struct ldap_searchmatch * ) calloc( 1,
+               sizeof( struct ldap_searchmatch ))) == NULL ) {
+           free_strarray( toks );
+           ldap_free_searchprefs( so );
+           return(  LDAP_SEARCHPREF_ERR_MEM );
+       }
+       ( *sm )->sm_matchprompt = toks[ 0 ];
+       ( *sm )->sm_filter = toks[ 1 ];
+       free( ( char * ) toks );
+       sm = &(( *sm )->sm_next );
+    }
+    *sm = NULL;
+
+    *sop = so;
+    return( 0 );
+}
diff --git a/libraries/libldap/test.c b/libraries/libldap/test.c
new file mode 100644 (file)
index 0000000..84f478d
--- /dev/null
@@ -0,0 +1,1023 @@
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#ifdef MACOS
+#include <stdlib.h>
+#ifdef THINK_C
+#include <console.h>
+#include <unix.h>
+#include <fcntl.h>
+#endif /* THINK_C */
+#include "macos.h"
+#else /* MACOS */
+#if defined( DOS ) || defined( _WIN32 )
+#include "msdos.h"
+#if defined( WINSOCK ) || defined( _WIN32 )
+#include "console.h"
+#endif /* WINSOCK */
+#else /* DOS */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#ifndef VMS
+#include <fcntl.h>
+#include <unistd.h>
+#endif /* VMS */
+#endif /* DOS */
+#endif /* MACOS */
+
+#include "lber.h"
+#include "ldap.h"
+
+#if !defined( PCNFS ) && !defined( WINSOCK ) && !defined( MACOS )
+#define MOD_USE_BVALS
+#endif /* !PCNFS && !WINSOCK && !MACOS */
+
+#ifdef NEEDPROTOS
+static void handle_result( LDAP *ld, LDAPMessage *lm );
+static void print_ldap_result( LDAP *ld, LDAPMessage *lm, char *s );
+static void print_search_entry( LDAP *ld, LDAPMessage *res );
+static void free_list( char **list );
+#else
+static void handle_result();
+static void print_ldap_result();
+static void print_search_entry();
+static void free_list();
+#endif /* NEEDPROTOS */
+
+#define NOCACHEERRMSG  "don't compile with -DNO_CACHE if you desire local caching"
+
+char *dnsuffix;
+
+#ifndef WINSOCK
+static char *
+getline( char *line, int len, FILE *fp, char *prompt )
+{
+       printf(prompt);
+
+       if ( fgets( line, len, fp ) == NULL )
+               return( NULL );
+
+       line[ strlen( line ) - 1 ] = '\0';
+
+       return( line );
+}
+#endif /* WINSOCK */
+
+static char **
+get_list( char *prompt )
+{
+       static char     buf[256];
+       int             num;
+       char            **result;
+
+       num = 0;
+       result = (char **) 0;
+       while ( 1 ) {
+               getline( buf, sizeof(buf), stdin, prompt );
+
+               if ( *buf == '\0' )
+                       break;
+
+               if ( result == (char **) 0 )
+                       result = (char **) malloc( sizeof(char *) );
+               else
+                       result = (char **) realloc( result,
+                           sizeof(char *) * (num + 1) );
+
+               result[num++] = (char *) strdup( buf );
+       }
+       if ( result == (char **) 0 )
+               return( NULL );
+       result = (char **) realloc( result, sizeof(char *) * (num + 1) );
+       result[num] = NULL;
+
+       return( result );
+}
+
+
+static void
+free_list( char **list )
+{
+       int     i;
+
+       if ( list != NULL ) {
+               for ( i = 0; list[ i ] != NULL; ++i ) {
+                       free( list[ i ] );
+               }
+               free( (char *)list );
+       }
+}
+
+
+#ifdef MOD_USE_BVALS
+static int
+file_read( char *path, struct berval *bv )
+{
+       FILE            *fp;
+       long            rlen;
+       int             eof;
+
+       if (( fp = fopen( path, "r" )) == NULL ) {
+               perror( path );
+               return( -1 );
+       }
+
+       if ( fseek( fp, 0L, SEEK_END ) != 0 ) {
+               perror( path );
+               fclose( fp );
+               return( -1 );
+       }
+
+       bv->bv_len = ftell( fp );
+
+       if (( bv->bv_val = (char *)malloc( bv->bv_len )) == NULL ) {
+               perror( "malloc" );
+               fclose( fp );
+               return( -1 );
+       }
+
+       if ( fseek( fp, 0L, SEEK_SET ) != 0 ) {
+               perror( path );
+               fclose( fp );
+               return( -1 );
+       }
+
+       rlen = fread( bv->bv_val, 1, bv->bv_len, fp );
+       eof = feof( fp );
+       fclose( fp );
+
+       if ( rlen != bv->bv_len ) {
+               perror( path );
+               free( bv->bv_val );
+               return( -1 );
+       }
+
+       return( bv->bv_len );
+}
+#endif /* MOD_USE_BVALS */
+
+
+static LDAPMod **
+get_modlist( char *prompt1, char *prompt2, char *prompt3 )
+{
+       static char     buf[256];
+       int             num;
+       LDAPMod         tmp;
+       LDAPMod         **result;
+#ifdef MOD_USE_BVALS
+       struct berval   **bvals;
+#endif /* MOD_USE_BVALS */
+
+       num = 0;
+       result = NULL;
+       while ( 1 ) {
+               if ( prompt1 ) {
+                       getline( buf, sizeof(buf), stdin, prompt1 );
+                       tmp.mod_op = atoi( buf );
+
+                       if ( tmp.mod_op == -1 || buf[0] == '\0' )
+                               break;
+               }
+
+               getline( buf, sizeof(buf), stdin, prompt2 );
+               if ( buf[0] == '\0' )
+                       break;
+               tmp.mod_type = strdup( buf );
+
+               tmp.mod_values = get_list( prompt3 );
+#ifdef MOD_USE_BVALS
+               if ( tmp.mod_values != NULL ) {
+                       int     i;
+
+                       for ( i = 0; tmp.mod_values[i] != NULL; ++i )
+                               ;
+                       bvals = (struct berval **)calloc( i + 1,
+                           sizeof( struct berval *));
+                       for ( i = 0; tmp.mod_values[i] != NULL; ++i ) {
+                               bvals[i] = (struct berval *)malloc(
+                                   sizeof( struct berval ));
+                               if ( strncmp( tmp.mod_values[i], "{FILE}",
+                                   6 ) == 0 ) {
+                                       if ( file_read( tmp.mod_values[i] + 6,
+                                           bvals[i] ) < 0 ) {
+                                               return( NULL );
+                                       }
+                               } else {
+                                       bvals[i]->bv_val = tmp.mod_values[i];
+                                       bvals[i]->bv_len =
+                                           strlen( tmp.mod_values[i] );
+                               }
+                       }
+                       tmp.mod_bvalues = bvals;
+                       tmp.mod_op |= LDAP_MOD_BVALUES;
+               }
+#endif /* MOD_USE_BVALS */
+
+               if ( result == NULL )
+                       result = (LDAPMod **) malloc( sizeof(LDAPMod *) );
+               else
+                       result = (LDAPMod **) realloc( result,
+                           sizeof(LDAPMod *) * (num + 1) );
+
+               result[num] = (LDAPMod *) malloc( sizeof(LDAPMod) );
+               *(result[num]) = tmp;   /* struct copy */
+               num++;
+       }
+       if ( result == NULL )
+               return( NULL );
+       result = (LDAPMod **) realloc( result, sizeof(LDAPMod *) * (num + 1) );
+       result[num] = NULL;
+
+       return( result );
+}
+
+
+#ifdef LDAP_REFERRALS
+int
+bind_prompt( LDAP *ld, char **dnp, char **passwdp, int *authmethodp,
+       int freeit )
+{
+       static char     dn[256], passwd[256];
+
+       if ( !freeit ) {
+#ifdef KERBEROS
+               getline( dn, sizeof(dn), stdin,
+                   "re-bind method (0->simple, 1->krbv41, 2->krbv42, 3->krbv41&2)? " );
+               if (( *authmethodp = atoi( dn )) == 3 ) {
+                       *authmethodp = LDAP_AUTH_KRBV4;
+               } else {
+                       *authmethodp |= 0x80;
+               }
+#else /* KERBEROS */
+               *authmethodp = LDAP_AUTH_SIMPLE;
+#endif /* KERBEROS */
+
+               getline( dn, sizeof(dn), stdin, "re-bind dn? " );
+               strcat( dn, dnsuffix );
+               *dnp = dn;
+
+               if ( *authmethodp == LDAP_AUTH_SIMPLE && dn[0] != '\0' ) {
+                       getline( passwd, sizeof(passwd), stdin,
+                           "re-bind password? " );
+               } else {
+                       passwd[0] = '\0';
+               }
+               *passwdp = passwd;
+       }
+
+       return( LDAP_SUCCESS );
+}
+#endif /* LDAP_REFERRALS */
+
+
+int
+#ifdef WINSOCK
+ldapmain(
+#else /* WINSOCK */
+main(
+#endif /* WINSOCK */
+       int argc, char **argv )
+{
+       LDAP            *ld;
+       int             i, c, port, cldapflg, errflg, method, id, msgtype;
+       char            line[256], command1, command2, command3;
+       char            passwd[64], dn[256], rdn[64], attr[64], value[256];
+       char            filter[256], *host, **types;
+       char            **exdn;
+       char            *usage = "usage: %s [-u] [-h host] [-d level] [-s dnsuffix] [-p port] [-t file] [-T file]\n";
+       int             bound, all, scope, attrsonly;
+       LDAPMessage     *res;
+       LDAPMod         **mods, **attrs;
+       struct timeval  timeout;
+       char            *copyfname = NULL;
+       int             copyoptions = 0;
+       LDAPURLDesc     *ludp;
+
+       extern char     *optarg;
+       extern int      optind;
+
+#ifdef MACOS
+       if (( argv = get_list( "cmd line arg?" )) == NULL ) {
+               exit( 1 );
+       }
+       for ( argc = 0; argv[ argc ] != NULL; ++argc ) {
+               ;
+       }
+#endif /* MACOS */
+
+       host = NULL;
+       port = LDAP_PORT;
+       dnsuffix = "";
+       cldapflg = errflg = 0;
+
+       while (( c = getopt( argc, argv, "uh:d:s:p:t:T:" )) != -1 ) {
+               switch( c ) {
+               case 'u':
+#ifdef CLDAP
+                       cldapflg++;
+#else /* CLDAP */
+                       printf( "Compile with -DCLDAP for UDP support\n" );
+#endif /* CLDAP */
+                       break;
+
+               case 'd':
+#ifdef LDAP_DEBUG
+                       ldap_debug = atoi( optarg );
+                       if ( ldap_debug & LDAP_DEBUG_PACKETS ) {
+                               lber_debug = ldap_debug;
+                       }
+#else
+                       printf( "Compile with -DLDAP_DEBUG for debugging\n" );
+#endif
+                       break;
+
+               case 'h':
+                       host = optarg;
+                       break;
+
+               case 's':
+                       dnsuffix = optarg;
+                       break;
+
+               case 'p':
+                       port = atoi( optarg );
+                       break;
+
+#if !defined(MACOS) && !defined(DOS)
+               case 't':       /* copy ber's to given file */
+                       copyfname = strdup( optarg );
+                       copyoptions = LBER_TO_FILE;
+                       break;
+
+               case 'T':       /* only output ber's to given file */
+                       copyfname = strdup( optarg );
+                       copyoptions = (LBER_TO_FILE | LBER_TO_FILE_ONLY);
+                       break;
+#endif
+
+               default:
+                   ++errflg;
+               }
+       }
+
+       if ( host == NULL && optind == argc - 1 ) {
+               host = argv[ optind ];
+               ++optind;
+       }
+
+       if ( errflg || optind < argc - 1 ) {
+               fprintf( stderr, usage, argv[ 0 ] );
+               exit( 1 );
+       }
+       
+       printf( "%sldap_open( %s, %d )\n", cldapflg ? "c" : "",
+               host == NULL ? "(null)" : host, port );
+
+       if ( cldapflg ) {
+#ifdef CLDAP
+               ld = cldap_open( host, port );
+#endif /* CLDAP */
+       } else {
+               ld = ldap_open( host, port );
+       }
+
+       if ( ld == NULL ) {
+               perror( "ldap_open" );
+               exit(1);
+       }
+
+#if !defined(MACOS) && !defined(DOS)
+       if ( copyfname != NULL ) {
+               if ( (ld->ld_sb.sb_fd = open( copyfname, O_WRONLY | O_CREAT,
+                   0600 ))  == -1 ) {
+                       perror( copyfname );
+                       exit ( 1 );
+               }
+               ld->ld_sb.sb_options = copyoptions;
+       }
+#endif
+
+       bound = 0;
+       timeout.tv_sec = 0;
+       timeout.tv_usec = 0;
+
+       (void) memset( line, '\0', sizeof(line) );
+       while ( getline( line, sizeof(line), stdin, "\ncommand? " ) != NULL ) {
+               command1 = line[0];
+               command2 = line[1];
+               command3 = line[2];
+
+               switch ( command1 ) {
+               case 'a':       /* add or abandon */
+                       switch ( command2 ) {
+                       case 'd':       /* add */
+                               getline( dn, sizeof(dn), stdin, "dn? " );
+                               strcat( dn, dnsuffix );
+                               if ( (attrs = get_modlist( NULL, "attr? ",
+                                   "value? " )) == NULL )
+                                       break;
+                               if ( (id = ldap_add( ld, dn, attrs )) == -1 )
+                                       ldap_perror( ld, "ldap_add" );
+                               else
+                                       printf( "Add initiated with id %d\n",
+                                           id );
+                               break;
+
+                       case 'b':       /* abandon */
+                               getline( line, sizeof(line), stdin, "msgid? " );
+                               id = atoi( line );
+                               if ( ldap_abandon( ld, id ) != 0 )
+                                       ldap_perror( ld, "ldap_abandon" );
+                               else
+                                       printf( "Abandon successful\n" );
+                               break;
+                       default:
+                               printf( "Possibilities: [ad]d, [ab]ort\n" );
+                       }
+                       break;
+
+               case 'b':       /* asynch bind */
+#ifdef KERBEROS
+                       getline( line, sizeof(line), stdin,
+                           "method (0->simple, 1->krbv41, 2->krbv42)? " );
+                       method = atoi( line ) | 0x80;
+#else /* KERBEROS */
+                       method = LDAP_AUTH_SIMPLE;
+#endif /* KERBEROS */
+                       getline( dn, sizeof(dn), stdin, "dn? " );
+                       strcat( dn, dnsuffix );
+
+                       if ( method == LDAP_AUTH_SIMPLE && dn[0] != '\0' )
+                               getline( passwd, sizeof(passwd), stdin,
+                                   "password? " );
+                       else
+                               passwd[0] = '\0';
+
+                       if ( ldap_bind( ld, dn, passwd, method ) == -1 ) {
+                               fprintf( stderr, "ldap_bind failed\n" );
+                               ldap_perror( ld, "ldap_bind" );
+                       } else {
+                               printf( "Bind initiated\n" );
+                               bound = 1;
+                       }
+                       break;
+
+               case 'B':       /* synch bind */
+#ifdef KERBEROS
+                       getline( line, sizeof(line), stdin,
+                           "method 0->simple 1->krbv41 2->krbv42 3->krb? " );
+                       method = atoi( line );
+                       if ( method == 3 )
+                               method = LDAP_AUTH_KRBV4;
+                       else
+                               method = method | 0x80;
+#else /* KERBEROS */
+                       method = LDAP_AUTH_SIMPLE;
+#endif /* KERBEROS */
+                       getline( dn, sizeof(dn), stdin, "dn? " );
+                       strcat( dn, dnsuffix );
+
+                       if ( dn[0] != '\0' )
+                               getline( passwd, sizeof(passwd), stdin,
+                                   "password? " );
+                       else
+                               passwd[0] = '\0';
+
+                       if ( ldap_bind_s( ld, dn, passwd, method ) !=
+                           LDAP_SUCCESS ) {
+                               fprintf( stderr, "ldap_bind_s failed\n" );
+                               ldap_perror( ld, "ldap_bind_s" );
+                       } else {
+                               printf( "Bind successful\n" );
+                               bound = 1;
+                       }
+                       break;
+
+               case 'c':       /* compare */
+                       getline( dn, sizeof(dn), stdin, "dn? " );
+                       strcat( dn, dnsuffix );
+                       getline( attr, sizeof(attr), stdin, "attr? " );
+                       getline( value, sizeof(value), stdin, "value? " );
+
+                       if ( (id = ldap_compare( ld, dn, attr, value )) == -1 )
+                               ldap_perror( ld, "ldap_compare" );
+                       else
+                               printf( "Compare initiated with id %d\n", id );
+                       break;
+
+               case 'd':       /* turn on debugging */
+#ifdef LDAP_DEBUG
+                       getline( line, sizeof(line), stdin, "debug level? " );
+                       ldap_debug = atoi( line );
+                       if ( ldap_debug & LDAP_DEBUG_PACKETS ) {
+                               lber_debug = ldap_debug;
+                       }
+#else
+                       printf( "Compile with -DLDAP_DEBUG for debugging\n" );
+#endif
+                       break;
+
+               case 'E':       /* explode a dn */
+                       getline( line, sizeof(line), stdin, "dn? " );
+                       exdn = ldap_explode_dn( line, 0 );
+                       for ( i = 0; exdn != NULL && exdn[i] != NULL; i++ ) {
+                               printf( "\t%s\n", exdn[i] );
+                       }
+                       break;
+
+               case 'g':       /* set next msgid */
+                       getline( line, sizeof(line), stdin, "msgid? " );
+                       ld->ld_msgid = atoi( line );
+                       break;
+
+               case 'v':       /* set version number */
+                       getline( line, sizeof(line), stdin, "version? " );
+                       ld->ld_version = atoi( line );
+                       break;
+
+               case 'm':       /* modify or modifyrdn */
+                       if ( strncmp( line, "modify", 4 ) == 0 ) {
+                               getline( dn, sizeof(dn), stdin, "dn? " );
+                               strcat( dn, dnsuffix );
+                               if ( (mods = get_modlist(
+                                   "mod (0=>add, 1=>delete, 2=>replace -1=>done)? ",
+                                   "attribute type? ", "attribute value? " ))
+                                   == NULL )
+                                       break;
+                               if ( (id = ldap_modify( ld, dn, mods )) == -1 )
+                                       ldap_perror( ld, "ldap_modify" );
+                               else
+                                       printf( "Modify initiated with id %d\n",
+                                           id );
+                       } else if ( strncmp( line, "modrdn", 4 ) == 0 ) {
+                               getline( dn, sizeof(dn), stdin, "dn? " );
+                               strcat( dn, dnsuffix );
+                               getline( rdn, sizeof(rdn), stdin, "newrdn? " );
+                               if ( (id = ldap_modrdn( ld, dn, rdn )) == -1 )
+                                       ldap_perror( ld, "ldap_modrdn" );
+                               else
+                                       printf( "Modrdn initiated with id %d\n",
+                                           id );
+                       } else {
+                               printf( "Possibilities: [modi]fy, [modr]dn\n" );
+                       }
+                       break;
+
+               case 'q':       /* quit */
+#ifdef CLDAP
+                       if ( cldapflg )
+                               cldap_close( ld );
+#endif /* CLDAP */
+#ifdef LDAP_REFERRALS
+                       if ( !cldapflg )
+#else /* LDAP_REFERRALS */
+                       if ( !cldapflg && bound )
+#endif /* LDAP_REFERRALS */
+                               ldap_unbind( ld );
+                       exit( 0 );
+                       break;
+
+               case 'r':       /* result or remove */
+                       switch ( command3 ) {
+                       case 's':       /* result */
+                               getline( line, sizeof(line), stdin,
+                                   "msgid (-1=>any)? " );
+                               if ( line[0] == '\0' )
+                                       id = -1;
+                               else
+                                       id = atoi( line );
+                               getline( line, sizeof(line), stdin,
+                                   "all (0=>any, 1=>all)? " );
+                               if ( line[0] == '\0' )
+                                       all = 1;
+                               else
+                                       all = atoi( line );
+                               if (( msgtype = ldap_result( ld, id, all,
+                                   &timeout, &res )) < 1 ) {
+                                       ldap_perror( ld, "ldap_result" );
+                                       break;
+                               }
+                               printf( "\nresult: msgtype %d msgid %d\n",
+                                   msgtype, res->lm_msgid );
+                               handle_result( ld, res );
+                               res = NULLMSG;
+                               break;
+
+                       case 'm':       /* remove */
+                               getline( dn, sizeof(dn), stdin, "dn? " );
+                               strcat( dn, dnsuffix );
+                               if ( (id = ldap_delete( ld, dn )) == -1 )
+                                       ldap_perror( ld, "ldap_delete" );
+                               else
+                                       printf( "Remove initiated with id %d\n",
+                                           id );
+                               break;
+
+                       default:
+                               printf( "Possibilities: [rem]ove, [res]ult\n" );
+                               break;
+                       }
+                       break;
+
+               case 's':       /* search */
+                       getline( dn, sizeof(dn), stdin, "searchbase? " );
+                       strcat( dn, dnsuffix );
+                       getline( line, sizeof(line), stdin,
+                           "scope (0=Base, 1=One Level, 2=Subtree)? " );
+                       scope = atoi( line );
+                       getline( filter, sizeof(filter), stdin,
+                           "search filter (e.g. sn=jones)? " );
+                       types = get_list( "attrs to return? " );
+                       getline( line, sizeof(line), stdin,
+                           "attrsonly (0=attrs&values, 1=attrs only)? " );
+                       attrsonly = atoi( line );
+
+                       if ( cldapflg ) {
+#ifdef CLDAP
+                           getline( line, sizeof(line), stdin,
+                               "Requestor DN (for logging)? " );
+                           if ( cldap_search_s( ld, dn, scope, filter, types,
+                                   attrsonly, &res, line ) != 0 ) {
+                               ldap_perror( ld, "cldap_search_s" );
+                           } else {
+                               printf( "\nresult: msgid %d\n",
+                                   res->lm_msgid );
+                               handle_result( ld, res );
+                               res = NULLMSG;
+                           }
+#endif /* CLDAP */
+                       } else {
+                           if (( id = ldap_search( ld, dn, scope, filter,
+                                   types, attrsonly  )) == -1 ) {
+                               ldap_perror( ld, "ldap_search" );
+                           } else {
+                               printf( "Search initiated with id %d\n", id );
+                           }
+                       }
+                       free_list( types );
+                       break;
+
+               case 't':       /* set timeout value */
+                       getline( line, sizeof(line), stdin, "timeout? " );
+                       timeout.tv_sec = atoi( line );
+                       break;
+
+               case 'U':       /* set ufn search prefix */
+                       getline( line, sizeof(line), stdin, "ufn prefix? " );
+                       ldap_ufn_setprefix( ld, line );
+                       break;
+
+               case 'u':       /* user friendly search w/optional timeout */
+                       getline( dn, sizeof(dn), stdin, "ufn? " );
+                       strcat( dn, dnsuffix );
+                       types = get_list( "attrs to return? " );
+                       getline( line, sizeof(line), stdin,
+                           "attrsonly (0=attrs&values, 1=attrs only)? " );
+                       attrsonly = atoi( line );
+
+                       if ( command2 == 't' ) {
+                               id = ldap_ufn_search_c( ld, dn, types,
+                                   attrsonly, &res, ldap_ufn_timeout,
+                                   &timeout );
+                       } else {
+                               id = ldap_ufn_search_s( ld, dn, types,
+                                   attrsonly, &res );
+                       }
+                       if ( res == NULL )
+                               ldap_perror( ld, "ldap_ufn_search" );
+                       else {
+                               printf( "\nresult: err %d\n", id );
+                               handle_result( ld, res );
+                               res = NULLMSG;
+                       }
+                       free_list( types );
+                       break;
+
+               case 'l':       /* URL search */
+                       getline( line, sizeof(line), stdin,
+                           "attrsonly (0=attrs&values, 1=attrs only)? " );
+                       attrsonly = atoi( line );
+                       getline( line, sizeof(line), stdin, "LDAP URL? " );
+                       if (( id = ldap_url_search( ld, line, attrsonly  ))
+                               == -1 ) {
+                           ldap_perror( ld, "ldap_url_search" );
+                       } else {
+                           printf( "URL search initiated with id %d\n", id );
+                       }
+                       break;
+
+               case 'p':       /* parse LDAP URL */
+                       getline( line, sizeof(line), stdin, "LDAP URL? " );
+                       if (( i = ldap_url_parse( line, &ludp )) != 0 ) {
+                           fprintf( stderr, "ldap_url_parse: error %d\n", i );
+                       } else {
+                           printf( "\t  host: " );
+                           if ( ludp->lud_host == NULL ) {
+                               printf( "DEFAULT\n" );
+                           } else {
+                               printf( "<%s>\n", ludp->lud_host );
+                           }
+                           printf( "\t  port: " );
+                           if ( ludp->lud_port == 0 ) {
+                               printf( "DEFAULT\n" );
+                           } else {
+                               printf( "%d\n", ludp->lud_port );
+                           }
+                           printf( "\t    dn: <%s>\n", ludp->lud_dn );
+                           printf( "\t attrs:" );
+                           if ( ludp->lud_attrs == NULL ) {
+                               printf( " ALL" );
+                           } else {
+                               for ( i = 0; ludp->lud_attrs[ i ] != NULL; ++i ) {
+                                   printf( " <%s>", ludp->lud_attrs[ i ] );
+                               }
+                           }
+                           printf( "\n\t scope: %s\n", ludp->lud_scope == LDAP_SCOPE_ONELEVEL ?
+                               "ONE" : ludp->lud_scope == LDAP_SCOPE_BASE ? "BASE" :
+                               ludp->lud_scope == LDAP_SCOPE_SUBTREE ? "SUB" : "**invalid**" );
+                           printf( "\tfilter: <%s>\n", ludp->lud_filter );
+                           ldap_free_urldesc( ludp );
+                       }
+                           break;
+
+               case 'n':       /* set dn suffix, for convenience */
+                       getline( line, sizeof(line), stdin, "DN suffix? " );
+                       strcpy( dnsuffix, line );
+                       break;
+
+               case 'e':       /* enable cache */
+#ifdef NO_CACHE
+                       printf( NOCACHEERRMSG );
+#else /* NO_CACHE */
+                       getline( line, sizeof(line), stdin, "Cache timeout (secs)? " );
+                       i = atoi( line );
+                       getline( line, sizeof(line), stdin, "Maximum memory to use (bytes)? " );
+                       if ( ldap_enable_cache( ld, i, atoi( line )) == 0 ) {
+                               printf( "local cache is on\n" ); 
+                       } else {
+                               printf( "ldap_enable_cache failed\n" ); 
+                       }
+#endif /* NO_CACHE */
+                       break;
+
+               case 'x':       /* uncache entry */
+#ifdef NO_CACHE
+                       printf( NOCACHEERRMSG );
+#else /* NO_CACHE */
+                       getline( line, sizeof(line), stdin, "DN? " );
+                       ldap_uncache_entry( ld, line );
+#endif /* NO_CACHE */
+                       break;
+
+               case 'X':       /* uncache request */
+#ifdef NO_CACHE
+                       printf( NOCACHEERRMSG );
+#else /* NO_CACHE */
+                       getline( line, sizeof(line), stdin, "request msgid? " );
+                       ldap_uncache_request( ld, atoi( line ));
+#endif /* NO_CACHE */
+                       break;
+
+               case 'o':       /* set ldap options */
+                       getline( line, sizeof(line), stdin, "alias deref (0=never, 1=searching, 2=finding, 3=always)?" );
+                       ld->ld_deref = atoi( line );
+                       getline( line, sizeof(line), stdin, "timelimit?" );
+                       ld->ld_timelimit = atoi( line );
+                       getline( line, sizeof(line), stdin, "sizelimit?" );
+                       ld->ld_sizelimit = atoi( line );
+
+                       ld->ld_options = 0;
+
+#ifdef STR_TRANSLATION
+                       getline( line, sizeof(line), stdin,
+                               "Automatic translation of T.61 strings (0=no, 1=yes)?" );
+                       if ( atoi( line ) == 0 ) {
+                               ld->ld_lberoptions &= ~LBER_TRANSLATE_STRINGS;
+                       } else {
+                               ld->ld_lberoptions |= LBER_TRANSLATE_STRINGS;
+#ifdef LDAP_CHARSET_8859
+                               getline( line, sizeof(line), stdin,
+                                       "Translate to/from ISO-8859 (0=no, 1=yes?" );
+                               if ( atoi( line ) != 0 ) {
+                                       ldap_set_string_translators( ld,
+                                           ldap_8859_to_t61,
+                                           ldap_t61_to_8859 );
+                               }
+#endif /* LDAP_CHARSET_8859 */
+                       }
+#endif /* STR_TRANSLATION */
+
+#ifdef LDAP_DNS
+                       getline( line, sizeof(line), stdin,
+                               "Use DN & DNS to determine where to send requests (0=no, 1=yes)?" );
+                       if ( atoi( line ) != 0 ) {
+                               ld->ld_options |= LDAP_OPT_DNS;
+                       }
+#endif /* LDAP_DNS */
+
+#ifdef LDAP_REFERRALS
+                       getline( line, sizeof(line), stdin,
+                               "Recognize and chase referrals (0=no, 1=yes)?" );
+                       if ( atoi( line ) != 0 ) {
+                               ld->ld_options |= LDAP_OPT_REFERRALS;
+                               getline( line, sizeof(line), stdin,
+                                       "Prompt for bind credentials when chasing referrals (0=no, 1=yes)?" );
+                               if ( atoi( line ) != 0 ) {
+                                       ldap_set_rebind_proc( ld, bind_prompt );
+                               }
+                       }
+#endif /* LDAP_REFERRALS */
+                       break;
+
+               case 'O':       /* set cache options */
+#ifdef NO_CACHE
+                       printf( NOCACHEERRMSG );
+#else /* NO_CACHE */
+                       getline( line, sizeof(line), stdin, "cache errors (0=smart, 1=never, 2=always)?" );
+                       switch( atoi( line )) {
+                       case 0:
+                               ldap_set_cache_options( ld, 0 );
+                               break;
+                       case 1:
+                               ldap_set_cache_options( ld,
+                                       LDAP_CACHE_OPT_CACHENOERRS );
+                               break;
+                       case 2:
+                               ldap_set_cache_options( ld,
+                                       LDAP_CACHE_OPT_CACHEALLERRS );
+                               break;
+                       default:
+                               printf( "not a valid cache option\n" );
+                       }
+#endif /* NO_CACHE */
+                       break;
+
+               case '?':       /* help */
+    printf( "Commands: [ad]d         [ab]andon         [b]ind\n" );
+    printf( "          [B]ind async  [c]ompare         [l]URL search\n" );
+    printf( "          [modi]fy      [modr]dn          [rem]ove\n" );
+    printf( "          [res]ult      [s]earch          [q]uit/unbind\n\n" );
+    printf( "          [u]fn search  [ut]fn search with timeout\n" );
+    printf( "          [d]ebug       [e]nable cache    set ms[g]id\n" );
+    printf( "          d[n]suffix    [t]imeout         [v]ersion\n" );
+    printf( "          [U]fn prefix  [x]uncache entry  [X]uncache request\n" );
+    printf( "          [?]help       [o]ptions         [O]cache options\n" );
+    printf( "          [E]xplode dn  [p]arse LDAP URL\n" );
+                       break;
+
+               default:
+                       printf( "Invalid command.  Type ? for help.\n" );
+                       break;
+               }
+
+               (void) memset( line, '\0', sizeof(line) );
+       }
+
+       return( 0 );
+}
+
+static void
+handle_result( LDAP *ld, LDAPMessage *lm )
+{
+       switch ( lm->lm_msgtype ) {
+       case LDAP_RES_COMPARE:
+               printf( "Compare result\n" );
+               print_ldap_result( ld, lm, "compare" );
+               break;
+
+       case LDAP_RES_SEARCH_RESULT:
+               printf( "Search result\n" );
+               print_ldap_result( ld, lm, "search" );
+               break;
+
+       case LDAP_RES_SEARCH_ENTRY:
+               printf( "Search entry\n" );
+               print_search_entry( ld, lm );
+               break;
+
+       case LDAP_RES_ADD:
+               printf( "Add result\n" );
+               print_ldap_result( ld, lm, "add" );
+               break;
+
+       case LDAP_RES_DELETE:
+               printf( "Delete result\n" );
+               print_ldap_result( ld, lm, "delete" );
+               break;
+
+       case LDAP_RES_MODRDN:
+               printf( "ModRDN result\n" );
+               print_ldap_result( ld, lm, "modrdn" );
+               break;
+
+       case LDAP_RES_BIND:
+               printf( "Bind result\n" );
+               print_ldap_result( ld, lm, "bind" );
+               break;
+
+       default:
+               printf( "Unknown result type 0x%x\n", lm->lm_msgtype );
+               print_ldap_result( ld, lm, "unknown" );
+       }
+}
+
+static void
+print_ldap_result( LDAP *ld, LDAPMessage *lm, char *s )
+{
+       ldap_result2error( ld, lm, 1 );
+       ldap_perror( ld, s );
+/*
+       if ( ld->ld_error != NULL && *ld->ld_error != '\0' )
+               fprintf( stderr, "Additional info: %s\n", ld->ld_error );
+       if ( NAME_ERROR( ld->ld_errno ) && ld->ld_matched != NULL )
+               fprintf( stderr, "Matched DN: %s\n", ld->ld_matched );
+*/
+}
+
+static void
+print_search_entry( LDAP *ld, LDAPMessage *res )
+{
+       BerElement      *ber;
+       char            *a, *dn, *ufn;
+       struct berval   **vals;
+       int             i;
+       LDAPMessage     *e;
+
+       for ( e = ldap_first_entry( ld, res ); e != NULLMSG;
+           e = ldap_next_entry( ld, e ) ) {
+               if ( e->lm_msgtype == LDAP_RES_SEARCH_RESULT )
+                       break;
+
+               dn = ldap_get_dn( ld, e );
+               printf( "\tDN: %s\n", dn );
+
+               ufn = ldap_dn2ufn( dn );
+               printf( "\tUFN: %s\n", ufn );
+#ifdef WINSOCK
+               ldap_memfree( dn );
+               ldap_memfree( ufn );
+#else /* WINSOCK */
+               free( dn );
+               free( ufn );
+#endif /* WINSOCK */
+
+               for ( a = ldap_first_attribute( ld, e, &ber ); a != NULL;
+                   a = ldap_next_attribute( ld, e, ber ) ) {
+                       printf( "\t\tATTR: %s\n", a );
+                       if ( (vals = ldap_get_values_len( ld, e, a ))
+                           == NULL ) {
+                               printf( "\t\t\t(no values)\n" );
+                       } else {
+                               for ( i = 0; vals[i] != NULL; i++ ) {
+                                       int     j, nonascii;
+
+                                       nonascii = 0;
+                                       for ( j = 0; j < vals[i]->bv_len; j++ )
+                                               if ( !isascii( vals[i]->bv_val[j] ) ) {
+                                                       nonascii = 1;
+                                                       break;
+                                               }
+
+                                       if ( nonascii ) {
+                                               printf( "\t\t\tlength (%ld) (not ascii)\n", vals[i]->bv_len );
+#ifdef BPRINT_NONASCII
+                                               lber_bprint( vals[i]->bv_val,
+                                                   vals[i]->bv_len );
+#endif /* BPRINT_NONASCII */
+                                               continue;
+                                       }
+                                       printf( "\t\t\tlength (%ld) %s\n",
+                                           vals[i]->bv_len, vals[i]->bv_val );
+                               }
+                               ber_bvecfree( vals );
+                       }
+               }
+       }
+
+       if ( res->lm_msgtype == LDAP_RES_SEARCH_RESULT
+           || res->lm_chain != NULLMSG )
+               print_ldap_result( ld, res, "search" );
+}
+
+
+#ifdef WINSOCK
+void
+ldap_perror( LDAP *ld, char *s )
+{
+       char    *errs;
+
+       if ( ld == NULL ) {
+               perror( s );
+               return;
+       }
+
+       errs = ldap_err2string( ld->ld_errno );
+       printf( "%s: %s\n", s, errs == NULL ? "unknown error" : errs );
+       if ( ld->ld_error != NULL && *ld->ld_error != '\0' ) {
+               printf( "%s: additional info: %s\n", s, ld->ld_error );
+       }
+}
+#endif /* WINSOCK */
diff --git a/libraries/libldap/tmplout.c b/libraries/libldap/tmplout.c
new file mode 100644 (file)
index 0000000..330527b
--- /dev/null
@@ -0,0 +1,1090 @@
+/*
+ * tmplout.c:  display template library output routines for LDAP clients
+ * 12 April 1994 by Mark C Smith
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+#include <stdlib.h>
+#ifdef MACOS
+#include "macos.h"
+#else /* MACOS */
+#ifdef DOS
+#include <malloc.h>
+#include "msdos.h"
+#else /* DOS */
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#endif /* DOS */
+#endif /* MACOS */
+
+#ifdef VMS
+#include <sys/socket.h>
+#endif /* VMS */
+
+#include "lber.h"
+#include "ldap.h"
+#include "disptmpl.h"
+
+#ifdef NEEDPROTOS
+static int do_entry2text( LDAP *ld, char *buf, char *base, LDAPMessage *entry,
+       struct ldap_disptmpl *tmpl, char **defattrs, char ***defvals,
+       writeptype writeproc, void *writeparm, char *eol, int rdncount,
+       unsigned long opts, char *urlprefix );
+static int do_entry2text_search( LDAP *ld, char *dn, char *base,
+       LDAPMessage *entry, struct ldap_disptmpl *tmpllist, char **defattrs,
+       char ***defvals, writeptype writeproc, void *writeparm, char *eol,
+       int rdncount, unsigned long opts, char *urlprefix );
+static int do_vals2text( LDAP *ld, char *buf, char **vals, char *label,
+       int labelwidth, unsigned long syntaxid, writeptype writeproc,
+       void *writeparm, char *eol, int rdncount, char *urlprefix );
+static int max_label_len( struct ldap_disptmpl *tmpl );
+static int output_label( char *buf, char *label, int width,
+       writeptype writeproc, void *writeparm, char *eol, int html );
+static int output_dn( char *buf, char *dn, int width, int rdncount,
+       writeptype writeproc, void *writeparm, char *eol, char *urlprefix );
+static void strcat_escaped( char *s1, char *s2 );
+static char *time2text( char *ldtimestr, int dateonly );
+static long gtime( struct tm *tm );
+static int searchaction( LDAP *ld, char *buf, char *base, LDAPMessage *entry,
+       char *dn, struct ldap_tmplitem *tip, int labelwidth, int rdncount,
+       writeptype writeproc, void *writeparm, char *eol, char *urlprefix );
+#else /* NEEDPROTOS */
+static int do_entry2text();
+static int do_entry2text_search();
+static int do_vals2text();
+static int max_label_len();
+static int output_label();
+static int output_dn();
+static void strcat_escaped();
+static char *time2text();
+static long gtime();
+static int searchaction();
+#endif /* NEEDPROTOS */
+
+#define DEF_LABEL_WIDTH                15
+#define SEARCH_TIMEOUT_SECS    120
+#define OCATTRNAME             "objectClass"
+
+
+#define NONFATAL_LDAP_ERR( err )       ( err == LDAP_SUCCESS || \
+       err == LDAP_TIMELIMIT_EXCEEDED || err == LDAP_SIZELIMIT_EXCEEDED )
+
+#define DEF_LDAP_URL_PREFIX    "ldap:///"
+
+int
+ldap_entry2text(
+       LDAP                    *ld,
+       char                    *buf,           /* NULL for "use internal" */
+       LDAPMessage             *entry,
+       struct ldap_disptmpl    *tmpl,
+       char                    **defattrs,
+       char                    ***defvals,
+       writeptype              writeproc,
+       void                    *writeparm,
+       char                    *eol,
+       int                     rdncount,
+       unsigned long           opts
+)
+{
+    Debug( LDAP_DEBUG_TRACE, "ldap_entry2text\n", 0, 0, 0 );
+
+    return( do_entry2text( ld, buf, NULL, entry, tmpl, defattrs, defvals,
+               writeproc, writeparm, eol, rdncount, opts, NULL ));
+
+}
+
+
+
+int
+ldap_entry2html(
+       LDAP                    *ld,
+       char                    *buf,           /* NULL for "use internal" */
+       LDAPMessage             *entry,
+       struct ldap_disptmpl    *tmpl,
+       char                    **defattrs,
+       char                    ***defvals,
+       writeptype              writeproc,
+       void                    *writeparm,
+       char                    *eol,
+       int                     rdncount,
+       unsigned long           opts,
+       char                    *base,
+       char                    *urlprefix
+)
+{
+    Debug( LDAP_DEBUG_TRACE, "ldap_entry2html\n", 0, 0, 0 );
+
+    if ( urlprefix == NULL ) {
+       urlprefix = DEF_LDAP_URL_PREFIX;
+    }
+
+    return( do_entry2text( ld, buf, base, entry, tmpl, defattrs, defvals,
+               writeproc, writeparm, eol, rdncount, opts, urlprefix ));
+}
+
+
+static int
+do_entry2text(
+       LDAP                    *ld,
+       char                    *buf,           /* NULL for use-internal */
+       char                    *base,          /* used for search actions */
+       LDAPMessage             *entry,
+       struct ldap_disptmpl    *tmpl,
+       char                    **defattrs,
+       char                    ***defvals,
+       writeptype              writeproc,
+       void                    *writeparm,
+       char                    *eol,
+       int                     rdncount,
+       unsigned long           opts,
+       char                    *urlprefix      /* if non-NULL, do HTML */
+)
+{
+    int                                i, err, html, show, labelwidth;
+    int                                freebuf,  freevals;
+    char                       *dn, **vals;
+    struct ldap_tmplitem       *rowp, *colp;
+
+    if (( dn = ldap_get_dn( ld, entry )) == NULL ) {
+       return( ld->ld_errno );
+    }
+
+    if ( buf == NULL ) {
+       if (( buf = malloc( LDAP_DTMPL_BUFSIZ )) == NULL ) {
+           ld->ld_errno = LDAP_NO_MEMORY;
+           free( dn );
+           return( ld->ld_errno );
+       }
+       freebuf = 1;
+    } else {
+       freebuf = 0;
+    }
+
+    html = ( urlprefix != NULL );
+
+    if ( html ) {
+       /*
+        * add HTML intro. and title
+        */
+       if (!(( opts & LDAP_DISP_OPT_HTMLBODYONLY ) != 0 )) {
+           sprintf( buf, "<HTML>%s<HEAD>%s<TITLE>%s%s - ", eol, eol, eol,
+                   ( tmpl == NULL ) ? "Entry" : tmpl->dt_name );
+           (*writeproc)( writeparm, buf, strlen( buf ));
+           output_dn( buf, dn, 0, rdncount, writeproc, writeparm, "", NULL );
+           sprintf( buf, "%s</TITLE>%s</HEAD>%s<BODY>%s<H3>%s - ", eol, eol,
+                   eol, eol, ( tmpl == NULL ) ? "Entry" : tmpl->dt_name );
+           (*writeproc)( writeparm, buf, strlen( buf ));
+           output_dn( buf, dn, 0, rdncount, writeproc, writeparm, "", NULL );
+           sprintf( buf, "</H3>%s", eol );
+           (*writeproc)( writeparm, buf, strlen( buf ));
+       }
+
+       if (( opts & LDAP_DISP_OPT_NONLEAF ) != 0 &&
+               ( vals = ldap_explode_dn( dn, 0 )) != NULL ) {
+           char        *untagged;
+
+           /*
+            * add "Move Up" link
+            */
+           sprintf( buf, "<A HREF=\"%s", urlprefix );
+           for ( i = 1; vals[ i ] != NULL; ++i ) {
+               if ( i > 1 ) {
+                    strcat_escaped( buf, ", " );
+               }
+               strcat_escaped( buf, vals[ i ] );
+           }
+           if ( vals[ 1 ] != NULL ) {
+               untagged = strchr( vals[ 1 ], '=' );
+           } else {
+               untagged = "=The World";
+           }
+           sprintf( buf + strlen( buf ),
+                   "%s\">Move Up To <EM>%s</EM></A>%s<BR>",
+                   ( vals[ 1 ] == NULL ) ? "??one" : "",
+                   ( untagged != NULL ) ? untagged + 1 : vals[ 1 ], eol, eol );
+           (*writeproc)( writeparm, buf, strlen( buf ));
+
+           /*
+            * add "Browse" link
+            */
+           untagged = strchr( vals[ 0 ], '=' );
+           sprintf( buf, "<A HREF=\"%s", urlprefix );
+           strcat_escaped( buf, dn );
+           sprintf( buf + strlen( buf ), "??one?(!(objectClass=dsa))\">Browse Below <EM>%s</EM></A>%s%s",
+                   ( untagged != NULL ) ? untagged + 1 : vals[ 0 ], eol, eol );
+           (*writeproc)( writeparm, buf, strlen( buf ));
+
+           ldap_value_free( vals );
+       }
+
+       (*writeproc)( writeparm, "<HR>", 4 );   /* horizontal rule */
+    } else {
+       (*writeproc)( writeparm, "\"", 1 );
+       output_dn( buf, dn, 0, rdncount, writeproc, writeparm, "", NULL );
+       sprintf( buf, "\"%s", eol );
+       (*writeproc)( writeparm, buf, strlen( buf ));
+    }
+
+    if ( tmpl != NULL && ( opts & LDAP_DISP_OPT_AUTOLABELWIDTH ) != 0 ) {
+       labelwidth = max_label_len( tmpl ) + 3;
+    } else {
+       labelwidth = DEF_LABEL_WIDTH;;
+    }
+
+    err = LDAP_SUCCESS;
+
+    if ( tmpl == NULL ) {
+       BerElement      *ber;
+       char            *attr;
+
+       ber = NULL;
+       for ( attr = ldap_first_attribute( ld, entry, &ber );
+               NONFATAL_LDAP_ERR( err ) && attr != NULL;
+               attr = ldap_next_attribute( ld, entry, ber )) {
+           if (( vals = ldap_get_values( ld, entry, attr )) == NULL ) {
+               freevals = 0;
+               if ( defattrs != NULL ) {
+                   for ( i = 0; defattrs[ i ] != NULL; ++i ) {
+                       if ( strcasecmp( attr, defattrs[ i ] ) == 0 ) {
+                           break;
+                       }
+                   }
+                   if ( defattrs[ i ] != NULL ) {
+                       vals = defvals[ i ];
+                   }
+               }
+           } else {
+               freevals = 1;
+           }
+
+           if ( islower( *attr )) {    /* cosmetic -- upcase attr. name */
+               *attr = toupper( *attr );
+           }
+
+           err = do_vals2text( ld, buf, vals, attr, labelwidth,
+                   LDAP_SYN_CASEIGNORESTR, writeproc, writeparm, eol, 
+                   rdncount, urlprefix );
+           if ( freevals ) {
+               ldap_value_free( vals );
+           }
+       }
+    } else {
+       for ( rowp = ldap_first_tmplrow( tmpl );
+               NONFATAL_LDAP_ERR( err ) && rowp != NULLTMPLITEM;
+               rowp = ldap_next_tmplrow( tmpl, rowp )) {
+           for ( colp = ldap_first_tmplcol( tmpl, rowp ); colp != NULLTMPLITEM;
+                   colp = ldap_next_tmplcol( tmpl, rowp, colp )) {
+               vals = NULL;
+               if ( colp->ti_attrname == NULL || ( vals = ldap_get_values( ld,
+                       entry, colp->ti_attrname )) == NULL ) {
+                   freevals = 0;
+                   if ( !LDAP_IS_TMPLITEM_OPTION_SET( colp,
+                           LDAP_DITEM_OPT_HIDEIFEMPTY ) && defattrs != NULL
+                           && colp->ti_attrname != NULL ) {
+                       for ( i = 0; defattrs[ i ] != NULL; ++i ) {
+                           if ( strcasecmp( colp->ti_attrname, defattrs[ i ] )
+                                   == 0 ) {
+                               break;
+                           }
+                       }
+                       if ( defattrs[ i ] != NULL ) {
+                           vals = defvals[ i ];
+                       }
+                   }
+               } else {
+                   freevals = 1;
+                   if ( LDAP_IS_TMPLITEM_OPTION_SET( colp,
+                           LDAP_DITEM_OPT_SORTVALUES ) && vals[ 0 ] != NULL
+                           && vals[ 1 ] != NULL ) {
+                       ldap_sort_values( ld, vals, ldap_sort_strcasecmp );
+                   }
+               }
+
+               /*
+                * don't bother even calling do_vals2text() if no values
+                * or boolean with value false and "hide if false" option set
+                */
+               show = ( vals != NULL && vals[ 0 ] != NULL );
+               if ( show && LDAP_GET_SYN_TYPE( colp->ti_syntaxid )
+                       == LDAP_SYN_TYPE_BOOLEAN && LDAP_IS_TMPLITEM_OPTION_SET(
+                       colp, LDAP_DITEM_OPT_HIDEIFFALSE ) &&
+                       toupper( vals[ 0 ][ 0 ] ) != 'T' ) {
+                   show = 0;
+               }
+
+               if ( colp->ti_syntaxid == LDAP_SYN_SEARCHACTION ) {
+                   if (( opts & LDAP_DISP_OPT_DOSEARCHACTIONS ) != 0 ) {
+                       if ( colp->ti_attrname == NULL || ( show &&
+                               toupper( vals[ 0 ][ 0 ] ) == 'T' )) {
+                           err = searchaction( ld, buf, base, entry, dn, colp,
+                                   labelwidth, rdncount, writeproc,
+                                   writeparm, eol, urlprefix );
+                       }
+                   }
+                   show = 0;
+               }
+
+               if ( show ) {
+                   err = do_vals2text( ld, buf, vals, colp->ti_label,
+                       labelwidth, colp->ti_syntaxid, writeproc, writeparm,
+                       eol, rdncount, urlprefix );
+               }
+
+               if ( freevals ) {
+                   ldap_value_free( vals );
+               }
+           }
+       }
+    }
+
+    if ( html  && !(( opts & LDAP_DISP_OPT_HTMLBODYONLY ) != 0 )) {
+       sprintf( buf, "</BODY>%s</HTML>%s", eol, eol );
+       (*writeproc)( writeparm, buf, strlen( buf ));
+    }
+
+    free( dn );
+    if ( freebuf ) {
+       free( buf );
+    }
+
+    return( err );
+}
+
+       
+int
+ldap_entry2text_search(
+       LDAP                    *ld,
+       char                    *dn,            /* if NULL, use entry */
+       char                    *base,          /* if NULL, no search actions */
+       LDAPMessage             *entry,         /* if NULL, use dn */
+       struct ldap_disptmpl*   tmpllist,       /* if NULL, load default file */
+       char                    **defattrs,
+       char                    ***defvals,
+       writeptype              writeproc,
+       void                    *writeparm,
+       char                    *eol,
+       int                     rdncount,       /* if 0, display full DN */
+       unsigned long           opts
+)
+{
+    Debug( LDAP_DEBUG_TRACE, "ldap_entry2text_search\n", 0, 0, 0 );
+
+    return( do_entry2text_search( ld, dn, base, entry, tmpllist, defattrs,
+           defvals, writeproc, writeparm, eol, rdncount, opts, NULL ));
+}
+
+
+
+int
+ldap_entry2html_search(
+       LDAP                    *ld,
+       char                    *dn,            /* if NULL, use entry */
+       char                    *base,          /* if NULL, no search actions */
+       LDAPMessage             *entry,         /* if NULL, use dn */
+       struct ldap_disptmpl*   tmpllist,       /* if NULL, load default file */
+       char                    **defattrs,
+       char                    ***defvals,
+       writeptype              writeproc,
+       void                    *writeparm,
+       char                    *eol,
+       int                     rdncount,       /* if 0, display full DN */
+       unsigned long           opts,
+       char                    *urlprefix
+)
+{
+    Debug( LDAP_DEBUG_TRACE, "ldap_entry2html_search\n", 0, 0, 0 );
+
+    return( do_entry2text_search( ld, dn, base, entry, tmpllist, defattrs,
+           defvals, writeproc, writeparm, eol, rdncount, opts, urlprefix ));
+}
+
+
+static int
+do_entry2text_search(
+       LDAP                    *ld,
+       char                    *dn,            /* if NULL, use entry */
+       char                    *base,          /* if NULL, no search actions */
+       LDAPMessage             *entry,         /* if NULL, use dn */
+       struct ldap_disptmpl*   tmpllist,       /* if NULL, load default file */
+       char                    **defattrs,
+       char                    ***defvals,
+       writeptype              writeproc,
+       void                    *writeparm,
+       char                    *eol,
+       int                     rdncount,       /* if 0, display full DN */
+       unsigned long           opts,
+       char                    *urlprefix
+)
+{
+    int                                err, freedn, freetmpls, html;
+    char                       *buf, **fetchattrs, **vals;
+    LDAPMessage                        *ldmp;
+    struct ldap_disptmpl       *tmpl;
+    struct timeval             timeout;
+
+    if ( dn == NULL && entry == NULLMSG ) {
+       ld->ld_errno = LDAP_PARAM_ERROR;
+       return( ld->ld_errno );
+    }
+
+    html = ( urlprefix != NULL );
+
+    timeout.tv_sec = SEARCH_TIMEOUT_SECS;
+    timeout.tv_usec = 0;
+
+    if (( buf = malloc( LDAP_DTMPL_BUFSIZ )) == NULL ) {
+       ld->ld_errno = LDAP_NO_MEMORY;
+       return( ld->ld_errno );
+    }
+
+    freedn = freetmpls = 0;
+    tmpl = NULL;
+
+    if ( tmpllist == NULL ) {
+       if (( err = ldap_init_templates( TEMPLATEFILE, &tmpllist )) != 0 ) {
+           sprintf( buf, "%sUnable to read template file %s (error %d)%s%s",
+                   html ? "<!-- " : "", TEMPLATEFILE, err,
+                   html ? "-->" : "", eol );
+           (*writeproc)( writeparm, buf, strlen( buf ));
+       }
+       freetmpls = 1;
+    }
+
+    if ( dn == NULL ) {
+       if (( dn = ldap_get_dn( ld, entry )) == NULL ) {
+           free( buf );
+           if ( freetmpls ) {
+               ldap_free_templates( tmpllist );
+           }
+           return( ld->ld_errno );
+       }
+       freedn = 1;
+    }
+
+
+    if ( tmpllist != NULL ) {
+       ldmp = NULLMSG;
+
+       if ( entry == NULL ) {
+           char        *ocattrs[2];
+
+           ocattrs[0] = OCATTRNAME;
+           ocattrs[1] = NULL;
+#ifdef CLDAP
+           if ( LDAP_IS_CLDAP( ld ))
+                   err = cldap_search_s( ld, dn, LDAP_SCOPE_BASE,
+                       "objectClass=*", ocattrs, 0, &ldmp, NULL );
+           else
+#endif /* CLDAP */
+                   err = ldap_search_st( ld, dn, LDAP_SCOPE_BASE,
+                           "objectClass=*", ocattrs, 0, &timeout, &ldmp );
+
+           if ( err == LDAP_SUCCESS ) {
+               entry = ldap_first_entry( ld, ldmp );
+           }
+       }
+
+       if ( entry != NULL ) {
+           vals = ldap_get_values( ld, entry, OCATTRNAME );
+           tmpl = ldap_oc2template( vals, tmpllist );
+           if ( vals != NULL ) {
+               ldap_value_free( vals );
+           }
+       }
+       if ( ldmp != NULL ) {
+           ldap_msgfree( ldmp );
+       }
+    }
+
+    entry = NULL;
+
+    if ( tmpl == NULL ) {
+       fetchattrs = NULL;
+    } else {
+       fetchattrs = ldap_tmplattrs( tmpl, NULL, 1, LDAP_SYN_OPT_DEFER );
+    }
+
+#ifdef CLDAP
+    if ( LDAP_IS_CLDAP( ld ))
+       err = cldap_search_s( ld, dn, LDAP_SCOPE_BASE, "objectClass=*",
+               fetchattrs, 0, &ldmp, NULL );
+    else
+#endif /* CLDAP */
+       err = ldap_search_st( ld, dn, LDAP_SCOPE_BASE, "objectClass=*",
+               fetchattrs, 0, &timeout, &ldmp );
+
+    if ( freedn ) {
+       free( dn );
+    }
+    if ( fetchattrs != NULL ) {
+       ldap_value_free( fetchattrs );
+    }
+
+    if ( err != LDAP_SUCCESS ||
+           ( entry = ldap_first_entry( ld, ldmp )) == NULL ) {
+       if ( freetmpls ) {
+            ldap_free_templates( tmpllist );
+        }
+       free( buf );
+       return( ld->ld_errno );
+    }
+
+    err = do_entry2text( ld, buf, base, entry, tmpl, defattrs, defvals,
+           writeproc, writeparm, eol, rdncount, opts, urlprefix );
+
+    free( buf );
+    if ( freetmpls ) {
+       ldap_free_templates( tmpllist );
+    }
+    ldap_msgfree( ldmp );
+    return( err );
+}
+           
+
+int
+ldap_vals2text(
+       LDAP                    *ld,
+       char                    *buf,           /* NULL for "use internal" */
+       char                    **vals,
+       char                    *label,
+       int                     labelwidth,     /* 0 means use default */
+       unsigned long           syntaxid,
+       writeptype              writeproc,
+       void                    *writeparm,
+       char                    *eol,
+       int                     rdncount
+)
+{
+    Debug( LDAP_DEBUG_TRACE, "ldap_vals2text\n", 0, 0, 0 );
+
+    return( do_vals2text( ld, buf, vals, label, labelwidth, syntaxid,
+               writeproc, writeparm, eol, rdncount, NULL ));
+}
+
+
+int
+ldap_vals2html(
+       LDAP                    *ld,
+       char                    *buf,           /* NULL for "use internal" */
+       char                    **vals,
+       char                    *label,
+       int                     labelwidth,     /* 0 means use default */
+       unsigned long           syntaxid,
+       writeptype              writeproc,
+       void                    *writeparm,
+       char                    *eol,
+       int                     rdncount,
+       char                    *urlprefix
+)
+{
+    Debug( LDAP_DEBUG_TRACE, "ldap_vals2html\n", 0, 0, 0 );
+
+    if ( urlprefix == NULL ) {
+       urlprefix = DEF_LDAP_URL_PREFIX;
+    }
+
+    return( do_vals2text( ld, buf, vals, label, labelwidth, syntaxid,
+               writeproc, writeparm, eol, rdncount, urlprefix ));
+}
+
+
+static int
+do_vals2text(
+       LDAP                    *ld,
+       char                    *buf,           /* NULL for "use internal" */
+       char                    **vals,
+       char                    *label,
+       int                     labelwidth,     /* 0 means use default */
+       unsigned long           syntaxid,
+       writeptype              writeproc,
+       void                    *writeparm,
+       char                    *eol,
+       int                     rdncount,
+       char                    *urlprefix
+)
+{
+    int                i, html, writeoutval, freebuf, notascii;
+    char       *p, *s, *outval;
+
+
+    if ( vals == NULL ) {
+       return( LDAP_SUCCESS );
+    }
+
+    html = ( urlprefix != NULL );
+
+    switch( LDAP_GET_SYN_TYPE( syntaxid )) {
+    case LDAP_SYN_TYPE_TEXT:
+    case LDAP_SYN_TYPE_BOOLEAN:
+       break;          /* we only bother with these two types... */
+    default:
+       return( LDAP_SUCCESS );
+    }
+
+    if ( labelwidth == 0 || labelwidth < 0 ) {
+       labelwidth = DEF_LABEL_WIDTH;
+    }
+
+    if ( buf == NULL ) {
+       if (( buf = malloc( LDAP_DTMPL_BUFSIZ )) == NULL ) {
+           ld->ld_errno = LDAP_NO_MEMORY;
+           return( ld->ld_errno );
+       }
+       freebuf = 1;
+    } else {
+       freebuf = 0;
+    }
+
+    output_label( buf, label, labelwidth, writeproc, writeparm, eol, html );
+
+    for ( i = 0; vals[ i ] != NULL; ++i ) {
+       for ( p = vals[ i ]; *p != '\0'; ++p ) {
+           if ( !isascii( *p )) {
+               break;
+           }
+       }
+       notascii = ( *p != '\0' );
+       outval = notascii ? "(unable to display non-ASCII text value)"
+               : vals[ i ];
+
+       writeoutval = 0;        /* if non-zero, write outval after switch */
+
+       switch( syntaxid ) {
+       case LDAP_SYN_CASEIGNORESTR:
+           ++writeoutval;
+           break;
+
+       case LDAP_SYN_RFC822ADDR:
+           if ( html ) {
+               strcpy( buf, "<DD><A HREF=\"mailto:" );
+               strcat_escaped( buf, outval );
+               sprintf( buf + strlen( buf ), "\">%s</A><BR>%s", outval, eol );
+               (*writeproc)( writeparm, buf, strlen( buf ));
+           } else {
+               ++writeoutval;
+           }
+           break;
+
+       case LDAP_SYN_DN:       /* for now */
+           output_dn( buf, outval, labelwidth, rdncount, writeproc,
+                   writeparm, eol, urlprefix );
+           break;
+
+       case LDAP_SYN_MULTILINESTR:
+           if ( i > 0 && !html ) {
+               output_label( buf, label, labelwidth, writeproc,
+                       writeparm, eol, html );
+           }
+
+           p = s = outval;
+           while (( s = strchr( s, '$' )) != NULL ) {
+               *s++ = '\0';
+               while ( isspace( *s )) {
+                   ++s;
+               }
+               if ( html ) {
+                   sprintf( buf, "<DD>%s<BR>%s", p, eol );
+               } else {
+                   sprintf( buf, "%-*s%s%s", labelwidth, " ", p, eol );
+               }
+               (*writeproc)( writeparm, buf, strlen( buf ));
+               p = s;
+           }
+           outval = p;
+           ++writeoutval;
+           break;
+
+       case LDAP_SYN_BOOLEAN:
+           outval = toupper( outval[ 0 ] ) == 'T' ? "TRUE" : "FALSE";
+           ++writeoutval;
+           break;
+
+       case LDAP_SYN_TIME:
+       case LDAP_SYN_DATE:
+           outval = time2text( outval, syntaxid == LDAP_SYN_DATE );
+           ++writeoutval;
+           break;
+
+       case LDAP_SYN_LABELEDURL:
+           if ( !notascii && ( p = strchr( outval, '$' )) != NULL ) {
+               *p++ = '\0';
+               while ( isspace( *p )) {
+                   ++p;
+               }
+               s = outval;
+           } else if ( !notascii && ( s = strchr( outval, ' ' )) != NULL ) {
+               *s++ = '\0';
+               while ( isspace( *s )) {
+                   ++s;
+               }
+               p = outval;
+           } else {
+               s = "URL";
+               p = outval;
+           }
+
+           /*
+            * at this point `s' points to the label & `p' to the URL
+            */
+           if ( html ) {
+               sprintf( buf, "<DD><A HREF=\"%s\">%s</A><BR>%s", p, s, eol );
+           } else {
+               sprintf( buf, "%-*s%s%s%-*s%s%s", labelwidth, " ",
+                   s, eol, labelwidth + 2, " ",p , eol );
+           }
+           (*writeproc)( writeparm, buf, strlen( buf ));
+           break;
+
+       default:
+           sprintf( buf, " Can't display item type %ld%s",
+                   syntaxid, eol );
+           (*writeproc)( writeparm, buf, strlen( buf ));
+       }
+
+       if ( writeoutval ) {
+           if ( html ) {
+               sprintf( buf, "<DD>%s<BR>%s", outval, eol );
+           } else {
+               sprintf( buf, "%-*s%s%s", labelwidth, " ", outval, eol );
+           }
+           (*writeproc)( writeparm, buf, strlen( buf ));
+       }
+    }
+
+    if ( freebuf ) {
+       free( buf );
+    }
+
+    return( LDAP_SUCCESS );
+}
+
+
+static int
+max_label_len( struct ldap_disptmpl *tmpl )
+{
+    struct ldap_tmplitem       *rowp, *colp;
+    int                                len, maxlen;
+
+    maxlen = 0;
+
+    for ( rowp = ldap_first_tmplrow( tmpl ); rowp != NULLTMPLITEM;
+           rowp = ldap_next_tmplrow( tmpl, rowp )) {
+       for ( colp = ldap_first_tmplcol( tmpl, rowp ); colp != NULLTMPLITEM;
+               colp = ldap_next_tmplcol( tmpl, rowp, colp )) {
+           if (( len = strlen( colp->ti_label )) > maxlen ) {
+               maxlen = len;
+           }
+       }
+    }
+
+    return( maxlen );
+}
+
+
+static int
+output_label( char *buf, char *label, int width, writeptype writeproc,
+       void *writeparm, char *eol, int html )
+{
+    char       *p;
+
+    if ( html ) {
+       sprintf( buf, "<DT><B>%s</B>", label );
+    } else {
+       sprintf( buf, " %s:", label );
+       p = buf + strlen( buf );
+
+       while ( p - buf < width ) {
+           *p++ = ' ';
+       }
+
+       *p = '\0';
+       strcat( buf, eol );
+    }
+
+    return ((*writeproc)( writeparm, buf, strlen( buf )));
+}
+
+
+static int
+output_dn( char *buf, char *dn, int width, int rdncount,
+       writeptype writeproc, void *writeparm, char *eol, char *urlprefix )
+{
+    char       **dnrdns;
+    int                i;
+
+    if (( dnrdns = ldap_explode_dn( dn, 1 )) == NULL ) {
+       return( -1 );
+    }
+
+    if ( urlprefix != NULL ) {
+       sprintf( buf, "<DD><A HREF=\"%s", urlprefix );
+       strcat_escaped( buf, dn );
+       strcat( buf, "\">" );
+    } else if ( width > 0 ) {
+       sprintf( buf, "%-*s", width, " " );
+    } else {
+       *buf = '\0';
+    }
+
+    for ( i = 0; dnrdns[ i ] != NULL && ( rdncount == 0 || i < rdncount );
+           ++i ) {
+       if ( i > 0 ) {
+           strcat( buf, ", " );
+       }
+       strcat( buf, dnrdns[ i ] );
+    }
+
+    if ( urlprefix != NULL ) {
+       strcat( buf, "</A><BR>" );
+    }
+
+    ldap_value_free( dnrdns );
+
+    strcat( buf, eol );
+
+    return ((*writeproc)( writeparm, buf, strlen( buf )));
+}
+
+
+
+#define HREF_CHAR_ACCEPTABLE( c )      (( c >= '-' && c <= '9' ) ||    \
+                                        ( c >= '@' && c <= 'Z' ) ||    \
+                                        ( c == '_' ) ||                \
+                                        ( c >= 'a' && c <= 'z' ))
+
+static void
+strcat_escaped( char *s1, char *s2 )
+{
+    char       *p, *q;
+    char       *hexdig = "0123456789ABCDEF";
+
+    p = s1 + strlen( s1 );
+    for ( q = s2; *q != '\0'; ++q ) {
+       if ( HREF_CHAR_ACCEPTABLE( *q )) {
+           *p++ = *q;
+       } else {
+           *p++ = '%';
+           *p++ = hexdig[ *q >> 4 ];
+           *p++ = hexdig[ *q & 0x0F ];
+       }
+    }
+
+    *p = '\0';
+}
+
+
+#define GET2BYTENUM( p )       (( *p - '0' ) * 10 + ( *(p+1) - '0' ))
+
+static char *
+time2text( char *ldtimestr, int dateonly )
+{
+    struct tm          t;
+    char               *p, *timestr, zone, *fmterr = "badly formatted time";
+    time_t             gmttime;
+
+    memset( (char *)&t, 0, sizeof( struct tm ));
+    if ( (int) strlen( ldtimestr ) < 13 ) {
+       return( fmterr );
+    }
+
+    for ( p = ldtimestr; p - ldtimestr < 12; ++p ) {
+       if ( !isdigit( *p )) {
+           return( fmterr );
+       }
+    }
+
+    p = ldtimestr;
+    t.tm_year = GET2BYTENUM( p ); p += 2;
+    t.tm_mon = GET2BYTENUM( p ) - 1; p += 2;
+    t.tm_mday = GET2BYTENUM( p ); p += 2;
+    t.tm_hour = GET2BYTENUM( p ); p += 2;
+    t.tm_min = GET2BYTENUM( p ); p += 2;
+    t.tm_sec = GET2BYTENUM( p ); p += 2;
+
+    if (( zone = *p ) == 'Z' ) {       /* GMT */
+       zone = '\0';    /* no need to indicate on screen, so we make it null */
+    }
+
+    gmttime = gtime( &t );
+    timestr = ctime( &gmttime );
+
+    timestr[ strlen( timestr ) - 1 ] = zone;   /* replace trailing newline */
+    if ( dateonly ) {
+       strcpy( timestr + 11, timestr + 20 );
+    }
+
+    return( timestr );
+}
+
+
+
+/* gtime.c - inverse gmtime */
+
+#if !defined( MACOS ) && !defined( _WIN32 ) && !defined( DOS )
+#include <sys/time.h>
+#endif /* !MACOS */
+
+/* gtime(): the inverse of localtime().
+       This routine was supplied by Mike Accetta at CMU many years ago.
+ */
+
+static int     dmsize[] = {
+    31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+#define        dysize(y)       \
+       (((y) % 4) ? 365 : (((y) % 100) ? 366 : (((y) % 400) ? 365 : 366)))
+
+#define        YEAR(y)         ((y) >= 100 ? (y) : (y) + 1900)
+
+/* \f */
+
+static long    gtime ( struct tm *tm )
+{
+    register int    i,
+                    sec,
+                    mins,
+                    hour,
+                    mday,
+                    mon,
+                    year;
+    register long   result;
+
+    if ((sec = tm -> tm_sec) < 0 || sec > 59
+           || (mins = tm -> tm_min) < 0 || mins > 59
+           || (hour = tm -> tm_hour) < 0 || hour > 24
+           || (mday = tm -> tm_mday) < 1 || mday > 31
+           || (mon = tm -> tm_mon + 1) < 1 || mon > 12)
+       return ((long) -1);
+    if (hour == 24) {
+       hour = 0;
+       mday++;
+    }
+    year = YEAR (tm -> tm_year);
+
+    result = 0L;
+    for (i = 1970; i < year; i++)
+       result += dysize (i);
+    if (dysize (year) == 366 && mon >= 3)
+       result++;
+    while (--mon)
+       result += dmsize[mon - 1];
+    result += mday - 1;
+    result = 24 * result + hour;
+    result = 60 * result + mins;
+    result = 60 * result + sec;
+
+    return result;
+}
+
+static int
+searchaction( LDAP *ld, char *buf, char *base, LDAPMessage *entry, char *dn,
+       struct ldap_tmplitem *tip, int labelwidth, int rdncount,
+       writeptype writeproc, void *writeparm, char *eol, char *urlprefix )
+{
+    int                        err, lderr, i, count, html;
+    char               **vals, **members;
+    char               *value, *filtpattern, *attr, *selectname;
+    char               *retattrs[2], filter[ 256 ];
+    LDAPMessage                *ldmp;
+    struct timeval     timeout;
+
+    html = ( urlprefix != NULL );
+
+    for ( i = 0; tip->ti_args != NULL && tip->ti_args[ i ] != NULL; ++i ) {
+       ;
+    }
+    if ( i < 3 ) {
+       return( LDAP_PARAM_ERROR );
+    }
+    attr = tip->ti_args[ 0 ];
+    filtpattern = tip->ti_args[ 1 ];
+    retattrs[ 0 ] = tip->ti_args[ 2 ];
+    retattrs[ 1 ] = NULL;
+    selectname = tip->ti_args[ 3 ];
+
+    vals = NULL;
+    if ( attr == NULL ) {
+       value = NULL;
+    } else if ( strcasecmp( attr, "-dnb" ) == 0 ) {
+       return( LDAP_PARAM_ERROR );
+    } else if ( strcasecmp( attr, "-dnt" ) == 0 ) {
+       value = dn;
+    } else if (( vals = ldap_get_values( ld, entry, attr )) != NULL ) {
+       value = vals[ 0 ];
+    } else {
+       value = NULL;
+    }
+
+    ldap_build_filter( filter, sizeof( filter ), filtpattern, NULL, NULL, NULL,
+           value, NULL );
+
+    if ( html ) {
+       /*
+        * if we are generating HTML, we add an HREF link that embodies this
+        * search action as an LDAP URL, instead of actually doing the search
+        * now.
+        */
+       sprintf( buf, "<DT><A HREF=\"%s", urlprefix );
+       if ( base != NULL ) {
+           strcat_escaped( buf, base );
+       }
+       strcat( buf, "??sub?" );
+       strcat_escaped( buf, filter );
+       sprintf( buf + strlen( buf ), "\"><B>%s</B></A><DD><BR>%s",
+               tip->ti_label, eol );
+       if ((*writeproc)( writeparm, buf, strlen( buf )) < 0 ) {
+           return( LDAP_LOCAL_ERROR );
+       }
+       return( LDAP_SUCCESS );
+    }
+
+    timeout.tv_sec = SEARCH_TIMEOUT_SECS;
+    timeout.tv_usec = 0;
+
+#ifdef CLDAP
+    if ( LDAP_IS_CLDAP( ld ))
+       lderr = cldap_search_s( ld, base, LDAP_SCOPE_SUBTREE, filter, retattrs,
+               0, &ldmp, NULL );
+    else
+#endif /* CLDAP */
+       lderr = ldap_search_st( ld, base, LDAP_SCOPE_SUBTREE, filter, retattrs,
+               0, &timeout, &ldmp );
+
+    if ( lderr == LDAP_SUCCESS || NONFATAL_LDAP_ERR( lderr )) {
+       if (( count = ldap_count_entries( ld, ldmp )) > 0 ) {
+           if (( members = (char **)malloc( (count + 1) * sizeof(char *)))
+                   == NULL ) {
+               err = LDAP_NO_MEMORY;
+           } else {
+               for ( i = 0, entry = ldap_first_entry( ld, ldmp );
+                       entry != NULL;
+                       entry = ldap_next_entry( ld, entry ), ++i ) {
+                   members[ i ] = ldap_get_dn( ld, entry );
+               }
+               members[ i ] = NULL;
+
+               ldap_sort_values( ld, members, ldap_sort_strcasecmp );
+
+               err = do_vals2text( ld, NULL, members, tip->ti_label,
+                       html ? -1 : 0, LDAP_SYN_DN, writeproc, writeparm,
+                       eol, rdncount, urlprefix );
+
+               ldap_value_free( members );
+           }
+       }
+       ldap_msgfree( ldmp );
+    }
+
+    
+    if ( vals != NULL ) {
+       ldap_value_free( vals );
+    }
+
+    return(( err == LDAP_SUCCESS ) ? lderr : err );
+}
diff --git a/libraries/libldap/tmpltest.c b/libraries/libldap/tmpltest.c
new file mode 100644 (file)
index 0000000..d108375
--- /dev/null
@@ -0,0 +1,277 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include "lber.h"
+#include "ldap.h"
+#include "disptmpl.h"
+#include "srchpref.h"
+
+#ifdef MACOS
+#include <stdlib.h>
+#include <console.h>
+#endif /* MACOS */
+
+#ifdef NEEDPROTOS
+void dump_tmpl( struct ldap_disptmpl *tmpl );
+void dump_srchpref( struct ldap_searchobj *sp );
+#else /* NEEDPROTOS */
+void dump_tmpl();
+void dump_srchpref();
+#endif /* NEEDPROTOS */
+
+
+#define NULLSTRINGIFNULL( s )  ( s == NULL ? "(null)" : s )
+
+
+int
+main( int argc, char **argv )
+{
+    struct ldap_disptmpl       *templates, *dtp;
+    struct ldap_searchobj      *so, *sop;
+    int                                err;
+
+#ifdef MACOS
+       ccommand( &argv );
+       for ( argc = 0; argv[ argc ] != NULL; ++argc ) {
+           ;
+       }
+       cshow( stdout );
+#endif /* MACOS */
+
+    if (( err = ldap_init_templates( "ldaptemplates.conf", &templates ))
+           != 0 ) {
+       fprintf( stderr, "ldap_init_templates failed (%d)\n", err );
+       exit( 1 );
+    }
+
+    if (( err = ldap_init_searchprefs( "ldapsearchprefs.conf", &so ))
+           != 0 ) {
+       fprintf( stderr, "ldap_init_searchprefs failed (%d)\n", err );
+       exit( 1 );
+    }
+
+    if ( argc == 1 ) {
+       printf( "*** Display Templates:\n" );
+       for ( dtp = ldap_first_disptmpl( templates ); dtp != NULLDISPTMPL;
+               dtp = ldap_next_disptmpl( templates, dtp )) {
+           dump_tmpl( dtp );
+           printf( "\n\n" );
+       }
+
+       printf( "\n\n*** Search Objects:\n" );
+       for ( sop = ldap_first_searchobj( so ); sop != NULLSEARCHOBJ;
+                   sop = ldap_next_searchobj( so, sop )) {
+           dump_srchpref( sop );
+           printf( "\n\n" );
+       }
+
+    } else {
+       if (( dtp = ldap_oc2template( ++argv, templates )) == NULL ) {
+           fprintf( stderr, "no matching template found\n" );
+       } else {
+           dump_tmpl( dtp );
+       }
+    }
+
+
+    ldap_free_templates( templates );
+    ldap_free_searchprefs( so );
+
+    exit( 0 );
+}
+
+
+static char *syn_name[] = {
+    "?", "CIS", "MLS", "DN", "BOOL", "JPEG", "JPEGBTN", "FAX", "FAXBTN",
+    "AUDIOBTN", "TIME", "DATE", "URL", "SEARCHACT", "LINKACT", "ADDDNACT",
+    "VERIFYACT",
+};
+
+static char *syn_type[] = {
+    "?", "txt", "img", "?", "bool", "?", "?", "?", "btn",
+    "?", "?", "?", "?", "?", "?", "?",
+    "action", "?"
+};
+
+static char *includeattrs[] = { "objectClass", "sn", NULL };
+
+static char *item_opts[] = {
+    "ro", "sort", "1val", "hide", "required", "hideiffalse", NULL
+};
+
+static unsigned long item_opt_vals[] = {
+    LDAP_DITEM_OPT_READONLY,           LDAP_DITEM_OPT_SORTVALUES,
+    LDAP_DITEM_OPT_SINGLEVALUED,       LDAP_DITEM_OPT_HIDEIFEMPTY,
+    LDAP_DITEM_OPT_VALUEREQUIRED,      LDAP_DITEM_OPT_HIDEIFFALSE,
+};
+
+
+void
+dump_tmpl( struct ldap_disptmpl *tmpl )
+{
+    struct ldap_tmplitem       *rowp, *colp;
+    int                                i, rowcnt, colcnt;
+    char                       **fetchattrs;
+    struct ldap_oclist         *ocp;
+    struct ldap_adddeflist     *adp;
+
+    printf( "** Template \"%s\" (plural \"%s\", icon \"%s\")\n",
+           NULLSTRINGIFNULL( tmpl->dt_name ),
+           NULLSTRINGIFNULL( tmpl->dt_pluralname ),
+           NULLSTRINGIFNULL( tmpl->dt_iconname ));
+
+    printf( "object class list:\n" );
+    for ( ocp = tmpl->dt_oclist; ocp != NULL; ocp = ocp->oc_next ) {
+       for ( i = 0; ocp->oc_objclasses[ i ] != NULL; ++i ) {
+           printf( "%s%s", i == 0 ? "  " : " & ",
+                   NULLSTRINGIFNULL( ocp->oc_objclasses[ i ] ));
+       }
+       putchar( '\n' );
+    }
+    putchar( '\n' );
+
+    printf( "template options:          " );
+    if ( tmpl->dt_options == 0L ) {
+       printf( "NONE\n" );
+    } else {
+       printf( "%s %s %s\n", LDAP_IS_DISPTMPL_OPTION_SET( tmpl,
+               LDAP_DTMPL_OPT_ADDABLE ) ? "addable" : "",
+               LDAP_IS_DISPTMPL_OPTION_SET( tmpl, LDAP_DTMPL_OPT_ALLOWMODRDN )
+               ? "modrdn" : "",
+               LDAP_IS_DISPTMPL_OPTION_SET( tmpl, LDAP_DTMPL_OPT_ALTVIEW )
+               ? "altview" : "" );
+    }
+
+    printf( "authenticate as attribute: %s\n", tmpl->dt_authattrname != NULL ?
+           tmpl->dt_authattrname : "<default>" );
+
+    printf( "default RDN attribute:     %s\n", tmpl->dt_defrdnattrname != NULL ?
+           tmpl->dt_defrdnattrname : "NONE" );
+
+    printf( "default add location:      %s\n", tmpl->dt_defaddlocation != NULL ?
+           tmpl->dt_defaddlocation : "NONE" );
+
+    printf( "\nnew entry value default rules:\n" );
+    for ( adp = tmpl->dt_adddeflist; adp != NULL; adp = adp->ad_next ) {
+       if ( adp->ad_source == LDAP_ADSRC_CONSTANTVALUE ) {
+           printf( "  attribute %s <-- constant value \"%s\"\n",
+               NULLSTRINGIFNULL( adp->ad_attrname),
+               NULLSTRINGIFNULL( adp->ad_value ));
+       } else {
+           printf( "  attribute %s <-- adder's DN\n",
+                   NULLSTRINGIFNULL( adp->ad_attrname ));
+       }
+    }
+    putchar( '\n' );
+
+    printf( "\nfetch attributes & values:\n" );
+    if (( fetchattrs = ldap_tmplattrs( tmpl, includeattrs, 1,
+               LDAP_SYN_OPT_DEFER )) == NULL ) {
+       printf( "  <none>\n" );
+    } else {
+       for ( i = 0; fetchattrs[ i ] != NULL; ++i ) {
+           printf( "  %s\n", fetchattrs[ i ] );
+           free( fetchattrs[ i ] );
+       }
+       free( (char *)fetchattrs );
+    }
+
+    printf( "\nfetch attributes only:\n" );
+    if (( fetchattrs = ldap_tmplattrs( tmpl, NULL, 0,
+               LDAP_SYN_OPT_DEFER )) == NULL ) {
+       printf( "  <none>\n" );
+    } else {
+       for ( i = 0; fetchattrs[ i ] != NULL; ++i ) {
+           printf( "  %s\n", fetchattrs[ i ] );
+           free( fetchattrs[ i ] );
+       }
+       free( (char *)fetchattrs );
+    }
+
+    printf( "\ntemplate items:\n" );
+    rowcnt = 0;
+    for ( rowp = ldap_first_tmplrow( tmpl ); rowp != NULLTMPLITEM;
+           rowp = ldap_next_tmplrow( tmpl, rowp )) {
+       ++rowcnt;
+       colcnt = 0;
+       for ( colp = ldap_first_tmplcol( tmpl, rowp ); colp != NULLTMPLITEM;
+               colp = ldap_next_tmplcol( tmpl, rowp, colp )) {
+           ++colcnt;
+           printf( "  %2d-%d: %s (%s%s", rowcnt, colcnt,
+               syn_name[ colp->ti_syntaxid & 0x0000FFFF ],
+               syn_type[ LDAP_GET_SYN_TYPE( colp->ti_syntaxid ) >> 24 ],
+               (( LDAP_GET_SYN_OPTIONS( colp->ti_syntaxid ) &
+               LDAP_SYN_OPT_DEFER ) != 0 ) ? ",defer" : "" );
+
+           for ( i = 0; item_opts[ i ] != NULL; ++i ) {
+               if ( LDAP_IS_TMPLITEM_OPTION_SET( colp, item_opt_vals[ i ] )) {
+                   printf( ",%s", NULLSTRINGIFNULL( item_opts[ i ] ));
+               }
+           }
+
+           printf( "), %s, %s", NULLSTRINGIFNULL( colp->ti_attrname ),
+                   NULLSTRINGIFNULL( colp->ti_label ));
+           if ( colp->ti_args != NULL ) {
+               printf( ",args=" );
+               for ( i = 0; colp->ti_args[ i ] != NULL; ++i ) {
+                   printf( "<%s>", NULLSTRINGIFNULL( colp->ti_args[ i ] ));
+               }
+           }
+
+           putchar( '\n' );
+       }
+    }
+}
+
+
+void
+dump_srchpref( struct ldap_searchobj *so )
+{
+    int i;
+    struct ldap_searchattr *sa;
+    struct ldap_searchmatch *sm;
+
+    printf( "Object type prompt:  %s\n",
+           NULLSTRINGIFNULL( so->so_objtypeprompt ));
+    printf( "Options:             %s\n",
+           LDAP_IS_SEARCHOBJ_OPTION_SET( so, LDAP_SEARCHOBJ_OPT_INTERNAL ) ?
+           "internal" : "NONE" );
+    printf( "Prompt:              %s\n", NULLSTRINGIFNULL( so->so_prompt ));
+    printf( "Scope:               " );
+    switch ( so->so_defaultscope ) {
+    case LDAP_SCOPE_BASE:
+       printf( "LDAP_SCOPE_BASE" );
+       break;
+    case LDAP_SCOPE_ONELEVEL:
+       printf( "LDAP_SCOPE_ONELEVEL" );
+       break;
+    case LDAP_SCOPE_SUBTREE:
+       printf( "LDAP_SCOPE_SUBTREE" );
+       break;
+    default:
+       printf("*** unknown!" );
+    }
+    puts( "\n" );
+    printf( "Filter prefix:       %s\n",
+           NULLSTRINGIFNULL( so->so_filterprefix ));
+    printf( "Filter tag:          %s\n",
+           NULLSTRINGIFNULL( so->so_filtertag ));
+    printf( "Default select attr: %s\n",
+           NULLSTRINGIFNULL( so->so_defaultselectattr ));
+    printf( "Default select text: %s\n",
+           NULLSTRINGIFNULL( so->so_defaultselecttext ));
+    printf( "Searchable attributes ---- \n" );
+    for ( sa = so->so_salist; sa != NULL; sa = sa->sa_next ) {
+       printf( "  Label: %s\n", NULLSTRINGIFNULL( sa->sa_attrlabel ));
+       printf( "  Attribute: %s\n", NULLSTRINGIFNULL( sa->sa_attr ));
+       printf( "  Select attr: %s\n", NULLSTRINGIFNULL( sa->sa_selectattr ));
+       printf( "  Select text: %s\n", NULLSTRINGIFNULL( sa->sa_selecttext ));
+       printf( "  Match types ---- \n" );
+       for ( i = 0, sm = so->so_smlist; sm != NULL; i++, sm = sm->sm_next ) {
+           if (( sa->sa_matchtypebitmap >> i ) & 1 ) {
+               printf( "    %s (%s)\n",
+                       NULLSTRINGIFNULL( sm->sm_matchprompt ),
+                       NULLSTRINGIFNULL( sm->sm_filter ));
+           }
+       }
+    }
+}
diff --git a/libraries/libldap/ufn.c b/libraries/libldap/ufn.c
new file mode 100644 (file)
index 0000000..9596adf
--- /dev/null
@@ -0,0 +1,510 @@
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  ufn.c
+ */
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1993 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef MACOS
+#include <stdlib.h>
+#include "macos.h"
+#else /* MACOS */
+#if defined( DOS ) || defined( _WIN32 )
+#include "msdos.h"
+#else /* DOS */
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#endif /* DOS */
+#endif /* MACOS */
+
+#include "lber.h"
+#include "ldap.h"
+
+#ifdef NEEDPROTOS
+typedef int (*cancelptype)( void *cancelparm );
+#else /* NEEDPROTOS */
+typedef int (*cancelptype)();
+#endif /* NEEDPROTOS */
+
+#ifdef NEEDPROTOS
+static int ldap_ufn_search_ctx( LDAP *ld, char **ufncomp, int ncomp, 
+       char *prefix, char **attrs, int attrsonly, LDAPMessage **res, 
+       cancelptype cancelproc, void *cancelparm, char *tag1, char *tag2,
+       char *tag3 );
+static LDAPMessage *ldap_msg_merge( LDAP *ld, LDAPMessage *a, LDAPMessage *b );
+static LDAPMessage *ldap_ufn_expand( LDAP *ld, cancelptype cancelproc,
+       void *cancelparm, char **dns, char *filter, int scope,
+       char **attrs, int aonly, int *err );
+LDAPFiltDesc *ldap_ufn_setfilter( LDAP *ld, char *fname );
+#else /* NEEDPROTOS */
+static LDAPMessage *ldap_msg_merge();
+static LDAPMessage *ldap_ufn_expand();
+LDAPFiltDesc *ldap_ufn_setfilter();
+#endif /* NEEDPROTOS */
+
+/*
+ * ldap_ufn_search_ctx - do user friendly searching; provide cancel feature;
+ *                     specify ldapfilter.conf tags for each phase of search
+ *
+ *     ld              LDAP descriptor
+ *     ufncomp         the exploded user friendly name to look for
+ *     ncomp           number of elements in ufncomp
+ *     prefix          where to start searching
+ *     attrs           list of attribute types to return for matches
+ *     attrsonly       1 => attributes only 0 => attributes and values
+ *     res             will contain the result of the search
+ *     cancelproc      routine that returns non-zero if operation should be
+ *                     cancelled.  This can be NULL.  If it is non-NULL, the
+ *                     routine will be called periodically.
+ *     cancelparm      void * that is passed to cancelproc
+ *     tag[123]        the ldapfilter.conf tag that will be used in phases
+ *                     1, 2, and 3 of the search, respectively
+ *
+ * Example:
+ *     char            *attrs[] = { "mail", "title", 0 };
+ *     char            *ufncomp[] = { "howes", "umich", "us", 0 }
+ *     LDAPMessage     *res;
+ *     error = ldap_ufn_search_ctx( ld, ufncomp, 3, NULL, attrs, attrsonly,
+ *                     &res, acancelproc, along, "ufn first",
+ *                     "ufn intermediate", "ufn last" );
+ */
+
+static int
+ldap_ufn_search_ctx( LDAP *ld, char **ufncomp, int ncomp, char *prefix,
+       char **attrs, int attrsonly, LDAPMessage **res, cancelptype cancelproc,
+       void *cancelparm, char *tag1, char *tag2, char *tag3 )
+{
+       char            *dn, *ftag;
+       char            **dns;
+       int             max, i, err, scope, phase, tries;
+       LDAPFiltInfo    *fi;
+       LDAPMessage     *tmpcand;
+       LDAPMessage     *candidates;
+       LDAPMessage     *ldap_msg_merge(), *ldap_ufn_expand();
+       static char     *objattrs[] = { "objectClass", NULL };
+
+       /* 
+        * look up ufn components from most to least significant.
+        * there are 3 phases.  
+        *      phase 1 search the root for orgs or countries
+        *      phase 2 search for orgs
+        *      phase 3 search for a person
+        * in phases 1 and 2, we are building a list of candidate DNs,
+        * below which we will search for the final component of the ufn.
+        * for each component we try the filters listed in the
+        * filterconfig file, first one-level (except the last compoment),
+        * then subtree.  if any of them produce any results, we go on to
+        * the next component.
+        */
+
+       *res = NULL;
+       candidates = NULL;
+       phase = 1;
+       for ( ncomp--; ncomp != -1; ncomp-- ) {
+               if ( *ufncomp[ncomp] == '"' ) {
+                       char    *quote;
+
+                       if ( (quote = strrchr( ufncomp[ncomp], '"' )) != NULL )
+                               *quote = '\0';
+                       strcpy( ufncomp[ncomp], ufncomp[ncomp] + 1 );
+               }
+               if ( ncomp == 0 )
+                       phase = 3;
+
+               switch ( phase ) {
+               case 1:
+                       ftag = tag1;
+                       scope = LDAP_SCOPE_ONELEVEL;
+                       break;
+               case 2:
+                       ftag = tag2;
+                       scope = LDAP_SCOPE_ONELEVEL;
+                       break;
+               case 3:
+                       ftag = tag3;
+                       scope = LDAP_SCOPE_SUBTREE;
+                       break;
+               }
+
+               /*
+                * construct an array of DN's to search below from the
+                * list of candidates.
+                */
+
+               if ( candidates == NULL ) {
+                       if ( prefix != NULL ) {
+                               if ( (dns = (char **) malloc( sizeof(char *)
+                                   * 2 )) == NULL ) {
+                                       return( ld->ld_errno = LDAP_NO_MEMORY );
+                               }
+                               dns[0] = strdup( prefix );
+                               dns[1] = NULL;
+                       } else {
+                               dns = NULL;
+                       }
+               } else {
+                       i = 0, max = 0;
+                       for ( tmpcand = candidates; tmpcand != NULL &&
+                           tmpcand->lm_msgtype != LDAP_RES_SEARCH_RESULT;
+                           tmpcand = tmpcand->lm_chain )
+                       {
+                               if ( (dn = ldap_get_dn( ld, tmpcand )) == NULL )
+                                       continue;
+
+                               if ( dns == NULL ) {
+                                       if ( (dns = (char **) malloc(
+                                           sizeof(char *) * 8 )) == NULL ) {
+                                               ld->ld_errno = LDAP_NO_MEMORY;
+                                               return( LDAP_NO_MEMORY );
+                                       }
+                                       max = 8;
+                               } else if ( i >= max ) {
+                                       if ( (dns = (char **) realloc( dns,
+                                           sizeof(char *) * 2 * max ))
+                                           == NULL )
+                                       {
+                                               ld->ld_errno = LDAP_NO_MEMORY;
+                                               return( LDAP_NO_MEMORY );
+                                       }
+                                       max *= 2;
+                               }
+                               dns[i++] = dn;
+                               dns[i] = NULL;
+                       }
+                       ldap_msgfree( candidates );
+                       candidates = NULL;
+               }
+               tries = 0;
+       tryagain:
+               tries++;
+               for ( fi = ldap_getfirstfilter( ld->ld_filtd, ftag,
+                   ufncomp[ncomp] ); fi != NULL;
+                   fi = ldap_getnextfilter( ld->ld_filtd ) )
+               {
+                       if ( (candidates = ldap_ufn_expand( ld, cancelproc,
+                           cancelparm, dns, fi->lfi_filter, scope,
+                           phase == 3 ? attrs : objattrs,
+                           phase == 3 ? attrsonly : 1, &err )) != NULL )
+                       {
+                               break;
+                       }
+
+                       if ( err == -1 || err == LDAP_USER_CANCELLED ) {
+                               if ( dns != NULL ) {
+                                       ldap_value_free( dns );
+                                       dns = NULL;
+                               }
+                               return( err );
+                       }
+               }
+
+               if ( candidates == NULL ) {
+                       if ( tries < 2 && phase != 3 ) {
+                               scope = LDAP_SCOPE_SUBTREE;
+                               goto tryagain;
+                       } else {
+                               if ( dns != NULL ) {
+                                       ldap_value_free( dns );
+                                       dns = NULL;
+                               }
+                               return( err );
+                       }
+               }
+
+               /* go on to the next component */
+               if ( phase == 1 )
+                       phase++;
+               if ( dns != NULL ) {
+                       ldap_value_free( dns );
+                       dns = NULL;
+               }
+       }
+       *res = candidates;
+
+       return( err );
+}
+
+int
+ldap_ufn_search_ct( LDAP *ld, char *ufn, char **attrs, int attrsonly,
+       LDAPMessage **res, cancelptype cancelproc, void *cancelparm,
+       char *tag1, char *tag2, char *tag3 )
+{
+       char    **ufncomp, **prefixcomp;
+       char    *pbuf;
+       int     ncomp, pcomp, i, err;
+
+       /* initialize the getfilter stuff if it's not already */
+       if ( ld->ld_filtd == NULL && ldap_ufn_setfilter( ld, FILTERFILE )
+           == NULL ) {
+               return( ld->ld_errno = LDAP_LOCAL_ERROR );
+       }
+
+       /* call ldap_explode_dn() to break the ufn into its components */
+       if ( (ufncomp = ldap_explode_dn( ufn, 0 )) == NULL )
+               return( ld->ld_errno = LDAP_LOCAL_ERROR );
+       for ( ncomp = 0; ufncomp[ncomp] != NULL; ncomp++ )
+               ;       /* NULL */
+
+       /* more than two components => try it fully qualified first */
+       if ( ncomp > 2 || ld->ld_ufnprefix == NULL ) {
+               err = ldap_ufn_search_ctx( ld, ufncomp, ncomp, NULL, attrs,
+                   attrsonly, res, cancelproc, cancelparm, tag1, tag2, tag3 );
+
+               if ( ldap_count_entries( ld, *res ) > 0 ) {
+                       ldap_value_free( ufncomp );
+                       return( err );
+               } else {
+                       ldap_msgfree( *res );
+                       *res = NULL;
+               }
+       }
+
+       if ( ld->ld_ufnprefix == NULL ) {
+               ldap_value_free( ufncomp );
+               return( err );
+       }
+
+       /* if that failed, or < 2 components, use the prefix */
+       if ( (prefixcomp = ldap_explode_dn( ld->ld_ufnprefix, 0 )) == NULL ) {
+               ldap_value_free( ufncomp );
+               return( ld->ld_errno = LDAP_LOCAL_ERROR );
+       }
+       for ( pcomp = 0; prefixcomp[pcomp] != NULL; pcomp++ )
+               ;       /* NULL */
+       if ( (pbuf = (char *) malloc( strlen( ld->ld_ufnprefix ) + 1 ))
+           == NULL ) { 
+               ldap_value_free( ufncomp );
+               ldap_value_free( prefixcomp );
+               return( ld->ld_errno = LDAP_NO_MEMORY );
+       }
+
+       for ( i = 0; i < pcomp; i++ ) {
+               int     j;
+
+               *pbuf = '\0';
+               for ( j = i; j < pcomp; j++ ) {
+                       strcat( pbuf, prefixcomp[j] );
+                       if ( j + 1 < pcomp )
+                               strcat( pbuf, "," );
+               }
+               err = ldap_ufn_search_ctx( ld, ufncomp, ncomp, pbuf, attrs,
+                   attrsonly, res, cancelproc, cancelparm, tag1, tag2, tag3 );
+
+               if ( ldap_count_entries( ld, *res ) > 0 ) {
+                       break;
+               } else {
+                       ldap_msgfree( *res );
+                       *res = NULL;
+               }
+       }
+
+       ldap_value_free( ufncomp );
+       ldap_value_free( prefixcomp );
+       free( pbuf );
+
+       return( err );
+}
+
+/*
+ * same as ldap_ufn_search_ct, except without the ability to specify
+ * ldapfilter.conf tags.
+ */
+int
+ldap_ufn_search_c( LDAP *ld, char *ufn, char **attrs, int attrsonly,
+       LDAPMessage **res, cancelptype cancelproc, void *cancelparm )
+{
+       return( ldap_ufn_search_ct( ld, ufn, attrs, attrsonly, res, cancelproc,
+           cancelparm, "ufn first", "ufn intermediate", "ufn last" ) );
+}
+
+/*
+ * same as ldap_ufn_search_c without the cancel function
+ */
+int
+ldap_ufn_search_s( LDAP *ld, char *ufn, char **attrs, int attrsonly,
+       LDAPMessage **res )
+{
+       struct timeval  tv;
+
+       tv.tv_sec = ld->ld_timelimit;
+
+       return( ldap_ufn_search_ct( ld, ufn, attrs, attrsonly, res,
+               ld->ld_timelimit ? ldap_ufn_timeout : NULL,
+               ld->ld_timelimit ? (void *) &tv : NULL,
+               "ufn first", "ufn intermediate", "ufn last" ) );
+}
+
+
+/*
+ * ldap_msg_merge - merge two ldap search result chains.  the more
+ * serious of the two error result codes is kept.
+ */
+
+static LDAPMessage *
+ldap_msg_merge( LDAP *ld, LDAPMessage *a, LDAPMessage *b )
+{
+       LDAPMessage     *end, *aprev, *aend, *bprev, *bend;
+
+       if ( a == NULL )
+               return( b );
+
+       if ( b == NULL )
+               return( a );
+
+       /* find the ends of the a and b chains */
+       aprev = NULL;
+       for ( aend = a; aend->lm_chain != NULL; aend = aend->lm_chain )
+               aprev = aend;
+       bprev = NULL;
+       for ( bend = b; bend->lm_chain != NULL; bend = bend->lm_chain )
+               bprev = bend;
+
+       /* keep result a */
+       if ( ldap_result2error( ld, aend, 0 ) != LDAP_SUCCESS ) {
+               /* remove result b */
+               ldap_msgfree( bend );
+               if ( bprev != NULL )
+                       bprev->lm_chain = NULL;
+               else
+                       b = NULL;
+               end = aend;
+               if ( aprev != NULL )
+                       aprev->lm_chain = NULL;
+               else
+                       a = NULL;
+       /* keep result b */
+       } else {
+               /* remove result a */
+               ldap_msgfree( aend );
+               if ( aprev != NULL )
+                       aprev->lm_chain = NULL;
+               else
+                       a = NULL;
+               end = bend;
+               if ( bprev != NULL )
+                       bprev->lm_chain = NULL;
+               else
+                       b = NULL;
+       }
+
+       if ( (a == NULL && b == NULL) || (a == NULL && bprev == NULL) ||
+           (b == NULL && aprev == NULL) )
+               return( end );
+
+       if ( a == NULL ) {
+               bprev->lm_chain = end;
+               return( b );
+       } else if ( b == NULL ) {
+               aprev->lm_chain = end;
+               return( a );
+       } else {
+               bprev->lm_chain = end;
+               aprev->lm_chain = b;
+               return( a );
+       }
+}
+
+static LDAPMessage *
+ldap_ufn_expand( LDAP *ld, cancelptype cancelproc, void *cancelparm,
+       char **dns, char *filter, int scope, char **attrs, int aonly,
+       int *err )
+{
+       LDAPMessage     *tmpcand, *tmpres;
+       char            *dn;
+       int             i, msgid;
+       struct timeval  tv;
+
+       /* search for this component below the current candidates */
+       tmpcand = NULL;
+       i = 0;
+       do {
+               if ( dns != NULL )
+                       dn = dns[i];
+               else
+                       dn = "";
+
+               if (( msgid = ldap_search( ld, dn, scope, filter, attrs,
+                   aonly )) == -1 ) {
+                       ldap_msgfree( tmpcand );
+                       *err = ld->ld_errno;
+                       return( NULL );
+               }
+
+               tv.tv_sec = 0;
+               tv.tv_usec = 100000;    /* 1/10 of a second */
+
+               do {
+                       *err = ldap_result( ld, msgid, 1, &tv, &tmpres );
+                       if ( *err == 0 && cancelproc != NULL &&
+                           (*cancelproc)( cancelparm ) != 0 ) {
+                               ldap_abandon( ld, msgid );
+                               *err = LDAP_USER_CANCELLED;
+                               ld->ld_errno = LDAP_USER_CANCELLED;
+                       }
+               } while ( *err == 0 );
+
+               if ( *err == LDAP_USER_CANCELLED || *err < 0 ||
+                   ( *err = ldap_result2error( ld, tmpres, 0 )) == -1 ) {
+                       ldap_msgfree( tmpcand );
+                       return( NULL );
+               }
+               
+               tmpcand = ldap_msg_merge( ld, tmpcand, tmpres );
+
+               i++;
+       } while ( dns != NULL && dns[i] != NULL );
+
+       if ( ldap_count_entries( ld, tmpcand ) > 0 ) {
+               return( tmpcand );
+       } else {
+               ldap_msgfree( tmpcand );
+               return( NULL );
+       }
+}
+
+/*
+ * ldap_ufn_setfilter - set the filter config file used in ufn searching
+ */
+
+LDAPFiltDesc *
+ldap_ufn_setfilter( LDAP *ld, char *fname )
+{
+       if ( ld->ld_filtd != NULL )
+               ldap_getfilter_free( ld->ld_filtd );
+
+       return( ld->ld_filtd = ldap_init_getfilter( fname ) );
+}
+
+void
+ldap_ufn_setprefix( LDAP *ld, char *prefix )
+{
+       if ( ld->ld_ufnprefix != NULL )
+               free( ld->ld_ufnprefix );
+
+       ld->ld_ufnprefix = strdup( prefix );
+}
+
+int
+ldap_ufn_timeout( void *tvparam )
+{
+       struct timeval  *tv;
+
+       tv = (struct timeval *)tvparam;
+
+       if ( tv->tv_sec != 0 ) {
+               tv->tv_usec = tv->tv_sec * 1000000;     /* sec => micro sec */
+               tv->tv_sec = 0;
+       }
+       tv->tv_usec -= 100000;  /* 1/10 of a second */
+
+       return( tv->tv_usec <= 0 ? 1 : 0 );
+}
diff --git a/libraries/libldap/unbind.c b/libraries/libldap/unbind.c
new file mode 100644 (file)
index 0000000..e7b5c40
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  unbind.c
+ */
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef MACOS
+#include <stdlib.h>
+#include "macos.h"
+#else /* MACOS */
+#if defined( DOS ) || defined( _WIN32 )
+#include "msdos.h"
+#ifdef NCSA
+#include "externs.h"
+#endif /* NCSA */
+#else /* DOS */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#endif /* DOS */
+#endif /* MACOS */
+
+#include "lber.h"
+#include "ldap.h"
+#include "ldap-int.h"
+
+
+int
+ldap_unbind( LDAP *ld )
+{
+       Debug( LDAP_DEBUG_TRACE, "ldap_unbind\n", 0, 0, 0 );
+
+       return( ldap_ld_free( ld, 1 ));
+}
+
+
+int
+ldap_ld_free( LDAP *ld, int close )
+{
+       LDAPMessage     *lm, *next;
+       int             err = LDAP_SUCCESS;
+#ifdef LDAP_REFERRALS
+       LDAPRequest     *lr, *nextlr;
+#endif /* LDAP_REFERRALS */
+
+       if ( ld->ld_sb.sb_naddr == 0 ) {
+#ifdef LDAP_REFERRALS
+               /* free LDAP structure and outstanding requests/responses */
+               for ( lr = ld->ld_requests; lr != NULL; lr = nextlr ) {
+                       nextlr = lr->lr_next;
+                       free_request( ld, lr );
+               }
+
+               /* free and unbind from all open connections */
+               while ( ld->ld_conns != NULL ) {
+                       free_connection( ld, ld->ld_conns, 1, close );
+               }
+#else /* LDAP_REFERRALS */
+               if ( close ) {
+                       err = send_unbind( ld, &ld->ld_sb );
+                       close_connection( &ld->ld_sb );
+               }
+#endif /* LDAP_REFERRALS */
+       } else {
+               int     i;
+
+               for ( i = 0; i < ld->ld_sb.sb_naddr; ++i ) {
+                       free( ld->ld_sb.sb_addrs[ i ] );
+               }
+               free( ld->ld_sb.sb_addrs );
+               free( ld->ld_sb.sb_fromaddr );
+       }
+
+       for ( lm = ld->ld_responses; lm != NULL; lm = next ) {
+               next = lm->lm_next;
+               ldap_msgfree( lm );
+       }
+
+#ifndef NO_CACHE
+       if ( ld->ld_cache != NULL )
+               ldap_destroy_cache( ld );
+#endif /* !NO_CACHE */
+       if ( ld->ld_error != NULL )
+               free( ld->ld_error );
+       if ( ld->ld_matched != NULL )
+               free( ld->ld_matched );
+       if ( ld->ld_host != NULL )
+               free( ld->ld_host );
+       if ( ld->ld_ufnprefix != NULL )
+               free( ld->ld_ufnprefix );
+       if ( ld->ld_filtd != NULL )
+               ldap_getfilter_free( ld->ld_filtd );
+#ifndef LDAP_REFERRALS
+       if ( ld->ld_sb.sb_ber.ber_buf != NULL )
+               free( ld->ld_sb.sb_ber.ber_buf );
+#endif /* !LDAP_REFERRALS */
+       if ( ld->ld_abandoned != NULL )
+               free( ld->ld_abandoned );
+
+#ifdef LDAP_REFERRALS
+       if ( ld->ld_selectinfo != NULL )
+               free_select_info( ld->ld_selectinfo );
+#endif /* LDAP_REFERRALS */
+
+       if ( ld->ld_defhost != NULL )
+               free( ld->ld_defhost );
+
+       free( (char *) ld );
+
+       return( err );
+}
+
+int
+ldap_unbind_s( LDAP *ld )
+{
+       return( ldap_ld_free( ld, 1 ));
+}
+
+
+int
+send_unbind( LDAP *ld, Sockbuf *sb )
+{
+       BerElement      *ber;
+
+       Debug( LDAP_DEBUG_TRACE, "send_unbind\n", 0, 0, 0 );
+
+       /* create a message to send */
+       if ( (ber = alloc_ber_with_options( ld )) == NULLBER ) {
+               return( ld->ld_errno );
+       }
+
+       /* fill it in */
+       if ( ber_printf( ber, "{itn}", ++ld->ld_msgid,
+           LDAP_REQ_UNBIND ) == -1 ) {
+               ld->ld_errno = LDAP_ENCODING_ERROR;
+               ber_free( ber, 1 );
+               return( ld->ld_errno );
+       }
+
+       /* send the message */
+       if ( ber_flush( sb, ber, 1 ) == -1 ) {
+               ld->ld_errno = LDAP_SERVER_DOWN;
+               ber_free( ber, 1 );
+               return( ld->ld_errno );
+       }
+
+       return( LDAP_SUCCESS );
+}
diff --git a/libraries/libldap/url.c b/libraries/libldap/url.c
new file mode 100644 (file)
index 0000000..08b47ef
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ *  Copyright (c) 1996 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  LIBLDAP url.c -- LDAP URL related routines
+ *
+ *  LDAP URLs look like this:
+ *    l d a p : / / hostport / dn [ ? attributes [ ? scope [ ? filter ] ] ]
+ *
+ *  where:
+ *   attributes is a comma separated list
+ *   scope is one of these three strings:  base one sub (default=base)
+ *   filter is an string-represented filter as in RFC 1558
+ *
+ *  e.g.,  ldap://ldap.itd.umich.edu/c=US?o,description?one?o=umich
+ *
+ *  We also tolerate URLs that look like: <ldapurl> and <URL:ldapurl>
+ */
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1996 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef MACOS
+#include <stdlib.h>
+#include "macos.h"
+#endif /* MACOS */
+
+#if defined( DOS ) || defined( _WIN32 )
+#include <stdlib.h>
+#include <malloc.h>
+#include "msdos.h"
+#endif /* DOS || _WIN32 */
+
+#if !defined(MACOS) && !defined(DOS) && !defined( _WIN32 )
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#endif /* !MACOS && !DOS && !_WIN32 */
+
+#include "lber.h"
+#include "ldap.h"
+#include "ldap-int.h"
+
+
+#ifdef NEEDPROTOS
+static int skip_url_prefix( char **urlp, int *enclosedp );
+static void hex_unescape( char *s );
+static int unhex( char c );
+#else /* NEEDPROTOS */
+static int skip_url_prefix();
+static void hex_unescape();
+static int unhex();
+#endif /* NEEDPROTOS */
+
+
+int
+ldap_is_ldap_url( char *url )
+{
+       int     enclosed;
+
+       return( url != NULL && skip_url_prefix( &url, &enclosed ));
+}
+
+
+static int
+skip_url_prefix( char **urlp, int *enclosedp )
+{
+/*
+ * return non-zero if this looks like a LDAP URL; zero if not
+ * if non-zero returned, *urlp will be moved past "ldap://" part of URL
+ */
+       if ( *urlp == NULL ) {
+               return( 0 );
+       }
+
+       /* skip leading '<' (if any) */
+       if ( **urlp == '<' ) {
+               *enclosedp = 1;
+               ++*urlp;
+       } else {
+               *enclosedp = 0;
+       }
+
+       /* skip leading "URL:" (if any) */
+       if ( strlen( *urlp ) >= LDAP_URL_URLCOLON_LEN && strncasecmp(
+           *urlp, LDAP_URL_URLCOLON, LDAP_URL_URLCOLON_LEN ) == 0 ) {
+               *urlp += LDAP_URL_URLCOLON_LEN;
+       }
+
+       /* check for missing "ldap://" prefix */
+       if ( strlen( *urlp ) < LDAP_URL_PREFIX_LEN ||
+           strncasecmp( *urlp, LDAP_URL_PREFIX, LDAP_URL_PREFIX_LEN ) != 0 ) {
+               return( 0 );
+       }
+
+       /* skip over "ldap://" prefix and return success */
+       *urlp += LDAP_URL_PREFIX_LEN;
+       return( 1 );
+}
+
+
+
+int
+ldap_url_parse( char *url, LDAPURLDesc **ludpp )
+{
+/*
+ *  Pick apart the pieces of an LDAP URL.
+ */
+
+       LDAPURLDesc     *ludp;
+       char            *attrs, *p, *q;
+       int             enclosed, i, nattrs;
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_url_parse(%s)\n", url, 0, 0 );
+
+       *ludpp = NULL;  /* pessimistic */
+
+       if ( !skip_url_prefix( &url, &enclosed )) {
+               return( LDAP_URL_ERR_NOTLDAP );
+       }
+
+       /* allocate return struct */
+       if (( ludp = (LDAPURLDesc *)calloc( 1, sizeof( LDAPURLDesc )))
+           == NULLLDAPURLDESC ) {
+               return( LDAP_URL_ERR_MEM );
+       }
+
+       /* make working copy of the remainder of the URL */
+       if (( url = strdup( url )) == NULL ) {
+               ldap_free_urldesc( ludp );
+               return( LDAP_URL_ERR_MEM );
+       }
+
+       if ( enclosed && *((p = url + strlen( url ) - 1)) == '>' ) {
+               *p = '\0';
+       }
+
+       /* set defaults */
+       ludp->lud_scope = LDAP_SCOPE_BASE;
+       ludp->lud_filter = "(objectClass=*)";
+
+       /* lud_string is the only malloc'd string space we use */
+       ludp->lud_string = url;
+
+       /* scan forward for '/' that marks end of hostport and begin. of dn */
+       if (( ludp->lud_dn = strchr( url, '/' )) == NULL ) {
+               ldap_free_urldesc( ludp );
+               return( LDAP_URL_ERR_NODN );
+       }
+
+       /* terminate hostport; point to start of dn */
+       *ludp->lud_dn++ = '\0';
+
+       if (( p = strchr( url, ':' )) != NULL ) {
+               *p++ = '\0';
+               ludp->lud_port = atoi( p );
+       }
+
+       if ( *url == '\0' ) {
+               ludp->lud_host = NULL;
+       } else {
+               ludp->lud_host = url;
+               hex_unescape( ludp->lud_host );
+       }
+
+       /* scan for '?' that marks end of dn and beginning of attributes */
+       if (( attrs = strchr( ludp->lud_dn, '?' )) != NULL ) {
+               /* terminate dn; point to start of attrs. */
+               *attrs++ = '\0';
+
+               /* scan for '?' that marks end of attrs and begin. of scope */
+               if (( p = strchr( attrs, '?' )) != NULL ) {
+                       /*
+                        * terminate attrs; point to start of scope and scan for
+                        * '?' that marks end of scope and begin. of filter
+                        */
+                       *p++ = '\0';
+
+                       if (( q = strchr( p, '?' )) != NULL ) {
+                               /* terminate scope; point to start of filter */
+                               *q++ = '\0';
+                               if ( *q != '\0' ) {
+                                       ludp->lud_filter = q;
+                                       hex_unescape( ludp->lud_filter );
+                               }
+                       }
+
+                       if ( strcasecmp( p, "one" ) == 0 ) {
+                               ludp->lud_scope = LDAP_SCOPE_ONELEVEL;
+                       } else if ( strcasecmp( p, "base" ) == 0 ) {
+                               ludp->lud_scope = LDAP_SCOPE_BASE;
+                       } else if ( strcasecmp( p, "sub" ) == 0 ) {
+                               ludp->lud_scope = LDAP_SCOPE_SUBTREE;
+                       } else if ( *p != '\0' ) {
+                               ldap_free_urldesc( ludp );
+                               return( LDAP_URL_ERR_BADSCOPE );
+                       }
+               }
+       }
+
+       if ( *ludp->lud_dn == '\0' ) {
+               ludp->lud_dn = NULL;
+       } else {
+               hex_unescape( ludp->lud_dn );
+       }
+
+       /*
+        * if attrs list was included, turn it into a null-terminated array
+        */
+       if ( attrs != NULL && *attrs != '\0' ) {
+               for ( nattrs = 1, p = attrs; *p != '\0'; ++p ) {
+                   if ( *p == ',' ) {
+                           ++nattrs;
+                   }
+               }
+
+               if (( ludp->lud_attrs = (char **)calloc( nattrs + 1,
+                   sizeof( char * ))) == NULL ) {
+                       ldap_free_urldesc( ludp );
+                       return( LDAP_URL_ERR_MEM );
+               }
+
+               for ( i = 0, p = attrs; i < nattrs; ++i ) {
+                       ludp->lud_attrs[ i ] = p;
+                       if (( p = strchr( p, ',' )) != NULL ) {
+                               *p++ ='\0';
+                       }
+                       hex_unescape( ludp->lud_attrs[ i ] );
+               }
+       }
+
+       *ludpp = ludp;
+
+       return( 0 );
+}
+
+
+void
+ldap_free_urldesc( LDAPURLDesc *ludp )
+{
+       if ( ludp != NULLLDAPURLDESC ) {
+               if ( ludp->lud_string != NULL ) {
+                       free( ludp->lud_string );
+               }
+               if ( ludp->lud_attrs != NULL ) {
+                       free( ludp->lud_attrs );
+               }
+               free( ludp );
+       }
+}
+
+
+
+int
+ldap_url_search( LDAP *ld, char *url, int attrsonly )
+{
+       int             err;
+       LDAPURLDesc     *ludp;
+       BerElement      *ber;
+#ifdef LDAP_REFERRALS
+       LDAPServer      *srv = NULL;
+#endif /* LDAP_REFERRALS */
+
+       if ( ldap_url_parse( url, &ludp ) != 0 ) {
+               ld->ld_errno = LDAP_PARAM_ERROR;
+               return( -1 );
+       }
+
+       if (( ber = ldap_build_search_req( ld, ludp->lud_dn, ludp->lud_scope,
+           ludp->lud_filter, ludp->lud_attrs, attrsonly )) == NULLBER ) {
+               return( -1 );
+       }
+
+       err = 0;
+
+       if ( ludp->lud_host != NULL || ludp->lud_port != 0 ) {
+#ifdef LDAP_REFERRALS
+               if (( srv = (LDAPServer *)calloc( 1, sizeof( LDAPServer )))
+                   == NULL || ( srv->lsrv_host = strdup( ludp->lud_host ==
+                   NULL ? ld->ld_defhost : ludp->lud_host )) == NULL ) {
+                       if ( srv != NULL ) {
+                               free( srv );
+                       }
+                       ld->ld_errno = LDAP_NO_MEMORY;
+                       err = -1;
+               } else {
+                       if ( ludp->lud_port == 0 ) {
+                               srv->lsrv_port = LDAP_PORT;
+                       } else {
+                                srv->lsrv_port = ludp->lud_port;
+                       }
+               }
+#else /* LDAP_REFERRALS */
+               ld->ld_errno = LDAP_LOCAL_ERROR;
+               err = -1;
+#endif /* LDAP_REFERRALS */
+       }
+
+       if ( err != 0 ) {
+               ber_free( ber, 1 );
+       } else {
+#ifdef LDAP_REFERRALS
+               err = send_server_request( ld, ber, ld->ld_msgid, NULL, srv,
+                   NULL, 1 );
+#else /* LDAP_REFERRALS */
+               err = send_initial_request( ld, LDAP_REQ_SEARCH,
+                   ludp->lud_dn, ber );
+#endif /* LDAP_REFERRALS */
+       }
+
+       ldap_free_urldesc( ludp );
+
+       return( err );
+}
+
+
+int
+ldap_url_search_st( LDAP *ld, char *url, int attrsonly,
+       struct timeval *timeout, LDAPMessage **res )
+{
+       int     msgid;
+
+       if (( msgid = ldap_url_search( ld, url, attrsonly )) == -1 ) {
+               return( ld->ld_errno );
+       }
+
+       if ( ldap_result( ld, msgid, 1, timeout, res ) == -1 ) {
+               return( ld->ld_errno );
+       }
+
+       if ( ld->ld_errno == LDAP_TIMEOUT ) {
+               (void) ldap_abandon( ld, msgid );
+               ld->ld_errno = LDAP_TIMEOUT;
+               return( ld->ld_errno );
+       }
+
+       return( ldap_result2error( ld, *res, 0 ));
+}
+
+
+int
+ldap_url_search_s( LDAP *ld, char *url, int attrsonly, LDAPMessage **res )
+{
+       int     msgid;
+
+       if (( msgid = ldap_url_search( ld, url, attrsonly )) == -1 ) {
+               return( ld->ld_errno );
+       }
+
+       if ( ldap_result( ld, msgid, 1, (struct timeval *)NULL, res ) == -1 ) {
+               return( ld->ld_errno );
+       }
+
+       return( ldap_result2error( ld, *res, 0 ));
+}
+
+
+static void
+hex_unescape( char *s )
+{
+/*
+ * Remove URL hex escapes from s... done in place.  The basic concept for
+ * this routine is borrowed from the WWW library HTUnEscape() routine.
+ */
+       char    *p;
+
+       for ( p = s; *s != '\0'; ++s ) {
+               if ( *s == '%' ) {
+                       if ( *++s != '\0' ) {
+                               *p = unhex( *s ) << 4;
+                       }
+                       if ( *++s != '\0' ) {
+                               *p++ += unhex( *s );
+                       }
+               } else {
+                       *p++ = *s;
+               }
+       }
+
+       *p = '\0';
+}
+
+
+static int
+unhex( char c )
+{
+       return( c >= '0' && c <= '9' ? c - '0'
+           : c >= 'A' && c <= 'F' ? c - 'A' + 10
+           : c - 'a' + 10 );
+}
diff --git a/libraries/libldbm/Make-template b/libraries/libldbm/Make-template
new file mode 100644 (file)
index 0000000..09ad2ee
--- /dev/null
@@ -0,0 +1,71 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1995 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       avl library makefile
+#
+#-----------------------------------------------------------------------------
+
+LDAPSRC        = ../..
+
+SRCS   = ldbm.c
+OBJS   = ldbm.o
+
+HDIR   = ../../include
+
+INCLUDES= -I$(HDIR)
+DEFINES        = $(DEFS)
+
+CFLAGS = $(INCLUDES) $(DEFINES) $(ACFLAGS)
+
+all:   libldbm.a
+
+libldbm.a:     version.o
+       $(AR) ruv $@ $(OBJS) version.o
+       @if [ ! -z "$(RANLIB)" ]; then \
+               $(RANLIB) $@; \
+       fi; \
+       $(RM) ../$@; \
+       $(LN) libldbm/$@ ../$@
+
+testldbm:      libldbm.a testldbm.o
+       $(CC) $(ALDFLAGS) -o $@ testldbm.o -L. -lavl
+
+version.c:     $(OBJS)
+       $(RM) $@
+       (u=$${USER-root} v=`$(CAT) ../../build/version` d=`$(PWD)` \
+       h=`$(HOSTNAME)` t=`$(DATE)`; $(SED) -e "s|%WHEN%|$${t}|" \
+       -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+       -e "s|%VERSION%|$${v}|" \
+       < Version.c > $@)
+
+install:       all
+
+lint:  FORCE
+       $(LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+5lint: FORCE
+       $(5LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+clean: FORCE
+       $(RM) libldbm.a ../libldbm.a testldbm *.o core a.out version.c
+
+depend:        FORCE
+       $(MKDEP) $(INCLUDES) $(DEFINES) $(SRCS)
+
+links:
+       @$(LN) .src/*.[ch] .
+
+# DO NOT DELETE THIS LINE -- mkdep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+ldbm.o: ldbm.c ../../include/ldbm.h
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/libraries/libldbm/Version.c b/libraries/libldbm/Version.c
new file mode 100644 (file)
index 0000000..c71ad08
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+static char Version[] = "  libldbm.a v%VERSION% (%WHEN%)\n\t%WHOANDWHERE%\n";
diff --git a/libraries/libldbm/ldbm.c b/libraries/libldbm/ldbm.c
new file mode 100644 (file)
index 0000000..6d15e46
--- /dev/null
@@ -0,0 +1,348 @@
+/* ldbm.c - ldap dbm compatibility routines */
+
+#include <stdio.h>
+#include "ldbm.h"
+
+#ifdef LDBM_USE_GDBM
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+/*****************************************************************
+ *                                                               *
+ * use gdbm                                                     *
+ *                                                               *
+ *****************************************************************/
+
+LDBM
+ldbm_open( char *name, int rw, int mode, int dbcachesize )
+{
+       LDBM            db;
+       struct stat     st;
+
+       if ( (db =  gdbm_open( name, 0, rw | GDBM_FAST, mode, 0 )) == NULL ) {
+               return( NULL );
+       }
+       if ( dbcachesize > 0 && stat( name, &st ) == 0 ) {
+               dbcachesize = (dbcachesize / st.st_blksize);
+               gdbm_setopt( db, GDBM_CACHESIZE, &dbcachesize, sizeof(int) );
+       }
+
+       return( db );
+}
+
+void
+ldbm_close( LDBM ldbm )
+{
+       gdbm_close( ldbm );
+}
+
+void
+ldbm_sync( LDBM ldbm )
+{
+       gdbm_sync( ldbm );
+}
+
+void
+ldbm_datum_free( LDBM ldbm, Datum data )
+{
+       free( data.dptr );
+}
+
+Datum
+ldbm_datum_dup( LDBM ldbm, Datum data )
+{
+       Datum   dup;
+
+       if ( data.dsize == 0 ) {
+               dup.dsize = 0;
+               dup.dptr = NULL;
+
+               return( dup );
+       }
+       dup.dsize = data.dsize;
+       if ( dup.dptr = (char *) malloc( data.dsize ) )
+               memcpy( dup.dptr, data.dptr, data.dsize );
+
+       return( dup );
+}
+
+Datum
+ldbm_fetch( LDBM ldbm, Datum key )
+{
+       return( gdbm_fetch( ldbm, key ) );
+}
+
+int
+ldbm_store( LDBM ldbm, Datum key, Datum data, int flags )
+{
+       int     rc;
+
+       rc = gdbm_store( ldbm, key, data, flags & ~LDBM_SYNC );
+       if ( flags & LDBM_SYNC )
+               gdbm_sync( ldbm );
+       return( rc );
+}
+
+int
+ldbm_delete( LDBM ldbm, Datum key )
+{
+       int     rc;
+
+       rc = gdbm_delete( ldbm, key );
+       gdbm_sync( ldbm );
+       return( rc );
+}
+
+Datum
+ldbm_firstkey( LDBM ldbm )
+{
+       return( gdbm_firstkey( ldbm ) );
+}
+
+Datum
+ldbm_nextkey( LDBM ldbm, Datum key )
+{
+       return( gdbm_nextkey( ldbm, key ) );
+}
+
+int
+ldbm_errno( LDBM ldbm )
+{
+       return( (int) gdbm_errno );
+}
+
+#else
+#if defined( LDBM_USE_DBHASH ) || defined( LDBM_USE_DBBTREE )
+
+/*****************************************************************
+ *                                                               *
+ * use berkeley db hash or btree package                         *
+ *                                                               *
+ *****************************************************************/
+
+LDBM
+ldbm_open( char *name, int rw, int mode, int dbcachesize )
+{
+       LDBM            ret;
+       void            *info;
+       BTREEINFO       binfo;
+       HASHINFO        hinfo;
+
+       if ( DB_TYPE == DB_HASH ) {
+               memset( (char *) &hinfo, '\0', sizeof(hinfo) );
+               hinfo.cachesize = dbcachesize;
+               info = &hinfo;
+       } else if ( DB_TYPE == DB_BTREE ) {
+               memset( (char *) &binfo, '\0', sizeof(binfo) );
+               binfo.cachesize = dbcachesize;
+               info = &binfo;
+       } else {
+               info = NULL;
+       }
+       ret = dbopen( name, rw, mode, DB_TYPE, info );
+       return( ret );
+}
+
+void
+ldbm_close( LDBM ldbm )
+{
+       (*ldbm->close)( ldbm );
+}
+
+void
+ldbm_sync( LDBM ldbm )
+{
+       (*ldbm->sync)( ldbm, 0 );
+}
+
+void
+ldbm_datum_free( LDBM ldbm, Datum data )
+{
+       free( data.dptr );
+}
+
+Datum
+ldbm_datum_dup( LDBM ldbm, Datum data )
+{
+       Datum   dup;
+
+       if ( data.dsize == 0 ) {
+               dup.dsize = 0;
+               dup.dptr = NULL;
+
+               return( dup );
+       }
+       dup.dsize = data.dsize;
+       if ( dup.dptr = (char *) malloc( data.dsize ) )
+               memcpy( dup.dptr, data.dptr, data.dsize );
+
+       return( dup );
+}
+
+Datum
+ldbm_fetch( LDBM ldbm, Datum key )
+{
+       Datum   data;
+       int     rc;
+
+       if ( (rc = (*ldbm->get)( ldbm, &key, &data, 0 )) == 0 ) {
+               data = ldbm_datum_dup( ldbm, data );
+       } else {
+               data.dptr = NULL;
+               data.dsize = 0;
+       }
+
+       return( data );
+}
+
+int
+ldbm_store( LDBM ldbm, Datum key, Datum data, int flags )
+{
+       int     rc;
+
+       rc = (*ldbm->put)( ldbm, &key, &data, flags & ~LDBM_SYNC );
+       if ( flags & LDBM_SYNC )
+               (*ldbm->sync)( ldbm, 0 );
+       return( rc );
+}
+
+int
+ldbm_delete( LDBM ldbm, Datum key )
+{
+       int     rc;
+
+       rc = (*ldbm->del)( ldbm, &key, 0 );
+       (*ldbm->sync)( ldbm, 0 );
+       return( rc );
+}
+
+Datum
+ldbm_firstkey( LDBM ldbm )
+{
+       Datum   key, data;
+       int     rc;
+
+       if ( (rc = (*ldbm->seq)( ldbm, &key, &data, R_FIRST )) == 0 ) {
+               key = ldbm_datum_dup( ldbm, key );
+       } else {
+               key.dptr = NULL;
+               key.dsize = 0;
+       }
+       return( key );
+}
+
+Datum
+ldbm_nextkey( LDBM ldbm, Datum key )
+{
+       Datum   data;
+       int     rc;
+
+       if ( (rc = (*ldbm->seq)( ldbm, &key, &data, R_NEXT )) == 0 ) {
+               key = ldbm_datum_dup( ldbm, key );
+       } else {
+               key.dptr = NULL;
+               key.dsize = 0;
+       }
+       return( key );
+}
+
+int
+ldbm_errno( LDBM ldbm )
+{
+       return( errno );
+}
+
+#else
+
+#ifdef LDBM_USE_NDBM
+
+/*****************************************************************
+ *                                                               *
+ * if no gdbm, fall back to using ndbm, the standard unix thing  *
+ *                                                               *
+ *****************************************************************/
+
+/* ARGSUSED */
+LDBM
+ldbm_open( char *name, int rw, int mode, int dbcachesize )
+{
+       return( dbm_open( name, rw, mode ) );
+}
+
+void
+ldbm_close( LDBM ldbm )
+{
+       dbm_close( ldbm );
+}
+
+/* ARGSUSED */
+void
+ldbm_sync( LDBM ldbm )
+{
+       return;
+}
+
+void
+ldbm_datum_free( LDBM ldbm, Datum data )
+{
+       return;
+}
+
+Datum
+ldbm_datum_dup( LDBM ldbm, Datum data )
+{
+       Datum   dup;
+
+       if ( data.dsize == 0 ) {
+               dup.dsize = 0;
+               dup.dptr = NULL;
+
+               return( dup );
+       }
+       dup.dsize = data.dsize;
+       if ( dup.dptr = (char *) malloc( data.dsize ) )
+               memcpy( dup.dptr, data.dptr, data.dsize );
+
+       return( dup );
+}
+
+Datum
+ldbm_fetch( LDBM ldbm, Datum key )
+{
+       return( ldbm_datum_dup( ldbm, dbm_fetch( ldbm, key ) ) );
+}
+
+int
+ldbm_store( LDBM ldbm, Datum key, Datum data, int flags )
+{
+       return( dbm_store( ldbm, key, data, flags ) );
+}
+
+int
+ldbm_delete( LDBM ldbm, Datum key )
+{
+       return( dbm_delete( ldbm, key ) );
+}
+
+Datum
+ldbm_firstkey( LDBM ldbm )
+{
+       return( dbm_firstkey( ldbm ) );
+}
+
+Datum
+ldbm_nextkey( LDBM ldbm, Datum key )
+{
+       return( dbm_nextkey( ldbm ) );
+}
+
+int
+ldbm_errno( LDBM ldbm )
+{
+       return( dbm_error( ldbm ) );
+}
+
+#endif /* ndbm */
+#endif /* db */
+#endif /* gdbm */
diff --git a/libraries/libldif/Make-template b/libraries/libldif/Make-template
new file mode 100644 (file)
index 0000000..75061f7
--- /dev/null
@@ -0,0 +1,69 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1996 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       ldif library makefile
+#
+#-----------------------------------------------------------------------------
+
+LDAPSRC        = ../..
+
+SRCS   = line64.c
+OBJS   = line64.o
+
+HDIR   = ../../include
+
+INCLUDES= -I$(HDIR)
+DEFINES        = $(DEFS)
+
+CFLAGS = $(INCLUDES) $(DEFINES) $(ACFLAGS)
+
+all:   libldif.a
+
+libldif.a:     version.o
+       $(AR) ruv $@ $(OBJS) version.o
+       @if [ ! -z "$(RANLIB)" ]; then \
+               $(RANLIB) $@; \
+       fi; \
+       $(RM) ../$@; \
+       $(LN) libldif/$@ ../$@
+
+version.c:     $(OBJS)
+       $(RM) $@
+       (u=$${USER-root} v=`$(CAT) ../../build/version` d=`$(PWD)` \
+       h=`$(HOSTNAME)` t=`$(DATE)`; $(SED) -e "s|%WHEN%|$${t}|" \
+       -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+       -e "s|%VERSION%|$${v}|" \
+       < Version.c > $@)
+
+install:       all
+
+lint:  FORCE
+       $(LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+5lint: FORCE
+       $(5LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+clean: FORCE
+       $(RM) libldif.a ../libldif.a *.o core a.out version.c
+
+depend:        FORCE
+       $(MKDEP) $(INCLUDES) $(DEFINES) $(SRCS)
+
+links:
+       @$(LN) .src/*.[ch] .
+
+# DO NOT DELETE THIS LINE -- mkdep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+line64.o: line64.c ../../include/lber.h ../../include/ldap.h
+line64.o: ../../include/ldif.h
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/libraries/libldif/Version.c b/libraries/libldif/Version.c
new file mode 100644 (file)
index 0000000..d4d4fbf
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 1996 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+static char Version[] = "  libldif.a v%VERSION% (%WHEN%)\n\t%WHOANDWHERE%\n";
diff --git a/libraries/libldif/line64.c b/libraries/libldif/line64.c
new file mode 100644 (file)
index 0000000..54832f2
--- /dev/null
@@ -0,0 +1,307 @@
+/* line64.c - routines for dealing with the slapd line format */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "lber.h"
+#include "ldap.h"
+#include "ldif.h"
+
+#define RIGHT2                 0x03
+#define RIGHT4                 0x0f
+#define CONTINUED_LINE_MARKER  '\001'
+
+static char nib2b64[0x40f] =
+        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static unsigned char b642nib[0x80] = {
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
+       0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
+       0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+       0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+       0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+       0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+       0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+       0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+       0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+/*
+ * str_parse_line - takes a line of the form "type:[:] value" and splits it
+ * into components "type" and "value".  if a double colon separates type from
+ * value, then value is encoded in base 64, and parse_line un-decodes it
+ * (in place) before returning.
+ */
+
+int
+str_parse_line(
+    char       *line,
+    char       **type,
+    char       **value,
+    int                *vlen
+)
+{
+       char    *p, *s, *d, *byte, *stop;
+       char    nib;
+       int     i, b64;
+
+       /* skip any leading space */
+       while ( isspace( *line ) ) {
+               line++;
+       }
+       *type = line;
+
+       for ( s = line; *s && *s != ':'; s++ )
+               ;       /* NULL */
+       if ( *s == '\0' ) {
+               Debug( LDAP_DEBUG_PARSE, "parse_line missing ':'\n", 0, 0, 0 );
+               return( -1 );
+       }
+
+       /* trim any space between type and : */
+       for ( p = s - 1; p > line && isspace( *p ); p-- ) {
+               *p = '\0';
+       }
+       *s++ = '\0';
+
+       /* check for double : - indicates base 64 encoded value */
+       if ( *s == ':' ) {
+               s++;
+               b64 = 1;
+
+       /* single : - normally encoded value */
+       } else {
+               b64 = 0;
+       }
+
+       /* skip space between : and value */
+       while ( isspace( *s ) ) {
+               s++;
+       }
+
+       /* if no value is present, error out */
+       if ( *s == '\0' ) {
+               Debug( LDAP_DEBUG_PARSE, "parse_line missing value\n", 0,0,0 );
+               return( -1 );
+       }
+
+       /* check for continued line markers that should be deleted */
+       for ( p = s, d = s; *p; p++ ) {
+               if ( *p != CONTINUED_LINE_MARKER )
+                       *d++ = *p;
+       }
+       *d = '\0';
+
+       *value = s;
+       if ( b64 ) {
+               stop = strchr( s, '\0' );
+               byte = s;
+               for ( p = s, *vlen = 0; p < stop; p += 4, *vlen += 3 ) {
+                       for ( i = 0; i < 3; i++ ) {
+                               if ( p[i] != '=' && (p[i] & 0x80 ||
+                                   b642nib[ p[i] & 0x7f ] > 0x3f) ) {
+                                       Debug( LDAP_DEBUG_ANY,
+                                   "invalid base 64 encoding char (%c) 0x%x\n",
+                                           p[i], p[i], 0 );
+                                       return( -1 );
+                               }
+                       }
+
+                       /* first digit */
+                       nib = b642nib[ p[0] & 0x7f ];
+                       byte[0] = nib << 2;
+                       /* second digit */
+                       nib = b642nib[ p[1] & 0x7f ];
+                       byte[0] |= nib >> 4;
+                       byte[1] = (nib & RIGHT4) << 4;
+                       /* third digit */
+                       if ( p[2] == '=' ) {
+                               *vlen += 1;
+                               break;
+                       }
+                       nib = b642nib[ p[2] & 0x7f ];
+                       byte[1] |= nib >> 2;
+                       byte[2] = (nib & RIGHT2) << 6;
+                       /* fourth digit */
+                       if ( p[3] == '=' ) {
+                               *vlen += 2;
+                               break;
+                       }
+                       nib = b642nib[ p[3] & 0x7f ];
+                       byte[2] |= nib;
+
+                       byte += 3;
+               }
+               s[ *vlen ] = '\0';
+       } else {
+               *vlen = (int) (d - s);
+       }
+
+       return( 0 );
+}
+
+/*
+ * str_getline - return the next "line" (minus newline) of input from a
+ * string buffer of lines separated by newlines, terminated by \n\n
+ * or \0.  this routine handles continued lines, bundling them into
+ * a single big line before returning.  if a line begins with a white
+ * space character, it is a continuation of the previous line. the white
+ * space character (nb: only one char), and preceeding newline are changed
+ * into CONTINUED_LINE_MARKER chars, to be deleted later by the
+ * str_parse_line() routine above.
+ *
+ * it takes a pointer to a pointer to the buffer on the first call,
+ * which it updates and must be supplied on subsequent calls.
+ */
+
+char *
+str_getline( char **next )
+{
+       char    *l;
+       char    c;
+
+       if ( *next == NULL || **next == '\n' || **next == '\0' ) {
+               return( NULL );
+       }
+
+       l = *next;
+       while ( (*next = strchr( *next, '\n' )) != NULL ) {
+               c = *(*next + 1);
+               if ( isspace( c ) && c != '\n' ) {
+                       **next = CONTINUED_LINE_MARKER;
+                       *(*next+1) = CONTINUED_LINE_MARKER;
+               } else {
+                       *(*next)++ = '\0';
+                       break;
+               }
+               *(*next)++;
+       }
+
+       return( l );
+}
+
+void
+put_type_and_value( char **out, char *t, char *val, int vlen )
+{
+       unsigned char   *byte, *p, *stop;
+       unsigned char   buf[3];
+       unsigned long   bits;
+       char            *save;
+       int             i, b64, pad, len, savelen;
+       len = 0;
+
+       /* put the type + ": " */
+       for ( p = (unsigned char *) t; *p; p++, len++ ) {
+               *(*out)++ = *p;
+       }
+       *(*out)++ = ':';
+       len++;
+       save = *out;
+       savelen = len;
+       *(*out)++ = ' ';
+       b64 = 0;
+
+       stop = (unsigned char *) (val + vlen);
+       if ( isascii( val[0] ) && isspace( val[0] ) || val[0] == ':' ) {
+               b64 = 1;
+       } else {
+               for ( byte = (unsigned char *) val; byte < stop;
+                   byte++, len++ ) {
+                       if ( !isascii( *byte ) || !isprint( *byte ) ) {
+                               b64 = 1;
+                               break;
+                       }
+                       if ( len > LINE_WIDTH ) {
+                               *(*out)++ = '\n';
+                               *(*out)++ = ' ';
+                               len = 1;
+                       }
+                       *(*out)++ = *byte;
+               }
+       }
+       if ( b64 ) {
+               *out = save;
+               *(*out)++ = ':';
+               *(*out)++ = ' ';
+               len = savelen + 2;
+               /* convert to base 64 (3 bytes => 4 base 64 digits) */
+               for ( byte = (unsigned char *) val; byte < stop - 2;
+                   byte += 3 ) {
+                       bits = (byte[0] & 0xff) << 16;
+                       bits |= (byte[1] & 0xff) << 8;
+                       bits |= (byte[2] & 0xff);
+
+                       for ( i = 0; i < 4; i++, len++, bits <<= 6 ) {
+                               if ( len > LINE_WIDTH ) {
+                                       *(*out)++ = '\n';
+                                       *(*out)++ = ' ';
+                                       len = 1;
+                               }
+
+                               /* get b64 digit from high order 6 bits */
+                               *(*out)++ = nib2b64[ (bits & 0xfc0000L) >> 18 ];
+                       }
+               }
+
+               /* add padding if necessary */
+               if ( byte < stop ) {
+                       for ( i = 0; byte + i < stop; i++ ) {
+                               buf[i] = byte[i];
+                       }
+                       for ( pad = 0; i < 3; i++, pad++ ) {
+                               buf[i] = '\0';
+                       }
+                       byte = buf;
+                       bits = (byte[0] & 0xff) << 16;
+                       bits |= (byte[1] & 0xff) << 8;
+                       bits |= (byte[2] & 0xff);
+
+                       for ( i = 0; i < 4; i++, len++, bits <<= 6 ) {
+                               if ( len > LINE_WIDTH ) {
+                                       *(*out)++ = '\n';
+                                       *(*out)++ = ' ';
+                                       len = 1;
+                               }
+
+                               /* get b64 digit from low order 6 bits */
+                               *(*out)++ = nib2b64[ (bits & 0xfc0000L) >> 18 ];
+                       }
+
+                       for ( ; pad > 0; pad-- ) {
+                               *(*out - pad) = '=';
+                       }
+               }
+       }
+       *(*out)++ = '\n';
+}
+
+
+char *
+ldif_type_and_value( char *type, char *val, int vlen )
+/*
+ * return malloc'd, zero-terminated LDIF line
+ */
+{
+    char       *buf, *p;
+    int                tlen;
+
+    tlen = strlen( type );
+    if (( buf = (char *)malloc( LDIF_SIZE_NEEDED( tlen, vlen ) + 1 )) !=
+           NULL ) {
+    }
+
+    p = buf;
+    put_type_and_value( &p, type, val, vlen );
+    *p = '\0';
+
+    return( buf );
+}
diff --git a/libraries/liblthread/Make-template b/libraries/liblthread/Make-template
new file mode 100644 (file)
index 0000000..2344ba9
--- /dev/null
@@ -0,0 +1,69 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1995 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       lthreads library makefile
+#
+#-----------------------------------------------------------------------------
+
+LDAPSRC        = ../..
+
+SRCS   = thread.c stack.c
+OBJS   = thread.o stack.o
+
+HDIR   = ../../include
+
+INCLUDES= -I$(HDIR)
+DEFINES        = $(DEFS) $(THREADS)
+
+CFLAGS = $(INCLUDES) $(THREADSINCLUDE) $(DEFINES) $(ACFLAGS)
+
+all:   liblthread.a
+
+liblthread.a:  version.o
+       $(AR) ruv $@ $(OBJS) version.o
+       @if [ ! -z "$(RANLIB)" ]; then \
+               $(RANLIB) $@; \
+       fi; \
+       $(RM) ../$@; \
+       $(LN) liblthread/$@ ../$@
+
+version.c:     $(OBJS)
+       $(RM) $@
+       (u=$${USER-root} v=`$(CAT) ../../build/version` d=`$(PWD)` \
+       h=`$(HOSTNAME)` t=`$(DATE)`; $(SED) -e "s|%WHEN%|$${t}|" \
+       -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+       -e "s|%VERSION%|$${v}|" \
+       < Version.c > $@)
+
+install:       all
+
+lint:  FORCE
+       $(LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+5lint: FORCE
+       $(5LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+clean: FORCE
+       $(RM) liblthread.a ../liblthread.a *.o core a.out version.c
+
+depend:        FORCE
+       $(MKDEP) $(INCLUDES) $(DEFINES) $(SRCS)
+
+links:
+       @$(LN) .src/*.[ch] .
+
+# DO NOT DELETE THIS LINE -- mkdep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+thread.o: thread.c ../../include/lthread.h
+stack.o: stack.c ../../include/lber.h ../../include/ldap.h
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/libraries/liblthread/Version.c b/libraries/liblthread/Version.c
new file mode 100644 (file)
index 0000000..f9e97e6
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+static char Version[] = "  liblthread.a v%VERSION% (%WHEN%)\n\t%WHOANDWHERE%\n";
diff --git a/libraries/liblthread/stack.c b/libraries/liblthread/stack.c
new file mode 100644 (file)
index 0000000..e57b44b
--- /dev/null
@@ -0,0 +1,69 @@
+/* stack.c - stack handling routines */
+
+#include <stdio.h>
+#include "lber.h"
+#include "ldap.h"
+
+#if defined( sunos4 )
+
+#include <lwp/lwp.h>
+#include <lwp/stackdep.h>
+
+#define MAX_STACK      51200
+#define MAX_THREADS    20
+
+struct stackinfo {
+       int             stk_inuse;
+       stkalign_t      *stk_stack;
+};
+
+static struct stackinfo        *stacks;
+
+stkalign_t *
+get_stack( int *stacknop )
+{
+       int     i;
+
+       if ( stacks == NULL ) {
+               stacks = (struct stackinfo *) ch_calloc( 1, MAX_THREADS *
+                   sizeof(struct stackinfo) );
+       }
+
+       for ( i = 0; i < MAX_THREADS; i++ ) {
+               if ( stacks[i].stk_inuse == 0 ) {
+                       break;
+               }
+       }
+
+       if ( i == MAX_THREADS ) {
+               Debug( LDAP_DEBUG_ANY,
+                   "no more stacks (max %d) - increase MAX_THREADS for more",
+                   MAX_THREADS, 0, 0 );
+               return( NULL );
+       }
+
+       if ( stacks[i].stk_stack == NULL ) {
+               stacks[i].stk_stack = (stkalign_t *) malloc(
+                   (MAX_STACK / sizeof(stkalign_t) + 1 )
+                   * sizeof(stkalign_t) );
+       }
+
+       *stacknop = i;
+       stacks[i].stk_inuse = 1;
+       return( stacks[i].stk_stack + MAX_STACK / sizeof(stkalign_t) );
+}
+
+void
+free_stack(
+    int        stackno
+)
+{
+       if ( stackno < 0 || stackno > MAX_THREADS ) {
+               Debug( LDAP_DEBUG_ANY, "free_stack of bogus stack %d",
+                   stackno, 0, 0 );
+       }
+
+       stacks[stackno].stk_inuse = 0;
+}
+
+#endif
diff --git a/libraries/liblthread/thread.c b/libraries/liblthread/thread.c
new file mode 100644 (file)
index 0000000..89a85c7
--- /dev/null
@@ -0,0 +1,487 @@
+/* thread.c - glue routines to provide a consistent thread interface */
+#include <stdio.h>
+#include "lthread.h"
+
+#if defined( THREAD_SUNOS4_LWP )
+
+/***********************************************************************
+ *                                                                     *
+ * under sunos 4 - use the built in non-preemptive lwp threads package *
+ *                                                                     *
+ ***********************************************************************/
+
+extern stkalign_t      *get_stack();
+static void            lwp_create_stack();
+
+int
+pthread_attr_init( pthread_attr_t *attr )
+{
+       *attr = 0;
+       return( 0 );
+}
+
+int
+pthread_attr_destroy( pthread_attr_t *attr )
+{
+       return( 0 );
+}
+
+int
+pthread_attr_getdetachstate( pthread_attr_t *attr, int *detachstate )
+{
+       *detachstate = *attr;
+       return( 0 );
+}
+
+int
+pthread_attr_setdetachstate( pthread_attr_t *attr, int detachstate )
+{
+       *attr = detachstate;
+       return( 0 );
+}
+
+/* ARGSUSED */
+int
+pthread_create(
+    pthread_t          *tid,
+    pthread_attr_t     attr,
+    VFP                        func,
+    void               *arg
+)
+{
+       stkalign_t      *stack;
+       int             stackno;
+
+       if ( (stack = get_stack( &stackno )) == NULL ) {
+               return( -1 );
+       }
+       return( lwp_create( tid, lwp_create_stack, MINPRIO, 0, stack, 3, func,
+           arg, stackno ) );
+}
+
+static void
+lwp_create_stack( VFP func, void *arg, int stackno )
+{
+       (*func)( arg );
+
+       free_stack( stackno );
+}
+
+void
+pthread_yield()
+{
+       lwp_yield( SELF );
+}
+
+void
+pthread_exit()
+{
+       lwp_destroy( SELF );
+}
+
+void
+pthread_join( pthread_t tid, int *status )
+{
+       lwp_join( tid );
+}
+
+/* ARGSUSED */
+void
+pthread_kill( pthread_t tid, int sig )
+{
+       return;
+}
+
+/* ARGSUSED */
+int
+pthread_mutex_init( pthread_mutex_t *mp, pthread_mutexattr_t *attr )
+{
+       return( mon_create( mp ) );
+}
+
+int
+pthread_mutex_destroy( pthread_mutex_t *mp )
+{
+       return( mon_destroy( *mp ) );
+}
+
+int
+pthread_mutex_lock( pthread_mutex_t *mp )
+{
+       return( mon_enter( *mp ) );
+}
+
+int
+pthread_mutex_unlock( pthread_mutex_t *mp )
+{
+       return( mon_exit( *mp ) );
+}
+
+int
+pthread_mutex_trylock( pthread_mutex_t *mp )
+{
+       return( mon_cond_enter( *mp ) );
+}
+
+int
+pthread_cond_init( pthread_cond_t *cv, pthread_condattr_t *attr )
+{
+       /*
+        * lwp cv_create requires the monitor id be passed in
+        * when the cv is created, pthreads passes it when the
+        * condition is waited for.  so, we fake the creation
+        * here and actually do it when the cv is waited for
+        * later.
+        */
+
+       cv->lcv_created = 0;
+
+       return( 0 );
+}
+
+int
+pthread_cond_destroy( pthread_cond_t *cv )
+{
+       return( cv->lcv_created ? cv_destroy( cv->lcv_cv ) : 0 );
+}
+
+int
+pthread_cond_wait( pthread_cond_t *cv, pthread_mutex_t *mp )
+{
+       if ( ! cv->lcv_created ) {
+               cv_create( &cv->lcv_cv, *mp );
+               cv->lcv_created = 1;
+       }
+
+       return( cv_wait( cv->lcv_cv ) );
+}
+
+int
+pthread_cond_signal( pthread_cond_t *cv )
+{
+       return( cv->lcv_created ? cv_notify( cv->lcv_cv ) : 0 );
+}
+
+int
+pthread_cond_broadcast( pthread_cond_t *cv )
+{
+       return( cv->lcv_created ? cv_broadcast( cv->lcv_cv ) : 0 );
+}
+
+#else /* end sunos4 */
+
+#  if defined( THREAD_SUNOS5_LWP )
+
+/***********************************************************************
+ *                                                                     *
+ * under sunos 5 - use the built in preemptive solaris threads package *
+ *                                                                     *
+ ***********************************************************************/
+
+int
+pthread_attr_init( pthread_attr_t *attr )
+{
+       *attr = 0;
+       return( 0 );
+}
+
+int
+pthread_attr_destroy( pthread_attr_t *attr )
+{
+       *attr = 0;
+       return( 0 );
+}
+
+int
+pthread_attr_getdetachstate( pthread_attr_t *attr, int *detachstate )
+{
+       *detachstate = *attr;
+       return( 0 );
+}
+
+int
+pthread_attr_setdetachstate( pthread_attr_t *attr, int detachstate )
+{
+       *attr = detachstate;
+       return( 0 );
+}
+
+/* ARGSUSED */
+int
+pthread_create(
+    pthread_t          *tid,
+    pthread_attr_t     attr,
+    VFP                        func,
+    void               *arg
+)
+{
+       return( thr_create( NULL, 0, func, arg, attr, tid ) );
+}
+
+void
+pthread_yield()
+{
+       thr_yield();
+}
+
+void
+pthread_exit()
+{
+       thr_exit( NULL );
+}
+
+void
+pthread_join( pthread_t tid, int *status )
+{
+       thr_join( tid, NULL, (void **) status );
+}
+
+void
+pthread_kill( pthread_t tid, int sig )
+{
+       thr_kill( tid, sig );
+}
+
+/* ARGSUSED */
+int
+pthread_mutex_init( pthread_mutex_t *mp, pthread_mutexattr_t *attr )
+{
+       return( mutex_init( mp, attr ? *attr : USYNC_THREAD, NULL ) );
+}
+
+int
+pthread_mutex_destroy( pthread_mutex_t *mp )
+{
+       return( mutex_destroy( mp ) );
+}
+
+int
+pthread_mutex_lock( pthread_mutex_t *mp )
+{
+       return( mutex_lock( mp ) );
+}
+
+int
+pthread_mutex_unlock( pthread_mutex_t *mp )
+{
+       return( mutex_unlock( mp ) );
+}
+
+int
+pthread_mutex_trylock( pthread_mutex_t *mp )
+{
+       return( mutex_trylock( mp ) );
+}
+
+int
+pthread_cond_init( pthread_cond_t *cv, pthread_condattr_t *attr )
+{
+       return( cond_init( cv, attr ? *attr : USYNC_THREAD, NULL ) );
+}
+
+int
+pthread_cond_destroy( pthread_cond_t *cv )
+{
+       return( cond_destroy( cv ) );
+}
+
+int
+pthread_cond_wait( pthread_cond_t *cv, pthread_mutex_t *mp )
+{
+       return( cond_wait( cv, mp ) );
+}
+
+int
+pthread_cond_signal( pthread_cond_t *cv )
+{
+       return( cond_signal( cv ) );
+}
+
+int
+pthread_cond_broadcast( pthread_cond_t *cv )
+{
+       return( cond_broadcast( cv ) );
+}
+
+
+#else /* end sunos5 threads */
+
+#if defined( THREAD_MIT_PTHREADS )
+
+/***********************************************************************
+ *                                                                     *
+ * pthreads package by Chris Provenzano of MIT - provides all the      *
+ * pthreads calls already, so no mapping to do                         *
+ *                                                                     *
+ ***********************************************************************/
+
+#else /* end mit pthreads */
+
+#if defined( THREAD_DCE_PTHREADS )
+
+/***********************************************************************
+ *                                                                     *
+ * pthreads package with DCE - no mapping to do (except to create a    *
+ * pthread_kill() routine)                                             *
+ *                                                                     *
+ ***********************************************************************/
+
+/* ARGSUSED */
+void
+pthread_kill( pthread_t tid, int sig )
+{
+       kill( getpid(), sig );
+}
+
+#endif /* dce pthreads */
+#endif /* mit pthreads */
+#endif /* sunos5 lwp */
+#endif /* sunos4 lwp */
+
+#ifndef _THREAD
+
+/***********************************************************************
+ *                                                                     *
+ * no threads package defined for this system - fake ok returns from   *
+ * all threads routines (making it single-threaded).                   *
+ *                                                                     *
+ ***********************************************************************/
+
+/* ARGSUSED */
+int
+pthread_attr_init( pthread_attr_t *attr )
+{
+       return( 0 );
+}
+
+/* ARGSUSED */
+int
+pthread_attr_destroy( pthread_attr_t *attr )
+{
+       return( 0 );
+}
+
+/* ARGSUSED */
+int
+pthread_attr_getdetachstate( pthread_attr_t *attr, int *detachstate )
+{
+       return( 0 );
+}
+
+/* ARGSUSED */
+int
+pthread_attr_setdetachstate( pthread_attr_t *attr, int detachstate )
+{
+       return( 0 );
+}
+
+/* ARGSUSED */
+int
+pthread_create(
+    pthread_t          *tid,
+    pthread_attr_t     attr,
+    VFP                        func,
+    void               *arg
+)
+{
+       (*func)( arg );
+
+       return( 0 );
+}
+
+void
+pthread_yield()
+{
+       return;
+}
+
+void
+pthread_exit()
+{
+       return;
+}
+
+/* ARGSUSED */
+void
+pthread_kill( pthread_t tid, int sig )
+{
+       return;
+}
+
+void
+pthread_join( pthread_t tid, int *status )
+{
+       return;
+}
+
+/* ARGSUSED */
+int
+pthread_mutex_init( pthread_mutex_t *mp, pthread_mutexattr_t *attr )
+{
+       return( 0 );
+}
+
+/* ARGSUSED */
+int
+pthread_mutex_destroy( pthread_mutex_t *mp )
+{
+       return( 0 );
+}
+
+/* ARGSUSED */
+int
+pthread_mutex_lock( pthread_mutex_t *mp )
+{
+       return( 0 );
+}
+
+/* ARGSUSED */
+int
+pthread_mutex_unlock( pthread_mutex_t *mp )
+{
+       return( 0 );
+}
+
+/* ARGSUSED */
+int
+pthread_mutex_trylock( pthread_mutex_t *mp )
+{
+       return( 0 );
+}
+
+/* ARGSUSED */
+int
+pthread_cond_init( pthread_cond_t *cv, pthread_condattr_t *attr )
+{
+       return( 0 );
+}
+
+/* ARGSUSED */
+int
+pthread_cond_destroy( pthread_cond_t *cv )
+{
+       return( 0 );
+}
+
+/* ARGSUSED */
+int
+pthread_cond_wait( pthread_cond_t *cv, pthread_mutex_t *mp )
+{
+       return( 0 );
+}
+
+/* ARGSUSED */
+int
+pthread_cond_signal( pthread_cond_t *cv )
+{
+       return( 0 );
+}
+
+/* ARGSUSED */
+int
+pthread_cond_broadcast( pthread_cond_t *cv )
+{
+       return( 0 );
+}
+
+#endif /* no threads package */
diff --git a/libraries/macintosh/Make-template b/libraries/macintosh/Make-template
new file mode 100644 (file)
index 0000000..0bc9cb9
--- /dev/null
@@ -0,0 +1,48 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1994 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP libraries/macintosh Makefile
+#
+#-----------------------------------------------------------------------------
+
+############################################################################
+#                                                                          #
+# You should not have to edit anything below this point                    #
+#                                                                          #
+############################################################################
+
+#
+# rules to make the software
+#
+
+all:   FORCE
+
+#
+# rules to install the software
+#
+
+install:       all
+
+#
+# rules to make clean
+#
+
+clean: FORCE
+
+veryclean:     clean
+
+#
+# rules to make depend
+#
+#
+depend:        FORCE
+
+links:
diff --git a/libraries/macintosh/README b/libraries/macintosh/README
new file mode 100644 (file)
index 0000000..ac5ceb9
--- /dev/null
@@ -0,0 +1,67 @@
+LDAP Macintosh README
+
+The lber and ldap client libraries have been ported to Macintosh.
+Build testing was originally done with Think C 5.0.4 and MPW 3.2, both
+running under System 7.1.  Recently, it has been built using Metrowerks
+CodeWarrior 8.0 and Symantec C++ 7.0.3.  The libaries have been tested
+under System 7.0, 7.1, and 7.5, and are believed to run under any
+System later than 6.0.  None of the LDAP clients included in the
+distribution have been tested on the Mac.
+
+MAKING THE DISTRIBUTION
+The instructions included here are for Symantec C 7.0.4, but the steps
+are very similar for the other environments.
+
+To build the ldap and lber libraries (easiest to do as one project):
+
+       1) create a new project that contains the following files:
+               libraries/liblber/decode.c
+               libraries/liblber/encode.c
+               libraries/liblber/io.c
+               libraries/macintosh/tcp/dnr.c
+               libraries/macintosh/tcp/tcp.c
+               libraries/macintosh/macos-ip.c
+               libraries/macintosh/strings.c
+         plus all the .c files in libraries/libldap/, except test.c,
+          tmpltest.c, and os-ip.c.
+
+       2) put all of the .h files in include/, libraries/macintosh/, 
+          libraries/libldap and libraries/macintosh/tcp somewhere
+          in the same folder where the project is located.
+
+       3) Add the MacTraps, MacTraps2, Unix, and ANSI-small libraries
+          (included with Symantec/ThinkC) to the project.
+
+       3) Bring up the Edit menu "Options..." dialog and set the following:
+            Language Settings:
+               Strict Prototype Enforcement/Require Prototypes
+            Prefix:
+               #define MACOS
+               #define NEEDPROTOS
+               #define NEEDGETOPT
+               #define NO_USERINTERFACE
+               #define FILTERFILE      "ldapfilter.conf"
+               #define TEMPLATEFILE    "ldaptemplates.conf"
+
+            If you want to build a version of the library that does
+            not have any global variables (such as for inclusion in a
+            driver or other code module), add a "#define NO_GLOBALS"
+            to the Prefix.  The only catch is that the tcp/dnr.c
+            file needs changes to remove the global variables.
+
+            If you want support for referrals (optionally enabled
+             for each LDAP connection), add '#define LDAP_REFERRALS'
+            to the prefix list.  This is recommended.
+
+       4) Compile the project (Bring Up To Date under the Project menu)
+
+       5) If you would like to use the libldap/test.c program to test the
+          library in an ugly console window, you will need to add the
+          test.c file itself and the full ANSI library (instead of
+          ANSI-small) to the project, and don't define NO_USERINTERFACE.
+
+BUG REPORTING
+
+    Bug reports should be sent to bug-ldap@terminator.cc.umich.edu.
+
+README Last updated 11 April 1996 by Mark Smith
diff --git a/libraries/macintosh/getopt.c b/libraries/macintosh/getopt.c
new file mode 100644 (file)
index 0000000..25e5d0b
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 1987 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[] = "@(#)getopt.c    4.12 (Berkeley) 6/1/90";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+#include <string.h>
+#include "lber.h"
+#define index strchr
+#define rindex strrchr
+
+/*
+ * get option letter from argument vector
+ */
+int     opterr = 1,             /* if error message should be printed */
+       optind = 1,             /* index into parent argv vector */
+       optopt;                 /* character checked for validity */
+char    *optarg;                /* argument associated with option */
+
+#define BADCH   (int)'?'
+#define EMSG    ""
+
+getopt(int nargc, char **nargv, char *ostr)
+{
+       static char *place = EMSG;              /* option letter processing */
+       register char *oli;                     /* option letter list index */
+       char *p;
+
+       if (!*place) {                          /* update scanning pointer */
+               if (optind >= nargc || *(place = nargv[optind]) != '-') {
+                       place = EMSG;
+                       return(EOF);
+               }
+               if (place[1] && *++place == '-') {      /* found "--" */
+                       ++optind;
+                       place = EMSG;
+                       return(EOF);
+               }
+       }                                       /* option letter okay? */
+       if ((optopt = (int)*place++) == (int)':' ||
+           !(oli = index(ostr, optopt))) {
+               /*
+                * if the user didn't specify '-' as an option,
+                * assume it means EOF.
+                */
+               if (optopt == (int)'-')
+                       return(EOF);
+               if (!*place)
+                       ++optind;
+               if (opterr) {
+                       if (!(p = rindex(*nargv, '/')))
+                               p = *nargv;
+                       else
+                               ++p;
+                       (void)fprintf(stderr, "%s: illegal option -- %c\n",
+                           p, optopt);
+               }
+               return(BADCH);
+       }
+       if (*++oli != ':') {                    /* don't need argument */
+               optarg = NULL;
+               if (!*place)
+                       ++optind;
+       }
+       else {                                  /* need an argument */
+               if (*place)                     /* no white space */
+                       optarg = place;
+               else if (nargc <= ++optind) {   /* no arg */
+                       place = EMSG;
+                       if (!(p = rindex(*nargv, '/')))
+                               p = *nargv;
+                       else
+                               ++p;
+                       if (opterr)
+                               (void)fprintf(stderr,
+                                   "%s: option requires an argument -- %c\n",
+                                   p, optopt);
+                       return(BADCH);
+               }
+               else                            /* white space */
+                       optarg = nargv[optind];
+               place = EMSG;
+               ++optind;
+       }
+       return(optopt);                         /* dump back option letter */
+}
diff --git a/libraries/macintosh/kerberos-macos.c b/libraries/macintosh/kerberos-macos.c
new file mode 100644 (file)
index 0000000..ee9c31c
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ *  Copyright (c) 1992, 1994 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  kerberos-macos.c
+ */
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1994 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include "lber.h"
+#include "ldap.h"
+
+#ifdef KERBEROS
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#ifdef THINK_C
+#include <pascal.h>
+#else /* THINK_C */
+#include <Strings.h>
+#endif /* THINK_C */
+#ifdef AUTHMAN
+#include <MixedMode.h>
+#include <Errors.h>
+#include "authLibrary.h"
+#include "ldap-int.h"
+
+/*
+ * get_kerberosv4_credentials - obtain kerberos v4 credentials for ldap.
+ */
+
+/* ARGSUSED */
+char *
+get_kerberosv4_credentials( LDAP *ld, char *who, char *service, int *len )
+{
+       static short    authman_refnum = 0;
+       char            *cred, ticket[ MAX_KTXT_LEN ];
+       short           version, ticketlen, err;
+       Str255          svcps, instps;
+       
+       /*
+        * make sure RJC's Authentication Manager 2.0 or better is available
+        */
+       if ( authman_refnum == 0 && (( err = openAuthMan( &authman_refnum, &version )) != noErr || version < 2 )) {
+               authman_refnum = 0;
+               ld->ld_errno = LDAP_AUTH_UNKNOWN;
+               return( NULL );
+       }
+       
+       strcpy( (char *)svcps, service );
+       CtoPstr( (char *)svcps );
+#ifdef LDAP_REFERRALS
+       strcpy( (char *)instps, ld->ld_defconn->lconn_krbinstance );
+#else /* LDAP_REFERRALS */
+       strcpy( (char *)instps, ld->ld_host );
+#endif /* LDAP_REFERRALS */
+
+       CtoPstr( (char *)instps );
+       if (( err = getV4Ticket( authman_refnum, &ticket, &ticketlen, &svcps, &instps,
+                       NULL, INFINITE_LIFETIME, 1 )) != noErr ) {
+               ld->ld_errno = ( err == userCanceledErr ) ?
+                       LDAP_USER_CANCELLED : LDAP_INVALID_CREDENTIALS;
+               return( NULL );
+       }
+
+       if (( cred = malloc( ticketlen )) == NULL ) {
+               ld->ld_errno = LDAP_NO_MEMORY;
+               return( NULL );
+       }
+
+       *len = ticketlen;
+       memcpy( cred, (char *)ticket, ticketlen );
+       return( cred );
+}
+
+#endif
+#endif
diff --git a/libraries/macintosh/macos-ip.c b/libraries/macintosh/macos-ip.c
new file mode 100644 (file)
index 0000000..3a6a180
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ *  Copyright (c) 1995 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  macos-ip.c -- Macintosh platform-specific TCP & UDP related code
+ */
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1995 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <Memory.h>
+#include "macos.h"
+#include "lber.h"
+#include "ldap.h"
+#include "ldap-int.h"
+
+int
+connect_to_host( Sockbuf *sb, char *host, unsigned long address,
+       int port, int async )
+/*
+ * if host == NULL, connect using address
+ * "address" and "port" must be in network byte order
+ * zero is returned upon success, -1 if fatal error, -2 EINPROGRESS
+ * async is only used ifndef NO_REFERRALS (non-0 means don't wait for connect)
+ * XXX async is not used yet!
+ */
+{
+       void                    *tcps;
+       short                   i;
+#ifdef SUPPORT_OPENTRANSPORT
+    InetHostInfo       hi;
+#else /* SUPPORT_OPENTRANSPORT */
+    struct hostInfo    hi;
+#endif /* SUPPORT_OPENTRANSPORT */
+
+       Debug( LDAP_DEBUG_TRACE, "connect_to_host: %s:%d\n",
+           ( host == NULL ) ? "(by address)" : host, ntohs( port ), 0 );
+
+       if ( host != NULL && gethostinfobyname( host, &hi ) != noErr ) {
+               return( -1 );
+       }
+
+       if (( tcps = tcpopen( NULL, TCP_BUFSIZ )) == NULL ) {
+               Debug( LDAP_DEBUG_TRACE, "tcpopen failed\n", 0, 0, 0 );
+               return( -1 );
+       }
+
+#ifdef SUPPORT_OPENTRANSPORT
+    for ( i = 0; host == NULL || hi.addrs[ i ] != 0; ++i ) {
+       if ( host != NULL ) {
+                       SAFEMEMCPY( (char *)&address, (char *)&hi.addrs[ i ], sizeof( long ));
+               }
+#else /* SUPPORT_OPENTRANSPORT */
+    for ( i = 0; host == NULL || hi.addr[ i ] != 0; ++i ) {
+       if ( host != NULL ) {
+                       SAFEMEMCPY( (char *)&address, (char *)&hi.addr[ i ], sizeof( long ));
+               }
+#endif /* SUPPORT_OPENTRANSPORT */
+
+               if ( tcpconnect( tcps, address, port ) > 0 ) {
+                       sb->sb_sd = (void *)tcps;
+                       return( 0 );
+               }
+
+               if ( host == NULL ) {   /* using single address -- not hi.addrs array */
+                       break;
+               }
+       }
+       
+       Debug( LDAP_DEBUG_TRACE, "tcpconnect failed\n", 0, 0, 0 );
+       tcpclose( tcps );
+       return( -1 );
+}
+
+
+void
+close_connection( Sockbuf *sb )
+{
+       tcpclose( (tcpstream *)sb->sb_sd );
+}
+
+
+#ifdef KERBEROS
+char *
+host_connected_to( Sockbuf *sb )
+{
+       ip_addr addr;
+       
+#ifdef SUPPORT_OPENTRANSPORT
+    InetHostInfo       hi;
+#else /* SUPPORT_OPENTRANSPORT */
+    struct hostInfo    hi;
+#endif /* SUPPORT_OPENTRANSPORT */
+
+       if ( tcpgetpeername( (tcpstream *)sb->sb_sd, &addr, NULL ) != noErr ) {
+               return( NULL );
+       }
+
+#ifdef SUPPORT_OPENTRANSPORT
+       if ( gethostinfobyaddr( addr, &hi ) == noErr ) {
+               return( strdup( hi.name ));
+       }
+#else /* SUPPORT_OPENTRANSPORT */
+       if ( gethostinfobyaddr( addr, &hi ) == noErr ) {
+               return( strdup( hi.cname ));
+       }
+#endif /* SUPPORT_OPENTRANSPORT */
+
+       return( NULL );
+}
+#endif /* KERBEROS */
+
+
+#ifdef LDAP_REFERRALS
+struct tcpstreaminfo {
+       struct tcpstream        *tcpsi_stream;
+       Boolean                         tcpsi_check_read;
+       Boolean                         tcpsi_is_read_ready;
+/*     Boolean                         tcpsi_check_write;              /* no write select support needed yet */
+/*     Boolean                         tcpsi_is_write_ready;   /* ditto */
+};
+
+struct selectinfo {
+       short                                   si_count;
+       struct tcpstreaminfo    *si_streaminfo;
+};
+
+
+void
+mark_select_read( LDAP *ld, Sockbuf *sb )
+{
+       struct selectinfo               *sip;
+       struct tcpstreaminfo    *tcpsip;
+       short                                   i;
+       
+       Debug( LDAP_DEBUG_TRACE, "mark_select_read: stream %x\n", (tcpstream *)sb->sb_sd, 0, 0 );
+
+       if (( sip = (struct selectinfo *)ld->ld_selectinfo ) == NULL ) {
+               return;
+       }
+       
+       for ( i = 0; i < sip->si_count; ++i ) { /* make sure stream is not already in the list... */
+               if ( sip->si_streaminfo[ i ].tcpsi_stream == (tcpstream *)sb->sb_sd ) {
+                       sip->si_streaminfo[ i ].tcpsi_check_read = true;
+                       sip->si_streaminfo[ i ].tcpsi_is_read_ready = false;
+                       return;
+               }
+       }
+
+       /* add a new stream element to our array... */
+       if ( sip->si_count <= 0 ) {
+               tcpsip = (struct tcpstreaminfo *)malloc( sizeof( struct tcpstreaminfo ));
+       } else {
+               tcpsip = (struct tcpstreaminfo *)realloc( sip->si_streaminfo,
+                               ( sip->si_count + 1 ) * sizeof( struct tcpstreaminfo ));
+       }
+       
+       if ( tcpsip != NULL ) {
+               tcpsip[ sip->si_count ].tcpsi_stream = (tcpstream *)sb->sb_sd;
+               tcpsip[ sip->si_count ].tcpsi_check_read = true;
+               tcpsip[ sip->si_count ].tcpsi_is_read_ready = false;
+               sip->si_streaminfo = tcpsip;
+               ++sip->si_count;
+       }
+}
+
+
+void
+mark_select_clear( LDAP *ld, Sockbuf *sb )
+{
+       struct selectinfo       *sip;
+       short                           i;
+
+       Debug( LDAP_DEBUG_TRACE, "mark_select_clear: stream %x\n", (tcpstream *)sb->sb_sd, 0, 0 );
+
+       sip = (struct selectinfo *)ld->ld_selectinfo;
+       if ( sip != NULL && sip->si_count > 0 && sip->si_streaminfo != NULL ) {
+               for ( i = 0; i < sip->si_count; ++i ) {
+                       if ( sip->si_streaminfo[ i ].tcpsi_stream == (tcpstream *)sb->sb_sd ) {
+                               break;
+                       }
+               }
+               if ( i < sip->si_count ) {
+                       --sip->si_count;
+                       for ( ; i < sip->si_count; ++i ) {
+                               sip->si_streaminfo[ i ] = sip->si_streaminfo[ i + 1 ];
+                       }
+                       /* we don't bother to use realloc to make the si_streaminfo array smaller */
+               }
+       }
+}
+
+
+int
+is_read_ready( LDAP *ld, Sockbuf *sb )
+{
+       struct selectinfo       *sip;
+       short                           i;
+       
+       sip = (struct selectinfo *)ld->ld_selectinfo;
+       if ( sip != NULL && sip->si_count > 0 && sip->si_streaminfo != NULL ) {
+               for ( i = 0; i < sip->si_count; ++i ) {
+                       if ( sip->si_streaminfo[ i ].tcpsi_stream == (tcpstream *)sb->sb_sd ) {
+#ifdef LDAP_DEBUG
+                               if ( sip->si_streaminfo[ i ].tcpsi_is_read_ready ) {
+                                       Debug( LDAP_DEBUG_TRACE, "is_read_ready: stream %x READY\n",
+                                                       (tcpstream *)sb->sb_sd, 0, 0 );
+                               } else {
+                                       Debug( LDAP_DEBUG_TRACE, "is_read_ready: stream %x Not Ready\n",
+                                                       (tcpstream *)sb->sb_sd, 0, 0 );
+                               }
+#endif /* LDAP_DEBUG */
+                               return( sip->si_streaminfo[ i ].tcpsi_is_read_ready ? 1 : 0 );
+                       }
+               }
+       }
+
+       Debug( LDAP_DEBUG_TRACE, "is_read_ready: stream %x: NOT FOUND\n", (tcpstream *)sb->sb_sd, 0, 0 );
+       return( 0 );
+}
+
+
+void *
+new_select_info()
+{
+       return( (void *)calloc( 1, sizeof( struct selectinfo )));
+}
+
+
+void
+free_select_info( void *sip )
+{
+       if ( sip != NULL ) {
+               free( sip );
+       }
+}
+
+
+int
+do_ldap_select( LDAP *ld, struct timeval *timeout )
+{
+       struct selectinfo       *sip;
+       Boolean                         ready, gotselecterr;
+       long                            ticks, endticks;
+       short                           i, err;
+
+       Debug( LDAP_DEBUG_TRACE, "do_ldap_select\n", 0, 0, 0 );
+
+       if (( sip = (struct selectinfo *)ld->ld_selectinfo ) == NULL ) {
+               return( -1 );
+       }
+
+       if ( sip->si_count == 0 ) {
+               return( 1 );
+       }
+
+       if ( timeout != NULL ) {
+               endticks = 60 * timeout->tv_sec + ( 60 * timeout->tv_usec ) / 1000000 + TickCount();
+       }
+
+       for ( i = 0; i < sip->si_count; ++i ) {
+               if ( sip->si_streaminfo[ i ].tcpsi_check_read ) {
+                       sip->si_streaminfo[ i ].tcpsi_is_read_ready = false;
+               }
+       }
+
+       ready = gotselecterr = false;
+       do {
+               for ( i = 0; i < sip->si_count; ++i ) {
+                       if ( sip->si_streaminfo[ i ].tcpsi_check_read && !sip->si_streaminfo[ i ].tcpsi_is_read_ready ) {
+                               if (( err = tcpreadready( sip->si_streaminfo[ i ].tcpsi_stream )) > 0 ) {
+                                       sip->si_streaminfo[ i ].tcpsi_is_read_ready = ready = true;
+                               } else if ( err < 0 ) {
+                                       gotselecterr = true;
+                               }
+                       }
+               }
+               if ( !ready && !gotselecterr ) {
+                       Delay( 2L, &ticks );
+                       SystemTask();
+               }
+       } while ( !ready && !gotselecterr && ( timeout == NULL || ticks < endticks ));
+
+       Debug( LDAP_DEBUG_TRACE, "do_ldap_select returns %d\n", ready ? 1 : ( gotselecterr ? -1 : 0 ), 0, 0 );
+       return( ready ? 1 : ( gotselecterr ? -1 : 0 ));
+}
+#endif /* LDAP_REFERRALS */
diff --git a/libraries/macintosh/macos.h b/libraries/macintosh/macos.h
new file mode 100644 (file)
index 0000000..d765413
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * macos.h: bridge unix and Mac for  LBER/LDAP
+ */
+#define ntohl( l )     (l)
+#define htonl( l )     (l)
+#define ntohs( s )     (s)
+#define htons( s )     (s)
+
+#ifdef NO_GLOBALS
+
+#ifdef macintosh       /* IUMagIDString declared in TextUtils.h under MPW */
+#include <TextUtils.h>
+#else /* macintosh */  /* IUMagIDString declared in Packages.h under ThinkC */
+#include <Packages.h>
+#endif /* macintosh */
+
+#define strcasecmp( s1, s2 )   IUMagIDString( s1, s2, strlen( s1 ), \
+                                       strlen( s2 ))
+#else /* NO_GLOBALS */
+int strcasecmp( char *s1, char *s2 );
+int strncasecmp( char *s1, char *s2, long n );
+#endif NO_GLOBALS
+
+#include <Memory.h>    /* to get BlockMove() */
+
+char *strdup( char *s );
+
+#ifndef isascii
+#define isascii(c)     ((unsigned)(c)<=0177)   /* for those who don't have this in ctype.h */
+#endif isascii
+
+#include "tcp.h"
diff --git a/libraries/macintosh/strings.c b/libraries/macintosh/strings.c
new file mode 100644 (file)
index 0000000..5b90441
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * strings.c
+ */
+#include <string.h>
+#include <stdlib.h>
+#include "macos.h"
+
+
+#ifndef NO_GLOBALS
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.  The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+/*
+ * This array is designed for mapping upper and lower case letter
+ * together for a case independent comparison.  The mappings are
+ * based upon ascii character sequences.
+ */
+static char charmap[] = {
+       '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+       '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+       '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+       '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+       '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+       '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+       '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+       '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+       '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+       '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+       '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+       '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+       '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+       '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+       '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+       '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+       '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+       '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+       '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+       '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+       '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+       '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+       '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+       '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+       '\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+       '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+       '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+       '\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337',
+       '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+       '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+       '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+       '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
+};
+
+int
+strcasecmp(char *s1, char *s2)
+{
+       register char *cm = charmap;
+
+       while (cm[*s1] == cm[*s2++])
+               if (*s1++ == '\0')
+                       return(0);
+       return(cm[*s1] - cm[*--s2]);
+}
+
+int
+strncasecmp(char *s1, char *s2, long n)
+{
+       register char *cm = charmap;
+
+       while (--n >= 0 && cm[*s1] == cm[*s2++])
+               if (*s1++ == '\0')
+                       return(0);
+       return(n < 0 ? 0 : cm[*s1] - cm[*--s2]);
+}
+#endif NO_GLOBALS
+
+
+char *
+strdup( char *p )
+{
+       char    *r;
+
+       r = (char *) malloc( strlen( p ) + 1 );
+       if ( r != NULL ) {
+               strcpy( r, p );
+       }
+
+       return( r );
+}
diff --git a/libraries/macintosh/tcp/AddressXlation.h b/libraries/macintosh/tcp/AddressXlation.h
new file mode 100644 (file)
index 0000000..8157cc5
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+       File:           AddressXlation.h
+
+       Copyright:      Â© 1984-1993 by Apple Computer, Inc., all rights reserved.
+
+       WARNING
+       This file was auto generated by the interfacer tool. Modifications
+       must be made to the master file.
+
+*/
+
+#ifndef __ADDRESSXLATION__
+#define __ADDRESSXLATION__
+
+#ifndef __MACTCPCOMMONTYPES__
+#include "MacTCPCommonTypes.h"
+#endif
+
+#define NUM_ALT_ADDRS 4
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct hostInfo {
+       long                                            rtnCode;
+       char                                            cname[255];
+       unsigned long                           addr[NUM_ALT_ADDRS];
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+typedef struct hostInfo hostInfo;
+
+enum AddrClasses {
+       A                                                       = 1,
+       NS,
+       CNAME                                           = 5,
+       HINFO                                           = 13,
+       MX                                                      = 15,
+       lastClass                                       = 32767
+};
+
+typedef enum AddrClasses AddrClasses;
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct HInfoRec {
+       char                                            cpuType[30];
+       char                                            osType[30];
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+typedef struct HInfoRec HInfoRec;
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct MXRec {
+       unsigned short                          preference;
+       char                                            exchange[255];
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+typedef struct MXRec MXRec;
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct returnRec {
+       long                                            rtnCode;
+       char                                            cname[255];
+       union {
+               unsigned long                           addr[NUM_ALT_ADDRS];
+               struct HInfoRec                         hinfo;
+               struct MXRec                            mx;
+       } rdata;
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+typedef struct returnRec returnRec;
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct cacheEntryRecord {
+       char                                            *cname;
+       unsigned short                          type;
+       unsigned short                          cacheClass;
+       unsigned long                           ttl;
+       union {
+               char                                            *name;
+               ip_addr                                         addr;
+       } rdata;
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+typedef struct cacheEntryRecord cacheEntryRecord;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef pascal void (*EnumResultProcPtr)(struct cacheEntryRecord *cacheEntryRecordPtr, char *userDataPtr);
+
+enum {
+       uppEnumResultProcInfo = kPascalStackBased
+                | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(struct cacheEntryRecord*)))
+                | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(char*)))
+};
+
+#if USESROUTINEDESCRIPTORS
+typedef UniversalProcPtr EnumResultUPP;
+
+#define CallEnumResultProc(userRoutine, cacheEntryRecordPtr, userDataPtr)              \
+               CallUniversalProc((UniversalProcPtr)userRoutine, uppEnumResultProcInfo, cacheEntryRecordPtr, userDataPtr)
+#define NewEnumResultProc(userRoutine)         \
+               (EnumResultUPP) NewRoutineDescriptor((ProcPtr)userRoutine, uppEnumResultProcInfo, GetCurrentISA())
+#else
+typedef EnumResultProcPtr EnumResultUPP;
+
+#define CallEnumResultProc(userRoutine, cacheEntryRecordPtr, userDataPtr)              \
+               (*userRoutine)(cacheEntryRecordPtr, userDataPtr)
+#define NewEnumResultProc(userRoutine)         \
+               (EnumResultUPP)(userRoutine)
+#endif
+
+typedef pascal void (*ResultProcPtr)(struct hostInfo *hostInfoPtr, char *userDataPtr);
+
+enum {
+       uppResultProcInfo = kPascalStackBased
+                | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(struct hostInfo*)))
+                | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(char*)))
+};
+
+#if USESROUTINEDESCRIPTORS
+typedef UniversalProcPtr ResultUPP;
+
+#define CallResultProc(userRoutine, hostInfoPtr, userDataPtr)          \
+               CallUniversalProc((UniversalProcPtr)userRoutine, uppResultProcInfo, hostInfoPtr, userDataPtr)
+#define NewResultProc(userRoutine)             \
+               (ResultUPP) NewRoutineDescriptor((ProcPtr)userRoutine, uppResultProcInfo, GetCurrentISA())
+#else
+typedef ResultProcPtr ResultUPP;
+
+#define CallResultProc(userRoutine, hostInfoPtr, userDataPtr)          \
+               (*userRoutine)(hostInfoPtr, userDataPtr)
+#define NewResultProc(userRoutine)             \
+               (ResultUPP)(userRoutine)
+#endif
+
+typedef pascal void (*ResultProc2ProcPtr)(struct returnRec *returnRecPtr, char *userDataPtr);
+
+enum {
+       uppResultProc2ProcInfo = kPascalStackBased
+                | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(struct returnRec*)))
+                | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(char*)))
+};
+
+#if USESROUTINEDESCRIPTORS
+typedef UniversalProcPtr ResultProc2UPP;
+
+#define CallResultProc2Proc(userRoutine, returnRecPtr, userDataPtr)            \
+               CallUniversalProc((UniversalProcPtr)userRoutine, uppResultProc2ProcInfo, returnRecPtr, userDataPtr)
+#define NewResultProc2Proc(userRoutine)                \
+               (ResultProc2UPP) NewRoutineDescriptor((ProcPtr)userRoutine, uppResultProc2ProcInfo, GetCurrentISA())
+#else
+typedef ResultProc2ProcPtr ResultProc2UPP;
+
+#define CallResultProc2Proc(userRoutine, returnRecPtr, userDataPtr)            \
+               (*userRoutine)(returnRecPtr, userDataPtr)
+#define NewResultProc2Proc(userRoutine)                \
+               (ResultProc2UPP)(userRoutine)
+#endif
+
+typedef ResultProc2ProcPtr ResultProc2Ptr;
+
+extern OSErr OpenResolver(char *fileName);
+extern OSErr StrToAddr(char *hostName, struct hostInfo *hostInfoPtr, ResultUPP ResultProc, char *userDataPtr);
+extern OSErr AddrToStr(unsigned long addr, char *addrStr);
+extern OSErr EnumCache(EnumResultUPP enumResultProc, char *userDataPtr);
+extern OSErr AddrToName(ip_addr addr, struct hostInfo *hostInfoPtr, ResultUPP ResultProc, char *userDataPtr);
+extern OSErr HInfo(char *hostName, struct returnRec *returnRecPtr, ResultProc2Ptr resultProc, char *userDataPtr);
+extern OSErr MXInfo(char *hostName, struct returnRec *returnRecPtr, ResultProc2Ptr resultProc, char *userDataPtr);
+extern OSErr CloseResolver(void);
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/libraries/macintosh/tcp/GetMyIPAddr.h b/libraries/macintosh/tcp/GetMyIPAddr.h
new file mode 100644 (file)
index 0000000..253cdf6
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+       File:           GetMyIPAddr.h
+
+       Copyright:      Â© 1984-1993 by Apple Computer, Inc., all rights reserved.
+
+       WARNING
+       This file was auto generated by the interfacer tool. Modifications
+       must be made to the master file.
+
+*/
+
+#ifndef __GETMYIPADDR__
+#define __GETMYIPADDR__
+
+#ifndef __MACTCPCOMMONTYPES__
+#include <MacTCPCommonTypes.h>
+#endif
+
+#define ipctlGetAddr 15                        /* csCode to get our IP address */
+
+#define GetIPParamBlockHeader  \
+       struct QElem *qLink;            \
+       short qType;                            \
+       short ioTrap;                           \
+       Ptr ioCmdAddr;                          \
+       ProcPtr ioCompletion;           \
+       OSErr ioResult;                         \
+       StringPtr ioNamePtr;            \
+       short ioVRefNum;                        \
+       short ioCRefNum;                        \
+       short csCode
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct GetAddrParamBlock {
+       GetIPParamBlockHeader;          /* standard I/O header */       
+       ip_addr         ourAddress;             /* our IP address */
+       long            ourNetMask;             /* our IP net mask */
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+#endif
+
diff --git a/libraries/macintosh/tcp/MacTCPCommonTypes.h b/libraries/macintosh/tcp/MacTCPCommonTypes.h
new file mode 100644 (file)
index 0000000..f806fdc
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+       File:           MacTCPCommonTypes.h
+
+       Copyright:      Â© 1984-1993 by Apple Computer, Inc., all rights reserved.
+
+       WARNING
+       This file was auto generated by the interfacer tool. Modifications
+       must be made to the master file.
+
+*/
+
+#ifndef __MACTCPCOMMONTYPES__
+#define __MACTCPCOMMONTYPES__
+
+#ifndef __TYPES__
+#include <Types.h>
+#endif
+
+/* MacTCP return Codes in the range -23000 through -23049 */
+#define inProgress                             1                       /* I/O in progress */
+
+#define ipBadLapErr                            -23000          /* bad network configuration */
+#define ipBadCnfgErr                   -23001          /* bad IP configuration error */
+#define ipNoCnfgErr                            -23002          /* missing IP or LAP configuration error */
+#define ipLoadErr                              -23003          /* error in MacTCP load */
+#define ipBadAddr                              -23004          /* error in getting address */
+#define connectionClosing              -23005          /* connection is closing */
+#define invalidLength                  -23006
+#define connectionExists               -23007          /* request conflicts with existing connection */
+#define connectionDoesntExist  -23008          /* connection does not exist */
+#define insufficientResources  -23009          /* insufficient resources to perform request */
+#define invalidStreamPtr               -23010
+#define streamAlreadyOpen              -23011
+#define connectionTerminated   -23012
+#define invalidBufPtr                  -23013
+#define invalidRDS                             -23014
+#define invalidWDS                             -23014
+#define openFailed                             -23015
+#define commandTimeout                 -23016
+#define duplicateSocket                        -23017
+
+/* Error codes from internal IP functions */
+#define ipDontFragErr                  -23032          /* Packet too large to send w/o fragmenting */
+#define ipDestDeadErr                  -23033          /* destination not responding */
+#define icmpEchoTimeoutErr             -23035          /* ICMP echo timed-out */
+#define ipNoFragMemErr                 -23036          /* no memory to send fragmented pkt */
+#define ipRouteErr                             -23037          /* can't route packet off-net */
+
+#define nameSyntaxErr                  -23041
+#define cacheFault                             -23042
+#define noResultProc                   -23043
+#define noNameServer                   -23044
+#define authNameErr                            -23045
+#define noAnsErr                               -23046
+#define dnrErr                                 -23047
+#define outOfMemory                            -23048
+
+#define BYTES_16WORD                   2                       /* bytes per 16 bit ip word */
+#define BYTES_32WORD                   4                       /* bytes per 32 bit ip word */
+#define BYTES_64WORD                   8                       /* bytes per 64 bit ip word */
+
+typedef unsigned char b_8;                                     /* 8-bit quantity */
+typedef unsigned short b_16;                           /* 16-bit quantity */
+typedef unsigned long b_32;                                    /* 32-bit quantity */
+typedef b_32 ip_addr;                                          /* IP address is 32-bits */
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct ip_addrbytes {
+       union {
+               b_32                                            addr;
+               char                                            byte[4];
+       } a;
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+typedef struct ip_addrbytes ip_addrbytes;
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct wdsEntry {
+       unsigned short                          length;
+       char                                            *ptr;
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+typedef struct wdsEntry wdsEntry;
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct rdsEntry {
+       unsigned short                          length;
+       char                                            *ptr;
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+typedef struct rdsEntry rdsEntry;
+
+typedef unsigned long BufferPtr;
+
+typedef unsigned long StreamPtr;
+
+enum ICMPMsgType {
+       netUnreach,
+       hostUnreach,
+       protocolUnreach,
+       portUnreach,
+       fragReqd,
+       sourceRouteFailed,
+       timeExceeded,
+       parmProblem,
+       missingOption,
+       lastICMPMsgType                         = 32767
+};
+
+typedef enum ICMPMsgType ICMPMsgType;
+
+typedef b_16 ip_port;
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct ICMPReport {
+       StreamPtr                                       streamPtr;
+       ip_addr                                         localHost;
+       ip_port                                         localPort;
+       ip_addr                                         remoteHost;
+       ip_port                                         remotePort;
+       short                                           reportType;
+       unsigned short                          optionalAddlInfo;
+       unsigned long                           optionalAddlInfoPtr;
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+typedef struct ICMPReport ICMPReport;
+
+typedef OSErr (*OSErrProcPtr)();
+
+enum {
+       uppOSErrProcInfo = kCStackBased
+                | RESULT_SIZE(SIZE_CODE(sizeof(OSErr)))
+};
+
+#if USESROUTINEDESCRIPTORS
+typedef UniversalProcPtr OSErrUPP;
+
+#define CallOSErrProc(userRoutine)             \
+               CallUniversalProc((UniversalProcPtr)userRoutine, uppOSErrProcInfo)
+#define NewOSErrProc(userRoutine)              \
+               (OSErrUPP) NewRoutineDescriptor((ProcPtr)userRoutine, uppOSErrProcInfo, GetCurrentISA())
+#else
+typedef OSErrProcPtr OSErrUPP;
+
+#define CallOSErrProc(userRoutine)             \
+               (*userRoutine)()
+#define NewOSErrProc(userRoutine)              \
+               (OSErrUPP)(userRoutine)
+#endif
+
+typedef Ptr (*PtrProcPtr)();
+
+enum {
+       uppPtrProcInfo = kCStackBased
+                | RESULT_SIZE(SIZE_CODE(sizeof(Ptr)))
+};
+
+#if USESROUTINEDESCRIPTORS
+typedef UniversalProcPtr PtrUPP;
+
+#define CallPtrProc(userRoutine)               \
+               CallUniversalProc((UniversalProcPtr)userRoutine, uppPtrProcInfo)
+#define NewPtrProc(userRoutine)                \
+               (PtrUPP) NewRoutineDescriptor((ProcPtr)userRoutine, uppPtrProcInfo, GetCurrentISA())
+#else
+typedef PtrProcPtr PtrUPP;
+
+#define CallPtrProc(userRoutine)               \
+               (*userRoutine)()
+#define NewPtrProc(userRoutine)                \
+               (PtrUPP)(userRoutine)
+#endif
+
+typedef Boolean (*BooleanProcPtr)();
+
+enum {
+       uppBooleanProcInfo = kCStackBased
+                | RESULT_SIZE(SIZE_CODE(sizeof(Boolean)))
+};
+
+#if USESROUTINEDESCRIPTORS
+typedef UniversalProcPtr BooleanUPP;
+
+#define CallBooleanProc(userRoutine)           \
+               CallUniversalProc((UniversalProcPtr)userRoutine, uppBooleanProcInfo)
+#define NewBooleanProc(userRoutine)            \
+               (BooleanUPP) NewRoutineDescriptor((ProcPtr)userRoutine, uppBooleanProcInfo, GetCurrentISA())
+#else
+typedef BooleanProcPtr BooleanUPP;
+
+#define CallBooleanProc(userRoutine)           \
+               (*userRoutine)()
+#define NewBooleanProc(userRoutine)            \
+               (BooleanUPP)(userRoutine)
+#endif
+
+typedef void (*voidProcPtr)();
+
+#endif
+
diff --git a/libraries/macintosh/tcp/MiscIPPB.h b/libraries/macintosh/tcp/MiscIPPB.h
new file mode 100644 (file)
index 0000000..28a2983
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+       File:           MiscIPPB.h
+
+       Copyright:      Â© 1984-1993 by Apple Computer, Inc., all rights reserved.
+
+       WARNING
+       This file was auto generated by the interfacer tool. Modifications
+       must be made to the master file.
+
+*/
+
+#ifndef __MISCIPPB__
+#define __MISCIPPB__
+
+#ifndef __MACTCPCOMMONTYPES__
+#include <MacTCPCommonTypes.h>
+#endif
+
+#ifndef __APPLETALK__
+#include <AppleTalk.h>
+#endif
+
+#define ipctlEchoICMP 17                       /* send icmp echo */
+#define ipctlLAPStats 19                       /* get lap stats */
+
+#define IPParamBlockHeader             \
+       struct QElem *qLink;            \
+       short qType;                            \
+       short ioTrap;                           \
+       Ptr ioCmdAddr;                          \
+       ProcPtr ioCompletion;           \
+       OSErr ioResult;                         \
+       StringPtr ioNamePtr;            \
+       short ioVRefNum;                        \
+       short ioCRefNum;                        \
+       short csCode
+
+typedef void (*ICMPEchoNotifyProcPtr)(struct ICMPParamBlock *iopb);
+
+enum {
+       uppICMPEchoNotifyProcInfo = kCStackBased
+                | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(struct ICMPParamBlock*)))
+};
+
+#if USESROUTINEDESCRIPTORS
+typedef UniversalProcPtr ICMPEchoNotifyUPP;
+
+#define CallICMPEchoNotifyProc(userRoutine, iopb)              \
+               CallUniversalProc((UniversalProcPtr)userRoutine, uppICMPEchoNotifyProcInfo, iopb)
+#define NewICMPEchoNotifyProc(userRoutine)             \
+               (ICMPEchoNotifyUPP) NewRoutineDescriptor((ProcPtr)userRoutine, uppICMPEchoNotifyProcInfo, GetCurrentISA())
+#else
+typedef ICMPEchoNotifyProcPtr ICMPEchoNotifyUPP;
+
+#define CallICMPEchoNotifyProc(userRoutine, iopb)              \
+               (*userRoutine)(iopb)
+#define NewICMPEchoNotifyProc(userRoutine)             \
+               (ICMPEchoNotifyUPP)(userRoutine)
+#endif
+
+typedef ICMPEchoNotifyProcPtr ICMPEchoNotifyProc;
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct IPParamBlock {
+       IPParamBlockHeader;                                                             /* standard I/O header */
+       union {
+               struct {
+                       ip_addr                                         dest;           /* echo to IP address */
+                       wdsEntry                                        data;
+                       short                                           timeout;
+                       Ptr                                                     options;
+                       unsigned short                          optLength;
+                       ICMPEchoNotifyProc                      icmpCompletion;
+                       unsigned long                           userDataPtr;
+               } IPEchoPB;
+               struct {
+                       struct LAPStats                         *lapStatsPtr;
+               } LAPStatsPB;
+       } csParam;
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct ICMPParamBlock {
+       IPParamBlockHeader;                                                             /* standard I/O header */
+       short                                           params[11];
+       struct {
+               unsigned long                   echoRequestOut;         /* time in ticks of when the echo request went out */
+               unsigned long                   echoReplyIn;            /* time in ticks of when the reply was received */
+               struct rdsEntry                 echoedData;                     /* data received in responce */
+               Ptr                                             options;
+               unsigned long                   userDataPtr;
+       } icmpEchoInfo;
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct LAPStats {
+       short                                           ifType;
+       char                                            *ifString;
+       short                                           ifMaxMTU;
+       long                                            ifSpeed;
+       short                                           ifPhyAddrLength;
+       char                                            *ifPhysicalAddress;
+       union {
+               struct arp_entry                        *arp_table;
+               struct nbp_entry                        *nbp_table;
+       } AddrXlation;
+       short                                           slotNumber;
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+typedef struct LAPStats LAPStats;
+
+#define NBP_TABLE_SIZE 20
+
+#define NBP_MAX_NAME_SIZE 16+10+2
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct nbp_entry {
+       ip_addr                                         ip_address;             /* IP address */
+       AddrBlock                                       at_address;             /* matching AppleTalk address */
+       Boolean                                         gateway;                /* TRUE if entry for a gateway */
+       Boolean                                         valid;                  /* TRUE if LAP address is valid */
+       Boolean                                         probing;                /* TRUE if NBP lookup pending */
+       long                                            age;                    /* ticks since cache entry verified */
+       long                                            access;                 /* ticks since last access */
+       char                                            filler[116];    /* for internal use only !!! */
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+#define ARP_TABLE_SIZE 20                                              /* number of ARP table entries */
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct Enet_addr {
+       b_16                                            en_hi;
+       b_32                                            en_lo;
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+typedef struct Enet_addr Enet_addr;
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct arp_entry {
+       short                                           age;                    /* cache aging field */
+       b_16                                            protocol;               /* Protocol type */
+       ip_addr                                         ip_address;             /* IP address */
+       Enet_addr                                       en_address;             /* matching Ethernet address */
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+typedef struct arp_entry arp_entry;
+
+#endif
+
diff --git a/libraries/macintosh/tcp/TCPPB.h b/libraries/macintosh/tcp/TCPPB.h
new file mode 100644 (file)
index 0000000..ddb6fa0
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+       File:           TCPPB.h
+
+       Copyright:      Â© 1984-1993 by Apple Computer, Inc., all rights reserved.
+
+       WARNING
+       This file was auto generated by the interfacer tool. Modifications
+       must be made to the master file.
+
+*/
+
+#ifndef __TCPPB__
+#define __TCPPB__
+
+#ifndef __MACTCPCOMMONTYPES__
+#include <MacTCPCommonTypes.h>
+#endif
+
+#define TCPCreate                      30
+#define TCPPassiveOpen         31
+#define TCPActiveOpen          32
+#define TCPSend                                34
+#define TCPNoCopyRcv           35
+#define TCPRcvBfrReturn                36
+#define TCPRcv                         37
+#define TCPClose                       38
+#define TCPAbort                       39
+#define TCPStatus                      40
+#define TCPExtendedStat                41
+#define TCPRelease                     42
+#define TCPGlobalInfo          43
+#define TCPCtlMax                      49
+
+enum TCPEventCode {
+       TCPClosing                              = 1,
+       TCPULPTimeout,
+       TCPTerminate,
+       TCPDataArrival,
+       TCPUrgent,
+       TCPICMPReceived,
+       lastEvent                               = 32767
+};
+
+typedef enum TCPEventCode TCPEventCode;
+
+enum TCPTerminationReason {
+       TCPRemoteAbort                  = 2,
+       TCPNetworkFailure,
+       TCPSecPrecMismatch,
+       TCPULPTimeoutTerminate,
+       TCPULPAbort,
+       TCPULPClose,
+       TCPServiceError,
+       lastReason                              = 32767
+};
+
+// typedef TCPTerminationReason TCPTerminationReason;
+
+typedef pascal void (*TCPNotifyProcPtr)(StreamPtr tcpStream, unsigned short eventCode, Ptr userDataPtr, unsigned short terminReason, struct ICMPReport *icmpMsg);
+
+enum {
+       uppTCPNotifyProcInfo = kPascalStackBased
+                | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(StreamPtr)))
+                | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(unsigned short)))
+                | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(Ptr)))
+                | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(unsigned short)))
+                | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(struct ICMPReport*)))
+};
+
+#if USESROUTINEDESCRIPTORS
+typedef UniversalProcPtr TCPNotifyUPP;
+
+#define CallTCPNotifyProc(userRoutine, tcpStream, eventCode, userDataPtr, terminReason, icmpMsg)               \
+               CallUniversalProc((UniversalProcPtr)userRoutine, uppTCPNotifyProcInfo, tcpStream, eventCode, userDataPtr, terminReason, icmpMsg)
+#define NewTCPNotifyProc(userRoutine)          \
+               (TCPNotifyUPP) NewRoutineDescriptor((ProcPtr)userRoutine, uppTCPNotifyProcInfo, GetCurrentISA())
+#else
+typedef TCPNotifyProcPtr TCPNotifyUPP;
+
+#define CallTCPNotifyProc(userRoutine, tcpStream, eventCode, userDataPtr, terminReason, icmpMsg)               \
+               (*userRoutine)(tcpStream, eventCode, userDataPtr, terminReason, icmpMsg)
+#define NewTCPNotifyProc(userRoutine)          \
+               (TCPNotifyUPP)(userRoutine)
+#endif
+
+typedef TCPNotifyProcPtr TCPNotifyProc;
+
+typedef void (*TCPIOCompletionProcPtr)(struct TCPiopb *iopb);
+
+enum {
+       uppTCPIOCompletionProcInfo = kCStackBased
+                | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(struct TCPiopb*)))
+};
+
+#if USESROUTINEDESCRIPTORS
+typedef UniversalProcPtr TCPIOCompletionUPP;
+
+#define CallTCPIOCompletionProc(userRoutine, iopb)             \
+               CallUniversalProc((UniversalProcPtr)userRoutine, uppTCPIOCompletionProcInfo, iopb)
+#define NewTCPIOCompletionProc(userRoutine)            \
+               (TCPIOCompletionUPP) NewRoutineDescriptor((ProcPtr)userRoutine, uppTCPIOCompletionProcInfo, GetCurrentISA())
+#else
+typedef TCPIOCompletionProcPtr TCPIOCompletionUPP;
+
+#define CallTCPIOCompletionProc(userRoutine, iopb)             \
+               (*userRoutine)(iopb)
+#define NewTCPIOCompletionProc(userRoutine)            \
+               (TCPIOCompletionUPP)(userRoutine)
+#endif
+
+typedef TCPIOCompletionProcPtr TCPIOCompletionProc;
+
+typedef unsigned short tcp_port;
+
+typedef unsigned char byte;
+
+enum  {                                        /* ValidityFlags */
+       timeoutValue                            = 0x80,
+       timeoutAction                           = 0x40,
+       typeOfService                           = 0x20,
+       precedence                                      = 0x10
+};
+
+enum  {                                        /* TOSFlags */
+       lowDelay                                        = 0x01,
+       throughPut                                      = 0x02,
+       reliability                                     = 0x04
+};
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct TCPCreatePB {
+       Ptr                                                     rcvBuff;
+       unsigned long                           rcvBuffLen;
+       TCPNotifyUPP                            notifyProc;
+       Ptr                                                     userDataPtr;
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+typedef struct TCPCreatePB TCPCreatePB;
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct TCPOpenPB {
+       byte                                            ulpTimeoutValue;
+       byte                                            ulpTimeoutAction;
+       byte                                            validityFlags;
+       byte                                            commandTimeoutValue;
+       ip_addr                                         remoteHost;
+       tcp_port                                        remotePort;
+       ip_addr                                         localHost;
+       tcp_port                                        localPort;
+       byte                                            tosFlags;
+       byte                                            precedence;
+       Boolean                                         dontFrag;
+       byte                                            timeToLive;
+       byte                                            security;
+       byte                                            optionCnt;
+       byte                                            options[40];
+       Ptr                                                     userDataPtr;
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+typedef struct TCPOpenPB TCPOpenPB;
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct TCPSendPB {
+       byte                                            ulpTimeoutValue;
+       byte                                            ulpTimeoutAction;
+       byte                                            validityFlags;
+       Boolean                                         pushFlag;
+       Boolean                                         urgentFlag;
+       Ptr                                                     wdsPtr;
+       unsigned long                           sendFree;
+       unsigned short                          sendLength;
+       Ptr                                                     userDataPtr;
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+typedef struct TCPSendPB TCPSendPB;
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct TCPReceivePB {
+       byte                                            commandTimeoutValue;
+       byte                                            filler;
+       Boolean                                         markFlag;
+       Boolean                                         urgentFlag;
+       Ptr                                                     rcvBuff;
+       unsigned short                          rcvBuffLen;
+       Ptr                                                     rdsPtr;
+       unsigned short                          rdsLength;
+       unsigned short                          secondTimeStamp;
+       Ptr                                                     userDataPtr;
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+typedef struct TCPReceivePB TCPReceivePB;
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct TCPClosePB {
+       byte                                            ulpTimeoutValue;
+       byte                                            ulpTimeoutAction;
+       byte                                            validityFlags;
+       Ptr                                                     userDataPtr;
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+typedef struct TCPClosePB TCPClosePB;
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct HistoBucket {
+       unsigned short                          value;
+       unsigned long                           counter;
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+typedef struct HistoBucket HistoBucket;
+
+#define NumOfHistoBuckets 7
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct TCPConnectionStats {
+       unsigned long                           dataPktsRcvd;
+       unsigned long                           dataPktsSent;
+       unsigned long                           dataPktsResent;
+       unsigned long                           bytesRcvd;
+       unsigned long                           bytesRcvdDup;
+       unsigned long                           bytesRcvdPastWindow;
+       unsigned long                           bytesSent;
+       unsigned long                           bytesResent;
+       unsigned short                          numHistoBuckets;
+       struct HistoBucket                      sentSizeHisto[NumOfHistoBuckets];
+       unsigned short                          lastRTT;
+       unsigned short                          tmrSRTT;
+       unsigned short                          rttVariance;
+       unsigned short                          tmrRTO;
+       byte                                            sendTries;
+       byte                                            sourchQuenchRcvd;
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+typedef struct TCPConnectionStats TCPConnectionStats;
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct TCPStatusPB {
+       byte                                            ulpTimeoutValue;
+       byte                                            ulpTimeoutAction;
+       long                                            unused;
+       ip_addr                                         remoteHost;
+       tcp_port                                        remotePort;
+       ip_addr                                         localHost;
+       tcp_port                                        localPort;
+       byte                                            tosFlags;
+       byte                                            precedence;
+       byte                                            connectionState;
+       unsigned short                          sendWindow;
+       unsigned short                          rcvWindow;
+       unsigned short                          amtUnackedData;
+       unsigned short                          amtUnreadData;
+       Ptr                                                     securityLevelPtr;
+       unsigned long                           sendUnacked;
+       unsigned long                           sendNext;
+       unsigned long                           congestionWindow;
+       unsigned long                           rcvNext;
+       unsigned long                           srtt;
+       unsigned long                           lastRTT;
+       unsigned long                           sendMaxSegSize;
+       struct TCPConnectionStats       *connStatPtr;
+       Ptr                                                     userDataPtr;
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+typedef struct TCPStatusPB TCPStatusPB;
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct TCPAbortPB {
+       Ptr                                                     userDataPtr;
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+typedef struct TCPAbortPB TCPAbortPB;
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct TCPParam {
+       unsigned long                           tcpRtoA;
+       unsigned long                           tcpRtoMin;
+       unsigned long                           tcpRtoMax;
+       unsigned long                           tcpMaxSegSize;
+       unsigned long                           tcpMaxConn;
+       unsigned long                           tcpMaxWindow;
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+typedef struct TCPParam TCPParam;
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct TCPStats {
+       unsigned long                           tcpConnAttempts;
+       unsigned long                           tcpConnOpened;
+       unsigned long                           tcpConnAccepted;
+       unsigned long                           tcpConnClosed;
+       unsigned long                           tcpConnAborted;
+       unsigned long                           tcpOctetsIn;
+       unsigned long                           tcpOctetsOut;
+       unsigned long                           tcpOctetsInDup;
+       unsigned long                           tcpOctetsRetrans;
+       unsigned long                           tcpInputPkts;
+       unsigned long                           tcpOutputPkts;
+       unsigned long                           tcpDupPkts;
+       unsigned long                           tcpRetransPkts;
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+typedef struct TCPStats TCPStats;
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct TCPGlobalInfoPB {
+       struct TCPParam                         *tcpParamPtr;
+       struct TCPStats                         *tcpStatsPtr;
+       StreamPtr                                       *tcpCDBTable[1];
+       Ptr                                                     userDataPtr;
+       unsigned short                          maxTCPConnections;
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+typedef struct TCPGlobalInfoPB TCPGlobalInfoPB;
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct TCPiopb {
+       char                                            fill12[12];
+       TCPIOCompletionProc                     ioCompletion;
+       short                                           ioResult;
+       char                                            *ioNamePtr;
+       short                                           ioVRefNum;
+       short                                           ioCRefNum;
+       short                                           csCode;
+       StreamPtr                                       tcpStream;
+       union {
+               struct TCPCreatePB                      create;
+               struct TCPOpenPB                        open;
+               struct TCPSendPB                        send;
+               struct TCPReceivePB                     receive;
+               struct TCPClosePB                       close;
+               struct TCPAbortPB                       abort;
+               struct TCPStatusPB                      status;
+               struct TCPGlobalInfoPB          globalInfo;
+       } csParam;
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+typedef struct TCPiopb TCPiopb;
+
+#endif
+
diff --git a/libraries/macintosh/tcp/UDPPB.h b/libraries/macintosh/tcp/UDPPB.h
new file mode 100644 (file)
index 0000000..f8c7bbd
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+       File:           UDPPB.h
+
+       Copyright:      Â© 1984-1993 by Apple Computer, Inc., all rights reserved.
+
+       WARNING
+       This file was auto generated by the interfacer tool. Modifications
+       must be made to the master file.
+
+*/
+
+#ifndef __UDPPB__
+#define __UDPPB__
+
+#ifndef __MACTCPCOMMONTYPES__
+#include <MacTCPCommonTypes.h>
+#endif
+
+#define UDPCreate              20
+#define UDPRead                        21
+#define UDPBfrReturn   22
+#define UDPWrite               23
+#define UDPRelease             24
+#define UDPMaxMTUSize  25
+#define UDPStatus              26
+#define UDPMultiCreate 27
+#define UDPMultiSend   28
+#define UDPMultiRead   29
+#define UDPCtlMax              29
+
+enum UDPEventCode {
+       UDPDataArrival          = 1,
+       UDPICMPReceived,
+       lastUDPEvent            = 32767
+};
+
+typedef enum UDPEventCode UDPEventCode;
+
+typedef pascal void (*UDPNotifyProcPtr)(StreamPtr udpStream, unsigned short eventCode, Ptr userDataPtr, struct ICMPReport *icmpMsg);
+
+enum {
+       uppUDPNotifyProcInfo = kPascalStackBased
+                | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(StreamPtr)))
+                | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(unsigned short)))
+                | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(Ptr)))
+                | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(struct ICMPReport*)))
+};
+
+#if USESROUTINEDESCRIPTORS
+typedef UniversalProcPtr UDPNotifyUPP;
+
+#define CallUDPNotifyProc(userRoutine, udpStream, eventCode, userDataPtr, icmpMsg)             \
+               CallUniversalProc((UniversalProcPtr)userRoutine, uppUDPNotifyProcInfo, udpStream, eventCode, userDataPtr, icmpMsg)
+#define NewUDPNotifyProc(userRoutine)          \
+               (UDPNotifyUPP) NewRoutineDescriptor((ProcPtr)userRoutine, uppUDPNotifyProcInfo, GetCurrentISA())
+#else
+typedef UDPNotifyProcPtr UDPNotifyUPP;
+
+#define CallUDPNotifyProc(userRoutine, udpStream, eventCode, userDataPtr, icmpMsg)             \
+               (*userRoutine)(udpStream, eventCode, userDataPtr, icmpMsg)
+#define NewUDPNotifyProc(userRoutine)          \
+               (UDPNotifyUPP)(userRoutine)
+#endif
+
+typedef UDPNotifyProcPtr UDPNotifyProc;
+
+typedef void (*UDPIOCompletionProcPtr)(struct UDPiopb *iopb);
+
+enum {
+       uppUDPIOCompletionProcInfo = kCStackBased
+                | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(struct UDPiopb*)))
+};
+
+#if USESROUTINEDESCRIPTORS
+typedef UniversalProcPtr UDPIOCompletionUPP;
+
+#define CallUDPIOCompletionProc(userRoutine, iopb)             \
+               CallUniversalProc((UniversalProcPtr)userRoutine, uppUDPIOCompletionProcInfo, iopb)
+#define NewUDPIOCompletionProc(userRoutine)            \
+               (UDPIOCompletionUPP) NewRoutineDescriptor((ProcPtr)userRoutine, uppUDPIOCompletionProcInfo, GetCurrentISA())
+#else
+typedef UDPIOCompletionProcPtr UDPIOCompletionUPP;
+
+#define CallUDPIOCompletionProc(userRoutine, iopb)             \
+               (*userRoutine)(iopb)
+#define NewUDPIOCompletionProc(userRoutine)            \
+               (UDPIOCompletionUPP)(userRoutine)
+#endif
+
+typedef UDPIOCompletionProcPtr UDPIOCompletionProc;
+
+typedef unsigned short udp_port;
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct UDPCreatePB {           /* for create and release calls */
+       Ptr                                                     rcvBuff;
+       unsigned long                           rcvBuffLen;
+       UDPNotifyProc                           notifyProc;
+       unsigned short                          localPort;
+       Ptr                                                     userDataPtr;
+       udp_port                                        endingPort;
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+typedef struct UDPCreatePB UDPCreatePB;
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct UDPSendPB {
+       unsigned short                          reserved;
+       ip_addr                                         remoteHost;
+       udp_port                                        remotePort;
+       Ptr                                                     wdsPtr;
+       Boolean                                         checkSum;
+       unsigned short                          sendLength;
+       Ptr                                                     userDataPtr;
+       udp_port                                        localPort;
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+typedef struct UDPSendPB UDPSendPB;
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct UDPReceivePB {          /* for receive and buffer return calls */
+       unsigned short                          timeOut;
+       ip_addr                                         remoteHost;
+       udp_port                                        remotePort;
+       Ptr                                                     rcvBuff;
+       unsigned short                          rcvBuffLen;
+       unsigned short                          secondTimeStamp;
+       Ptr                                                     userDataPtr;
+       ip_addr                                         destHost;               /* only for use with multi rcv */
+       udp_port                                        destPort;               /* only for use with multi rcv */
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+typedef struct UDPReceivePB UDPReceivePB;
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct UDPMTUPB {
+       unsigned short                          mtuSize;
+       ip_addr                                         remoteHost;
+       Ptr                                                     userDataPtr;
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+typedef struct UDPMTUPB UDPMTUPB;
+
+#if defined(powerc) || defined (__powerc)
+#pragma options align=mac68k
+#endif
+struct UDPiopb {
+       char                                            fill12[12];
+       UDPIOCompletionProc                     ioCompletion;
+       short                                           ioResult;
+       char                                            *ioNamePtr;
+       short                                           ioVRefNum;
+       short                                           ioCRefNum;
+       short                                           csCode;
+       StreamPtr                                       udpStream;
+       union {
+               struct UDPCreatePB              create;
+               struct UDPSendPB                send;
+               struct UDPReceivePB             receive;
+               struct UDPMTUPB                 mtu;
+       } csParam;
+};
+#if defined(powerc) || defined(__powerc)
+#pragma options align=reset
+#endif
+
+typedef struct UDPiopb UDPiopb;
+
+#endif
+
diff --git a/libraries/macintosh/tcp/dnr.c b/libraries/macintosh/tcp/dnr.c
new file mode 100644 (file)
index 0000000..47ea30a
--- /dev/null
@@ -0,0 +1,529 @@
+/*
+       DNR.c - DNR library for MPW
+
+       Â© Copyright 1988 by Apple Computer.  All rights reserved
+       
+*/
+
+#define MPW3.0
+
+#include <OSUtils.h>
+#include <Errors.h>
+#include <Files.h>
+#include <Resources.h>
+#include <Memory.h>
+#include <Traps.h>
+#include <GestaltEqu.h>
+#include <Folders.h>
+#include <MixedMode.h>                                                                         
+#include <ToolUtils.h>                                                                         
+#include "AddressXlation.h"
+
+/*
+ * function prototypes
+ */
+static void GetSystemFolder(short *vRefNumP, long *dirIDP);
+static void GetCPanelFolder(short *vRefNumP, long *dirIDP);
+static short SearchFolderForDNRP(long targetType, long targetCreator, short vRefNum,
+               long dirID);
+static short OpenOurRF( void );
+
+
+#define OPENRESOLVER   1L
+#define CLOSERESOLVER  2L
+#define STRTOADDR              3L
+#define        ADDRTOSTR               4L
+#define        ENUMCACHE               5L
+#define ADDRTONAME             6L
+#define        HINFO                   7L
+#define MXINFO                 8L
+
+Handle                                 codeHndl = nil;
+UniversalProcPtr       dnr = nil;
+
+
+static TrapType GetTrapType(unsigned long theTrap)
+{
+       if (BitAnd(theTrap, 0x0800) > 0)
+               return(ToolTrap);
+       else
+               return(OSTrap);
+       }
+       
+static Boolean TrapAvailable(unsigned long trap)
+{
+TrapType trapType = ToolTrap;
+unsigned long numToolBoxTraps;
+
+       if (NGetTrapAddress(_InitGraf, ToolTrap) == NGetTrapAddress(0xAA6E, ToolTrap))
+               numToolBoxTraps = 0x200;
+       else
+               numToolBoxTraps = 0x400;
+
+       trapType = GetTrapType(trap);
+       if (trapType == ToolTrap) {
+               trap = BitAnd(trap, 0x07FF);
+               if (trap >= numToolBoxTraps)
+                       trap = _Unimplemented;
+               }
+       return(NGetTrapAddress(trap, trapType) != NGetTrapAddress(_Unimplemented, ToolTrap));
+
+}
+
+static void GetSystemFolder(short *vRefNumP, long *dirIDP)
+{
+       SysEnvRec info;
+       long wdProcID;
+       
+       SysEnvirons(1, &info);
+       if (GetWDInfo(info.sysVRefNum, vRefNumP, dirIDP, &wdProcID) != noErr) {
+               *vRefNumP = 0;
+               *dirIDP = 0;
+               }
+       }
+
+static void GetCPanelFolder(short *vRefNumP, long *dirIDP)
+{
+       Boolean hasFolderMgr = false;
+       long feature;
+       
+       if (Gestalt(gestaltFindFolderAttr, &feature) == noErr) 
+               hasFolderMgr = true;
+       if (!hasFolderMgr) {
+               GetSystemFolder(vRefNumP, dirIDP);
+               return;
+               }
+       else {
+               if (FindFolder(kOnSystemDisk, kControlPanelFolderType, kDontCreateFolder, vRefNumP, dirIDP) != noErr) {
+                       *vRefNumP = 0;
+                       *dirIDP = 0;
+                       }
+               }
+       }
+       
+/* SearchFolderForDNRP is called to search a folder for files that might 
+       contain the 'dnrp' resource */
+static short SearchFolderForDNRP(long targetType, long targetCreator, short vRefNum, long dirID)
+{
+       HParamBlockRec fi;
+       Str255 filename;
+       short refnum;
+       
+       fi.fileParam.ioCompletion = nil;
+       fi.fileParam.ioNamePtr = filename;
+       fi.fileParam.ioVRefNum = vRefNum;
+       fi.fileParam.ioDirID = dirID;
+       fi.fileParam.ioFDirIndex = 1;
+       
+       while (PBHGetFInfoSync(&fi) == noErr) {
+               /* scan system folder for driver resource files of specific type & creator */
+               if (fi.fileParam.ioFlFndrInfo.fdType == targetType &&
+                       fi.fileParam.ioFlFndrInfo.fdCreator == targetCreator) {
+                       /* found the MacTCP driver file? */
+                       refnum = HOpenResFile(vRefNum, dirID, filename, fsRdPerm);
+                       if (GetIndResource('dnrp', 1) == NULL)
+                               CloseResFile(refnum);
+                       else
+                               return refnum;
+                       }
+               /* check next file in system folder */
+               fi.fileParam.ioFDirIndex++;
+               fi.fileParam.ioDirID = dirID;   /* PBHGetFInfo() clobbers ioDirID */
+               }
+       return(-1);
+       }       
+
+
+
+/* OpenOurRF is called to open the MacTCP driver resources */
+
+static short OpenOurRF()
+{
+       short refnum;
+       short vRefNum;
+       long dirID;
+       
+       /* first search Control Panels for MacTCP 1.1 */
+       GetCPanelFolder(&vRefNum, &dirID);
+       refnum = SearchFolderForDNRP('cdev', 'ztcp', vRefNum, dirID);
+       if (refnum != -1) return(refnum);
+               
+       /* next search System Folder for MacTCP 1.0.x */
+       GetSystemFolder(&vRefNum, &dirID);
+       refnum = SearchFolderForDNRP('cdev', 'mtcp', vRefNum, dirID);
+       if (refnum != -1) return(refnum);
+               
+       /* finally, search Control Panels for MacTCP 1.0.x */
+       GetCPanelFolder(&vRefNum, &dirID);
+       refnum = SearchFolderForDNRP('cdev', 'mtcp', vRefNum, dirID);
+       if (refnum != -1) return(refnum);
+               
+       return -1;
+       }       
+
+
+
+
+typedef OSErr (*OpenResolverProcPtr)(long selector, char* fileName);
+
+enum {
+       uppOpenResolverProcInfo = kCStackBased
+                | RESULT_SIZE(SIZE_CODE(sizeof(short)))
+                | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(short)))
+                | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(char *)))
+};
+
+#if USESROUTINEDESCRIPTORS
+typedef UniversalProcPtr OpenResolverUPP;
+
+#define        NewOpenResolverProc(userRoutine)                                                \
+               (OpenResolverUPP) NewRoutineDescriptor(userRoutine, uppOpenResolverProcInfo, GetCurrentISA())
+#define        CallOpenResolverProc(userRoutine, selector, filename)   \
+               CallUniversalProc(userRoutine, uppOpenResolverProcInfo, selector, filename)
+#else
+typedef OpenResolverProcPtr OpenResolverUPP;
+
+#define        NewOpenResolverProc(userRoutine)                                        \
+               (OpenResolverUPP)(userRoutine)
+#define        CallOpenResolverProc(userRoutine, selector, filename)   \
+               (*(OpenResolverProcPtr)userRoutine)(selector, filename)
+#endif
+
+
+
+OSErr OpenResolver(char *fileName)
+{
+       short                   refnum;
+       OSErr                   rc;
+       
+       if (dnr != nil)
+               /* resolver already loaded in */
+               return(noErr);
+               
+       /* open the MacTCP driver to get DNR resources. Search for it based on
+          creator & type rather than simply file name */       
+       refnum = OpenOurRF();
+
+       /* ignore failures since the resource may have been installed in the 
+          System file if running on a Mac 512Ke */
+          
+       /* load in the DNR resource package */
+       codeHndl = GetIndResource('dnrp', 1);
+       if (codeHndl == nil) {
+               /* can't open DNR */
+               return(ResError());
+       }
+       
+       DetachResource(codeHndl);
+       if (refnum != -1) {
+               CloseWD(refnum);
+               CloseResFile(refnum);
+       }
+               
+       /* lock the DNR resource since it cannot be relocated while opened */
+       HLock(codeHndl);
+       dnr = (UniversalProcPtr) *codeHndl;
+       
+       /* call open resolver */
+       rc = CallOpenResolverProc(dnr, OPENRESOLVER, fileName);
+       if (rc != noErr) {
+               /* problem with open resolver, flush it */
+               HUnlock(codeHndl);
+               DisposeHandle(codeHndl);
+               dnr = nil;
+       }
+       return(rc);
+}
+
+
+
+typedef OSErr (*CloseResolverProcPtr)(long selector);
+
+enum {
+       uppCloseResolverProcInfo = kCStackBased
+                | RESULT_SIZE(SIZE_CODE(sizeof(short)))
+                | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(short)))
+};
+
+#if USESROUTINEDESCRIPTORS
+typedef UniversalProcPtr CloseResolverUPP;
+
+#define        NewCloseResolverProc(userRoutine)                                               \
+               (CloseResolverUPP) NewRoutineDescriptor(userRoutine, uppCloseResolverProcInfo, GetCurrentISA())
+#define        CallCloseResolverProc(userRoutine, selector)    \
+               CallUniversalProc(userRoutine, uppCloseResolverProcInfo, selector)
+#else
+typedef CloseResolverProcPtr CloseResolverUPP;
+
+#define        NewCloseResolverProc(userRoutine)                                               \
+               (CloseResolverUPP)(userRoutine)
+#define        CallCloseResolverProc(userRoutine, selector)    \
+               (*(CloseResolverProcPtr)userRoutine)(selector)
+#endif
+
+
+
+OSErr CloseResolver()
+{
+       if (dnr == nil)
+               /* resolver not loaded error */
+               return(notOpenErr);
+               
+       /* call close resolver */
+       CallCloseResolverProc(dnr, CLOSERESOLVER);
+
+       /* release the DNR resource package */
+       HUnlock(codeHndl);
+       DisposeHandle(codeHndl);
+       dnr = nil;
+       return(noErr);
+}
+
+
+
+
+typedef OSErr (*StrToAddrProcPtr)(long selector, char* hostName, struct hostInfo* rtnStruct,
+                                                                       long resultProc, char* userData);
+                                                                       
+enum {
+       uppStrToAddrProcInfo = kCStackBased
+                | RESULT_SIZE(SIZE_CODE(sizeof(short)))
+                | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(short)))
+                | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(char *)))
+                | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(struct hostInfo *)))
+                | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(long)))
+                | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(char *)))
+};
+
+#if USESROUTINEDESCRIPTORS
+typedef UniversalProcPtr StrToAddrUPP;
+
+#define        NewStrToAddrProc(userRoutine)                                           \
+               (StrToAddrUPP) NewRoutineDescriptor(userRoutine, uppStrToAddrProcInfo, GetCurrentISA())
+#define        CallStrToAddrProc(userRoutine, selector, hostName, rtnStruct, resultProc, userData)     \
+               CallUniversalProc(userRoutine, uppStrToAddrProcInfo, selector, hostName, rtnStruct, resultProc, userData)
+#else
+typedef StrToAddrProcPtr StrToAddrUPP;
+
+#define        NewStrToAddrProc(userRoutine)                                           \
+               (StrToAddrUPP)(userRoutine)
+#define        CallStrToAddrProc(userRoutine, selector, hostName, rtnStruct, resultProc, userData)     \
+               (*(StrToAddrProcPtr)userRoutine)(selector, hostName, rtnStruct, resultProc, userData)
+#endif
+
+
+
+OSErr StrToAddr(char *hostName, struct hostInfo *rtnStruct, ResultUPP resultupp, char *userDataPtr)
+{
+       if (dnr == nil)
+               /* resolver not loaded error */
+               return(notOpenErr);
+               
+       return(CallStrToAddrProc(dnr, STRTOADDR, hostName, rtnStruct, (long)resultupp, userDataPtr));
+}
+
+
+typedef OSErr (*AddrToStrProcPtr)(long selector, long address, char* hostName);
+
+enum {
+       uppAddrToStrProcInfo = kCStackBased
+                | RESULT_SIZE(SIZE_CODE(sizeof(short)))
+                | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(short)))
+                | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(unsigned long)))
+                | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(char *)))
+};
+
+#if USESROUTINEDESCRIPTORS
+typedef UniversalProcPtr AddrToStrUPP;
+
+#define        NewAddrToStrProc(userRoutine)                                           \
+               (AddrToStrUPP) NewRoutineDescriptor(userRoutine, uppAddrToStrProcInfo, GetCurrentISA())
+#define        CallAddrToStrProc(userRoutine, selector, address, hostName)     \
+               CallUniversalProc(userRoutine, uppAddrToStrProcInfo, selector, address, hostName)
+#else
+typedef AddrToStrProcPtr AddrToStrUPP;
+
+#define        NewAddrToStrProc(userRoutine)                                           \
+               (AddrToStrUPP)(userRoutine)
+#define        CallAddrToStrProc(userRoutine, selector, address, hostName)     \
+               (*(AddrToStrProcPtr)userRoutine)(selector, address, hostName)
+#endif
+
+       
+OSErr AddrToStr(unsigned long addr, char *addrStr)
+{
+       if (dnr == nil)
+               /* resolver not loaded error */
+               return(notOpenErr);
+               
+       CallAddrToStrProc(dnr, ADDRTOSTR, addr, addrStr);
+
+       return(noErr);
+}
+
+
+
+typedef OSErr (*EnumCacheProcPtr)(long selector, long result, char* userData);
+
+enum {
+       uppEnumCacheProcInfo = kCStackBased
+                | RESULT_SIZE(SIZE_CODE(sizeof(short)))
+                | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(short)))
+                | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(long)))
+                | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(char *)))
+};
+
+#if USESROUTINEDESCRIPTORS
+typedef UniversalProcPtr EnumCacheUPP;
+
+#define        NewEnumCacheProc(userRoutine)                                           \
+               (EnumCacheUPP) NewRoutineDescriptor(userRoutine, uppEnumCacheProcInfo, GetCurrentISA())
+#define        CallEnumCacheProc(userRoutine, selector, result, userData)      \
+               CallUniversalProc(userRoutine, uppEnumCacheProcInfo, selector, result, userData)
+#else
+typedef EnumCacheProcPtr EnumCacheUPP;
+
+#define        NewEnumCacheProc(userRoutine)                                           \
+               (EnumCacheUPP)(userRoutine)
+#define        CallEnumCacheProc(userRoutine, selector, result, userData)      \
+               (*(EnumCacheProcPtr)userRoutine)(selector, result, userData)
+#endif
+
+
+       
+OSErr EnumCache(EnumResultUPP resultupp, char *userDataPtr)
+{
+       if (dnr == nil)
+               /* resolver not loaded error */
+               return(notOpenErr);
+               
+       return(CallEnumCacheProc(dnr, ENUMCACHE, (long)resultupp, userDataPtr));
+}
+
+
+
+typedef OSErr (*AddrToNameProcPtr)(long selector, unsigned long addr, struct hostInfo* rtnStruct,
+                                                                       long resultProc, char* userData);
+
+enum {
+       uppAddrToNameProcInfo = kCStackBased
+                | RESULT_SIZE(SIZE_CODE(sizeof(short)))
+                | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(short)))
+                | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(unsigned long)))
+                | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(struct hostInfo *)))
+                | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(long)))
+                | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(char *)))
+
+};
+
+#if USESROUTINEDESCRIPTORS
+typedef UniversalProcPtr AddrToNameUPP;
+
+#define        NewAddrToNameProc(userRoutine)                                          \
+               (AddrToNameUPP) NewRoutineDescriptor(userRoutine, uppAddrToNameProcInfo, GetCurrentISA())
+#define        CallAddrToNameProc(userRoutine, selector, addr, rtnStruct, resultProc, userData)        \
+               CallUniversalProc(userRoutine, uppAddrToNameProcInfo, selector, addr, rtnStruct, resultProc, userData)
+#else
+typedef AddrToNameProcPtr AddrToNameUPP;
+
+#define        NewAddrToNameProc(userRoutine)                                          \
+               (AddrToNameUPP)(userRoutine)
+#define        CallAddrToNameProc(userRoutine, selector, addr, rtnStruct, resultProc, userData)        \
+               (*(AddrToNameProcPtr)userRoutine)(selector, addr, rtnStruct, resultProc, userData)
+#endif
+
+       
+       
+OSErr AddrToName(unsigned long addr, struct hostInfo *rtnStruct, ResultUPP resultupp,
+       char *userDataPtr)
+{
+       if (dnr == nil)
+               /* resolver not loaded error */
+               return(notOpenErr);
+               
+       return(CallAddrToNameProc(dnr, ADDRTONAME, addr, rtnStruct, (long)resultupp, userDataPtr));
+}
+
+
+typedef OSErr (*HInfoProcPtr)(long selector, char* hostName, struct returnRec* returnRecPtr,
+                                                               long resultProc, char* userData);
+
+enum {
+       uppHInfoProcInfo = kCStackBased
+                | RESULT_SIZE(SIZE_CODE(sizeof(short)))
+                | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(short)))
+                | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(char *)))
+                | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(struct returnRec *)))
+                | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(long)))
+                | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(char *)))
+
+};
+
+#if USESROUTINEDESCRIPTORS
+typedef UniversalProcPtr HInfoUPP;
+
+#define        NewHInfoProc(userRoutine)                                               \
+               (HInfoUPP) NewRoutineDescriptor(userRoutine, uppHInfoProcInfo, GetCurrentISA())
+#define        CallHInfoProc(userRoutine, selector, hostName, returnRecPtr, resultProc, userData)      \
+               CallUniversalProc(userRoutine, uppHInfoProcInfo, selector, hostName, returnRecPtr, resultProc, userData)
+#else
+typedef HInfoProcPtr HInfoUPP;
+
+#define        NewHInfoProc(userRoutine)                                               \
+               (HInfoUPP)(userRoutine)
+#define        CallHInfoProc(userRoutine, selector, hostName, returnRecPtr, resultProc, userData)      \
+               (*(HInfoProcPtr)userRoutine)( selector, hostName, returnRecPtr, resultProc, userData)
+#endif
+
+extern OSErr HInfo(char *hostName, struct returnRec *returnRecPtr, ResultProc2Ptr resultProc,
+       char *userDataPtr)
+{
+       if (dnr == nil)
+               /* resolver not loaded error */
+               return(notOpenErr);
+               
+       return(CallHInfoProc(dnr, HINFO, hostName, returnRecPtr, (long)resultProc, userDataPtr));
+}
+
+
+
+typedef OSErr (*MXInfoProcPtr)(long selector, char* hostName, struct returnRec* returnRecPtr,
+                                                               long resultProc, char* userData);
+
+enum {
+       uppMXInfoProcInfo = kCStackBased
+                | RESULT_SIZE(SIZE_CODE(sizeof(short)))
+                | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(short)))
+                | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(char *)))
+                | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(struct returnRec *)))
+                | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(long)))
+                | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(char *)))
+
+};
+
+#if USESROUTINEDESCRIPTORS
+typedef UniversalProcPtr MXInfoUPP;
+
+#define        NewMXInfoProc(userRoutine)                                              \
+               (MXInfoUPP) NewRoutineDescriptor(userRoutine, uppMXInfoProcInfo, GetCurrentISA())
+#define        CallMXInfoProc(userRoutine, selector, hostName, returnRecPtr, resultProc, userData)     \
+               CallUniversalProc(userRoutine, selector, hostName, returnRecPtr, resultProc, userData)
+#else
+typedef MXInfoProcPtr MXInfoUPP;
+
+#define        NewMXInfoProc(userRoutine)                                              \
+               (MXInfoUPP)(userRoutine)
+#define        CallMXInfoProc(userRoutine, selector, hostName, returnRecPtr, resultProc, userData)     \
+               (*(MXInfoProcPtr)userRoutine)(selector, hostName, returnRecPtr, resultProc, userData)
+#endif
+       
+       
+extern OSErr MXInfo(char *hostName, struct returnRec *returnRecPtr, ResultProc2Ptr resultProc,
+       char *userDataPtr)
+{
+       if (dnr == nil)
+               /* resolver not loaded error */
+               return(notOpenErr);
+               
+       return(CallMXInfoProc(dnr, MXINFO, hostName, returnRecPtr, (long)resultProc, userDataPtr));
+}
diff --git a/libraries/macintosh/tcp/tcp.c b/libraries/macintosh/tcp/tcp.c
new file mode 100644 (file)
index 0000000..80d0878
--- /dev/null
@@ -0,0 +1,982 @@
+/*
+ *     Copyright (c) 1990-92 Regents of the University of Michigan.
+ *     All rights reserved.
+ *
+ *     tcp.c -- TCP communication related routines
+ */
+#include "lber.h"
+#include "ldap.h"
+#include "tcp.h"
+
+#include <Devices.h>
+#include <Desk.h>              /* to get SystemTask() */
+#include <Memory.h>
+#include <Errors.h>
+#include <Gestalt.h>
+
+/*
+ * local prototypes
+ */
+#ifdef NEEDPROTOS
+void           bzero( char *buf, unsigned long count );
+pascal void setdoneflag( struct hostInfo *hip, char *donep );
+pascal void tcp_asynchnotify( StreamPtr tstream, unsigned short event, Ptr userdatap,
+                                                       unsigned short term_reason, struct ICMPReport *icmpmsg );
+OSErr          kick_mactcp( short *drefnump );
+#ifdef SUPPORT_OPENTRANSPORT
+pascal void EventHandler(tcpstream *tsp, OTEventCode event, OTResult result, void * /* cookie */);
+#endif /* SUPPORT_OPENTRANSPORT */
+#else /* NEEDPROTOS */
+void           bzero();
+pascal void setdoneflag();
+pascal void tcp_asynchnotify();
+OSErr          kick_mactcp();
+#ifdef SUPPORT_OPENTRANSPORT
+pascal void EventHandler();
+#endif /* SUPPORT_OPENTRANSPORT */
+#endif /* NEEDPROTOS */
+
+#ifdef SUPPORT_OPENTRANSPORT
+static Boolean gHaveOT = false;
+#endif /* SUPPORT_OPENTRANSPORT */
+
+
+#ifdef SUPPORT_OPENTRANSPORT
+/*
+ * Initialize the tcp module.  This mainly consists of seeing if we have
+ * Open Transport and initializing it and setting our global saying so.
+ */ 
+OSStatus
+tcp_init( void )
+{
+       long            result;
+       OSStatus        err;
+
+       gHaveOT = (( err = Gestalt( gestaltOpenTpt, &result )) == noErr &&
+                       ( result & gestaltOpenTptPresent ) != 0 &&
+                       ( result & gestaltOpenTptTCPPresent ) != 0 );
+
+       if ( gHaveOT ) {
+               return( InitOpenTransport());
+       } else {
+               return( kOTNoError );   /* assume we have MacTCP */
+       }
+}
+
+
+void
+tcp_shutdown( void )
+{
+       if ( gHaveOT ) {
+               CloseOpenTransport();
+       }
+}
+
+Boolean
+tcp_have_opentransport( void )
+{
+       return( gHaveOT );
+}
+#endif /* SUPPORT_OPENTRANSPORT */
+
+
+/*
+ * open and return an pointer to a TCP stream (return NULL if error)
+ * "buf" is a buffer for receives of length "buflen."
+ */
+tcpstream *
+tcpopen( unsigned char * buf, long buflen ) {
+       TCPiopb                 pb;
+       OSStatus                err;
+       tcpstream *             tsp;
+       short                   drefnum;
+#ifdef SUPPORT_OPENTRANSPORT
+       TEndpointInfo   info;
+#endif /* SUPPORT_OPENTRANSPORT */
+
+       if (nil == (tsp = (tcpstream *)NewPtrClear(sizeof(tcpstream)))) {
+               return( nil );
+       }
+       
+#ifdef SUPPORT_OPENTRANSPORT
+       if ( gHaveOT ) {
+       
+               //
+               // Now create a TCP
+               //
+               tsp->tcps_ep = OTOpenEndpoint( OTCreateConfiguration( kTCPName ), 0, &info, &err );
+
+               if ( !tsp->tcps_ep ) {
+                       if ( err == kOTNoError ) {
+                               err = -1;
+                       }
+               }
+       
+               if ( !err ) {
+                       err = OTSetSynchronous( tsp->tcps_ep );
+               }
+       
+               tsp->tcps_data = 0;
+               tsp->tcps_terminated = tsp->tcps_connected = false;
+               
+               //
+               // Install notifier we're going to use
+               //
+               if ( !err ) {
+                       err = OTInstallNotifier( tsp->tcps_ep, (OTNotifyProcPtr) EventHandler, 0 );
+               }
+       
+               if ( err != kOTNoError ) {
+                       if ( tsp->tcps_ep ) {
+                               OTCloseProvider( tsp->tcps_ep );
+                       }
+                       DisposePtr( (Ptr)tsp );
+                       tsp = nil;
+               }
+       } else {
+#endif /* SUPPORT_OPENTRANSPORT */
+
+               if ( kick_mactcp( &drefnum ) != noErr ) {
+                       return ( nil );
+               }
+       
+               if (( tsp->tcps_notifyupp = NewTCPNotifyProc( tcp_asynchnotify )) == NULL ) {
+                       DisposePtr( (Ptr)tsp );
+                       return( nil );
+               }
+               
+               tsp->drefnum = drefnum;
+               
+               if ( buflen == 0 ) {
+                       buflen = TCP_BUFSIZ;
+               }
+               
+               if ( buf == NULL && 
+                        (nil == ( buf = tsp->tcps_buffer = (unsigned char *)NewPtr( buflen )))) {
+                       DisposeRoutineDescriptor( tsp->tcps_notifyupp );
+                       DisposePtr( (Ptr)tsp );
+                       return( nil );
+               }
+               bzero( (char *)&pb, sizeof( pb ));      
+               pb.csCode = TCPCreate;
+               pb.ioCRefNum = tsp->drefnum;
+               pb.csParam.create.rcvBuff = (Ptr) buf;
+               pb.csParam.create.rcvBuffLen = buflen;
+               pb.csParam.create.notifyProc = tsp->tcps_notifyupp;
+               pb.csParam.create.userDataPtr = (Ptr)tsp;
+                       
+               if (( err = PBControlSync( (ParmBlkPtr)&pb )) != noErr || pb.ioResult != noErr ) {
+                       DisposeRoutineDescriptor( tsp->tcps_notifyupp );
+                       DisposePtr( (Ptr)tsp->tcps_buffer );
+                       DisposePtr( (Ptr)tsp );
+                       return( nil );
+               }
+
+               tsp->tcps_data = 0;
+               tsp->tcps_terminated = tsp->tcps_connected = false;
+               tsp->tcps_sptr = pb.tcpStream;
+
+#ifdef SUPPORT_OPENTRANSPORT
+       }
+#endif /* SUPPORT_OPENTRANSPORT */
+
+       return( tsp );
+}
+
+/*
+ * connect to remote host at IP address "addr", TCP port "port"
+ * return local port assigned, 0 if error
+ */
+#ifdef SUPPORT_OPENTRANSPORT
+InetPort
+tcpconnect( tcpstream * tsp, InetHost addr, InetPort port ) {
+#else /* SUPPORT_OPENTRANSPORT */
+ip_port
+tcpconnect( tcpstream * tsp, ip_addr addr, ip_port port ) {
+#endif /* SUPPORT_OPENTRANSPORT */
+       TCPiopb         pb;
+       OSStatus        err;
+#ifdef SUPPORT_OPENTRANSPORT
+       struct InetAddress sndsin, rcvsin, retsin;
+       TCall           sndcall, rcvcall;
+       TBind           ret;
+#endif /* SUPPORT_OPENTRANSPORT */
+
+#ifdef SUPPORT_OPENTRANSPORT
+       if ( gHaveOT ) {
+       
+               if ( tsp->tcps_ep == NULL ) {
+                       return( 0 );
+               }
+       
+               bzero( (char *)&sndsin, sizeof( struct InetAddress ));
+               bzero( (char *)&rcvsin, sizeof( struct InetAddress ));
+               bzero( (char *)&retsin, sizeof( struct InetAddress ));
+               bzero( (char *)&sndcall, sizeof( TCall ));
+               bzero( (char *)&rcvcall, sizeof( TCall));
+               bzero( (char *)&ret, sizeof( TBind ));
+               
+               // Bind TCP to an address and port.  We don't care which one, so we pass null for
+               // the requested address.
+               ret.addr.maxlen = sizeof( struct InetAddress );
+               ret.addr.buf = (unsigned char *)&retsin;
+               err = OTBind( tsp->tcps_ep, NULL, &ret );
+               if ( err != kOTNoError ) {
+                       return( 0 );
+               }
+       
+               OTInitInetAddress( &sndsin, port, addr );
+               sndcall.addr.len = sizeof( struct InetAddress );
+               sndcall.addr.buf = (UInt8 *)&sndsin;
+       
+               rcvcall.addr.maxlen = sizeof( struct InetAddress );
+               rcvcall.addr.buf = (unsigned char *)&rcvsin;
+       
+               err = OTConnect( tsp->tcps_ep, &sndcall, &rcvcall );
+               if ( err != kOTNoError ) {
+                       return 0;
+               }
+       
+               tsp->tcps_connected = true;
+               tsp->tcps_remoteport = rcvsin.fPort;
+               tsp->tcps_remoteaddr = rcvsin.fHost;
+               return( retsin.fPort );
+       
+       } else {
+#endif /* SUPPORT_OPENTRANSPORT */
+       
+               if ( tsp->tcps_sptr == (StreamPtr)NULL ) {
+                       return( 0 );
+               }
+                       
+               bzero( (char *)&pb, sizeof( pb ));      
+               pb.csCode = TCPActiveOpen;
+               pb.ioCRefNum = tsp->drefnum;
+               pb.tcpStream = tsp->tcps_sptr;
+               pb.csParam.open.remoteHost = addr;
+               pb.csParam.open.remotePort = port;
+               pb.csParam.open.ulpTimeoutValue = 15;
+               pb.csParam.open.validityFlags = timeoutValue;
+                       
+               if (( err = PBControlSync( (ParmBlkPtr)&pb )) != noErr || pb.ioResult != noErr ) {
+                       return( 0 );
+               }
+               
+               tsp->tcps_connected = true;
+               return( pb.csParam.open.localPort );
+       
+#ifdef SUPPORT_OPENTRANSPORT
+       }
+#endif /* SUPPORT_OPENTRANSPORT */
+       
+}
+
+
+/*
+ * close and release a TCP stream
+ * returns 0 if no error, -1 if any error occurs
+ */
+short
+tcpclose( tcpstream * tsp ) {
+       TCPiopb         pb;
+       OSStatus                rc;
+       
+#ifdef SUPPORT_OPENTRANSPORT
+       if ( gHaveOT ) {
+       
+       
+               if ( tsp->tcps_ep == NULL ) {
+                       return( -1 );
+               }
+       
+#ifdef notdef
+               /*
+                * if connected execute a close
+                */
+               if ( tcp->tcps_connected ) {
+                       Call OTSndOrderlyDisconnect and wait for the other end to respond.  This requires
+                       waiting for and reading any data that comes in in the meantime.  This code was ifdefed
+                       out in the MacTCP so it is here too.
+               }
+#endif /* notdef */
+               
+               rc = OTSndDisconnect( tsp->tcps_ep, NULL );
+       
+               OTCloseProvider( tsp->tcps_ep );
+               DisposePtr( (Ptr)tsp );
+               
+               if ( rc != 0 ) {
+                       rc = -1;
+               }
+
+       } else {
+#endif /* SUPPORT_OPENTRANSPORT */
+       
+               if ( tsp->tcps_sptr == (StreamPtr)NULL ) {
+                       return( -1 );
+               }
+               
+#ifdef notdef
+               /*
+                * if connected execute a close
+                */
+               if ( tcp->tcps_connected ) {
+                       bzero( (char *)&pb, sizeof( pb ));
+                       pb.csCode = TCPClose;
+                       pb.ioCRefNum = tsp->drefnum;
+                       pb.tcpStream = sp;
+                       pb.csParam.close.validityFlags = 0;
+                       PBControlSync( (ParmBlkPtr)&pb );
+               }
+#endif /* notdef */
+                       
+               bzero( (char *)&pb, sizeof( pb ));
+               pb.csCode = TCPRelease;
+               pb.ioCRefNum = tsp->drefnum;
+               pb.tcpStream = tsp->tcps_sptr;
+               pb.csParam.close.validityFlags = 0;
+               rc = 0;
+               
+               if ( PBControlSync( (ParmBlkPtr)&pb ) != noErr || pb.ioResult != noErr ) {
+                       rc = -1;
+               }
+               
+               DisposeRoutineDescriptor( tsp->tcps_notifyupp );
+               DisposePtr( (Ptr)tsp->tcps_buffer );
+               DisposePtr( (Ptr)tsp );
+       
+#ifdef SUPPORT_OPENTRANSPORT
+       }
+#endif /* SUPPORT_OPENTRANSPORT */
+               
+       return( rc );   
+}
+
+
+/*
+ * wait for new data to arrive
+ *
+ * if "timeout" is NULL, wait until data arrives or connection goes away
+ * if "timeout" is a pointer to a zero'ed struct, poll
+ * else wait for "timeout->tv_sec + timeout->tv_usec" seconds
+ */
+short
+tcpselect( tcpstream * tsp, struct timeval * timeout )
+{
+       long    ticks, endticks;
+       short   rc;
+
+       if ( timeout != NULL ) {
+               endticks = 60 * timeout->tv_sec + ( 60 * timeout->tv_usec ) / 1000000 + TickCount();
+       }
+       ticks = 0;      
+
+       while (( rc = tcpreadready( tsp )) == 0 && ( timeout == NULL || ticks < endticks )) {
+               Delay( 2L, &ticks );
+               SystemTask();
+       }
+
+       return ( rc );
+}
+
+
+short
+tcpreadready( tcpstream *tsp )
+{
+#ifdef SUPPORT_OPENTRANSPORT
+       size_t  dataAvail;
+
+       if (gHaveOT) {
+               if ( tsp->tcps_ep == NULL ) {
+                       return( -1 );
+               }
+       
+               OTCountDataBytes( tsp->tcps_ep, &dataAvail );
+               tsp->tcps_data = ( dataAvail != 0 );    
+       } else {
+#endif /* SUPPORT_OPENTRANSPORT */
+               if ( tsp->tcps_sptr == (StreamPtr)NULL ) {
+                       return( -1 );
+               }
+       
+               /* tsp->tcps_data is set in async. notify proc, so nothing for us to do here */
+#ifdef SUPPORT_OPENTRANSPORT
+       }
+#endif /* SUPPORT_OPENTRANSPORT */
+       return ( tsp->tcps_terminated ? -1 : ( tsp->tcps_data < 1 ) ? 0 : 1 );
+}
+
+
+/*
+ * read up to "rbuflen" bytes into "rbuf" from a connected TCP stream
+ * wait up to "timeout" seconds for data (if timeout == 0, wait "forever")
+ */
+long
+tcpread( tcpstream * tsp, byte timeout, unsigned char * rbuf,
+                                                 unsigned short rbuflen, DialogPtr dlp ) {
+       TCPiopb                 pb;
+       unsigned long   time, end_time;
+#ifdef SUPPORT_OPENTRANSPORT
+       OTFlags                 flags;
+       OTResult                result;
+       size_t                  dataAvail;
+#endif /* SUPPORT_OPENTRANSPORT */
+       
+#ifdef SUPPORT_OPENTRANSPORT
+       if ( gHaveOT ) {
+       
+               if ( tsp->tcps_ep == NULL ) {
+                       return( -1 );
+               }
+               
+               // Try to read data.  Since we're in non-blocking mode, this will fail with kOTNoDataErr
+               // if no data is available.
+               result = OTRcv( tsp->tcps_ep, rbuf, rbuflen, &flags );
+               if ( result == kOTNoDataErr ) {
+                       // Nothing available, wait for some.  The ugly spin loop below is the way the old
+                       // MacTCP code worked.  I should fix it, but I don't have time right now.
+                       tsp->tcps_data = 0;
+                       GetDateTime( &time );
+                       end_time = time + timeout;
+               
+                       while (( timeout <= 0 || end_time > time ) && tsp->tcps_data < 1 && !tsp->tcps_terminated ) {
+                               OTCountDataBytes( tsp->tcps_ep, &dataAvail );
+                               if ( dataAvail > 0 ) {
+                                       tsp->tcps_data = 1;
+                               }
+                               GetDateTime( &time );
+                               SystemTask();
+                       }
+                       
+                       if ( tsp->tcps_data < 1 ) {
+                               return( tsp->tcps_terminated ? -3 : -1 );
+                       }
+                       
+                       // Should have data available now, try again.
+                       result = OTRcv( tsp->tcps_ep, rbuf, rbuflen, &flags );
+               }
+               
+               if ( result < 0 ) {
+                       return( -1 );
+               }
+               
+               OTCountDataBytes( tsp->tcps_ep, &dataAvail );
+               if ( dataAvail == 0 ) {
+                       tsp->tcps_data = 0;
+               }
+
+               return( result );
+       
+       } else {
+#endif /* SUPPORT_OPENTRANSPORT */
+       
+               if ( tsp->tcps_sptr == (StreamPtr)NULL ) {
+                       return( -1 );
+               }
+               
+               GetDateTime( &time );
+               end_time = time + timeout;
+       
+               while(( timeout <= 0 || end_time > time ) && tsp->tcps_data < 1 &&
+                               !tsp->tcps_terminated ) {
+                       GetDateTime( &time );
+                       SystemTask();
+               }
+               
+               if ( tsp->tcps_data < 1 ) {
+                       return( tsp->tcps_terminated ? -3 : -1 );
+               }
+                       
+               bzero( (char *)&pb, sizeof( pb ));      
+               pb.csCode = TCPRcv;
+               pb.ioCRefNum = tsp->drefnum;
+               pb.tcpStream = tsp->tcps_sptr;
+               pb.csParam.receive.commandTimeoutValue = timeout;
+               pb.csParam.receive.rcvBuff = (char *)rbuf;      
+               pb.csParam.receive.rcvBuffLen = rbuflen;
+               
+               if ( PBControlSync( (ParmBlkPtr)&pb ) != noErr || pb.ioResult != noErr ) {
+                       return( -1 );
+               }
+               
+               if ( --(tsp->tcps_data) < 0 ) {
+                       tsp->tcps_data = 0;
+               }
+               
+               return( pb.csParam.receive.rcvBuffLen );
+
+#ifdef SUPPORT_OPENTRANSPORT           
+       }       
+#endif /* SUPPORT_OPENTRANSPORT */
+#pragma unused (dlp)
+}
+
+/*
+ * send TCP data
+ * "sp" is the stream to write to
+ * "wbuf" is "wbuflen" bytes of data to send
+ * returns < 0 if error, number of bytes written if no error
+ */
+long
+tcpwrite( tcpstream * tsp, unsigned char * wbuf, unsigned short wbuflen ) {
+       TCPiopb         pb;
+       wdsEntry        wds[ 2 ];
+       OSErr           err;
+#ifdef SUPPORT_OPENTRANSPORT           
+       OTResult                result;
+       unsigned short  nwritten;
+#endif /* SUPPORT_OPENTRANSPORT */
+       
+#ifdef SUPPORT_OPENTRANSPORT           
+       if ( gHaveOT ) {
+       
+               if ( tsp->tcps_ep == NULL ) {
+                       return( -1 );
+               }
+
+               /*
+                * We used to do a single call to OTSnd() here, framed with OTSetBlocking() and OTSetNonBlocking()
+                * this caused crashes deep inside OpenTransport when writes were large or done in
+                * rapid succession, so now we never turn on blocking mode
+                */
+               nwritten = 0;
+               while ( wbuflen > 0 ) {
+                       if (( result = OTSnd( tsp->tcps_ep, wbuf, wbuflen, 0 )) < 0 ) {
+                               if ( result != kOTFlowErr ) {
+                                       break;
+                               }
+                       } else {
+                               nwritten += result;
+                               if (( wbuflen -= result ) > 0 ) {
+                                       SystemTask();
+                                       wbuf += result;
+                               }
+                       }
+               }
+               return(( wbuflen == 0 ) ? nwritten : result );
+
+       } else {
+#endif /* SUPPORT_OPENTRANSPORT */
+       
+               if ( tsp->tcps_sptr == (StreamPtr)NULL ) {
+                       return( -1 );
+               }
+               
+               wds[ 0 ].length = wbuflen;
+               wds[ 0 ].ptr = (char *)wbuf;
+               wds[ 1 ].length = 0;
+               
+               bzero( (char *)&pb, sizeof( pb ));      
+               pb.csCode = TCPSend;
+               pb.ioCRefNum = tsp->drefnum;
+               pb.tcpStream = tsp->tcps_sptr;
+               pb.csParam.send.wdsPtr = (Ptr)wds;
+               pb.csParam.send.validityFlags = 0;
+               
+               if (( err = PBControlSync( (ParmBlkPtr)&pb )) != noErr || pb.ioResult != noErr ) {
+                       return( -1 );
+               }
+               
+               return( wbuflen );
+
+#ifdef SUPPORT_OPENTRANSPORT           
+       }
+#endif /* SUPPORT_OPENTRANSPORT */
+}
+
+static pascal void
+tcp_asynchnotify(
+       StreamPtr                       tstream,
+       unsigned short          event,
+       Ptr                                     userdatap,
+       unsigned short          term_reason,    
+       struct ICMPReport       *icmpmsg
+)
+{
+       tcpstream       *tsp;
+       
+       tsp = (tcpstream *)userdatap;
+       switch( event ) {
+               case TCPDataArrival:
+                       ++(tsp->tcps_data);
+                       break;
+               case TCPClosing:
+               case TCPTerminate:
+               case TCPULPTimeout:
+                       tsp->tcps_terminated = true;
+                       break;
+               default:
+                       break;
+       }
+#pragma unused (tstream, term_reason, icmpmsg)
+}
+
+
+short
+tcpgetpeername( tcpstream *tsp, ip_addr *addrp, tcp_port *portp ) {
+       TCPiopb         pb;
+       OSErr           err;
+
+#ifdef SUPPORT_OPENTRANSPORT           
+       if ( gHaveOT ) {
+       
+               if ( tsp->tcps_ep == NULL ) {
+                       return( -1 );
+               }
+                       
+               if ( addrp != NULL ) {
+                       *addrp = tsp->tcps_remoteaddr;
+               }
+       
+               if ( portp != NULL ) {
+                       *portp = tsp->tcps_remoteport;
+               }
+               
+       } else {
+#endif /* SUPPORT_OPENTRANSPORT */
+       
+               if ( tsp->tcps_sptr == (StreamPtr)NULL ) {
+                       return( -1 );
+               }
+                       
+               bzero( (char *)&pb, sizeof( pb ));      
+               pb.csCode = TCPStatus;
+               pb.ioCRefNum = tsp->drefnum;
+               pb.tcpStream = tsp->tcps_sptr;
+               
+               if (( err = PBControlSync( (ParmBlkPtr)&pb )) != noErr || pb.ioResult != noErr ) {
+                       return( err );
+               }
+       
+               if ( addrp != NULL ) {
+                       *addrp = pb.csParam.status.remoteHost;
+               }
+       
+               if ( portp != NULL ) {
+                       *portp = pb.csParam.status.remotePort;
+               }
+
+#ifdef SUPPORT_OPENTRANSPORT           
+       }
+
+       return( kOTNoError );
+#else /* SUPPORT_OPENTRANSPORT */
+       return( noErr );
+#endif /* SUPPORT_OPENTRANSPORT */
+}
+
+
+/*
+ * bzero -- set "len" bytes starting at "p" to zero
+ */
+static void
+bzero( char *p, unsigned long len )
+{
+       unsigned long   i;
+       
+       for ( i = 0; i < len; ++i ) {
+               *p++ = '\0';
+       }
+}
+
+
+pascal void
+setdoneflag( struct hostInfo *hip, char *donep )
+{
+       ++(*donep);
+#pragma unused (hip)
+}
+
+
+/*
+ * return a hostInfo structure for "host" (return != noErr if error)
+ */
+short
+#ifdef SUPPORT_OPENTRANSPORT           
+gethostinfobyname( char *host, InetHostInfo *hip ) {
+#else /* SUPPORT_OPENTRANSPORT */
+gethostinfobyname( char *host, struct hostInfo *hip ) {
+#endif /* SUPPORT_OPENTRANSPORT */
+       char                                    done = 0;
+       OSStatus                                err;
+       long                                    time;
+       ResultUPP                               rupp;
+#ifdef notdef
+       struct dnr_struct               dnr_global = {nil, 0};
+#endif /* notdef */
+#ifdef SUPPORT_OPENTRANSPORT           
+       hostInfo                                hi;                             /* Old MacTCP version of hostinfo */
+       InetSvcRef                              inetsvc;                /* Internet services reference */
+#endif /* SUPPORT_OPENTRANSPORT */
+
+#ifdef SUPPORT_OPENTRANSPORT           
+       if ( gHaveOT ) {
+       
+               // Get an Internet Services reference
+               inetsvc = OTOpenInternetServices( kDefaultInternetServicesPath, 0, &err );
+               if ( !inetsvc || err != kOTNoError ) {
+                       if ( err == kOTNoError ) {
+                               err = -1;
+                       }
+                       inetsvc = nil;
+               }
+               
+               if ( !err ) {   
+                       err = OTInetStringToAddress( inetsvc, host, hip );
+               }
+               
+               if ( inetsvc ) {
+                       OTCloseProvider(inetsvc);
+               }
+               
+       } else {
+#endif /* SUPPORT_OPENTRANSPORT */
+       
+               if (( err = kick_mactcp( NULL )) != noErr
+                               || ( err = OpenResolver( /* &dnr_global, */ NULL )) != noErr ) {
+                       return( err );
+               }
+       
+               if (( rupp = NewResultProc( setdoneflag )) == NULL ) {
+                       err = memFullErr;
+               } else {
+#ifdef SUPPORT_OPENTRANSPORT           
+                       bzero( (char *)&hi, sizeof( hostInfo ));
+                       if (( err = StrToAddr( /* &dnr_global, */ host, &hi, rupp, &done ))  == cacheFault ) {
+#else /* SUPPORT_OPENTRANSPORT */
+                       bzero((char *) hip, sizeof( hostInfo ));
+                       if (( err = StrToAddr( /* &dnr_global, */ host, hip, rupp, &done ))  == cacheFault ) {
+#endif /* SUPPORT_OPENTRANSPORT */
+                               while( !done ) {
+                                       Delay( 2L, &time );                     // querying DN servers; wait for reply
+                                       SystemTask();
+                               }
+#ifdef SUPPORT_OPENTRANSPORT           
+                               err = hi.rtnCode;
+#else /* SUPPORT_OPENTRANSPORT */
+                               err = hip->rtnCode;
+#endif /* SUPPORT_OPENTRANSPORT */
+                       }
+                       DisposeRoutineDescriptor( rupp );
+               }
+       
+               CloseResolver( /* &dnr_global */ );
+               
+#ifdef SUPPORT_OPENTRANSPORT           
+               /* Copy the results to the InetHostInfo area passed in by caller */
+               BlockMove(hi.cname, hip->name, kMaxHostNameLen);
+               BlockMove(hi.addr, hip->addrs, 4*NUM_ALT_ADDRS);
+               hip->addrs[NUM_ALT_ADDRS] = 0;
+               
+               /* Convert the return code to an OT style return code */
+               if ( err == nameSyntaxErr ) {
+                       err = kOTBadNameErr;
+               } else if ( err == noNameServer || err == authNameErr || err == noAnsErr ) {
+                       err = kOTBadNameErr;
+               } else if (err != noErr) {
+                       err = kOTSysErrorErr;
+               }
+       
+       }
+
+       if (( err == kOTNoError ) && ( hip->addrs[ 0 ] == 0 )) {
+               err = kOTBadNameErr;
+       }
+       return( err );
+
+#else /* SUPPORT_OPENTRANSPORT */
+       if ( err != noErr || (( err == noErr ) && ( hip->addr[ 0 ] == 0 ))) {
+               return( err == noErr ? noAnsErr : err );
+       }
+       return( noErr );
+#endif /* SUPPORT_OPENTRANSPORT */
+}
+
+/*
+ * return a hostInfo structure for "addr" (return != noErr if error)
+ */
+short
+#ifdef SUPPORT_OPENTRANSPORT           
+gethostinfobyaddr( InetHost addr, InetHostInfo *hip )
+#else /* SUPPORT_OPENTRANSPORT */
+gethostinfobyaddr( ip_addr addr, struct hostInfo *hip )
+#endif /* SUPPORT_OPENTRANSPORT */
+{
+       
+       char                                    done = 0;
+       OSStatus                                err;
+       long                                    time;
+       ResultUPP                               rupp;
+#ifdef notdef
+       struct dnr_struct               dnr_global = {nil, 0};
+#endif /* notdef */
+#ifdef SUPPORT_OPENTRANSPORT           
+       hostInfo                                hi;                             /* Old MacTCP version of hostinfo */
+       InetSvcRef                              inetsvc;                /* Internet services reference */
+#endif /* SUPPORT_OPENTRANSPORT */
+
+#ifdef SUPPORT_OPENTRANSPORT           
+       if ( gHaveOT ) {
+               // Get an Internet Services reference
+               inetsvc = OTOpenInternetServices( kDefaultInternetServicesPath, 0, &err );
+               if ( !inetsvc || err != kOTNoError ) {
+                       if ( err == kOTNoError ) {
+                               err = -1;
+                       }
+                       inetsvc = nil;
+               }
+               
+               if ( !err ) {
+                       err = OTInetAddressToName( inetsvc, addr, hip->name );
+               }
+               
+               if ( inetsvc ) {
+                       OTCloseProvider( inetsvc );
+               }
+       
+       } else {
+#endif /* SUPPORT_OPENTRANSPORT */
+       
+               if (( err = kick_mactcp( NULL )) != noErr ||
+                               ( err = OpenResolver( /* &dnr_global, */ NULL )) != noErr )
+                       return( err );
+       
+               if (( rupp = NewResultProc( setdoneflag )) == NULL ) {
+                       err = memFullErr;
+               } else {
+#ifdef SUPPORT_OPENTRANSPORT           
+                       bzero( (char *) &hi, sizeof( hostInfo ));
+                       if (( err = AddrToName( /* &dnr_global, */ addr, &hi, rupp, &done ))  == cacheFault ) {
+#else /* SUPPORT_OPENTRANSPORT */
+                       bzero( (char *)hip, sizeof( hostInfo ));
+                       if (( err = AddrToName( /* &dnr_global, */ addr, hip, rupp, &done ))  == cacheFault ) {
+#endif /* SUPPORT_OPENTRANSPORT */
+                               while( !done ) {
+                                       Delay( 2L, &time );                     // querying DN servers; wait for reply
+                                       SystemTask();
+                               }
+#ifdef SUPPORT_OPENTRANSPORT           
+                               err = hi.rtnCode;
+#else /* SUPPORT_OPENTRANSPORT */
+                               err = hip->rtnCode;
+#endif /* SUPPORT_OPENTRANSPORT */
+                       }
+                       DisposeRoutineDescriptor( rupp );
+               }
+       
+               CloseResolver( /* &dnr_global */ );
+       
+#ifdef SUPPORT_OPENTRANSPORT           
+               /* Copy the results to the InetHostInfo area passed in by caller */
+               BlockMove(hi.cname, hip->name, kMaxHostNameLen);
+               BlockMove(hi.addr, hip->addrs, 4*NUM_ALT_ADDRS);
+               hip->addrs[NUM_ALT_ADDRS] = 0;
+               
+               /* Convert the return code to an OT style return code */
+               if (err == nameSyntaxErr) {
+                       err = kOTBadNameErr;
+               } else if (err == noNameServer || err == authNameErr || err == noAnsErr) {
+                       err = kOTBadNameErr;
+               } else if (err != noErr) {
+                       err = kOTSysErrorErr;
+               }
+       
+       }
+#endif /* SUPPORT_OPENTRANSPORT */
+       
+       return( err );
+}
+
+/*
+ * return a ASCII equivalent of ipaddr.  addrstr must be at large enough to hold the
+ * result which is of the form "AAA.BBB.CCC.DDD" and can be a maximum of 16 bytes in size
+ */
+short
+#ifdef SUPPORT_OPENTRANSPORT           
+ipaddr2str( InetHost ipaddr, char *addrstr )
+#else /* SUPPORT_OPENTRANSPORT */
+ipaddr2str( ip_addr ipaddr, char *addrstr )
+#endif /* SUPPORT_OPENTRANSPORT */
+{
+       OSStatus                                err;
+#ifdef notdef
+       struct dnr_struct               dnr_global = {nil, 0};
+#endif /* notdef */
+
+#ifdef SUPPORT_OPENTRANSPORT           
+       if ( gHaveOT ) {
+       
+               OTInetHostToString( ipaddr, addrstr );
+               err = kOTNoError;
+       
+       } else {
+#endif /* SUPPORT_OPENTRANSPORT */
+       
+               if (( err = kick_mactcp( NULL )) != noErr ||
+                               ( err = OpenResolver( /* &dnr_global, */ NULL )) != noErr )
+                       return( err );
+       
+               err = AddrToStr( ipaddr, addrstr );
+       
+               CloseResolver( /* &dnr_global */ );
+               
+#ifdef SUPPORT_OPENTRANSPORT           
+       }
+#endif /* SUPPORT_OPENTRANSPORT */
+       
+       return( err );
+}
+
+
+#ifdef SUPPORT_OPENTRANSPORT           
+/*******************************************************************************
+** EventHandler
+********************************************************************************/
+pascal void EventHandler(tcpstream *tsp, OTEventCode event, OTResult result, void * /* cookie */)
+{
+
+       switch(event)
+       {
+               case T_ORDREL:
+               case T_DISCONNECT:
+                       tsp->tcps_terminated = true;
+                       break;
+               case T_DATA:
+               case T_EXDATA:
+                       tsp->tcps_data += 1;
+                       break;
+               default:
+                       break;
+       }
+       return;
+}
+#endif /* SUPPORT_OPENTRANSPORT */
+
+
+static OSErr
+kick_mactcp( short *drefnump )
+{
+       short                                           dref;
+       OSErr                                           err;
+       struct GetAddrParamBlock        gapb;
+
+/*
+ * we make sure the MacTCP driver is open and issue a "Get My Address" call
+ * so that adevs like MacPPP are initialized (MacTCP is dumb)
+ */
+       if (( err = OpenDriver( "\p.IPP", &dref )) != noErr ) {
+               return( err );
+       }
+
+       if ( drefnump != NULL ) {
+               *drefnump = dref;
+       }
+
+       bzero( (char *)&gapb, sizeof( gapb ));
+       gapb.csCode = ipctlGetAddr;
+       gapb.ioCRefNum = dref;
+
+       err = PBControlSync( (ParmBlkPtr)&gapb );
+
+       return( noErr );
+}
diff --git a/libraries/macintosh/tcp/tcp.h b/libraries/macintosh/tcp/tcp.h
new file mode 100644 (file)
index 0000000..0c7b8e4
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * tcp.h  interface to MCS's TCP routines
+ */
+#include <Dialogs.h>
+#ifdef SUPPORT_OPENTRANSPORT
+#include <OpenTransport.h>
+#include <OpenTptInternet.h>
+#endif /* SUPPORT_OPENTRANSPORT */
+#include "MacTCPCommonTypes.h"
+#include "AddressXlation.h"
+#include "TCPPB.h"
+#include "GetMyIPAddr.h"
+
+#ifndef TCP_BUFSIZ
+#define TCP_BUFSIZ     8192
+#endif /* TCP_BUFSIZ */
+
+typedef struct tcpstream {
+       StreamPtr                       tcps_sptr;                      /* stream pointer for MacTCP TCP PB calls */
+#ifdef SUPPORT_OPENTRANSPORT
+       EndpointRef                     tcps_ep;                        /* OpenTransport end point */
+#endif /* SUPPORT_OPENTRANSPORT */
+       short                           tcps_data;                      /* count of packets on read queue */
+       short                           drefnum;                        /* driver ref num, for convenience */
+       Boolean                         tcps_connected;         /* true if connection was made */
+       Boolean                         tcps_terminated;        /* true if connection no longer exists */
+#ifdef SUPPORT_OPENTRANSPORT
+       InetHost                        tcps_remoteaddr;        /* Address of our peer */
+       InetPort                        tcps_remoteport;        /* Port number of our peer */
+#endif /* SUPPORT_OPENTRANSPORT */
+       unsigned char           *tcps_buffer;           /* buffer given over to system to use */
+       struct tcpstream        *tcps_next;                     /* next one in chain */
+       TCPNotifyUPP            tcps_notifyupp;         /* universal proc pointer for notify routine */
+} tcpstream, *tcpstreamptr;
+
+/*
+ * the Unix-y struct timeval
+ */
+struct timeval {
+       long    tv_sec;         /* seconds */
+       long    tv_usec;        /* and microseconds */
+};
+
+#ifdef SUPPORT_OPENTRANSPORT
+typedef                UInt8 byte;
+typedef                UInt32 ip_addr;
+typedef                UInt16 tcp_port;
+#endif /* SUPPORT_OPENTRANSPORT */
+
+#define TCP_IS_TERMINATED( tsp )               (tsp)->tcps_terminated
+
+/*
+ * function prototypes
+ */
+#ifdef SUPPORT_OPENTRANSPORT
+OSStatus       tcp_init(void);
+void           tcp_shutdown(void);
+Boolean                tcp_have_opentransport( void );
+#endif /* SUPPORT_OPENTRANSPORT */
+tcpstream      *tcpopen( unsigned char * buf, long buflen );
+tcp_port       tcpconnect( tcpstream *s, ip_addr addr, tcp_port port );
+short          tcpclose( tcpstream *s );
+long           tcpread(  tcpstream *s, byte timeout, unsigned char * rbuf,
+                               unsigned short rbuflen, DialogPtr dlp );
+long           tcpwrite( tcpstream *s, unsigned char * wbuf, unsigned short wbuflen );
+short          tcpselect( tcpstream *s, struct timeval * timeout );
+short          tcpreadready( tcpstream *tsp );
+short          tcpgetpeername( tcpstream * tsp, ip_addr *addrp, tcp_port *portp );
+
+#ifdef SUPPORT_OPENTRANSPORT
+short          gethostinfobyname( char *host, InetHostInfo *hip );
+short          gethostinfobyaddr(InetHost addr, InetHostInfo *hip );
+short          ipaddr2str( InetHost ipaddr, char *addrstr );
+#else /* SUPPORT_OPENTRANSPORT */
+short          gethostinfobyname( char *host, struct hostInfo *hip );
+short          gethostinfobyaddr( ip_addr addr, struct hostInfo *hip );
+short          ipaddr2str( ip_addr ipaddr, char *addrstr );
+#endif /* SUPPORT_OPENTRANSPORT */
diff --git a/libraries/msdos/Make-template b/libraries/msdos/Make-template
new file mode 100644 (file)
index 0000000..205e936
--- /dev/null
@@ -0,0 +1,48 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1994 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP libraries/msdos Makefile
+#
+#-----------------------------------------------------------------------------
+
+############################################################################
+#                                                                          #
+# You should not have to edit anything below this point                    #
+#                                                                          #
+############################################################################
+
+#
+# rules to make the software
+#
+
+all:   FORCE
+
+#
+# rules to install the software
+#
+
+install:       all
+
+#
+# rules to make clean
+#
+
+clean: FORCE
+
+veryclean:     clean
+
+#
+# rules to make depend
+#
+#
+depend:        FORCE
+
+links:
diff --git a/libraries/msdos/README b/libraries/msdos/README
new file mode 100644 (file)
index 0000000..9552017
--- /dev/null
@@ -0,0 +1,12 @@
+LDAP MSDOS Overview README
+
+The lber and ldap client libraries have been ported to MSDOS, running
+over various flavors of TCP/IP.  A list of ports and README files to
+see for further instruction follows:
+
+MSDOS over NCSA Telnet TCP/IP          README.CSA
+MSDOS over PCNFS                       README.NFS
+MSWindows over WinSock API             README.WSA
+
+
+README Last updated 26 July 1993 Mark Smith
diff --git a/libraries/msdos/README.CSA b/libraries/msdos/README.CSA
new file mode 100644 (file)
index 0000000..0b00539
--- /dev/null
@@ -0,0 +1,100 @@
+LDAP MSDOS with NCSA Telnet TCP/IP stack README
+
+The lber and ldap client libraries, and the ud client (called BUD on
+DOS) have been ported to MSDOS, running over the NCSA Telnet TCP/IP
+code (available from ftp.ncsa.uiuc.edu).  Build testing was done with
+Microsoft C 5.00 and MSDOS 5.0.  We plan to get Microsoft C 7.0 and
+join the 1990s soon....
+
+This port was just completed as this is being written (4 September 1992),
+so it goes without saying that the code is largely untested under DOS.
+Be sure to report and bugs to us (see the end of this file for where to
+report bugs).
+
+None of the other clients included in the distribution have been tested
+on the PC.  The synchronous LDAP interface is also untested, although it
+does build okay.
+
+MAKING THE DISTRIBUTION
+To build the ldap and lber libraries:
+
+       1) obtain the NCSA source and build it.  The remainder of this
+          README will assume the root of the NCSA source is a directory
+          called "NCSA".
+
+       2) Create an NCSA\LDAP directory, and the following three
+          directories underneath it: h, liblber, libldap.  You should
+          have a structure that looks like this:
+               NCSA\
+                       LDAP\
+                               H\
+                               LIBLBER\
+                               LIBLDAP\
+
+                       (lots of other NCSA directories)
+
+       3) Populate them from the distribution (files from the h/, liblber/,
+          and libldap/ distribution directories get copied to H\,
+          LIBLBER\, and LIBLDAP\ respectively).
+
+       4) Copy additional files for MSDOS to proper places:
+          distribution file                    PC file
+            msdos/makefile.msc                   LDAP\MAKEFILE.MSC
+            msdos/msdos.h                        LDAP\H\MSDOS.H
+            msdos/lp.c                           LDAP\LIBLBER\LP.C
+            msdos/makelber.msc                   LDAP\LIBLBER\MAKELBER.MSC
+            msdos/msdos.c                        LDAP\LIBLBER\MSDOS.C
+            msdos/makeldap.msc                   LDAP\LIBLDAP\MAKELDAP.MSC
+            msdos/opendos.c                      LDAP\LIBLDAP\OPENDOS.C
+
+       5) If you wish to change any compiler or linker switches, you
+          should be able to do so just by editing the top-level
+          MAKEFILE.MSC make file.  There seems to be a problem if you
+           add -DLDAP_DEBUG: the linker is unable to resolve the
+          lber_debug variable (defined in liblber/decode.c, used there
+           and in liblber/io.c).  If anyone can figure out how to get it
+          to work, let us know.
+
+       6) Build the library (this will also build the LDAP test program):
+            cd NCSA\LDAP
+             make makefile.msc
+          If your DOS C compiler is as picky as ours, you will get many
+          screen fulls of warnings that can safely be ignored.
+          Note that if you try to make while sitting in the lower
+           directories (LIBLDAP or LIBLBER), it will fail.  This will
+          hopefully be cleaned up in a later release.
+
+       7) Test the library using LTEST.EXE:
+            cd to somewhere where there is a proper NCSA CONFIG.TEL file
+            execute "LTEST <LDAP server host>" from there, and test away.
+
+To build the ud client "BUD":
+       1) Build the ldap and lber libraries (see above).
+
+       2) Create a directory called UD underneath your LDAP directory,
+          and populate it with all the files from the ud/ directory
+          from the distribution.  Also add the following files:
+            msdos/makeud.msc
+            msdos/protoud.h
+            macintosh/getopt.c (yes, put this in the LDAP\UD directory)
+
+       3) Change any desired options in UD.H or in the LDAP\MAKEFILE.MSC
+          make file.  You will probably want to set up your own
+          site-specific values for DEFAULT_BASE and DEFAULT_SERVER (in
+          UD.H).
+
+       4) Uncomment out the lines near the end of LDAP\MAKEFILE.MSC
+          that define the rules to make ud.
+
+       5) Build bud.exe:
+            cd NCSA\LDAP
+            make makefile.msc
+          You should now have a working bud.exe.  Make sure you test
+          it while in a directory that has a proper NCSA CONFIG.TEL file
+          in it.
+
+BUG REPORTING
+
+    Bug reports should be sent to bug-ldap@terminator.cc.umich.edu.
+
+README Last updated 4 September 1992 Mark Smith
diff --git a/libraries/msdos/README.NFS b/libraries/msdos/README.NFS
new file mode 100644 (file)
index 0000000..0965a8b
--- /dev/null
@@ -0,0 +1,55 @@
+LDAP MSDOS with SUN PC-NFS README
+
+The lber and ldap client libraries have been ported to MSDOS, running over
+SUN PC-NFS.  Build testing was done with Microsoft C 7.00, SUN PC-NFS
+Programmer's Toolkit version 4.0 and MSDOS 5.0.
+
+This port is relatively untested so please be sure to report any bugs to
+us (see the end of this file for where to report bugs).
+
+None of the clients included in the distribution have been tested
+on the PC over PC-NFS although UD has been tested over the NCSA TCP/IP port.
+
+MAKING THE DISTRIBUTION
+To build the ldap and lber libraries on the PC:
+
+1) Create a directory somewhere for your LDAP source files and then create
+   the following three directories in it: h, liblber and libldap.  You
+   should have a structure something like
+
+       LDAP\H
+       LDAP\LIBLDAP
+       LDAP\LIBLBER
+
+2) Populate them from the distribution (files from the h/, liblber/,
+   and libldap/ distribution directories get copied to H\,
+   LIBLBER\, and LIBLDAP\ respectively).
+
+3) Copy additional files for MSDOS PC-NFS to proper places:
+       distribution file               PC file
+       msdos/makefile.nfs              LDAP\MAKEFILE
+       msdos/msdos.h                   LDAP\H\MSDOS.H
+       msdos/lp.c                      LDAP\LIBLBER\LP.C
+       msdos/makelber.nfs              LDAP\LIBLBER\MAKEFILE
+       msdos/msdos.c                   LDAP\LIBLBER\MSDOS.C
+       msdos/makeldap.nfs              LDAP\LIBLDAP\MAKEFILE
+       msdos/opendos.c                 LDAP\LIBLDAP\OPENDOS.C
+
+4) If you wish to change any compiler or linker switches, you
+   should be able to do so just by editing the top-level
+   MAKEFILE.
+
+5) Build the library (this will also build the LDAP test program):
+
+       CD LDAP
+        NMAKE
+
+   You will get many screen fulls of warnings that can safely be ignored.
+
+6) Test the library using LTEST.EXE.
+
+BUG REPORTING
+
+    Bug reports should be sent to bug-ldap@terminator.cc.umich.edu.
+
+README.NFS Last updated January 1993 Andy Powell (University of Bath)
diff --git a/libraries/msdos/README.WSA b/libraries/msdos/README.WSA
new file mode 100644 (file)
index 0000000..3e8d75f
--- /dev/null
@@ -0,0 +1,228 @@
+LDAP MSWindows with WinSock API README
+
+The lber and ldap client libraries have been ported to Microsoft Windows
+in the form of a Windows Dynamic Link library called LIBLDAP.DLL and
+Ldap32.dll (16 and 32 bit versions respectively).
+
+A Windows Socket API version 1.1 conformant TCP/IP WINSOCK.DLL is
+required for the LIBLDAP.DLL to run.  Some patches have been
+incorporated that should make it possible to build the LIBLDAP.DLL under
+Borland C++ 3.1.  Brief instructions are included later in this file. 
+(There are no changes to the Borland support in this release.)
+
+This release also include 16 and 32 bit versions of the ltest (&
+ltest32) API test programs.  Instructions for building it are in the
+second half of this document.  None of the other clients included in the
+distribution have been tested under Windows.  The synchronous LDAP
+interface is also untested, although it does build okay.
+
+At the very end of this document are some hints for writing applications
+that use the LIBLDAP.DLL.
+
+We have also made a windows "kit" available at:
+
+   ftp://terminator.rs.itd.umich.edu/ldap/windows/winldap.zip
+
+Our hope is that with this kit, you won't have to compile all this 
+yourself (unless you want to).  The kit includes:
+        16 and 32bit dlls
+        debug and release builds
+        the LTest utility program
+        man pages in the form of HLP files (new and old formats)
+        include files
+        sample config files
+
+MAKING THE DISTRIBUTION
+
+Build testing was done on Windows NT workstation 3.51 (service patch 2)
+(on NTFS which supports long filenames) using Microsoft Visual C++ 1.52c
+(16 bit) and Visual C++ 4.0 (32 bit).
+
+To build the LIBLDAP.DLL library under Microsoft Visual C++ 1.52c
+(16bit) or Visual C++ 4.0 (32bit):  (search forward in this file for
+"Borland" if you are using Borland C++)
+
+       1) Untar the ldap distribution somewhere on MSDOS.  You will
+           need at least the include and libraries subdirectories.
+           A version of tar that works under MSDOS is a big help for
+           this step
+
+               tar xf ldap.tar
+
+          This will create a directory called ldap or similar that
+          contains the ldap source distribution.  We will refer to
+          that directory simply as "\ldap" from now on, but it could
+          be anywhere and have any name on your system
+
+           Note that a lot of empty include files are on this distribution. 
+          This is because some compilers are not smart enough to properly
+           generate dependencies (i.e. they ignore #ifdefs) so the file needs
+          to be present, even if not used.
+
+       2) cd to the LDAP directory (root of your LDAP area on MSDOS) and
+          execute the setupwsa batch file.  This will copy a bunch of
+          files from the ldap\libraries\msdos and
+          ldap\libraries\msdos\winsock directories to the ldap\include
+          and ldap\libraries\libldap directories:
+               cd \ldap
+               libraries\msdos\winsock\setupwsa.bat
+           Note that a lot of empty include files are copied over... this
+           is because some compilers are not smart enough to properly
+           generate dependencies.
+
+       3) Create a WINSOCK.LIB import library from the WINSOCK.DEF file.
+          You can also obtain a pre-built .LIB from ftp.microdyne.com in
+          /pub/winsock/winsock-1.1/winsock.lib.  To build an import
+          library using Microsoft's IMPLIB utility:
+               cd \ldap\libraries\libldap
+               implib winsock.lib winsock.def
+
+       4) Now fire up MS Windows and start the Visual C++ Workbench.  Open
+          the project \ldap\libraries\libldap\libldap.mak or 
+          \ldap\libraries\libldap\ldap32.mak with the appropriate compiler.
+
+          Change the project "Include" directory to list the ldap
+          include directory as well as the standard include directories
+          (change by using the command found under the
+          Options...Directories menu in the 16 bit compiler and
+          Build/Settings in the 32bit compiler).
+
+          The preprocessor symbols I have defined are:
+             WINSOCK, DOS, NEEDPROTOS, NO_USERINTERFACE, KERBEROS I ran
+          into buffer length limitations when I tried to define more
+          preprocessor symbols this way.  So all the rest are defined
+          in msdos.h.  This makes the order of inclusion critical for
+          msdos.h.
+
+
+        Note: If you are using something other than Visual C++ you will
+          need to create a makefile or other project file.  It should
+          include all of the .c files in the liblber and libldap
+          directories, plus the libraries\libldap\libldap.def (or
+          libraries\libldap\ldap32.def) module definition file.  It
+          will need to link in winsock.lib.  You should use the large
+          memory model.
+
+       5) Select Build LIBLDAP.DLL (or Rebuild All) from the Project
+          menu to build the DLL.  You will see many warnings,
+          especially from the liblber code.  Our experience is that it
+          is safe to ignore them.
+
+       6) If you want to change what symbols are defined (for example
+          WSHELPER, or LDAP_DEBUG), change them in msdos.h and
+          recompile.  LDAP_DEBUG now works in the windows environment.
+          The comments in msdos.h explain what the various options are.
+
+You should now have a functional LIBLDAP (or ldap32) dynamic link
+library.  If you wish to build a version of ltest for MSWindows to test
+it, follow these next steps.
+
+       1) Copy the libldap test.c and LIBLDAP.DLL import library files
+          to the Windows ltest directory.  Under DOS:
+             cd \ldap
+             copy libraries\libldap\test.c libraries\msdos\winsock\ltest
+             copy libraries\libldap\libldap.lib libraries\msdos\winsock\ltest
+
+       2) Open the project \ldap\libraries\msdos\winsock\ltest\ltest.mak
+          (or ltest32.mdp) under the Microsoft Visual C++ Workbench.
+          Change the project include directory to list the
+          \ldap\include directory as well as the standard include
+          directories.
+
+       3) Edit the string resource IDS_LDAP_HOST_NAME in ltest.rc (or
+          ltest32.rc) and change the string "truelies" to the name of
+          the LDAP server host you would like to test against.  
+          
+          Since this is a string resource, it may also be edited in the
+          DLL with AppStudio.  So you can change it without having to
+          recompile.
+
+       4) Build the project.  If you are not using Visual C++, you will
+          need to create a makefile or other project file, and then
+          build.  The project should include all of the .c files in
+          the ldap\libraries\msdos\winsock\ltest directory and the
+          ltest.def module definition file.  You will need to link in
+          libldap.lib and winsock.lib (import libraries).
+
+You should now have a functional ltest application.  It is ugly, but it
+is useful for testing purposes.  It doesn't try very hard to be a pretty
+MS Windows application.
+
+
+To build the LIBLDAP.DLL library under Borland C++ 3.1:
+
+       Note: No changes have been made wrt Borland compiler in this release.
+
+       1) Untar the ldap distribution somewhere on MSDOS.  You will
+           need at least the include and libaries subdirectories.
+           A version of tar that works under MSDOS is a big help for
+           this step:
+               tar xf ldap.tar
+
+          This will create a directory called ldap or similar that
+          contains the ldap source distribution.  We will refer to
+          that directory simply as "\ldap" from now on, but it could
+          be anywhere and have any name on your system
+
+       2) cd to the LDAP directory (root of your LDAP area on MSDOS) and
+           execute the setupwsa batch file.  This will copy a bunch of
+          files from the ldap\libraries\msdos and ldap\libraries\msdos\winsock
+          directories to the ldap\include and ldap\libraries\libldap
+          directories:
+               cd \ldap
+               libraries\msdos\winsock\setupwsa.bat
+
+       3) Start Borland C++ and create a new project here named
+           libraries\libldap\libldap.prj and add all .c files in
+            the libraries\liblber and libraries/libldap directories
+           except open.c and test.c.  Also add libldap.def and
+           the winsock.lib.
+
+       4) Configure the project:
+           Set include directories to have ..\..\include in them
+           Set these #defines: NO_USERINTERFACE;DOS;NEEDPROTOS;WIN31;BC31
+           Switch case-sensitive link/exports off
+           Include the runtime library statically, and 'none' of the others
+
+       5) Do Build All
+
+
+WRITING APPLICATIONS THAT USE LIBLDAP.DLL
+
+    All of the normal LDAP and LBER calls documented in the man pages
+    (contained in the ldap\doc\man directory) should work, except for
+    ldap_perror (this is not supported under Windows since you will
+    want to use an application-defined dialog; you can use ldap_err2string
+    to obtain an error string to display in a message box or dialog).
+    The LIBLDAP.DEF file has a complete list of available routines.
+
+    Any memory that you obtain as the result of a call to an LIBLDAP.DLL
+    routine should NOT be freed by calling the free() routine in your
+    C library.  Instead, use the the new utility routine ldap_memfree.
+    This is so the malloc/calloc and free routines all come from the same
+    library (the one in libldap) rather than using libldap's malloc/calloc
+    and the calling program's free.  The 32bit compiler (in debug mode) 
+    FORCED me to be compulsive about this for the application I used to test.
+
+    To be friendly under Windows, you should use the asynchronous LDAP
+    calls whenever possible.
+
+    One limitation of the current LIBLDAP.DLL is that each X.500 LDAP
+    result message has to be smaller than 64K bytes.  Ldap32.dll does
+    NOT have this limitation.
+
+    To compile the dlls we define the following preprocessor variables.
+
+        WINSOCK, DOS, NEEDPROTOS, NO_USERINTERFACE, KERBEROS
+    
+    Presumably you don't need KERBEROS.  You may need some/all the
+    others to take the right path through the include files.  Also note
+    that a few more preprocessor variables are defined in msdos.h.  This
+    means that msdos.h must be included before ldap.h or lber.h.
+
+
+BUG REPORTING
+
+    Bug reports should be sent to bug-ldap@umich.edu.
+
+README Last updated 13 January 1996 by Steve Rothwell
diff --git a/libraries/msdos/lp.c b/libraries/msdos/lp.c
new file mode 100644 (file)
index 0000000..85551d4
--- /dev/null
@@ -0,0 +1,265 @@
+/*  -------------------------------------------------------------
+    lp.c
+
+    Routines common to lpr, lpq, and lprm.
+
+    Paul Hilchey    May 1989
+
+    Copyright (C) 1989 The University of British Columbia
+    All rights reserved.
+
+        history
+        -------
+        1/6/89   Microsoft C port by Heeren Pathak (NCSA)
+    -------------------------------------------------------------
+*/
+
+#ifdef DOS
+#ifndef PCNFS
+
+#define LPR
+
+#include <stdio.h>
+#include <conio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#ifdef MEMORY_DEBUG
+#include "memdebug.h"
+#endif
+#include "netevent.h"
+#include "hostform.h"
+#include "lp.h"
+#include "externs.h"
+
+#ifdef MSC
+#define EXIT_FAILURE 1
+#endif
+
+void checkerr( void );
+
+/****************************************************************
+ * lookup                                                      *
+ * Try to find the remote host in the local cache or from a    *
+ * domain name server.                                         *
+ * parameters: null terminated string containing the name or   *
+ *               ip address of the host                        *
+ * return value: pointer to machine info record, or 0 if the   *
+ *              lookup failed                                  *
+ ****************************************************************/
+struct machinfo *lookup(char *host)
+{
+       int what,dat;
+       int machine_number;     /* used to identify domain lookup events */
+       struct machinfo *machine_info;
+
+       machine_info = Sgethost(host);  /* look up in hosts cache */
+
+       if (!machine_info) {
+               if ((machine_number = Sdomain(host)) < 0)
+                       return(0);  /* initiate domain name lookup */
+
+               /* wait for DOMOK or DOMFAIL event */
+               while (machine_info==NULL) {
+                       switch(lgetevent(USERCLASS,&what,&dat)) {
+                       case DOMFAIL:
+                               /* lookup failed, return 0 */
+                               return(0);
+                       case DOMOK:
+                               /* get pointer to machine record */
+                               machine_info=Slooknum(machine_number);
+                       default: 
+                               break;
+                       }
+               }
+               if (debug) puts("Domain lookup worked");
+       }
+       return(machine_info);
+}
+
+/*****************************************************************
+ *  open_connection                                             *
+ *  Open the TCP connection.                                    *
+ *  parameters: pointer to machine info record                  *
+ *             source port number                               *
+ *             destination port number                          *
+ *  return value: connection identifier (port number), or -1 if  *
+ *               connection could not be opened                 *
+ *****************************************************************/
+int open_connection(struct machinfo *machine_record, int source_port,
+int dest_port)
+{
+       int ev,what,dat;  /* parameters for lgetevent */
+       int conid;        /* connection identifier */
+
+       /* set the source port */
+       netfromport(source_port);
+
+       /* initiate connection open */
+       if (0 > (conid = Snetopen(machine_record,dest_port)))
+               return(-1);
+
+       if (debug) puts("snetopen ok");
+
+       /* wait for connection to open or for attempt to fail */
+       while(1) {
+               if (0 != (ev = lgetevent(CONCLASS,&what,&dat))) {
+                       if (dat != conid) {     /* not for us */
+                               /*              netputevent(what,ev,dat); */
+                               continue;
+                       }
+                       if (ev == CONOPEN)
+                               break;
+                       else
+                               return(-1);
+               }
+       }
+       if (debug) puts("Conopen");
+       return(conid);
+}
+
+
+/*******************************************************************
+ * crash                                                          *
+ * Shut down all network stuff, print an error message to stderr,  *
+ * and abort.                                                     *
+ * parameters: variable length argument list for the error        *
+ *               message (a la printf)                            *
+ *******************************************************************/
+void crash(char *msg,...)
+{
+       va_list argptr;
+
+       fprintf(stderr,"\nError: ");
+       va_start(argptr,msg);
+       vfprintf(stderr,msg,argptr);
+       va_end(argptr);
+       fprintf(stderr,"\n");
+
+       /* shut everything down */
+       netshut();
+       exit(EXIT_FAILURE);
+}
+
+/*********************************************************************
+ * Check for any error events that may have occured.  Either print   *
+ * the message on stderr or just ignore it if it is probably not     *
+ * serious.  Set debug on to see all error messages.                *
+ *********************************************************************/
+void checkerr(void )
+{
+       char *errmsg;
+       int i,j;
+
+       while (ERR1 == Sgetevent(ERRCLASS,&i,&j)) {
+               if ((!debug) &&
+                   ((300 <= j && j <= 399) ||  /* IP messages */
+               (400 <= j && j <= 499) ||       /* TCP messages */
+               (600 <= j && j <= 699) ||       /* ICMP messages */
+               j == 801  || j == 805  ||       /* misc. domain stuff */
+               j == 806))
+                       continue;              /* just ignore them */
+               errmsg = neterrstring(j);
+               fprintf(stderr,"%s\n",errmsg);
+       }
+}
+
+/*********************************************************************
+ * lgetevent                                                        *
+ * Check for network events. The next pending non-error event is     *
+ * returned (if any).                                               *
+ * Takes the same parameters as sgetevent.                          *
+ *********************************************************************/
+int lgetevent(int class, int *what, int *datp)
+{
+       checkerr();
+       return(Sgetevent(class, what, datp));
+}
+
+/******************************************************************
+ * nprintf                                                       *
+ * Formatted write to an open TCP conection.  Like fprintf, but   *
+ * use a connection id returned from snteopen instead of a file   *
+ * handle.  The formatted string must not exceed 1023 bytes.     *
+ * Returns EOF if an error occurs                                *
+ ******************************************************************/
+int nprintf(int connection_id, char *format,...)
+#define BUFF_SIZE 1024
+{
+       va_list argptr;
+       char    buff[BUFF_SIZE], *buff_ptr;
+       int     len1, len2;
+
+       va_start(argptr,format);
+       len1 = vsprintf(buff,format,argptr);
+       va_end(argptr);
+       if ((len1 == EOF) || len1+1 >= BUFF_SIZE) return(EOF);
+       buff_ptr = buff;
+       while (buff_ptr < (buff + len1)) {
+               len2 = netwrite(connection_id, buff_ptr,
+                   len1-(buff_ptr - buff));
+               checkerr();
+               Stask();
+               if (len2 < 0) return(EOF);
+               buff_ptr += len2;
+       }
+       if (debug) puts(buff);
+       return (len1);
+}
+
+/******************************************************************
+ * nread                                                         *
+ * Read from an open TCP connection.  Waits for incoming data if  *
+ * there is none in the queue. Returns EOF if the connection     *
+ * closes and there is no more data.                             *
+ *                                                               *
+ * parameters: connection id returned by Snetopen                *
+ *            buffer for returned data                           *
+ *            size of buffer                                     *
+ * returned value: number of characters read into the buffer     *
+ ******************************************************************/
+
+int nread(int connection_id, char *buff, int buff_size)
+{
+       int class,data,ev;
+       int len;
+
+       netpush(connection_id);  /* flush buffer */
+
+       while (0 == netest(connection_id)) {
+               ev = lgetevent(CONCLASS, &class, &data);
+               if (!ev) continue;
+               if (data != connection_id) {   /* not for us; throw away */
+                       /*         netputevent(class, ev, data); */
+                       continue;
+               }
+               if (debug) printf("nread %d %d\n",class,ev);
+               if (ev == CONDATA) {
+                       len = netread(connection_id,buff,buff_size);
+                       if (len == 0) continue;
+                       return (len);
+               }
+       }
+       /* throw away other events.  getevent should be changed so we
+       can retrieve events for a selected port only  */
+       while (lgetevent(USERCLASS | CONCLASS, &class, &data));
+       return (EOF);    /* connection is closed and no data in queue */
+}
+
+#ifdef MSC
+#else
+#pragma warn .par
+#endif
+
+/******************************************************************
+ * breakstop                                                     *
+ * Handle break interrupts by shutting down the network stuff and *
+ * aborting.                                                     *
+ ******************************************************************/
+int breakstop(void )
+{
+       netshut();
+       return(0);
+}
+
+#endif PCNFS
+#endif /* DOS */
diff --git a/libraries/msdos/makefile.msc b/libraries/msdos/makefile.msc
new file mode 100644 (file)
index 0000000..f70f03b
--- /dev/null
@@ -0,0 +1,78 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1992 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP lightweight X.500 Directory access top level makefile for MSC
+#
+#-----------------------------------------------------------------------------
+
+
+
+#
+# Edit the following variables to have appropriate values for your system
+#
+
+#
+# You may want to change some of these things too
+#
+# two kinds of things go in ACFLAGS, global compiler flags (like -g to
+# generate symbol table info), and global defines (like -DKERBEROS to enable
+# kerberos version 4 authentication, or -DLDAP_DEBUG to compile in some
+# debugging info you can then turn on by setting ldap_debug)
+#
+ACFLAGS                = -g -DNEEDPROTOS #-DLDAP_DEBUG # added to every $(CFLAGS)
+ALDFLAGS       = # -g                  # always passed to ld
+UDDEFINES      = -DUOFM                # particular to ud
+
+#
+# you probably don't need to edit these things, but if you want to use
+# a different make or c compiler, change it here.
+#
+MAKE   = nmake
+CC     = cl
+CFLAGS = /c /AL /DDOS /DMSC /Ox /W1 $(ACFLAGS) -I../h
+LD     = link
+LDFLAGS        = /m /ST:8192 $(ALDFLAGS)
+
+############################################################################
+#                                                                          #
+# You should not have to edit anything below this point                    #
+#                                                                          #
+############################################################################
+
+SDIRS  = liblber ldapd libldap
+OTHERS = finger gopher ud
+
+all: lber-library ldap-server ldap-library
+
+library-only: lber-library ldap-library
+
+others: ldap-finger ldap-gopher ldap-ud
+
+lber-library:
+       echo "cd liblber; $(MAKE) all"
+       cd liblber
+        $(MAKE) CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" LIBDIR=$(LIBDIR) \
+               CC=$(CC) LD=$(LD) /F makelber.msc
+       cd ..
+
+ldap-library:
+       echo "cd libldap; $(MAKE) all"
+       cd libldap
+        $(MAKE) CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" LIBDIR=$(LIBDIR) \
+               CC=$(CC) LD=$(LD) /F makeldap.msc
+       cd ..
+
+#ldap-ud:
+#      echo "cd ud; $(MAKE) all"
+#      cd ud
+#       $(MAKE) CFLAGS="$(CFLAGS) $(UDDEFINES)" LDFLAGS="$(LDFLAGS)" \
+#              LIBDIR=$(LIBDIR) CC=$(CC) LD=$(LD) makeud.msc
+#      cd ..
diff --git a/libraries/msdos/makefile.nfs b/libraries/msdos/makefile.nfs
new file mode 100644 (file)
index 0000000..ae827f2
--- /dev/null
@@ -0,0 +1,60 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1992 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP lightweight X.500 Directory access top level makefile for MSC
+#
+#-----------------------------------------------------------------------------
+#
+# Edit the following variables to have appropriate values for your system
+#
+NOLOGO = /nologo
+MAKE   = nmake $(NOLOGO)
+CFLAGS = /c /AL /DDOS /DMSC /DNEEDPROTOS /DPCNFS /W3 /Oas $(ACFLAGS) -I../h
+LDFLAGS        = /m /SEG:256 /ST:8192
+
+############################################################################
+#                                                                          #
+# You should not have to edit anything below this point                    #
+#                                                                          #
+############################################################################
+
+SDIRS  = liblber ldapd libldap
+OTHERS = finger gopher ud
+
+all: lber-lib ldap-lib
+
+lib-only: lber-lib ldap-lib
+
+others: ldap-finger ldap-gopher ldap-ud
+
+lber-lib:
+       cd liblber
+        $(MAKE) CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" all
+       cd ..
+
+ldap-lib:
+       cd libldap
+        $(MAKE) CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" all
+       cd ..
+
+#ldap-ud:
+#      echo "cd ud; $(MAKE) all"
+#      cd ud
+#       $(MAKE) CFLAGS="$(CFLAGS) $(UDDEFINES)" LDFLAGS="$(LDFLAGS)" \
+#              LIBDIR=$(LIBDIR) CC=$(CC) LD=$(LD) makeud.msc
+#      cd ..
+
+clean:
+       cd liblber
+       $(MAKE) clean
+       cd ..\libldap
+       $(MAKE) clean
+       cd ..
diff --git a/libraries/msdos/makelber.msc b/libraries/msdos/makelber.msc
new file mode 100644 (file)
index 0000000..ae5bf67
--- /dev/null
@@ -0,0 +1,58 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1992 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       lightweight ber library makefile for MicroSoft C
+#
+#-----------------------------------------------------------------------------
+
+SRCS   = decode.c encode.c io.c msdos.c lp.c
+OBJS   = decode.obj encode.obj io.obj msdos.obj lp.obj
+
+CFLAGS = $(ACFLAGS) -I../h
+CC     = echo "cd up a level first"
+
+NCFLAGS        = -I../../include
+
+#default:
+#      (cd ../; make lber-library)
+
+all:   $(OBJS) liblber.lib
+
+decode.obj:    decode.c
+       $(CC) $(CFLAGS) decode.c
+
+encode.obj:    encode.c
+       $(CC) $(CFLAGS) encode.c
+
+io.obj:        io.c
+       $(CC) $(CFLAGS) io.c
+
+msdos.obj:     msdos.c
+       $(CC) $(CFLAGS) $(NCFLAGS) msdos.c
+
+lp.obj:        lp.c
+       $(CC) $(CFLAGS) $(NCFLAGS) lp.c
+
+liblber.lib:   $(OBJS)
+       del liblber.lib
+       lib liblber.lib +decode.obj+encode.obj+io.obj+msdos.obj+lp.obj;
+
+#etest.obj:    etest.c
+#      $(CC) $(CFLAGS) etest.c
+
+#etest:        liblber.lib etest.obj
+#      $(LD) $(LDFLAGS) etest,etest,nul,liblber
+
+#dtest.obj:    dtest.c
+#      $(CC) $(CFLAGS) dtest.c
+
+#dtest:        liblber.lib dtest.obj
+#      $(LD) $(LDFLAGS) dtest,dtest,nul,liblber
diff --git a/libraries/msdos/makelber.nfs b/libraries/msdos/makelber.nfs
new file mode 100644 (file)
index 0000000..f0025a6
--- /dev/null
@@ -0,0 +1,50 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1992 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP lightweight X.500 Directory access top level makefile for MSC
+#
+#-----------------------------------------------------------------------------
+
+SRCS   = decode.c encode.c io.c msdos.c lp.c
+OBJS   = decode.obj encode.obj io.obj msdos.obj lp.obj
+
+NOLOGO = /nologo
+CC     = cl $(NOLOGO)
+MAKE   = nmake $(NOLOGO)
+
+default:
+       cd ..
+       $(MAKE) lber-lib
+
+all:   $(OBJS) liblber.lib
+
+decode.obj:    decode.c
+       $(CC) $(CFLAGS) decode.c
+
+encode.obj:    encode.c
+       $(CC) $(CFLAGS) encode.c
+
+io.obj:        io.c
+       $(CC) $(CFLAGS) io.c
+
+msdos.obj:     msdos.c
+       $(CC) $(CFLAGS) msdos.c
+
+lp.obj:        lp.c
+       $(CC) $(CFLAGS) lp.c
+
+liblber.lib:   $(OBJS)
+       del liblber.lib
+       lib $(NOLOGO) liblber.lib +decode.obj+encode.obj+io.obj+msdos.obj+lp.obj;
+
+clean:
+       del *.obj
+       del *.lib
diff --git a/libraries/msdos/makeldap.msc b/libraries/msdos/makeldap.msc
new file mode 100644 (file)
index 0000000..1d06897
--- /dev/null
@@ -0,0 +1,92 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1992 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP library makefile for MicroSoft C
+#
+#-----------------------------------------------------------------------------
+
+SRCS   = bind.c opendos.c result.c error.c compare.c search.c parse.c \
+       modify.c add.c modrdn.c delete.c abandon.c synchronous.c \
+       kerberos.c
+OBJS   = bind.obj opendos.obj result.obj error.obj compare.obj search.obj \
+       parse.obj modify.obj add.obj modrdn.obj delete.obj abandon.obj \
+       synchronous.obj kerberos.obj
+
+CFLAGS = $(ACFLAGS) -I../h $(KRBINCLUDEDIR)
+NCFLAGS        = -I../../include
+CC     = echo "cd up a level first"
+
+#default:
+#      (cd ../; make ldap-library)
+
+all:   libldap.lib ltest
+
+bind.obj:      bind.c
+       $(CC) $(CFLAGS) $(NCFLAGS) bind.c
+
+opendos.obj:   opendos.c
+       $(CC) $(CFLAGS) $(NCFLAGS) opendos.c
+
+result.obj:    result.c
+       $(CC) $(CFLAGS) $(NCFLAGS) result.c
+
+error.obj:     error.c
+       $(CC) $(CFLAGS) error.c
+
+compare.obj:   compare.c
+       $(CC) $(CFLAGS) compare.c
+
+search.obj:    search.c
+       $(CC) $(CFLAGS) search.c
+
+parse.obj:     parse.c
+       $(CC) $(CFLAGS) parse.c
+
+modify.obj:    modify.c
+       $(CC) $(CFLAGS) modify.c
+
+add.obj:       add.c
+       $(CC) $(CFLAGS) add.c
+
+modrdn.obj:    modrdn.c
+       $(CC) $(CFLAGS) modrdn.c
+
+delete.obj:    delete.c
+       $(CC) $(CFLAGS) delete.c
+
+abandon.obj:   abandon.c
+       $(CC) $(CFLAGS) abandon.c
+
+synchronous.obj:       synchronous.c
+       $(CC) $(CFLAGS) synchronous.c
+
+kerberos.obj:  kerberos.c
+       $(CC) $(CFLAGS) kerberos.c
+
+libldap.lib:   $(OBJS)
+       del libldap.lib
+       lib libldap.lib +bind.obj+opendos.obj+result.obj+error.obj+compare.obj;
+       lib libldap.lib +search.obj+parse.obj+modify.obj+add.obj+modrdn.obj;
+       lib libldap.lib +delete.obj+abandon.obj+synchronous.obj+kerberos.obj;
+
+test.obj:      test.c
+       $(CC) $(CFLAGS) test.c
+
+ltest: libldap.lib test.obj ..\liblber\liblber.lib
+       copy libldap.lib ..\..\lib
+       copy ..\liblber\liblber.lib ..\..\lib
+       cd ..\..\lib
+       $(LD) $(LDFLAGS) ..\ldap\libldap\test+memdebug+ncsaio,ltest,nul,libldap+liblber.lib+tcp+sess+enet+common
+       copy ltest.exe ..\ldap\libldap\ltest.exe
+       del libldap.lib
+       del liblber.lib
+       del ltest.exe
+       cd ..\ldap\libldap
diff --git a/libraries/msdos/makeldap.nfs b/libraries/msdos/makeldap.nfs
new file mode 100644 (file)
index 0000000..939264b
--- /dev/null
@@ -0,0 +1,97 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1992 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP lightweight X.500 Directory access top level makefile for MSC
+#
+#-----------------------------------------------------------------------------
+
+SRCS   = bind.c opendos.c result.c error.c compare.c search.c parse.c \
+       modify.c add.c modrdn.c delete.c abandon.c synchron.c \
+       kerberos.c cache.c ufn.c
+OBJS   = bind.obj opendos.obj result.obj error.obj compare.obj search.obj \
+       parse.obj modify.obj add.obj modrdn.obj delete.obj abandon.obj \
+       synchron.obj kerberos.obj cache.obj ufn.obj
+
+NOLOGO = /nologo
+CC     = cl $(NOLOGO)
+MAKE   = nmake $(NOLOGO)
+LD     = link $(NOLOGO)
+
+default:
+       cd ..
+       $(MAKE) ldap-lib
+
+all:   libldap.lib ltest
+
+bind.obj:      bind.c
+       $(CC) $(CFLAGS) bind.c
+
+opendos.obj:   opendos.c
+       $(CC) $(CFLAGS) opendos.c
+
+result.obj:    result.c
+       $(CC) $(CFLAGS) result.c
+
+error.obj:     error.c
+       $(CC) $(CFLAGS) error.c
+
+compare.obj:   compare.c
+       $(CC) $(CFLAGS) compare.c
+
+search.obj:    search.c
+       $(CC) $(CFLAGS) search.c
+
+parse.obj:     parse.c
+       $(CC) $(CFLAGS) parse.c
+
+modify.obj:    modify.c
+       $(CC) $(CFLAGS) modify.c
+
+add.obj:       add.c
+       $(CC) $(CFLAGS) add.c
+
+modrdn.obj:    modrdn.c
+       $(CC) $(CFLAGS) modrdn.c
+
+delete.obj:    delete.c
+       $(CC) $(CFLAGS) delete.c
+
+abandon.obj:   abandon.c
+       $(CC) $(CFLAGS) abandon.c
+
+synchron.obj:  synchron.c
+       $(CC) $(CFLAGS) synchron.c
+
+kerberos.obj:  kerberos.c
+       $(CC) $(CFLAGS) kerberos.c
+
+cache.obj:     cache.c
+       $(CC) $(CFLAGS) cache.c
+
+ufn.obj:       ufn.c
+       $(CC) $(CFLAGS) ufn.c
+
+libldap.lib:   $(OBJS)
+       del libldap.lib
+       lib $(NOLOGO) libldap.lib +bind.obj+opendos.obj+result.obj+error.obj+compare.obj;
+       lib $(NOLOGO) libldap.lib +search.obj+parse.obj+modify.obj+add.obj+modrdn.obj;
+       lib $(NOLOGO) libldap.lib +delete.obj+abandon.obj+synchron.obj+kerberos.obj+cache.obj+ufn.obj;
+
+test.obj:      test.c
+       $(CC) $(CFLAGS) test.c
+
+ltest: libldap.lib test.obj ..\liblber\liblber.lib
+       $(LD) $(LDFLAGS) test,ltest,nul,libldap+..\liblber\liblber+ltklib ;
+
+clean:
+       del *.obj
+       del *.lib
+       del *.exe
diff --git a/libraries/msdos/makeud.msc b/libraries/msdos/makeud.msc
new file mode 100644 (file)
index 0000000..dfa1197
--- /dev/null
@@ -0,0 +1,76 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1992 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#      ud makefile for Microsoft C
+#
+#      Use -DUOFM for University of Michigan specifics like:
+#              if ud should know about noBatchUpdates
+#      Use -DDOS if building for a DOS machine
+#      Use -DNOTERMCAP if there is no termcap library
+#              also need to redefine/undefine the Makefile TERMLIB variable
+#-----------------------------------------------------------------------------
+SRCS=  find.c mod.c print.c auth.c util.c help.c getopt.c versio.c
+OBJS=  find.obj mod.obj print.obj auth.obj util.obj help.obj \
+               getopt.obj version.obj
+HDRS=  ud.h protoud.h
+
+CFLAGS = $(ACFLAGS) -I../h
+NCFLAGS        = -I../../include
+CC     = echo "cd up a level first"
+
+#default:
+#      (cd ../; make ud)
+
+all:   ud
+
+main.obj:      main.c
+       $(CC) $(CFLAGS) main.c
+
+find.obj:      find.c
+       $(CC) $(CFLAGS) find.c
+
+mod.obj:       mod.c
+       $(CC) $(CFLAGS) mod.c
+
+print.obj:     print.c
+       $(CC) $(CFLAGS) print.c
+
+auth.obj:      auth.c
+       $(CC) $(CFLAGS) auth.c
+
+util.obj:      util.c
+       $(CC) $(CFLAGS) util.c
+
+help.obj:      help.c
+       $(CC) $(CFLAGS) help.c
+
+getopt.obj:    getopt.c
+       $(CC) $(CFLAGS) getopt.c
+
+version.obj:   version.c
+       $(CC) $(CFLAGS) version.c
+
+libud.lib:     $(OBJS)
+       del libud.lib
+       lib libud.lib find.obj+mod.obj+print.obj+auth.obj+util.obj+help.obj+getopt+version;
+
+bud:   libud.lib ../libldap/libldap.lib ../liblber/liblber.lib
+       copy libud.lib ..\..\lib
+       copy ..\libldap\libldap.lib ..\..\lib
+       copy ..\liblber\liblber.lib ..\..\lib
+       cd ..\..\lib
+       $(LD) $(LDFLAGS) ..\ldap\ud\main+memdebug+ncsaio,bud,nul,libud+libldap+liblber+tcp+sess+enet+common
+       copy bud.exe ..\ldap\ud\bud.exe
+       del libldap.lib
+       del liblber.lib
+       del bud.exe
+       cd ..\ldap\ud
+
diff --git a/libraries/msdos/msdos.c b/libraries/msdos/msdos.c
new file mode 100644 (file)
index 0000000..ecfc957
--- /dev/null
@@ -0,0 +1,84 @@
+#ifndef PCNFS
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <dos.h>
+#include <stdarg.h>
+#include <io.h>
+#include <time.h>
+#define ffblk find_t
+#define ff_name name
+#include <signal.h>
+#include <direct.h>
+#include <malloc.h>
+
+#define WINMASTER
+#define LPR
+
+#ifdef MEMORY_DEBUG
+#include "memdebug.h"
+#endif
+#include "whatami.h"
+#include "hostform.h"
+#include "windat.h"
+#include "lp.h"
+#include "externs.h"
+#include "msdos.h"
+
+/*  Function prototypes  */
+
+int    netup = 0;
+int    connection_id;
+int    cf_length = 0;      /* current length of control_file */
+int    sequence_number;    /* sequence number for spooled file names */
+struct config *cp;         /* configuration information */
+char   username[9];        /* name of user */
+int    debug = 0;          /* 1 = print debugging info; set with -D option */
+
+int    ftppassword,        /* not used; just to avoid unresolved external */
+bypass_passwd=0;       /* whether to bypass the password check */
+
+unsigned char path_name[_MAX_DRIVE+_MAX_DIR],          /* character storage for the path name */
+temp_str[20],s[_MAX_DIR],temp_data[30];
+
+/* Do session initialization.  Snetinit reads config file. */
+ncsainit()
+{
+       char *ptr;
+       int i;
+       if (netup) return;
+       ptr = getenv("CONFIG.TEL");
+       if (ptr != NULL) Shostfile(ptr);
+       if(i=Snetinit()) {
+               if(i==-2)               /* BOOTP server not responding */
+                       netshut();      /* release network */
+               crash("network initialization failed.");
+       }       /* end if */
+       netup = 1;
+}
+
+
+int ncsaopen( address, port )
+unsigned long   address;
+short    port;
+{
+       unsigned char  *bob;
+       struct machinfo *mr;
+       short source_port;
+       short handle;
+       char s[256];
+
+       bob = (unsigned char *) &address;
+       sprintf(s,"%u.%u.%u.%u\n",bob[0],bob[1],bob[2],bob[3]);
+       mr = lookup(s);
+
+       /* open connection */
+       /* pick a source port at random from the set of privileged ports */
+
+       srand((unsigned)time(NULL));
+
+       source_port = rand() % MAX_PRIV_PORT;
+       handle = open_connection(mr, source_port, port);
+       return(handle);
+}
+#endif /* PCNFS */
diff --git a/libraries/msdos/msdos.h b/libraries/msdos/msdos.h
new file mode 100644 (file)
index 0000000..b670463
--- /dev/null
@@ -0,0 +1,52 @@
+/* ldapmsdos.h */
+/*
+ * Copyright (c) 1992 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#ifdef PCNFS
+#include <sys/tk_types.h>
+#include <sys/socket.h>
+#include <sys/nfs_time.h>
+#endif /* PCNFS */
+
+#ifdef NCSA
+#define NCSADOMAINFIX  1       /* see README.dos */
+
+typedef unsigned short us;
+typedef unsigned long ul;
+#define ntohs(i) ((us)( (((us)i & 0xff) << 8)  + (((us)i & 0xff00) >> 8) ))
+#define ntohl(i) ((ul)( (((ul)i & 0xff) << 24) + (((ul)i & 0xff00) << 8) + \
+                       (((ul)i & 0xff0000) >> 8) +  \
+                       (((ul)i & 0xff000000) >> 24) ))
+#define htons(i) ntohs(i)
+#define htonl(i) ntohl(i)
+
+typedef unsigned long ip_addr;
+typedef unsigned long u_long;
+typedef unsigned short u_short;
+typedef unsigned char u_char;
+
+extern int ncsainit( void );
+extern int ncsaopen( unsigned long addr, short port );
+extern int nread(int connection_id, char *buff, int buff_size);
+#endif /* NCSA */
+
+#if defined( PCNFS ) || defined( NCSA )
+#include <malloc.h>
+
+struct timeval {
+       long tv_sec;
+       long tv_usec;
+};
+#endif /* PCNFS */
+
+#define strcasecmp(a,b) stricmp(a,b)
+#define strncasecmp(a,b,len) strnicmp(a,b,len)
diff --git a/libraries/msdos/opendos.c b/libraries/msdos/opendos.c
new file mode 100644 (file)
index 0000000..68752db
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+ *  Copyright (c) 1992 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  open-dos.c
+ */
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1992 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include "lber.h"
+#include "ldap.h"
+#include <stdio.h>
+#include <string.h>
+#include <malloc.h>
+#ifdef PCNFS
+#include <tklib.h>
+#include <sys/tk_types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#else /* PCNFS */
+#include "hostform.h"
+#include "externs.h"
+#endif /* PCNFS */
+#include "msdos.h"
+
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK        ((u_long) 0x7f000001)
+#endif
+
+#ifdef LDAP_DEBUG
+int    ldap_debug;
+#endif
+
+#ifndef PCNFS
+u_long *lookup_addrs( char *host );
+extern long inet_addr( char *addr );
+extern struct machinfo *lookup( char *host );
+#endif /* PCNFS */
+
+/*
+ * ldap_open - initialize and connect to an ldap server.  A magic cookie to
+ * be used for future communication is returned on success, NULL on failure.
+ *
+ * Example:
+ *     LDAP    *ld;
+ *     ld = ldap_open( hostname, port );
+ */
+
+#ifdef PCNFS
+LDAP *ldap_open( host, port )
+    char       *host;
+    int                port;
+{
+       int                     s;
+       unsigned long           address;
+       struct sockaddr_in      sock;
+       struct hostent          *hp;
+       LDAP                    *ld;
+       char                    *p, hostname[BUFSIZ];
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_open\n", 0, 0, 0 );
+
+       if ( host == NULL ) {
+               fprintf(stderr, "No hostname!\n");
+               return( NULL );
+       }
+       if ( (hp = gethostbyname( host )) == NULL ) {
+               perror( "gethostbyname" );
+               return( NULL );
+       }
+       SAFEMEMCPY( (char *) &address, (char *) hp->h_addr, hp->h_length );
+       strcpy( hostname, hp->h_name );
+       if ( (p = strchr( hostname, '.' )) != NULL )
+               *p = '\0';
+       if ( port == 0 )
+               port = LDAP_PORT;
+
+       if ( (s = socket( AF_INET, SOCK_STREAM, 0 )) < 0 ) {
+               tk_perror( "socket" );
+               return( NULL );
+       }
+
+       memset( (char *)&sock, 0, sizeof(sock));
+       SAFEMEMCPY( &sock.sin_addr, hp->h_addr, hp->h_length );
+       sock.sin_family = hp->h_addrtype;
+       sock.sin_port = htons( (u_short) port);
+
+       if (connect( s, (struct sockaddr *)&sock, sizeof(sock) ) < 0 ) {
+               tk_perror( "connect" );
+               return( NULL );
+       }
+
+       if ( (ld = (LDAP *) calloc( sizeof(LDAP), 1 )) == NULL ) {
+               close( s );
+               return( NULL );
+       }
+       ld->ld_sb.sb_sd = s;
+       ld->ld_host = strdup( hostname );
+       ld->ld_version = LDAP_VERSION;
+
+       return( ld );
+}
+#else /* PCNFS */
+
+LDAP *ldap_open( host, port )
+char   *host;
+int    port;
+{
+       int                     s, i;
+       unsigned long           tmpaddr[2], *addrs;
+       LDAP                    *ld;
+       char                    *p, hostname[BUFSIZ];
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_open\n", 0, 0, 0 );
+
+       ncsainit();
+       tmpaddr[ 1 ] = 0;
+       addrs = tmpaddr;
+       if ( host != NULL ) {
+               strcpy( hostname, host );
+               if ( (tmpaddr[0] = inet_addr( host )) == -1 ) {
+                       if (( addrs = lookup_addrs( host )) == NULL ) {
+                               netshut();
+                               return( NULL );
+                       }
+               }
+       } else {
+               tmpaddr[0] = INADDR_LOOPBACK;
+               strcpy( hostname, "localhost" );
+       }
+       if ( (p = strchr( hostname, '.' )) != NULL )
+               *p = '\0';
+       if ( port == 0 )
+               port = LDAP_PORT;
+
+       for ( i = 0; addrs[ i ] != 0; ++i ) {
+               if ( (s = ncsaopen( addrs[ i ], port )) >= 0 ) {
+                       break;
+               }
+       }
+
+       if ( addrs[ i ] == 0 ) {
+               netshut();
+               return( NULL );
+       }
+
+       if ( (ld = (LDAP *) calloc( sizeof(LDAP), 1 )) == NULL ) {
+               netclose( s );
+               netshut();
+               return( NULL );
+       }
+       ld->ld_sb.sb_sd = s;
+       ld->ld_host = strdup( hostname );
+       ld->ld_version = LDAP_VERSION;
+
+       return( ld );
+}
+
+
+u_long *
+lookup_addrs( host )
+    char       *host;
+{
+    struct machinfo    *mr;
+    int                        numaddrs, i;
+    char               *ipp;
+    u_long             *addrs, along;
+
+    if (( mr = lookup( host )) == NULL ) {
+       return( NULL );
+    }
+
+    ipp = mr->hostip;
+#ifdef NCSADOMAINFIX
+    numaddrs = 0;
+    while ( numaddrs < 4 ) {   /* maximum of 4 addresses */
+        SAFEMEMCPY( (char *)&along, (char *)ipp, sizeof( u_long ));
+       if ( along == 0 ) {
+               break;
+       }
+       ++numaddrs;
+       ipp += 4;
+    }
+#else /* NCSADOMAINFIX */
+    numaddrs = 1;
+#endif /* NCSADOMAINFIX */
+
+    if (( addrs = (u_long *)malloc(( numaddrs + 1 ) * sizeof( u_long )))
+               == NULL ) {
+       return( NULL );
+    }
+    addrs[ numaddrs ] = 0;
+
+    for ( i = 0, ipp = mr->hostip; i < numaddrs; ++i, ipp += 4 ) {
+       SAFEMEMCPY( (char *)&addrs[ i ], (char *)ipp, sizeof( u_long ));
+    }
+
+    return( addrs );
+}
+
+/*
+ * Stand alone inet_addr derived from BSD 4.3 Networking Release 2 by MCS
+ *
+ *  Copyright (c) 1992 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  inet_addr.c
+ */
+
+/*
+ * Copyright (c) 1983, 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)inet_addr.c        5.10 (Berkeley) 2/24/91";
+#endif /* LIBC_SCCS and not lint */
+
+#define STANDALONE     1
+
+#ifdef STANDALONE
+#define        INADDR_NONE     0xffffffff              /* -1 return */
+#define const
+int inet_aton( char *cp, u_long *addr);
+
+#else STANDALONE
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif STANDALONE
+
+#include <ctype.h>
+
+#ifndef isascii
+#define isascii(c)     ((unsigned)(c)<=0177)   /* for broken machines */
+#endif isascii
+
+/*
+ * Ascii internet address interpretation routine.
+ * The value returned is in network order.
+ */
+long
+inet_addr(cp)
+       register const char *cp;
+{
+#ifdef STANDALONE
+       u_long val;
+#else STANDALONE
+       struct in_addr val;
+#endif STANDALONE
+
+       if (inet_aton(cp, &val))
+#ifdef STANDALONE
+               return (val);
+#else STANDALONE
+               return (val.s_addr);
+#endif STANDALONE
+       return (INADDR_NONE);
+}
+
+/* 
+ * Check whether "cp" is a valid ascii representation
+ * of an Internet address and convert to a binary address.
+ * Returns 1 if the address is valid, 0 if not.
+ * This replaces inet_addr, the return value from which
+ * cannot distinguish between failure and a local broadcast address.
+ */
+
+inet_aton(cp, addr)
+       register char *cp;
+#ifdef STANDALONE
+       u_long *addr;
+#else STANDALONE
+       struct in_addr *addr;
+#endif STANDALONE
+{
+       register u_long val, base, n;
+       register char c;
+       u_long parts[4], *pp = parts;
+
+       for (;;) {
+               /*
+                * Collect number up to ``.''.
+                * Values are specified as for C:
+                * 0x=hex, 0=octal, other=decimal.
+                */
+               val = 0; base = 10;
+               if (*cp == '0') {
+                       if (*++cp == 'x' || *cp == 'X')
+                               base = 16, cp++;
+                       else
+                               base = 8;
+               }
+               while ((c = *cp) != '\0') {
+                       if (isascii(c) && isdigit(c)) {
+                               val = (val * base) + (c - '0');
+                               cp++;
+                               continue;
+                       }
+                       if (base == 16 && isascii(c) && isxdigit(c)) {
+                               val = (val << 4) + 
+                                       (c + 10 - (islower(c) ? 'a' : 'A'));
+                               cp++;
+                               continue;
+                       }
+                       break;
+               }
+               if (*cp == '.') {
+                       /*
+                        * Internet format:
+                        *      a.b.c.d
+                        *      a.b.c   (with c treated as 16-bits)
+                        *      a.b     (with b treated as 24 bits)
+                        */
+                       if (pp >= parts + 3 || val > 0xff)
+                               return (0);
+                       *pp++ = val, cp++;
+               } else
+                       break;
+       }
+       /*
+        * Check for trailing characters.
+        */
+       if (*cp && (!isascii(*cp) || !isspace(*cp)))
+               return (0);
+       /*
+        * Concoct the address according to
+        * the number of parts specified.
+        */
+       n = pp - parts + 1;
+       switch (n) {
+
+       case 1:                         /* a -- 32 bits */
+               break;
+
+       case 2:                         /* a.b -- 8.24 bits */
+               if (val > 0xffffff)
+                       return (0);
+               val |= parts[0] << 24;
+               break;
+
+       case 3:                         /* a.b.c -- 8.8.16 bits */
+               if (val > 0xffff)
+                       return (0);
+               val |= (parts[0] << 24) | (parts[1] << 16);
+               break;
+
+       case 4:                         /* a.b.c.d -- 8.8.8.8 bits */
+               if (val > 0xff)
+                       return (0);
+               val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
+               break;
+       }
+       if (addr)
+#ifdef STANDALONE
+               *addr = htonl(val);
+#else STANDALONE
+               addr->s_addr = htonl(val);
+#endif STANDALONE
+       return (1);
+}
+
+#endif /* PCNFS */
diff --git a/libraries/msdos/protoud.h b/libraries/msdos/protoud.h
new file mode 100644 (file)
index 0000000..d78f5b7
--- /dev/null
@@ -0,0 +1,28 @@
+extern  int bind_info(void);
+extern  int auth(char *who,char *best_guess);
+extern  char *mygetpass(char *prompt);
+extern  int iam(char *who);
+extern  int print_my_name(void);
+extern  int init_search(char * *attributes);
+extern  int init_read(char * *attributes);
+extern  int dxi_vrfy(char *dn);
+extern  LDAPMessage *find(char *who);
+extern  int pick_one(int i);
+extern  int print_list(LDAPMessage *list,char * *names,int *matches);
+extern  int main(int argc,char * *argv);
+extern  int do_commands(void);
+extern  int status(void);
+extern  int change_base(char *s);
+extern  int initialize_client(void);
+extern  int attn(void);
+extern  int print_help(char *s);
+extern  char *alias(char *s);
+extern  void printbase(char *lead,char *s);
+extern  int fetch_buffer(char *buffer,int length,struct _iobuf *where);
+extern  int modify(char *who);
+extern  void set_pw(char *who);
+extern  int change_field(char *tag,char *id,char (*val)[256],char *who);
+extern  char *get_value(char *id,char *prompt);
+extern  int parse_answer(LDAPMessage *s);
+extern  int print_person(void);
+extern  int print_entry(char (*s)[256],char *label);
diff --git a/libraries/msdos/winsock/include/file.h b/libraries/msdos/winsock/include/file.h
new file mode 100644 (file)
index 0000000..cead080
--- /dev/null
@@ -0,0 +1,4 @@
+/*
+ * This file is intentionally empty.  Some compilers require the presence of
+ * an include file, even if the "#ifdef"s exclude it from actual use. PTUI !
+ */
diff --git a/libraries/msdos/winsock/include/filio.h b/libraries/msdos/winsock/include/filio.h
new file mode 100644 (file)
index 0000000..cead080
--- /dev/null
@@ -0,0 +1,4 @@
+/*
+ * This file is intentionally empty.  Some compilers require the presence of
+ * an include file, even if the "#ifdef"s exclude it from actual use. PTUI !
+ */
diff --git a/libraries/msdos/winsock/include/in.h b/libraries/msdos/winsock/include/in.h
new file mode 100644 (file)
index 0000000..cead080
--- /dev/null
@@ -0,0 +1,4 @@
+/*
+ * This file is intentionally empty.  Some compilers require the presence of
+ * an include file, even if the "#ifdef"s exclude it from actual use. PTUI !
+ */
diff --git a/libraries/msdos/winsock/include/ioctl.h b/libraries/msdos/winsock/include/ioctl.h
new file mode 100644 (file)
index 0000000..cead080
--- /dev/null
@@ -0,0 +1,4 @@
+/*
+ * This file is intentionally empty.  Some compilers require the presence of
+ * an include file, even if the "#ifdef"s exclude it from actual use. PTUI !
+ */
diff --git a/libraries/msdos/winsock/include/krb/des.h b/libraries/msdos/winsock/include/krb/des.h
new file mode 100644 (file)
index 0000000..58699c5
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * $Source: Q:/SRC/KRB/MIT/ORIGINAL/INCLUDE/RCS/DES.H $
+ * $Author: shabby $
+ * $Header: Q:/SRC/KRB/MIT/ORIGINAL/INCLUDE/RCS/DES.H 1.3 1994/08/31 07:02:28 shabby Exp $
+ *
+ * Copyright 1987, 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * Include file for the Data Encryption Standard library.
+ */
+
+/* only do the whole thing once  */
+#ifndef DES_DEFS
+#define DES_DEFS
+
+#include <mit_copy.h>
+
+typedef unsigned char des_cblock[8];    /* crypto-block size */
+/* Key schedule */
+typedef struct des_ks_struct { des_cblock _; } des_key_schedule[16];
+
+#define DES_KEY_SZ      (sizeof(des_cblock))
+#define DES_ENCRYPT     1
+#define DES_DECRYPT     0
+
+#ifndef NCOMPAT
+#define C_Block des_cblock
+#define Key_schedule des_key_schedule
+#define ENCRYPT DES_ENCRYPT
+#define DECRYPT DES_DECRYPT
+#define KEY_SZ DES_KEY_SZ
+#define string_to_key des_string_to_key
+#define read_pw_string des_read_pw_string
+#define random_key des_random_key
+#define pcbc_encrypt des_pcbc_encrypt
+#define key_sched des_key_sched
+#define cbc_encrypt des_cbc_encrypt
+#define cbc_cksum des_cbc_cksum
+#define C_Block_print des_cblock_print
+#define quad_cksum des_quad_cksum
+typedef struct des_ks_struct bit_64;
+#endif
+
+#define des_cblock_print(x) des_cblock_print_file(x, stdout)
+
+int des_check_key_parity(des_cblock);
+int des_is_weak_key(des_cblock);
+
+/* Function prototypes */
+int des_key_sched(des_cblock,des_key_schedule);
+int des_ecb_encrypt(unsigned long*,unsigned long*,des_key_schedule,int);
+int des_pcbc_encrypt(des_cblock*,des_cblock*,long,des_key_schedule,
+                                                des_cblock*,int);
+
+unsigned long des_cbc_cksum(des_cblock*,des_cblock*,long,
+                              des_key_schedule,des_cblock*);
+
+int des_is_weak_key(des_cblock);
+void des_fixup_key_parity(des_cblock);
+int des_check_key_parity(des_cblock);
+#endif  /* DES_DEFS */
diff --git a/libraries/msdos/winsock/include/krb/krb.h b/libraries/msdos/winsock/include/krb/krb.h
new file mode 100644 (file)
index 0000000..d9e2b17
--- /dev/null
@@ -0,0 +1,504 @@
+/*
+ * $Source: Q:/SRC/KRB/MIT/ORIGINAL/RCS/KRB.H $
+ * $Author: pbh $
+ * $Header: Q:/SRC/KRB/MIT/ORIGINAL/RCS/KRB.H 1.5 1994/09/08 22:47:00 pbh Exp $
+ *
+ * Copyright 1987, 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * Include file for the Kerberos library.
+ */
+
+/* Only one time, please */
+#ifndef KRB_DEFS
+#define KRB_DEFS
+
+#include <mit_copy.h>
+#include <conf.h>
+
+/* Need some defs from des.h     */
+#include <des.h>
+
+/* Text describing error codes */
+#define         MAX_KRB_ERRORS  256
+#ifndef WINDOWS
+extern char *krb_err_txt[MAX_KRB_ERRORS];
+#else
+extern char FAR *krb_err_txt[MAX_KRB_ERRORS];
+#endif
+
+
+/* These are not defined for at least SunOS 3.3 and Ultrix 2.2 */
+#if defined(ULTRIX022) || (defined(SunOS) && SunOS < 40)
+#define FD_ZERO(p)  ((p)->fds_bits[0] = 0)
+#define FD_SET(n, p)   ((p)->fds_bits[0] |= (1 << (n)))
+#define FD_ISSET(n, p)   ((p)->fds_bits[0] & (1 << (n)))
+#endif /* ULTRIX022 || SunOS */
+
+/* General definitions */
+#define         KSUCCESS        0
+#define         KFAILURE        255
+
+#ifdef NO_UIDGID_T
+typedef unsigned short uid_t;
+typedef unsigned short gid_t;
+#endif /* NO_UIDGID_T */
+
+/*
+ * Kerberos specific definitions
+ *
+ * KRBLOG is the log file for the kerberos master server. KRB_CONF is
+ * the configuration file where different host machines running master
+ * and slave servers can be found. KRB_MASTER is the name of the
+ * machine with the master database.  The admin_server runs on this
+ * machine, and all changes to the db (as opposed to read-only
+ * requests, which can go to slaves) must go to it. KRB_HOST is the
+ * default machine * when looking for a kerberos slave server.  Other
+ * possibilities are * in the KRB_CONF file. KRB_REALM is the name of
+ * the realm.
+ */
+
+#ifdef notdef
+this is server - only, does not belong here;
+#define         KRBLOG          "/kerberos/kerberos.log"
+are these used anyplace '?';
+#define         VX_KRB_HSTFILE  "/etc/krbhst"
+#define         PC_KRB_HSTFILE  "\\kerberos\\krbhst"
+#endif
+#ifdef IBMPC
+#define         KRB_CONF        "%s\\kerb\\krb.con"
+#define         KRB_RLM_TRANS   "%s\\KERB\\krbrealm.con"
+#else
+#define         KRB_CONF        "/etc/krb.conf"
+#define         KRB_RLM_TRANS   "/etc/krb.realms"
+#endif
+#define         KRB_MASTER      "kerberos.mit.edu"
+#define         KRB_REALM       "ATHENA.MIT.EDU"
+#define         KRB_HOST         KRB_MASTER
+
+/* The maximum sizes for aname, realm, sname, and instance +1 */
+#define         ANAME_SZ        40
+#define         REALM_SZ        40
+#define         SNAME_SZ        40
+#define         INST_SZ         40
+/* include space for '.' and '@' */
+#define         MAX_K_NAME_SZ   (ANAME_SZ + INST_SZ + REALM_SZ + 2)
+#define         KKEY_SZ         100
+#define         VERSION_SZ      1
+#define         MSG_TYPE_SZ     1
+#define         DATE_SZ         26      /* RTI date output */
+
+#define         MAX_HSTNM       100
+
+#ifndef DEFAULT_TKT_LIFE                /* allow compile-time override */
+#define         DEFAULT_TKT_LIFE        96 /* default lifetime for krb_mk_req
+                                              & co., 8 hrs */
+#endif
+
+/* Definition of text structure used to pass text around */
+#define         MAX_KTXT_LEN    1250
+
+struct ktext {
+    int     length;             /* Length of the text */
+    unsigned char dat[MAX_KTXT_LEN];    /* The data itself */
+    unsigned long mbz;          /* zero to catch runaway strings */
+};
+
+typedef struct ktext far *KTEXT;
+typedef struct ktext far *KTEXT_FP;
+typedef struct ktext KTEXT_ST;
+
+
+/* Definitions for send_to_kdc */
+#define CLIENT_KRB_TIMEOUT      10       /* time between retries */ /* changed from 4, 8-14-94 pbh */
+#define CLIENT_KRB_RETRY        5       /* retry this many times */
+#define CLIENT_KRB_BUFLEN       512     /* max unfragmented packet */
+
+/* Definitions for ticket file utilities */
+#define R_TKT_FIL       0
+#define W_TKT_FIL       1
+
+/* Definitions for cl_get_tgt */
+#ifdef PC
+#define CL_GTGT_INIT_FILE               "\\kerberos\\k_in_tkts"
+#else
+#define CL_GTGT_INIT_FILE               "/etc/k_in_tkts"
+#endif /* PC */
+
+/* Parameters for rd_ap_req */
+/* Maximum alloable clock skew in seconds */
+#define         CLOCK_SKEW      5*60
+/* Filename for readservkey */
+#define         KEYFILE         "/etc/srvtab"
+
+/* Structure definition for rd_ap_req */
+
+struct auth_dat {
+    unsigned char k_flags;      /* Flags from ticket */
+    char    pname[ANAME_SZ];    /* Principal's name */
+    char    pinst[INST_SZ];     /* His Instance */
+    char    prealm[REALM_SZ];   /* His Realm */
+    unsigned long checksum;     /* Data checksum (opt) */
+    C_Block session;            /* Session Key */
+    int     life;               /* Life of ticket */
+    unsigned long time_sec;     /* Time ticket issued */
+    unsigned long address;      /* Address in ticket */
+    KTEXT_ST reply;             /* Auth reply (opt) */
+};
+
+typedef struct auth_dat AUTH_DAT;
+
+/* Structure definition for credentials returned by get_cred */
+
+struct credentials {
+    char    service[ANAME_SZ];  /* Service name */
+    char    instance[INST_SZ];  /* Instance */
+    char    realm[REALM_SZ];    /* Auth domain */
+    C_Block session;            /* Session key */
+    int     lifetime;           /* Lifetime */
+    int     kvno;               /* Key version number */
+    KTEXT_ST ticket_st;         /* The ticket itself */
+    long    issue_date;         /* The issue time */
+    char    pname[ANAME_SZ];    /* Principal's name */
+    char    pinst[INST_SZ];     /* Principal's instance */
+};
+
+typedef struct credentials CREDENTIALS;
+
+/* Structure definition for rd_private_msg and rd_safe_msg */
+
+struct msg_dat {
+    unsigned char far *app_data;        /* pointer to appl data */
+    unsigned long app_length;   /* length of appl data */
+    unsigned long hash;         /* hash to lookup replay */
+    int     swap;               /* swap bytes? */
+    long    time_sec;           /* msg timestamp seconds */
+    unsigned char time_5ms;     /* msg timestamp 5ms units */
+};
+
+typedef struct msg_dat MSG_DAT;
+
+
+/* Location of ticket file for save_cred and get_cred */
+#define TKT_FILE tkt_string()
+#define TKT_ENV                 "KERBEROS_TICKETS"
+typedef struct {
+        unsigned buf_size;
+        unsigned dummy;
+        unsigned eof_ptr;
+        int sema;               /* semaphore 0 - OK, -1 - lock write, +ve lock read */
+} tkt_header;
+
+tkt_header far *tkt_ptr(void);
+
+#define KM_TKFILE 0
+#define KM_KRBMEM 1
+
+#define TKT_ROOT        "/tmp/tkt"  /* not used in OS/2 anyway */
+
+/* Error codes returned from the KDC */
+#define         KDC_OK          0       /* Request OK */
+#define         KDC_NAME_EXP    1       /* Principal expired */
+#define         KDC_SERVICE_EXP 2       /* Service expired */
+#define         KDC_AUTH_EXP    3       /* Auth expired */
+#define         KDC_PKT_VER     4       /* Protocol version unknown */
+#define         KDC_P_MKEY_VER  5       /* Wrong master key version */
+#define         KDC_S_MKEY_VER  6       /* Wrong master key version */
+#define         KDC_BYTE_ORDER  7       /* Byte order unknown */
+#define         KDC_PR_UNKNOWN  8       /* Principal unknown */
+#define         KDC_PR_N_UNIQUE 9       /* Principal not unique */
+#define         KDC_NULL_KEY   10       /* Principal has null key */
+#define         KDC_GEN_ERR    20       /* Generic error from KDC */
+
+
+/* Values returned by get_credentials */
+#define         GC_OK           0       /* Retrieve OK */
+#define         RET_OK          0       /* Retrieve OK */
+#define         GC_TKFIL       21       /* Can't read ticket file */
+#define         RET_TKFIL      21       /* Can't read ticket file */
+#define         GC_NOTKT       22       /* Can't find ticket or TGT */
+#define         RET_NOTKT      22       /* Can't find ticket or TGT */
+
+
+/* Values returned by mk_ap_req  */
+#define         MK_AP_OK        0       /* Success */
+#define         MK_AP_TGTEXP   26       /* TGT Expired */
+
+/* Values returned by rd_ap_req */
+#define         RD_AP_OK        0       /* Request authentic */
+#define         RD_AP_UNDEC    31       /* Can't decode authenticator */
+#define         RD_AP_EXP      32       /* Ticket expired */
+#define         RD_AP_NYV      33       /* Ticket not yet valid */
+#define         RD_AP_REPEAT   34       /* Repeated request */
+#define         RD_AP_NOT_US   35       /* The ticket isn't for us */
+#define         RD_AP_INCON    36       /* Request is inconsistent */
+#define         RD_AP_TIME     37       /* delta_t too big */
+#define         RD_AP_BADD     38       /* Incorrect net address */
+#define         RD_AP_VERSION  39       /* protocol version mismatch */
+#define         RD_AP_MSG_TYPE 40       /* invalid msg type */
+#define         RD_AP_MODIFIED 41       /* message stream modified */
+#define         RD_AP_ORDER    42       /* message out of order */
+#define         RD_AP_UNAUTHOR 43       /* unauthorized request */
+
+/* Values returned by get_pw_tkt */
+#define         GT_PW_OK        0       /* Got password changing tkt */
+#define         GT_PW_NULL     51       /* Current PW is null */
+#define         GT_PW_BADPW    52       /* Incorrect current password */
+#define         GT_PW_PROT     53       /* Protocol Error */
+#define         GT_PW_KDCERR   54       /* Error returned by KDC */
+#define         GT_PW_NULLTKT  55       /* Null tkt returned by KDC */
+
+
+/* Values returned by send_to_kdc */
+#define         SKDC_OK         0       /* Response received */
+#define         SKDC_RETRY     56       /* Retry count exceeded */
+#define         SKDC_CANT      57       /* Can't send request */
+
+/*
+ * Values returned by get_intkt
+ * (can also return SKDC_* and KDC errors)
+ */
+
+#define         INTK_OK         0       /* Ticket obtained */
+#define         INTK_W_NOTALL  61       /* Not ALL tickets returned */
+#define         INTK_BADPW     62       /* Incorrect password */
+#define         INTK_PROT      63       /* Protocol Error */
+#define         INTK_ERR       70       /* Other error */
+
+/* Values returned by get_adtkt */
+#define         AD_OK           0       /* Ticket Obtained */
+#define         AD_NOTGT       71       /* Don't have tgt */
+
+/* Error codes returned by ticket file utilities */
+#define         NO_TKT_FIL      76      /* No ticket file found */
+#define         TKT_FIL_ACC     77      /* Couldn't access tkt file */
+#define         TKT_FIL_LCK     78      /* Couldn't lock ticket file */
+#define         TKT_FIL_FMT     79      /* Bad ticket file format */
+#define         TKT_FIL_INI     80      /* tf_init not called first */
+
+/* Error code returned by kparse_name */
+#define         KNAME_FMT       81      /* Bad Kerberos name format */
+
+/* Error code returned by krb_mk_safe */
+#define         SAFE_PRIV_ERROR -1      /* syscall error */
+
+/*
+ * macros for byte swapping; also scratch space
+ * u_quad  0-->7, 1-->6, 2-->5, 3-->4, 4-->3, 5-->2, 6-->1, 7-->0
+ * u_long  0-->3, 1-->2, 2-->1, 3-->0
+ * u_short 0-->1, 1-->0
+ */
+
+#define     swap_u_16(x) {\
+ unsigned long   _krb_swap_tmp[4];\
+ _swab(((char *) x) +0, ((char *)  _krb_swap_tmp) +14 ,2); \
+ _swab(((char *) x) +2, ((char *)  _krb_swap_tmp) +12 ,2); \
+ _swab(((char *) x) +4, ((char *)  _krb_swap_tmp) +10 ,2); \
+ _swab(((char *) x) +6, ((char *)  _krb_swap_tmp) +8  ,2); \
+ _swab(((char *) x) +8, ((char *)  _krb_swap_tmp) +6 ,2); \
+ _swab(((char *) x) +10,((char *)  _krb_swap_tmp) +4 ,2); \
+ _swab(((char *) x) +12,((char *)  _krb_swap_tmp) +2 ,2); \
+ _swab(((char *) x) +14,((char *)  _krb_swap_tmp) +0 ,2); \
+ bcopy((char *)_krb_swap_tmp,(char *)x,16);\
+                            }
+
+#define     swap_u_12(x) {\
+ unsigned long   _krb_swap_tmp[4];\
+ _swab(( char *) x,     ((char *)  _krb_swap_tmp) +10 ,2); \
+ _swab(((char *) x) +2, ((char *)  _krb_swap_tmp) +8 ,2); \
+ _swab(((char *) x) +4, ((char *)  _krb_swap_tmp) +6 ,2); \
+ _swab(((char *) x) +6, ((char *)  _krb_swap_tmp) +4 ,2); \
+ _swab(((char *) x) +8, ((char *)  _krb_swap_tmp) +2 ,2); \
+ _swab(((char *) x) +10,((char *)  _krb_swap_tmp) +0 ,2); \
+ bcopy((char *)_krb_swap_tmp,(char *)x,12);\
+                            }
+
+#define     swap_C_Block(x) {\
+ unsigned long   _krb_swap_tmp[4];\
+ _swab(( char *) x,    ((char *)  _krb_swap_tmp) +6 ,2); \
+ _swab(((char *) x) +2,((char *)  _krb_swap_tmp) +4 ,2); \
+ _swab(((char *) x) +4,((char *)  _krb_swap_tmp) +2 ,2); \
+ _swab(((char *) x) +6,((char *)  _krb_swap_tmp)    ,2); \
+ bcopy((char *)_krb_swap_tmp,(char *)x,8);\
+                            }
+#define     swap_u_quad(x) {\
+ unsigned long   _krb_swap_tmp[4];\
+ _swab(( char *) &x,    ((char *)  _krb_swap_tmp) +6 ,2); \
+ _swab(((char *) &x) +2,((char *)  _krb_swap_tmp) +4 ,2); \
+ _swab(((char *) &x) +4,((char *)  _krb_swap_tmp) +2 ,2); \
+ _swab(((char *) &x) +6,((char *)  _krb_swap_tmp)    ,2); \
+ bcopy((char *)_krb_swap_tmp,(char *)&x,8);\
+                            }
+
+#define     swap_u_long(x) {\
+ unsigned long   _krb_swap_tmp[4];\
+ _swab((char *)  &x,    ((char *)  _krb_swap_tmp) +2 ,2); \
+ _swab(((char *) &x) +2,((char *)  _krb_swap_tmp),2); \
+ x = _krb_swap_tmp[0];   \
+                           }
+
+#define     swap_u_short(x) {\
+ unsigned short _krb_swap_sh_tmp; \
+ _swab((char *)  &x,    ( &_krb_swap_sh_tmp) ,2); \
+ x = (unsigned short) _krb_swap_sh_tmp; \
+                            }
+
+/* Kerberos ticket flag field bit definitions */
+#define K_FLAG_ORDER    0       /* bit 0 --> lsb */
+#define K_FLAG_1                /* reserved */
+#define K_FLAG_2                /* reserved */
+#define K_FLAG_3                /* reserved */
+#define K_FLAG_4                /* reserved */
+#define K_FLAG_5                /* reserved */
+#define K_FLAG_6                /* reserved */
+#define K_FLAG_7                /* reserved, bit 7 --> msb */
+
+char *tkt_string();
+
+#ifdef  OLDNAMES
+#define krb_mk_req      mk_ap_req
+#define krb_rd_req      rd_ap_req
+#define krb_kntoln      an_to_ln
+#define krb_set_key     set_serv_key
+#define krb_get_cred    get_credentials
+#define krb_mk_priv     mk_private_msg
+#define krb_rd_priv     rd_private_msg
+#define krb_mk_safe     mk_safe_msg
+#define krb_rd_safe     rd_safe_msg
+#define krb_mk_err      mk_appl_err_msg
+#define krb_rd_err      rd_appl_err_msg
+#define krb_ck_repl     check_replay
+#define krb_get_pw_in_tkt       get_in_tkt
+#define krb_get_svc_in_tkt      get_svc_in_tkt
+#define krb_get_pw_tkt          get_pw_tkt
+#define krb_realmofhost         krb_getrealm
+#define krb_get_phost           get_phost
+#define krb_get_krbhst          get_krbhst
+#define krb_get_lrealm          get_krbrlm
+#endif  /* OLDNAMES */
+
+/* Defines for krb_sendauth and krb_recvauth */
+
+#define KOPT_DONT_MK_REQ 0x00000001 /* don't call krb_mk_req */
+#define KOPT_DO_MUTUAL   0x00000002 /* do mutual auth */
+
+#define KOPT_DONT_CANON  0x00000004 /*
+                                     * don't canonicalize inst as
+                                     * a hostname
+                                     */
+
+#define KRB_SENDAUTH_VLEN 8         /* length for version strings */
+
+#ifdef ATHENA_COMPAT
+#define KOPT_DO_OLDSTYLE 0x00000008 /* use the old-style protocol */
+#endif /* ATHENA_COMPAT */
+
+#ifdef WINDOWS
+#include <lsh_pwd.h>
+int gettimeofday(struct timeval *tv, struct timezone *tz);
+void tkt_free(tkt_header FAR* hdr);
+int krb_get_tf_fullname(char *tf, char *name, char *inst, char *realm);
+/*      Windows prototypes */
+int FAR PASCAL krb_sendauth(long,int,KTEXT_FP,LPSTR,LPSTR,LPSTR,unsigned long,
+        MSG_DAT FAR *,CREDENTIALS FAR *, Key_schedule FAR *,
+        struct sockaddr_in FAR *,struct sockaddr_in FAR *, LPSTR);
+char FAR* FAR* FAR get_krb_err_txt(void);
+/* 2-22-93, pbh */
+int FAR krb_get_tf_realm(char FAR *,char FAR *);
+int FAR tf_init(char FAR*,int);
+int FAR tf_get_pname(char FAR*);
+int FAR tf_get_pinst(char FAR*);
+int FAR tf_get_cred(CREDENTIALS FAR*);
+void FAR tf_close(void);
+int FAR tf_save_cred(char FAR*,char FAR*,char FAR*,C_Block,int,int,KTEXT,long);
+BOOL FAR k_isinst(char FAR *s);
+BOOL FAR k_isrealm(char FAR *s);
+BOOL FAR k_isname(char FAR *s);
+int FAR set_krb_debug( int );   /* Warning, unique to Windows! */
+int FAR set_krb_ap_req_debug( int );    /* Warning, unique to Windows! */
+LPSTR FAR PASCAL get_krb_err_txt_entry( int i);           /* Warning, unique to Windows! */
+int FAR PASCAL krb_mk_req(KTEXT,LPSTR,LPSTR,LPSTR,long);
+LPSTR FAR PASCAL krb_getrealm( char FAR *host);
+/* end 2-22-93, pbh */
+
+#ifdef WINSOCK
+#define bcopy(a,b,c) memcpy( (b), (a), (c) )
+#define bzero(a,b) memset( (a), 0, (b) )
+#endif /* WINSOCK */
+
+
+/*
+#ifdef __cplusplus
+int printf(char far*,...);
+#else
+int printf();
+#endif
+*/
+
+int FAR kname_parse(char FAR*,char FAR*,char FAR*,char FAR*);
+int FAR krb_get_pw_in_tkt(char FAR*,char FAR*,char FAR*,char FAR*,char FAR*,int,char FAR*);
+int FAR dest_tkt(void);
+int FAR krb_get_lrealm(LPSTR ,int);
+
+int FAR krb_use_kerbmem();
+int FAR krb_check_tgt();
+int FAR krb_check_serv(char *);
+
+int FAR krb_get_cred(char FAR*,char FAR*,char FAR*,CREDENTIALS FAR*);
+int FAR send_to_kdc(KTEXT,KTEXT,char FAR*);
+
+#define MIT_PWD_DLL_CLASS "MITPasswordWndDLL"
+
+#else  /* end of WINDOWS start of DOS */
+
+/*      DOS prototypes */
+int krb_get_in_tkt(char *, char *, char *, char *, char *, int, int (*)(), int (*)(), char *);
+long krb_mk_priv( u_char *, u_char *, u_long, Key_schedule, C_Block,
+                  struct sockaddr_in *, struct sockaddr_in *);
+char* krb_getrealm( char *host);
+char* krb_realmofhost( char *host);
+int krb_get_tf_realm(char*,char*);
+int krb_get_tf_fullname(char*,char*,char*,char*);
+int get_ad_tkt(char*,char*,char*,int);
+int krb_get_cred(char*,char*,char*,CREDENTIALS*);
+int krb_get_krbhst(char*,char*,int);
+int krb_get_lrealm(char*,int);
+char* krb_get_phost(char*);
+int krb_mk_req(KTEXT,char*,char*,char*,long);
+int krb_set_lifetime(int);
+
+#ifndef WINSOCK
+int krb_net_read(int,char*,int);
+int krb_net_write(int,char*,int);
+#else
+int krb_net_read(SOCKET,char*,int);
+int krb_net_write(SOCKET,char*,int);
+#endif /*winsock*/
+
+KTEXT pkt_cipher(KTEXT);
+int pkt_clen(KTEXT);
+long krb_rd_priv(unsigned char*,unsigned long,Key_schedule,C_Block,
+                                struct sockaddr_in*, struct sockaddr_in*,MSG_DAT*);
+int save_credentials(char*,char*,char*,C_Block,int,int,KTEXT,long);
+int send_to_kdc(KTEXT,KTEXT,char*);
+int krb_sendauth(long,int,KTEXT,char*,char*,char*,u_long,
+    MSG_DAT*,CREDENTIALS*,Key_schedule,
+        struct sockaddr_in*,struct sockaddr_in*,char*);
+int tf_init(char*,int);
+int tf_get_pname(char*);
+int tf_get_pinst(char*);
+int tf_get_cred(CREDENTIALS*);
+void tf_close(void);
+int tf_save_cred(char*,char*,char*,C_Block,int,int,KTEXT,long);
+int kname_parse(char*,char*,char*,char*);
+int krb_get_pw_in_tkt(char*,char*,char*,char*,char*,int,char*);
+int dest_tkt(void);
+
+int krb_use_kerbmem();
+int krb_check_tgt();
+int krb_check_serv(char *);
+
+#endif  /* WINDOWS */
+#endif  /* KRB_DEFS */
diff --git a/libraries/msdos/winsock/include/krb/mit/arpa/nameser.h b/libraries/msdos/winsock/include/krb/mit/arpa/nameser.h
new file mode 100644 (file)
index 0000000..bc6ffcb
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 1983, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)nameser.h   5.25 (Berkeley) 4/3/91
+ */
+
+#ifndef _NAMESER_H_
+#define        _NAMESER_H_
+
+/*
+ * Define constants based on rfc883
+ */
+#define PACKETSZ       512             /* maximum packet size */
+#define MAXDNAME       256             /* maximum domain name */
+#define MAXCDNAME      255             /* maximum compressed domain name */
+#define MAXLABEL       63              /* maximum length of domain label */
+       /* Number of bytes of fixed size data in query structure */
+#define QFIXEDSZ       4
+       /* number of bytes of fixed size data in resource record */
+#define RRFIXEDSZ      10
+
+/*
+ * Internet nameserver port number
+ */
+#define NAMESERVER_PORT        53
+
+/*
+ * Currently defined opcodes
+ */
+#define QUERY          0x0             /* standard query */
+#define IQUERY         0x1             /* inverse query */
+#define STATUS         0x2             /* nameserver status query */
+/*#define xxx          0x3             /* 0x3 reserved */
+       /* non standard */
+#define UPDATEA                0x9             /* add resource record */
+#define UPDATED                0xa             /* delete a specific resource record */
+#define UPDATEDA       0xb             /* delete all nemed resource record */
+#define UPDATEM                0xc             /* modify a specific resource record */
+#define UPDATEMA       0xd             /* modify all named resource record */
+
+#define ZONEINIT       0xe             /* initial zone transfer */
+#define ZONEREF                0xf             /* incremental zone referesh */
+
+/*
+ * Currently defined response codes
+ */
+#define NOERROR                0               /* no error */
+#define FORMERR                1               /* format error */
+#define SERVFAIL       2               /* server failure */
+#define NXDOMAIN       3               /* non existent domain */
+#define NOTIMP         4               /* not implemented */
+#define REFUSED                5               /* query refused */
+       /* non standard */
+#define NOCHANGE       0xf             /* update failed to change db */
+
+/*
+ * Type values for resources and queries
+ */
+#define T_A            1               /* host address */
+#define T_NS           2               /* authoritative server */
+#define T_MD           3               /* mail destination */
+#define T_MF           4               /* mail forwarder */
+#define T_CNAME                5               /* connonical name */
+#define T_SOA          6               /* start of authority zone */
+#define T_MB           7               /* mailbox domain name */
+#define T_MG           8               /* mail group member */
+#define T_MR           9               /* mail rename name */
+#define T_NULL         10              /* null resource record */
+#define T_WKS          11              /* well known service */
+#define T_PTR          12              /* domain name pointer */
+#define T_HINFO                13              /* host information */
+#define T_MINFO                14              /* mailbox information */
+#define T_MX           15              /* mail routing information */
+#define T_TXT          16              /* text strings */
+       /* non standard */
+#define T_UINFO                100             /* user (finger) information */
+#define T_UID          101             /* user ID */
+#define T_GID          102             /* group ID */
+#define T_UNSPEC       103             /* Unspecified format (binary data) */
+       /* Query type values which do not appear in resource records */
+#define T_AXFR         252             /* transfer zone of authority */
+#define T_MAILB                253             /* transfer mailbox records */
+#define T_MAILA                254             /* transfer mail agent records */
+#define T_ANY          255             /* wildcard match */
+
+/*
+ * Values for class field
+ */
+
+#define C_IN           1               /* the arpa internet */
+#define C_CHAOS                3               /* for chaos net at MIT */
+#define C_HS           4               /* for Hesiod name server at MIT */
+       /* Query class values which do not appear in resource records */
+#define C_ANY          255             /* wildcard match */
+
+/*
+ * Status return codes for T_UNSPEC conversion routines
+ */
+#define CONV_SUCCESS 0
+#define CONV_OVERFLOW -1
+#define CONV_BADFMT -2
+#define CONV_BADCKSUM -3
+#define CONV_BADBUFLEN -4
+
+#ifndef BYTE_ORDER
+#define        LITTLE_ENDIAN   1234    /* least-significant byte first (vax) */
+#define        BIG_ENDIAN      4321    /* most-significant byte first (IBM, net) */
+#define        PDP_ENDIAN      3412    /* LSB first in word, MSW first in long (pdp) */
+
+#if defined(vax) || defined(ns32000) || defined(sun386) || defined(MIPSEL) || \
+    defined(BIT_ZERO_ON_RIGHT)
+#define BYTE_ORDER     LITTLE_ENDIAN
+
+#endif
+#if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \
+    defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \
+    defined(MIPSEB) || defined (BIT_ZERO_ON_LEFT)
+#define BYTE_ORDER     BIG_ENDIAN
+#endif
+#endif /* BYTE_ORDER */
+
+#ifndef BYTE_ORDER
+       /* you must determine what the correct bit order is for your compiler */
+       #define BYTE_ORDER LITTLE_ENDIAN        /* for Intel x86 series */
+#endif
+/*
+ * Structure for query header, the order of the fields is machine and
+ * compiler dependent, in our case, the bits within a byte are assignd 
+ * least significant first, while the order of transmition is most 
+ * significant first.  This requires a somewhat confusing rearrangement.
+ */
+
+#ifdef _WINDLL
+/* define UNIX types */
+#include <winsock.h>
+#endif
+
+typedef struct {
+       u_short id;             /* query identification number */
+#if BYTE_ORDER == BIG_ENDIAN
+                       /* fields in third byte */
+       u_char  qr:1;           /* response flag */
+       u_char  opcode:4;       /* purpose of message */
+       u_char  aa:1;           /* authoritive answer */
+       u_char  tc:1;           /* truncated message */
+       u_char  rd:1;           /* recursion desired */
+                       /* fields in fourth byte */
+       u_char  ra:1;           /* recursion available */
+       u_char  pr:1;           /* primary server required (non standard) */
+       u_char  unused:2;       /* unused bits */
+       u_char  rcode:4;        /* response code */
+#endif
+#if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
+                       /* fields in third byte */
+       u_char  rd:1;           /* recursion desired */
+       u_char  tc:1;           /* truncated message */
+       u_char  aa:1;           /* authoritive answer */
+       u_char  opcode:4;       /* purpose of message */
+       u_char  qr:1;           /* response flag */
+                       /* fields in fourth byte */
+       u_char  rcode:4;        /* response code */
+       u_char  unused:2;       /* unused bits */
+       u_char  pr:1;           /* primary server required (non standard) */
+       u_char  ra:1;           /* recursion available */
+#endif
+                       /* remaining bytes */
+       u_short qdcount;        /* number of question entries */
+       u_short ancount;        /* number of answer entries */
+       u_short nscount;        /* number of authority entries */
+       u_short arcount;        /* number of resource entries */
+} HEADER;
+
+/*
+ * Defines for handling compressed domain names
+ */
+#define INDIR_MASK     0xc0
+
+/*
+ * Structure for passing resource records around.
+ */
+struct rrec {
+       short   r_zone;                 /* zone number */
+       short   r_class;                /* class number */
+       short   r_type;                 /* type number */
+       u_long  r_ttl;                  /* time to live */
+       int     r_size;                 /* size of data area */
+       char    *r_data;                /* pointer to data */
+};
+
+extern u_short _getshort();
+extern u_long  _getlong();
+
+/*
+ * Inline versions of get/put short/long.
+ * Pointer is advanced; we assume that both arguments
+ * are lvalues and will already be in registers.
+ * cp MUST be u_char *.
+ */
+#define GETSHORT(s, cp) { \
+       (s) = *(cp)++ << 8; \
+       (s) |= *(cp)++; \
+}
+
+#define GETLONG(l, cp) { \
+       (l) = *(cp)++ << 8; \
+       (l) |= *(cp)++; (l) <<= 8; \
+       (l) |= *(cp)++; (l) <<= 8; \
+       (l) |= *(cp)++; \
+}
+
+
+#define PUTSHORT(s, cp) { \
+       *(cp)++ = (s) >> 8; \
+       *(cp)++ = (s); \
+}
+
+/*
+ * Warning: PUTLONG destroys its first argument.
+ */
+#define PUTLONG(l, cp) { \
+       (cp)[3] = l; \
+       (cp)[2] = (l >>= 8); \
+       (cp)[1] = (l >>= 8); \
+       (cp)[0] = l >> 8; \
+       (cp) += sizeof(u_long); \
+}
+
+#endif /* !_NAMESER_H_ */
diff --git a/libraries/msdos/winsock/include/krb/mit/conf-pc.h b/libraries/msdos/winsock/include/krb/mit/conf-pc.h
new file mode 100644 (file)
index 0000000..169a5e2
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * $Source: F:/DOSDEV/NEWKRB/INCLUDE/RCS/conf-pc.h $
+ * $Author: pbh $
+ * $Header: F:/DOSDEV/NEWKRB/INCLUDE/RCS/conf-pc.h 1.2 1994/08/16 18:43:42 pbh Exp $
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * Machine-type definitions: IBM PC 8086
+ */
+
+#include <mit_copy.h>
+
+#ifndef IBMPC
+        #define IBMPC
+#endif
+
+#if defined(__WINDOWS__) && !defined(WINDOWS)
+#define WINDOWS
+#endif
+
+#if defined(__OS2__) && !defined(OS2)
+#define OS2
+#endif
+
+#ifndef OS2
+#define BITS16
+#define CROSSMSDOS
+/* OS/2 is 32 bit!!!! */
+#else
+#define BITS32
+#endif
+#define LSBFIRST
+
+#define index(s,c) strchr(s,c)          /* PC version of index */
+#define rindex(s,c) strrchr(s,c)
+
+typedef unsigned char u_char;
+typedef unsigned long u_long;
+typedef unsigned short u_short;
+typedef short uid_t;
+
+#if !defined(WINDOWS) && !defined(DWORD)
+typedef long DWORD;
+#endif
+
+#ifdef OS2
+typedef char *LPSTR;
+typedef char *LPBYTE;
+typedef char *CHARPTR;
+typedef char *LPINT;
+typedef unsigned int WORD;
+
+#define far
+#define near
+#define FAR
+#define PASCAL
+#include <utils.h>
+#define lstrcpy strcpy
+#define lstrlen strlen
+#define lstrcmp strcmp
+#define lstrcpyn strncpy
+#endif
+
+#if defined(OS2) || defined(WINDOWS)
+#define creat _creat
+#define read _read
+#define write _write
+#define open _open
+#define close _close
+#define stat(x,y) _stat(x,y)
+#define putch _putch
+#define getch _getch
+#endif
+
+#ifdef WINDOWS
+#include <windows.h>
+#endif
diff --git a/libraries/msdos/winsock/include/krb/mit/conf.h b/libraries/msdos/winsock/include/krb/mit/conf.h
new file mode 100644 (file)
index 0000000..17c5345
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * $Source: F:/DOSDEV/NEWKRB/INCLUDE/RCS/conf.h $
+ * $Author: pbh $
+ * $Header: F:/DOSDEV/NEWKRB/INCLUDE/RCS/conf.h 1.2 1994/08/16 18:43:42 pbh Exp $
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * Configuration info for operating system, hardware description,
+ * language implementation, C library, etc.
+ *
+ * This file should be included in (almost) every file in the Kerberos
+ * sources, and probably should *not* be needed outside of those
+ * sources.  (How do we deal with /usr/include/des.h and
+ * /usr/include/krb.h?)
+ */
+
+#ifndef _CONF_H_
+#define _CONF_H_
+
+#include <mit_copy.h>
+
+#include "osconf.h"
+
+#ifdef SHORTNAMES
+#include "names.h"
+#endif
+
+/*
+ * Language implementation-specific definitions
+ */
+
+/* special cases */
+#ifdef __HIGHC__
+/* broken implementation of ANSI C */
+#undef __STDC__
+#endif
+
+#if !defined(__STDC__) && !defined(__BORLANDC__)
+#define const
+#define volatile
+#define signed
+typedef char *pointer;          /* pointer to generic data */
+#define PROTOTYPE(p) ()
+#else
+typedef void *pointer;
+#define PROTOTYPE(p) p
+#endif
+
+/* Does your compiler understand "void"? */
+#ifdef notdef
+#define void int
+#endif
+
+/*
+ * A few checks to see that necessary definitions are included.
+ */
+
+/* byte order */
+/* #define LSBFIRST */
+/* #define BITS16 */
+/* #define CROSSMSDOS */
+
+#ifndef MSBFIRST
+#ifndef LSBFIRST
+#error byte order not defined
+#endif
+#endif
+
+/* machine size */
+#ifndef BITS16
+#ifndef BITS32
+#error number of bits?
+#endif
+#endif
+
+/* end of checks */
+
+#endif /* _CONF_H_ */
diff --git a/libraries/msdos/winsock/include/krb/mit/hesiod.h b/libraries/msdos/winsock/include/krb/mit/hesiod.h
new file mode 100644 (file)
index 0000000..c357444
--- /dev/null
@@ -0,0 +1,113 @@
+/* This file contains definitions for use by the Hesiod name service and
+ * applications.
+ *
+ * For copying and distribution information, see the file <mit-copyright.h>.
+ *
+ * Original version by Steve Dyer, IBM/Project Athena.
+ *
+ *      $Author: probe $
+ *      $Athena: hesiod.h,v 1.3 88/08/07 21:52:39 treese Locked $
+ *      $Header: /afs/rel-eng.athena.mit.edu/project/release/current/source/athena/athena.lib/hesiod/RCS/hesiod.h,v 1.6 90/07/20 13:09:16 probe Exp $
+ *      $Source: /afs/rel-eng.athena.mit.edu/project/release/current/source/athena/athena.lib/hesiod/RCS/hesiod.h,v $
+ *      $Log:   hesiod.h,v $
+ * Revision 1.6  90/07/20  13:09:16  probe
+ * Incorrect declaration of hes_getpwnam()
+ * 
+ * Revision 1.5  90/07/11  16:49:12  probe
+ * Patches from <mar>
+ * Added missing declarations
+ * 
+ * Revision 1.5  90/07/09  18:44:30  mar
+ * mention hes_getservbyname(), hes_getpwent()
+ * 
+ * Revision 1.4  88/08/07  23:18:00  treese
+ * Second-public-distribution
+ * 
+ * Revision 1.3  88/08/07  21:52:39  treese
+ * First public distribution
+ * 
+ * Revision 1.2  88/06/05  19:51:32  treese
+ * Cleaned up for public distribution
+ * 
+ */
+
+/* Configuration information. */
+
+#ifndef _HESIOD_
+#define _HESIOD_
+
+#ifdef WINDOWS
+#include <windows.h>
+#endif
+
+#if !defined(WINDOWS) && !defined(_WINDOWS)
+#define HESIOD_CONF     "/etc/hesiod.conf"      /* Configuration file. */
+#else
+#define HESIOD_CONF     "c:\\net\\tcp\\hesiod.cfg"
+#endif
+
+#define DEF_RHS         ".Athena.MIT.EDU"       /* Defaults if HESIOD_CONF */
+#define DEF_LHS         ".ns"                   /*    file is not present. */
+
+/* Error codes. */
+
+#define HES_ER_UNINIT   -1      /* uninitialized */
+#define HES_ER_OK       0       /* no error */
+#define HES_ER_NOTFOUND 1       /* Hesiod name not found by server */
+#define HES_ER_CONFIG   2       /* local problem (no config file?) */
+#define HES_ER_NET      3       /* network problem */
+
+/* Declaration of routines */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(WINDOWS) && !defined(_WINDOWS)
+char *hes_to_bind();
+char **hes_resolve();
+int hes_error();
+#else 
+#ifndef _WSHELPER_
+LPSTR FAR PASCAL hes_to_bind(LPSTR HesiodName, LPSTR HesiodNameType);
+LPSTR * FAR PASCAL hes_resolve(LPSTR HesiodName, LPSTR HesiodNameType);
+int FAR PASCAL hes_error(void);
+#endif
+#endif
+
+
+/* For use in getting post-office information. */
+
+#if !defined(WINDOWS) && !defined(_WINDOWS)
+struct hes_postoffice {
+       char    *po_type;
+       char    *po_host;
+       char    *po_name;
+};
+#else
+struct hes_postoffice {
+       LPSTR   po_type;
+       LPSTR   po_host;
+       LPSTR   po_name;
+};
+#endif
+
+/* Other routines */
+
+#if !defined(WINDOWS) && !defined(_WINDOWS)
+struct hes_postoffice *hes_getmailhost();
+struct servent *hes_getservbyname();
+struct passwd *hes_getpwnam();
+struct passwd *hes_getpwuid();
+#else
+struct hes_postoffice FAR * WINAPI hes_getmailhost(LPSTR user);
+struct servent FAR * WINAPI hes_getservbyname(LPSTR name, LPSTR proto);
+struct passwd FAR * WINAPI hes_getpwnam(LPSTR nam);
+struct passwd FAR * WINAPI hes_getpwuid(int uid);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _HESIOD_ */
diff --git a/libraries/msdos/winsock/include/krb/mit/lsh_pwd.h b/libraries/msdos/winsock/include/krb/mit/lsh_pwd.h
new file mode 100644 (file)
index 0000000..c51a296
--- /dev/null
@@ -0,0 +1,56 @@
+/* LSH_PWD.H this is the include file for the LSH_PWD.C  */
+
+/* Included from krb.h - CRS 940805 */
+
+#ifndef __LSH_PWD__
+#define __LSH_PWD__
+
+// Definition of the info structure that is passed to tell the dialog box what state it
+//  should be in.
+
+#include <stdio.h>
+
+typedef struct {
+  int dlgtype;
+#define DLGTYPE_PASSWD   0
+#define DLGTYPE_CHPASSWD 1
+  int dlgstatemax;             // I am not sure what this is yet.  STUFF TO DO!
+  LPSTR title;                 // The title on the Dialog box - for Renewing or Initializing.
+  LPSTR principal;
+} LSH_DLGINFO, FAR *LPLSH_DLGINFO;
+
+
+// Some defines swiped from leash.h
+//  These are necessary but they must be kept sync'ed with leash.h
+#define HELPFILE "kerberos.hlp"
+#define PASSWORDCHAR '#'
+
+#define DLGHT(ht) (HIWORD(GetDialogBaseUnits())*(ht)/8)
+#define DLGWD(wd) (LOWORD(GetDialogBaseUnits())*(wd)/4)
+
+// external variables
+#ifdef PDLL
+long lsh_errno;
+char *err_context;       /* error context */
+char FAR *kadm_info; /* to get info from the kadm* files */
+long dlgu;                              /* dialog units  */
+#ifdef WINSOCK
+HINSTANCE hinstWinSock = NULL;
+#endif // WINSOCK
+#endif // PDLL
+
+// local macros  stolen from leash.h
+#ifndef MAKEWORD
+#define MAKEWORD(low, high) ((WORD)(((BYTE)(low)) | (((UINT)((BYTE)(high))) << 8)))
+#endif /*MAKEWORD*/
+
+
+// Function Prototypes.
+int FAR PASCAL _export Lsh_Enter_Password_Dialog(HWND hParent, LPLSH_DLGINFO lpdlginfo);
+int FAR PASCAL _export Lsh_Change_Password_Dialog(HWND hParent, LPLSH_DLGINFO lpdlginfo);
+int lsh_com_err_proc (LPSTR whoami, long code, LPSTR fmt, va_list args);
+int _export DoNiftyErrorReport(long errnum, LPSTR what);
+LONG FAR PASCAL _export MITPwdWinProcDLL(HWND hWnd, WORD message, WORD wParam, LONG lParam);
+BOOL FAR PASCAL _export PasswordProcDLL(HWND hDialog, WORD message, WORD wParam, LONG lParam);
+LONG FAR PASCAL _export lsh_get_lsh_errno( LONG FAR *err_val);
+#endif __LSH_PWD__
diff --git a/libraries/msdos/winsock/include/krb/mit/mit_copy.h b/libraries/msdos/winsock/include/krb/mit/mit_copy.h
new file mode 100644 (file)
index 0000000..b47de92
--- /dev/null
@@ -0,0 +1,22 @@
+/* 
+  Copyright (C) 1989 by the Massachusetts Institute of Technology
+
+   Export of this software from the United States of America is assumed
+   to require a specific license from the United States Government.
+   It is the responsibility of any person or organization contemplating
+   export to obtain such a license before exporting.
+
+WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+distribute this software and its documentation for any purpose and
+without fee is hereby granted, provided that the above copyright
+notice appear in all copies and that both that copyright notice and
+this permission notice appear in supporting documentation, and that
+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.
+
+  */
+
+
diff --git a/libraries/msdos/winsock/include/krb/mit/osconf.h b/libraries/msdos/winsock/include/krb/mit/osconf.h
new file mode 100644 (file)
index 0000000..644b0e3
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * $Source: F:/DOSDEV/NEWKRB/INCLUDE/RCS/osconf.h $
+ * $Author: pbh $
+ * $Header: F:/DOSDEV/NEWKRB/INCLUDE/RCS/osconf.h 1.2 1994/08/16 18:43:42 pbh Exp $
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * Athena configuration.
+ */
+
+#include <mit_copy.h>
+
+#ifndef _OSCONF_H_
+#define _OSCONF_H_
+
+#if defined(IBMPC) && !defined(PC)
+#define PC
+#endif
+
+#ifdef tahoe
+#include "conf-bsdtahoe.h"
+#else /* !tahoe */
+#ifdef vax
+#include "conf-bsdvax.h"
+#else /* !vax */
+#if defined(mips) && defined(ultrix)
+#include "conf-ultmips2.h"
+#else /* !Ultrix MIPS-2 */
+#ifdef ibm032
+#include "conf-bsdibm032.h"
+#else /* !ibm032 */
+#ifdef apollo
+#include "conf-bsdapollo.h"
+#else /* !apollo */
+#ifdef sun
+#ifdef sparc
+#include "conf-bsdsparc.h"
+#else /* sun but not sparc */
+#ifdef i386
+#include "conf-bsd386i.h"
+#else /* sun but not (sparc or 386i) */
+#include "conf-bsdm68k.h"
+#endif /* i386 */
+#endif /* sparc */
+#else /* !sun */
+#ifdef pyr
+#include "conf-pyr.h"
+#else
+#if defined(PC) || defined(__MSDOS__) || defined(OS2)
+#include "conf-pc.h"
+#endif /* PC */
+#endif /* pyr */
+#endif /* sun */
+#endif /* apollo */
+#endif /* ibm032 */
+#endif /* mips */
+#endif /* vax */
+#endif /* tahoe */
+
+#endif /* _OSCONF_H_ */
diff --git a/libraries/msdos/winsock/include/krb/mit/resolv.h b/libraries/msdos/winsock/include/krb/mit/resolv.h
new file mode 100644 (file)
index 0000000..ebe0a28
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+       WSHelper DNS/Hesiod Library for WINSOCK
+       resolv.h
+*/
+
+/*
+ * Copyright (c) 1983, 1987, 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by the University of
+ *      California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *      @(#)resolv.h    5.15 (Berkeley) 4/3/91
+ */
+
+#ifndef _RESOLV_H_
+#define _RESOLV_H_
+
+/*
+ * Resolver configuration file.
+ * Normally not present, but may contain the address of the
+ * inital name server(s) to query and the domain search list.
+ */
+
+#ifndef _PATH_RESCONF
+#if !defined(WINDOWS) && !defined(_WINDOWS)
+#define _PATH_RESCONF        "/etc/resolv.conf"
+#else
+#define _PATH_RESCONF            "c:\\net\\tcp\\resolv.cfg"
+#endif
+#endif
+
+#ifndef MAXDNAME
+#include <arpa/nameser.h>
+#endif
+
+/*
+ * Global defines and variables for resolver stub.
+ */
+#define MAXNS                   3       /* max # name servers we'll track */
+#define MAXDFLSRCH              3       /* # default domain levels to try */
+#define MAXDNSRCH               6       /* max # domains in search path */
+#define LOCALDOMAINPARTS        2       /* min levels in name that is "local" */
+
+#define RES_TIMEOUT             5       /* min. seconds between retries */
+
+// new
+#define MAXMXRECS                              8
+
+struct mxent {
+       int numrecs;
+       u_short pref[MAXMXRECS];
+       char FAR * FAR * hostname;
+};
+
+struct state {
+       int     retrans;                /* retransmition time interval */
+       int     retry;                  /* number of times to retransmit */
+       long    options;                /* option flags - see below. */
+       int     nscount;                /* number of name servers */
+       struct  sockaddr_in nsaddr_list[MAXNS]; /* address of name server */
+#define nsaddr  nsaddr_list[0]          /* for backward compatibility */
+       u_short id;                     /* current packet id */
+       char    defdname[MAXDNAME];     /* default domain */
+       char    *dnsrch[MAXDNSRCH+1];   /* components of domain to search */
+};
+
+/*
+ * Resolver options
+ */
+#define RES_INIT        0x0001          /* address initialized */
+#define RES_DEBUG       0x0002          /* print debug messages */
+#define RES_AAONLY      0x0004          /* authoritative answers only */
+#define RES_USEVC       0x0008          /* use virtual circuit */
+#define RES_PRIMARY     0x0010          /* query primary server only */
+#define RES_IGNTC       0x0020          /* ignore trucation errors */
+#define RES_RECURSE     0x0040          /* recursion desired */
+#define RES_DEFNAMES    0x0080          /* use default domain name */
+#define RES_STAYOPEN    0x0100          /* Keep TCP socket open */
+#define RES_DNSRCH      0x0200          /* search up local domain tree */
+
+#define RES_DEFAULT     (RES_RECURSE | RES_DEFNAMES | RES_DNSRCH)
+
+extern struct state _res;
+
+#include <stdio.h>
+
+/* Private routines shared between libc/net, named, nslookup and others. */
+#define dn_skipname     __dn_skipname
+#define fp_query        __fp_query
+#define hostalias       __hostalias
+#define putlong         __putlong
+#define putshort        __putshort
+#define p_class         __p_class
+#define p_time          __p_time
+#define p_type          __p_type
+
+#if !defined(WINDOWS) && !defined(_WINDOWS)
+__BEGIN_DECLS
+int      __dn_skipname __P((const u_char *, const u_char *));
+void     __fp_query __P((char *, FILE *));
+char    *__hostalias __P((const char *));
+void     __putlong __P((u_long, u_char *));
+void     __putshort __P((u_short, u_char *));
+char    *__p_class __P((int));
+char    *__p_time __P((u_long));
+char    *__p_type __P((int));
+
+int      dn_comp __P((const u_char *, u_char *, int, u_char **, u_char **));
+int      dn_expand __P((const u_char *, const u_char *, const u_char *,
+               u_char *, int));
+int      res_init __P((void));
+int      res_mkquery __P((int, const char *, int, int, const char *, int,
+               const struct rrec *, char *, int));
+int      res_send __P((const char *, int, char *, int));
+__END_DECLS
+#endif
+
+#endif /* !_RESOLV_H_ */
diff --git a/libraries/msdos/winsock/include/krb/mit/wshelper.h b/libraries/msdos/winsock/include/krb/mit/wshelper.h
new file mode 100644 (file)
index 0000000..971c85a
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+       WSHelper DNS/Hesiod Library for WINSOCK
+       wshelper.h
+*/
+
+#ifndef _WSHELPER_
+#define _WSHELPER_
+
+#include <winsock.h>
+#include <resolv.h>
+#include <hesiod.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int FAR PASCAL res_mkquery(int op, char FAR *dname, int qclass, int type,
+                          char FAR *data, int datalen, struct rrec FAR *newrr,
+                          char FAR *buf, int buflen);
+
+int FAR PASCAL res_send(char FAR *msg, int msglen, char FAR *answer, int anslen);
+
+int FAR PASCAL res_init();
+
+int FAR PASCAL dn_comp(char FAR *exp_dn, char FAR *comp_dn, int length,
+                      char FAR * FAR *dnptrs, char FAR * FAR *lastdnptr);
+
+int FAR PASCAL dn_expand(char FAR *msg, char FAR *eomorig, char FAR *comp_dn,
+                        char FAR *exp_dn, int length);
+
+struct hostent FAR* FAR PASCAL rgethostbyname(char FAR *name);
+
+struct hostent FAR* FAR PASCAL rgethostbyaddr(char FAR *addr, int len, int type);
+
+LPSTR FAR PASCAL hes_to_bind(char FAR *HesiodName, char FAR *HesiodNameType);
+     
+LPSTR * FAR PASCAL hes_resolve(char FAR *HesiodName, char FAR *HesiodNameType);
+
+int FAR PASCAL hes_error(void);
+
+void FAR PASCAL res_setopts(long opts);
+
+long FAR PASCAL res_getopts(void);
+
+unsigned long FAR PASCAL inet_aton(register const char *cp, struct in_addr *addr);
+
+LPSTR FAR PASCAL gethinfobyname(LPSTR name);
+
+LPSTR FAR PASCAL getmxbyname(LPSTR name);
+
+LPSTR FAR PASCAL getrecordbyname(LPSTR name, int rectype);
+
+DWORD FAR PASCAL rrhost( LPSTR lpHost );
+
+struct servent FAR * FAR PASCAL rgetservbyname(LPSTR name, LPSTR proto);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* _WSHELPER_ */
+
diff --git a/libraries/msdos/winsock/include/net/_sys/filio.h b/libraries/msdos/winsock/include/net/_sys/filio.h
new file mode 100644 (file)
index 0000000..f352fdd
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef _SOCKET
+#include <sys\socket.h>
+#endif
+
diff --git a/libraries/msdos/winsock/include/net/_sys/ioctl.h b/libraries/msdos/winsock/include/net/_sys/ioctl.h
new file mode 100644 (file)
index 0000000..f352fdd
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef _SOCKET
+#include <sys\socket.h>
+#endif
+
diff --git a/libraries/msdos/winsock/include/net/netdb.h b/libraries/msdos/winsock/include/net/netdb.h
new file mode 100644 (file)
index 0000000..f352fdd
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef _SOCKET
+#include <sys\socket.h>
+#endif
+
diff --git a/libraries/msdos/winsock/include/param.h b/libraries/msdos/winsock/include/param.h
new file mode 100644 (file)
index 0000000..cead080
--- /dev/null
@@ -0,0 +1,4 @@
+/*
+ * This file is intentionally empty.  Some compilers require the presence of
+ * an include file, even if the "#ifdef"s exclude it from actual use. PTUI !
+ */
diff --git a/libraries/msdos/winsock/include/select.h b/libraries/msdos/winsock/include/select.h
new file mode 100644 (file)
index 0000000..cead080
--- /dev/null
@@ -0,0 +1,4 @@
+/*
+ * This file is intentionally empty.  Some compilers require the presence of
+ * an include file, even if the "#ifdef"s exclude it from actual use. PTUI !
+ */
diff --git a/libraries/msdos/winsock/include/socket.h b/libraries/msdos/winsock/include/socket.h
new file mode 100644 (file)
index 0000000..cead080
--- /dev/null
@@ -0,0 +1,4 @@
+/*
+ * This file is intentionally empty.  Some compilers require the presence of
+ * an include file, even if the "#ifdef"s exclude it from actual use. PTUI !
+ */
diff --git a/libraries/msdos/winsock/include/time.h b/libraries/msdos/winsock/include/time.h
new file mode 100644 (file)
index 0000000..cead080
--- /dev/null
@@ -0,0 +1,4 @@
+/*
+ * This file is intentionally empty.  Some compilers require the presence of
+ * an include file, even if the "#ifdef"s exclude it from actual use. PTUI !
+ */
diff --git a/libraries/msdos/winsock/include/wsa.h b/libraries/msdos/winsock/include/wsa.h
new file mode 100644 (file)
index 0000000..808697c
--- /dev/null
@@ -0,0 +1,132 @@
+/* wsa.h */
+/*
+ * Copyright (c) 1993 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#ifndef _MSDOS_H
+#define _MSDOS_H
+
+/*
+ * NOTE: This file should be included via ldap.h.  Many symbols are
+ * defined here that are needed BEFORE anything else is included.
+ * Be careful !!!
+ */
+/*
+ * The following are defined within the Integrated Development Environment
+ * of Microsoft's Visual C++ Compiler (v1.52c)
+ * (Options/Project/Compiler/Preprocessor/Symbols and Macros to Define)
+ * But there's a (buffer length) limit to how long this list can be, so 
+ * I'm doing the rest here in msdos.h
+ * WINSOCK, DOS, NEEDPROTOS, NO_USERINTERFACE
+ */
+/*
+ * MIT's krb.h doesn't use the symbols provided by Microsoft.
+ * It needs __MSDOS__ and WINDOWS.  Normally _WINDOWS is provided by MS
+ * but it's based on having the prolog/epilog optimization switches set
+ * in a way that we don't set them. So define it manually.
+ *
+ * kbind.c needs __MSDOS__ for krb.h to include osconf.h 
+ * which includes conf-pc.h which defines byte order and such
+ */
+#define __MSDOS__
+/*
+ * conf-pc.h wants WINDOWS rather than _WINDOWS which Microsoft provides
+ */
+#define WINDOWS
+
+/*
+ * Where two of the config files live in the windows environment
+ * There are two others also; ldfriend.cfg, & srchpref.cfg
+ * These names are different that the unix names due to 8.3 rule
+ */
+#define FILTERFILE     "ldfilter.cfg"
+#define TEMPLATEFILE   "disptmpl.cfg"
+/*
+ * These are not automatically defined for us even though we're a DLL.  They
+ * are triggered by prolog/epilog configuration options that we don't use.
+ * But be careful not to redefine them for other apps that include this file.
+ */
+#ifndef _WINDLL
+/*
+ * Needed by wshelper.h
+ */
+#define _WINDLL
+#endif
+
+#ifndef _WINDOWS
+/*
+ * Needed by authlib.h via kerberos.c via AUTHMAN
+ */
+#define _WINDOWS 1
+#endif
+  
+/*
+ * KERBEROS must be defined as a preprocessor symbol in the compiler.
+ * It's too late to define it in this file.
+ */
+
+/*
+ * AUTHMAN - Use Authlib.dll as a higher level interface to krbv4win.dll 
+ * (kerberos).  If defined, get_kerberosv4_credentials in kerberos.c is
+ * used and authlib.dll (and krbv4win.dll) are dynamically loaded and used.  
+ * If AUTHMAN is not defined, the get_kerberosv4_credentials in 
+ * kbind.c works just fine, but requires the presence of krbv4win.dll at
+ * load time.
+ */
+/* don't want to be dependent on authman
+ * #define AUTHMAN
+ */
+
+/*
+ * define WSHELPER if you want wsockip.c to use rgethostbyaddr() (in
+ * WSHELPER.DLL) rather than gethostbyaddr().  You might want this if your
+ * gethostbyaddr() returns the WRONG host name and you want to use
+ * kerberos authentication (need host name to form service ticket
+ * request).  Most won't want kerberos, and of those, there might actually
+ * be some vendors who really do the lookup rather than use cached info
+ * from gethostbyname() calls.
+ */
+#define WSHELPER
+/*
+ * The new slapd stuff
+ */
+#define LDAP_REFERRALS
+/*
+ * LDAP character string translation routines
+ * I compiled and tested these and they seemed to work.
+ * The thing to test with is: 
+ *   cn=Charset Test Entry, ou=SWITCHdirectory, o=SWITCH, c=CH
+ *
+ * I'm disabling it for release.
+#define STR_TRANSLATION
+#define LDAP_CHARSET_8859 88591
+#define LDAP_DEFAULT_CHARSET LDAP_CHARSET_8859
+ */
+
+
+
+#define LDAP_DEBUG
+#include <winsock.h>
+
+
+#include <string.h>
+#include <malloc.h>
+#ifndef _WIN32
+#define memcpy( a, b, n )      _fmemcpy( a, b, n )
+#define strcpy( a, b )         _fstrcpy( a, b )
+#define strchr( a, c )         _fstrchr( a, c )
+#endif /* !_WIN32 */
+#define strcasecmp(a,b)        stricmp(a,b)
+#define strncasecmp(a,b,len)   strnicmp(a,b,len)
+
+#endif /* _MSDOS_H */
+
+
diff --git a/libraries/msdos/winsock/include/wsa/errno.c b/libraries/msdos/winsock/include/wsa/errno.c
new file mode 100644 (file)
index 0000000..cb49c5f
--- /dev/null
@@ -0,0 +1,21 @@
+#include <winsock.h>
+
+/* Copies string corresponding to the error code provided    */
+/* into buf, maximum length len. Returns length actually     */
+/* copied to buffer, or zero if error code is unknown.       */
+/* String resources should be present for each error code    */
+/* using the value of the code as the string ID (except for  */
+/* error = 0, which is mapped to WSABASEERR to keep it with  */
+/* the others). The DLL is free to use any string IDs that   */
+/* are less than WSABASEERR for its own use. The LibMain     */
+/* procedure of the DLL is presumed to have saved its        */
+/* HINSTANCE in the global variable hInst.                   */
+
+int PASCAL FAR WSAsperror (int errorcode, char far * buf, int len)
+{
+        if (errorcode == 0)
+                errorcode = WSABASEERR;
+        if (errorcode < WSABASEERR)
+                return 0;
+        return LoadString(hInst,errorcode,buf,len);
+}
diff --git a/libraries/msdos/winsock/include/wsa/errno.rc b/libraries/msdos/winsock/include/wsa/errno.rc
new file mode 100644 (file)
index 0000000..1252957
--- /dev/null
@@ -0,0 +1,57 @@
+#include <winsock.h>
+
+STRINGTABLE
+BEGIN
+  WSABASEERR,         "[0] No Error"
+  WSAEINTR,           "[10004] Interrupted system call"
+  WSAEBADF,           "[10009] Bad file number"
+  WSAEACCES,          "[10013] Permission denied"
+  WSAEFAULT,          "[10014] Bad address"
+  WSAEINVAL,          "[10022] Invalid argument"
+  WSAEMFILE,          "[10024] Too many open files"
+  WSAEWOULDBLOCK,     "[10035] Operation would block"
+  WSAEINPROGRESS,     "[10036] Operation now in progress"
+  WSAEALREADY,        "[10037] Operation already in progress"
+  WSAENOTSOCK,        "[10038] Socket operation on non-socket"
+  WSAEDESTADDRREQ,    "[10039] Destination address required"
+  WSAEMSGSIZE,        "[10040] Message too long"
+  WSAEPROTOTYPE,      "[10041] Protocol wrong type for socket"
+  WSAENOPROTOOPT,     "[10042] Bad protocol option"
+  WSAEPROTONOSUPPORT, "[10043] Protocol not supported"
+  WSAESOCKTNOSUPPORT, "[10044] Socket type not supported"
+  WSAEOPNOTSUPP,      "[10045] Operation not supported on socket"
+  WSAEPFNOSUPPORT,    "[10046] Protocol family not supported"
+  WSAEAFNOSUPPORT,    "[10047] Address family not supported by protocol family"
+  WSAEADDRINUSE,      "[10048] Address already in use"
+  WSAEADDRNOTAVAIL,   "[10049] Can't assign requested address"
+  WSAENETDOWN,        "[10050] Network is down"
+  WSAENETUNREACH,     "[10051] Network is unreachable"
+  WSAENETRESET,       "[10052] Net dropped connection or reset"
+  WSAECONNABORTED,    "[10053] Software caused connection abort"
+  WSAECONNRESET,      "[10054] Connection reset by peer"
+  WSAENOBUFS,         "[10055] No buffer space available"
+  WSAEISCONN,         "[10056] Socket is already connected"
+  WSAENOTCONN,        "[10057] Socket is not connected"
+  WSAESHUTDOWN,       "[10058] Can't send after socket shutdown"
+  WSAETOOMANYREFS,    "[10059] Too many references, can't splice"
+  WSAETIMEDOUT,       "[10060] Connection timed out"
+  WSAECONNREFUSED,    "[10061] Connection refused"
+  WSAELOOP,           "[10062] Too many levels of symbolic links"
+  WSAENAMETOOLONG,    "[10063] File name too long"
+  WSAEHOSTDOWN,       "[10064] Host is down"
+  WSAEHOSTUNREACH,    "[10065] No Route to Host"
+  WSAENOTEMPTY,       "[10066] Directory not empty"
+  WSAEPROCLIM,        "[10067] Too many processes"
+  WSAEUSERS,          "[10068] Too many users"
+  WSAEDQUOT,          "[10069] Disc Quota Exceeded"
+  WSAESTALE,          "[10070] Stale NFS file handle"
+  WSAEREMOTE,         "[10071] Too many levels of remote in path"
+  WSASYSNOTREADY,     "[10091] Network SubSystem is unavailable"
+  WSAVERNOTSUPPORTED, "[10092] WINSOCK DLL Version out of range"
+  WSANOTINITIALIZED,  "[10093] Successful WSASTARTUP not yet performed"
+  WSAHOST_NOT_FOUND,  "[11001] Host not found"
+  WSATRY_AGAIN,       "[11002] Non-Authoritative Host not found"
+  WSANO_RECOVERY,     "[11003] Non-Recoverable errors: FORMERR, REFUSED, NOTIMP"
+  WSANO_DATA,         "[11004] Valid name, no data record of requested 
+type"
+END
diff --git a/libraries/msdos/winsock/include/wsa/winsock.def b/libraries/msdos/winsock/include/wsa/winsock.def
new file mode 100644 (file)
index 0000000..0aa0953
--- /dev/null
@@ -0,0 +1,84 @@
+;  
+;         File: winsock.def 
+;       System: MS-Windows 3.x 
+;      Summary: Module definition file for Windows Sockets DLL.  
+;  
+
+LIBRARY         WINSOCK         ; Application's module name 
+
+DESCRIPTION     'BSD Socket API for Windows' 
+
+EXETYPE         WINDOWS         ; required for all windows applications 
+
+STUB            'WINSTUB.EXE'   ; generates error message if application 
+                                ; is run without Windows 
+
+;CODE can be FIXED in memory because of potential upcalls 
+CODE            PRELOAD         FIXED 
+
+;DATA must be SINGLE and at a FIXED location since this is a DLL 
+DATA            PRELOAD         FIXED           SINGLE
+
+HEAPSIZE        1024 
+STACKSIZE       16384 
+
+; All functions that will be called by any Windows routine 
+; must be exported.  Any additional exports beyond those defined
+; here must have ordinal numbers 1000 or above. 
+
+EXPORTS 
+        accept                         @1 
+        bind                           @2 
+        closesocket                    @3 
+        connect                        @4 
+        getpeername                    @5 
+        getsockname                    @6 
+        getsockopt                     @7 
+        htonl                          @8 
+        htons                          @9 
+        inet_addr                      @10 
+        inet_ntoa                      @11 
+        ioctlsocket                    @12 
+        listen                         @13 
+        ntohl                          @14 
+        ntohs                          @15 
+        recv                           @16 
+        recvfrom                       @17 
+        select                         @18 
+        send                           @19 
+        sendto                         @20 
+        setsockopt                     @21 
+        shutdown                       @22 
+        socket                         @23 
+
+        gethostbyaddr                  @51 
+        gethostbyname                  @52 
+        getprotobyname                 @53 
+        getprotobynumber               @54 
+        getservbyname                  @55 
+        getservbyport                  @56 
+        gethostname                    @57
+
+        WSAAsyncSelect                 @101 
+        WSAAsyncGetHostByAddr          @102 
+        WSAAsyncGetHostByName          @103 
+        WSAAsyncGetProtoByNumber       @104 
+        WSAAsyncGetProtoByName         @105 
+        WSAAsyncGetServByPort          @106 
+        WSAAsyncGetServByName          @107 
+        WSACancelAsyncRequest          @108 
+        WSASetBlockingHook             @109 
+        WSAUnhookBlockingHook          @110 
+        WSAGetLastError                @111 
+        WSASetLastError                @112 
+        WSACancelBlockingCall          @113 
+        WSAIsBlocking                  @114 
+        WSAStartup                     @115 
+        WSACleanup                     @116 
+
+        __WSAFDIsSet                   @151 
+
+        WEP                            @500    RESIDENTNAME 
+
+;eof 
+
diff --git a/libraries/msdos/winsock/include/wsa/winsock.h b/libraries/msdos/winsock/include/wsa/winsock.h
new file mode 100644 (file)
index 0000000..c73fe4c
--- /dev/null
@@ -0,0 +1,906 @@
+/* WINSOCK.H--definitions to be used with the WINSOCK.DLL
+ *
+ * This header file corresponds to version 1.1 of the Windows Sockets specification.
+ *
+ * This file includes parts which are Copyright (c) 1982-1986 Regents
+ * of the University of California.  All rights reserved.  The
+ * Berkeley Software License Agreement specifies the terms and
+ * conditions for redistribution.
+ *
+ * Change log:
+ *
+ * Fri Apr 23 16:31:01 1993  Mark Towfiq  (towfiq@Microdyne.COM)
+ *     New version from David Treadwell which adds extern "C" around
+ *     __WSAFDIsSet() and removes "const" from buf param of
+ *     WSAAsyncGetHostByAddr().  Added change log.
+ *
+ * Sat May 15 10:55:00 1993 David Treadwell (davidtr@microsoft.com)
+ *  Fix the IN_CLASSC macro to account for class-D multicasts.
+ *  Add AF_IPX == AF_NS.
+ *
+ */
+
+#ifndef _WINSOCKAPI_
+#define _WINSOCKAPI_
+
+/*
+ * Pull in WINDOWS.H if necessary
+ */
+#ifndef _INC_WINDOWS
+#include <windows.h>
+#endif /* _INC_WINDOWS */
+
+/*
+ * Basic system type definitions, taken from the BSD file sys/types.h.
+ */
+typedef unsigned char   u_char;
+typedef unsigned short  u_short;
+typedef unsigned int    u_int;
+typedef unsigned long   u_long;
+
+/*
+ * The new type to be used in all
+ * instances which refer to sockets.
+ */
+typedef u_int           SOCKET;
+
+/*
+ * Select uses arrays of SOCKETs.  These macros manipulate such
+ * arrays.  FD_SETSIZE may be defined by the user before including
+ * this file, but the default here should be >= 64.
+ *
+ * CAVEAT IMPLEMENTOR and USER: THESE MACROS AND TYPES MUST BE
+ * INCLUDED IN WINSOCK.H EXACTLY AS SHOWN HERE.
+ */
+#ifndef FD_SETSIZE
+#define FD_SETSIZE      64
+#endif /* FD_SETSIZE */
+
+typedef struct fd_set {
+        u_int   fd_count;               /* how many are SET? */
+        SOCKET  fd_array[FD_SETSIZE];   /* an array of SOCKETs */
+} fd_set;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int PASCAL FAR __WSAFDIsSet(SOCKET, fd_set FAR *);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#define FD_CLR(fd, set) do { \
+    u_int __i; \
+    for (__i = 0; __i < ((fd_set FAR *)(set))->fd_count ; __i++) { \
+        if (((fd_set FAR *)(set))->fd_array[__i] == fd) { \
+            while (__i < ((fd_set FAR *)(set))->fd_count-1) { \
+                ((fd_set FAR *)(set))->fd_array[__i] = \
+                    ((fd_set FAR *)(set))->fd_array[__i+1]; \
+                __i++; \
+            } \
+            ((fd_set FAR *)(set))->fd_count--; \
+            break; \
+        } \
+    } \
+} while(0)
+
+#define FD_SET(fd, set) do { \
+    if (((fd_set FAR *)(set))->fd_count < FD_SETSIZE) \
+        ((fd_set FAR *)(set))->fd_array[((fd_set FAR *)(set))->fd_count++]=(fd);\
+} while(0)
+
+#define FD_ZERO(set) (((fd_set FAR *)(set))->fd_count=0)
+
+#define FD_ISSET(fd, set) __WSAFDIsSet((SOCKET)(fd), (fd_set FAR *)(set))
+
+/*
+ * Structure used in select() call, taken from the BSD file sys/time.h.
+ */
+struct timeval {
+        long    tv_sec;         /* seconds */
+        long    tv_usec;        /* and microseconds */
+};
+
+/*
+ * Operations on timevals.
+ *
+ * NB: timercmp does not work for >= or <=.
+ */
+#define timerisset(tvp)         ((tvp)->tv_sec || (tvp)->tv_usec)
+#define timercmp(tvp, uvp, cmp) \
+        ((tvp)->tv_sec cmp (uvp)->tv_sec || \
+         (tvp)->tv_sec == (uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec)
+#define timerclear(tvp)         (tvp)->tv_sec = (tvp)->tv_usec = 0
+
+/*
+ * Commands for ioctlsocket(),  taken from the BSD file fcntl.h.
+ *
+ *
+ * Ioctl's have the command encoded in the lower word,
+ * and the size of any in or out parameters in the upper
+ * word.  The high 2 bits of the upper word are used
+ * to encode the in/out status of the parameter; for now
+ * we restrict parameters to at most 128 bytes.
+ */
+#define IOCPARM_MASK    0x7f            /* parameters must be < 128 bytes */
+#define IOC_VOID        0x20000000      /* no parameters */
+#define IOC_OUT         0x40000000      /* copy out parameters */
+#define IOC_IN          0x80000000      /* copy in parameters */
+#define IOC_INOUT       (IOC_IN|IOC_OUT)
+                                        /* 0x20000000 distinguishes new &
+                                           old ioctl's */
+#define _IO(x,y)        (IOC_VOID|((x)<<8)|(y))
+
+#define _IOR(x,y,t)     (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))
+
+#define _IOW(x,y,t)     (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))
+
+#define FIONREAD    _IOR('f', 127, u_long) /* get # bytes to read */
+#define FIONBIO     _IOW('f', 126, u_long) /* set/clear non-blocking i/o */
+#define FIOASYNC    _IOW('f', 125, u_long) /* set/clear async i/o */
+
+/* Socket I/O Controls */
+#define SIOCSHIWAT  _IOW('s',  0, u_long)  /* set high watermark */
+#define SIOCGHIWAT  _IOR('s',  1, u_long)  /* get high watermark */
+#define SIOCSLOWAT  _IOW('s',  2, u_long)  /* set low watermark */
+#define SIOCGLOWAT  _IOR('s',  3, u_long)  /* get low watermark */
+#define SIOCATMARK  _IOR('s',  7, u_long)  /* at oob mark? */
+
+/*
+ * Structures returned by network data base library, taken from the
+ * BSD file netdb.h.  All addresses are supplied in host order, and
+ * returned in network order (suitable for use in system calls).
+ */
+
+struct  hostent {
+        char    FAR * h_name;           /* official name of host */
+        char    FAR * FAR * h_aliases;  /* alias list */
+        short   h_addrtype;             /* host address type */
+        short   h_length;               /* length of address */
+        char    FAR * FAR * h_addr_list; /* list of addresses */
+#define h_addr  h_addr_list[0]          /* address, for backward compat */
+};
+
+/*
+ * It is assumed here that a network number
+ * fits in 32 bits.
+ */
+struct  netent {
+        char    FAR * n_name;           /* official name of net */
+        char    FAR * FAR * n_aliases;  /* alias list */
+        short   n_addrtype;             /* net address type */
+        u_long  n_net;                  /* network # */
+};
+
+struct  servent {
+        char    FAR * s_name;           /* official service name */
+        char    FAR * FAR * s_aliases;  /* alias list */
+        short   s_port;                 /* port # */
+        char    FAR * s_proto;          /* protocol to use */
+};
+
+struct  protoent {
+        char    FAR * p_name;           /* official protocol name */
+        char    FAR * FAR * p_aliases;  /* alias list */
+        short   p_proto;                /* protocol # */
+};
+
+/*
+ * Constants and structures defined by the internet system,
+ * Per RFC 790, September 1981, taken from the BSD file netinet/in.h.
+ */
+
+/*
+ * Protocols
+ */
+#define IPPROTO_IP              0               /* dummy for IP */
+#define IPPROTO_ICMP            1               /* control message protocol */
+#define IPPROTO_GGP             2               /* gateway^2 (deprecated) */
+#define IPPROTO_TCP             6               /* tcp */
+#define IPPROTO_PUP             12              /* pup */
+#define IPPROTO_UDP             17              /* user datagram protocol */
+#define IPPROTO_IDP             22              /* xns idp */
+#define IPPROTO_ND              77              /* UNOFFICIAL net disk proto */
+
+#define IPPROTO_RAW             255             /* raw IP packet */
+#define IPPROTO_MAX             256
+
+/*
+ * Port/socket numbers: network standard functions
+ */
+#define IPPORT_ECHO             7
+#define IPPORT_DISCARD          9
+#define IPPORT_SYSTAT           11
+#define IPPORT_DAYTIME          13
+#define IPPORT_NETSTAT          15
+#define IPPORT_FTP              21
+#define IPPORT_TELNET           23
+#define IPPORT_SMTP             25
+#define IPPORT_TIMESERVER       37
+#define IPPORT_NAMESERVER       42
+#define IPPORT_WHOIS            43
+#define IPPORT_MTP              57
+
+/*
+ * Port/socket numbers: host specific functions
+ */
+#define IPPORT_TFTP             69
+#define IPPORT_RJE              77
+#define IPPORT_FINGER           79
+#define IPPORT_TTYLINK          87
+#define IPPORT_SUPDUP           95
+
+/*
+ * UNIX TCP sockets
+ */
+#define IPPORT_EXECSERVER       512
+#define IPPORT_LOGINSERVER      513
+#define IPPORT_CMDSERVER        514
+#define IPPORT_EFSSERVER        520
+
+/*
+ * UNIX UDP sockets
+ */
+#define IPPORT_BIFFUDP          512
+#define IPPORT_WHOSERVER        513
+#define IPPORT_ROUTESERVER      520
+                                        /* 520+1 also used */
+
+/*
+ * Ports < IPPORT_RESERVED are reserved for
+ * privileged processes (e.g. root).
+ */
+#define IPPORT_RESERVED         1024
+
+/*
+ * Link numbers
+ */
+#define IMPLINK_IP              155
+#define IMPLINK_LOWEXPER        156
+#define IMPLINK_HIGHEXPER       158
+
+/*
+ * Internet address (old style... should be updated)
+ */
+struct in_addr {
+        union {
+                struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
+                struct { u_short s_w1,s_w2; } S_un_w;
+                u_long S_addr;
+        } S_un;
+#define s_addr  S_un.S_addr
+                                /* can be used for most tcp & ip code */
+#define s_host  S_un.S_un_b.s_b2
+                                /* host on imp */
+#define s_net   S_un.S_un_b.s_b1
+                                /* network */
+#define s_imp   S_un.S_un_w.s_w2
+                                /* imp */
+#define s_impno S_un.S_un_b.s_b4
+                                /* imp # */
+#define s_lh    S_un.S_un_b.s_b3
+                                /* logical host */
+};
+
+/*
+ * Definitions of bits in internet address integers.
+ * On subnets, the decomposition of addresses to host and net parts
+ * is done according to subnet mask, not the masks here.
+ */
+#define IN_CLASSA(i)            (((long)(i) & 0x80000000) == 0)
+#define IN_CLASSA_NET           0xff000000
+#define IN_CLASSA_NSHIFT        24
+#define IN_CLASSA_HOST          0x00ffffff
+#define IN_CLASSA_MAX           128
+
+#define IN_CLASSB(i)            (((long)(i) & 0xc0000000) == 0x80000000)
+#define IN_CLASSB_NET           0xffff0000
+#define IN_CLASSB_NSHIFT        16
+#define IN_CLASSB_HOST          0x0000ffff
+#define IN_CLASSB_MAX           65536
+
+#define IN_CLASSC(i)            (((long)(i) & 0xe0000000) == 0xc0000000)
+#define IN_CLASSC_NET           0xffffff00
+#define IN_CLASSC_NSHIFT        8
+#define IN_CLASSC_HOST          0x000000ff
+
+#define INADDR_ANY              (u_long)0x00000000
+#define INADDR_LOOPBACK         0x7f000001
+#define INADDR_BROADCAST        (u_long)0xffffffff
+#define INADDR_NONE             0xffffffff
+
+/*
+ * Socket address, internet style.
+ */
+struct sockaddr_in {
+        short   sin_family;
+        u_short sin_port;
+        struct  in_addr sin_addr;
+        char    sin_zero[8];
+};
+
+#define WSADESCRIPTION_LEN      256
+#define WSASYS_STATUS_LEN       128
+
+typedef struct WSAData {
+        WORD                    wVersion;
+        WORD                    wHighVersion;
+        char                    szDescription[WSADESCRIPTION_LEN+1];
+        char                    szSystemStatus[WSASYS_STATUS_LEN+1];
+        unsigned short          iMaxSockets;
+        unsigned short          iMaxUdpDg;
+        char FAR *              lpVendorInfo;
+} WSADATA;
+
+typedef WSADATA FAR *LPWSADATA;
+
+/*
+ * Options for use with [gs]etsockopt at the IP level.
+ */
+#define IP_OPTIONS          1           /* set/get IP per-packet options    */
+#define IP_MULTICAST_IF     2           /* set/get IP multicast interface   */
+#define IP_MULTICAST_TTL    3           /* set/get IP multicast timetolive  */
+#define IP_MULTICAST_LOOP   4           /* set/get IP multicast loopback    */
+#define IP_ADD_MEMBERSHIP   5           /* add  an IP group membership      */
+#define IP_DROP_MEMBERSHIP  6           /* drop an IP group membership      */
+
+#define IP_DEFAULT_MULTICAST_TTL   1    /* normally limit m'casts to 1 hop  */
+#define IP_DEFAULT_MULTICAST_LOOP  1    /* normally hear sends if a member  */
+#define IP_MAX_MEMBERSHIPS         20   /* per socket; must fit in one mbuf */
+
+/*
+ * Argument structure for IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP.
+ */
+struct ip_mreq {
+        struct in_addr  imr_multiaddr;  /* IP multicast address of group */
+        struct in_addr  imr_interface;  /* local IP address of interface */
+};
+
+/*
+ * Definitions related to sockets: types, address families, options,
+ * taken from the BSD file sys/socket.h.
+ */
+
+/*
+ * This is used instead of -1, since the
+ * SOCKET type is unsigned.
+ */
+#define INVALID_SOCKET  (SOCKET)(~0)
+#define SOCKET_ERROR            (-1)
+
+/*
+ * Types
+ */
+#define SOCK_STREAM     1               /* stream socket */
+#define SOCK_DGRAM      2               /* datagram socket */
+#define SOCK_RAW        3               /* raw-protocol interface */
+#define SOCK_RDM        4               /* reliably-delivered message */
+#define SOCK_SEQPACKET  5               /* sequenced packet stream */
+
+/*
+ * Option flags per-socket.
+ */
+#define SO_DEBUG        0x0001          /* turn on debugging info recording */
+#define SO_ACCEPTCONN   0x0002          /* socket has had listen() */
+#define SO_REUSEADDR    0x0004          /* allow local address reuse */
+#define SO_KEEPALIVE    0x0008          /* keep connections alive */
+#define SO_DONTROUTE    0x0010          /* just use interface addresses */
+#define SO_BROADCAST    0x0020          /* permit sending of broadcast msgs */
+#define SO_USELOOPBACK  0x0040          /* bypass hardware when possible */
+#define SO_LINGER       0x0080          /* linger on close if data present */
+#define SO_OOBINLINE    0x0100          /* leave received OOB data in line */
+
+#define SO_DONTLINGER   (u_int)(~SO_LINGER)
+
+/*
+ * Additional options.
+ */
+#define SO_SNDBUF       0x1001          /* send buffer size */
+#define SO_RCVBUF       0x1002          /* receive buffer size */
+#define SO_SNDLOWAT     0x1003          /* send low-water mark */
+#define SO_RCVLOWAT     0x1004          /* receive low-water mark */
+#define SO_SNDTIMEO     0x1005          /* send timeout */
+#define SO_RCVTIMEO     0x1006          /* receive timeout */
+#define SO_ERROR        0x1007          /* get error status and clear */
+#define SO_TYPE         0x1008          /* get socket type */
+
+/*
+ * Options for connect and disconnect data and options.  Used only by
+ * non-TCP/IP transports such as DECNet, OSI TP4, etc.
+ */
+#define SO_CONNDATA     0x7000
+#define SO_CONNOPT      0x7001
+#define SO_DISCDATA     0x7002
+#define SO_DISCOPT      0x7003
+#define SO_CONNDATALEN  0x7004
+#define SO_CONNOPTLEN   0x7005
+#define SO_DISCDATALEN  0x7006
+#define SO_DISCOPTLEN   0x7007
+
+/*
+ * Option for opening sockets for synchronous access.
+ */
+#define SO_OPENTYPE     0x7008
+
+#define SO_SYNCHRONOUS_ALERT    0x10
+#define SO_SYNCHRONOUS_NONALERT 0x20
+
+/*
+ * Other NT-specific options.
+ */
+#define SO_MAXDG        0x7009
+#define SO_MAXPATHDG    0x700A
+
+/*
+ * TCP options.
+ */
+#define TCP_NODELAY     0x0001
+#define TCP_BSDURGENT   0x7000
+
+/*
+ * Address families.
+ */
+#define AF_UNSPEC       0               /* unspecified */
+#define AF_UNIX         1               /* local to host (pipes, portals) */
+#define AF_INET         2               /* internetwork: UDP, TCP, etc. */
+#define AF_IMPLINK      3               /* arpanet imp addresses */
+#define AF_PUP          4               /* pup protocols: e.g. BSP */
+#define AF_CHAOS        5               /* mit CHAOS protocols */
+#define AF_IPX          6               /* IPX and SPX */
+#define AF_NS           6               /* XEROX NS protocols */
+#define AF_ISO          7               /* ISO protocols */
+#define AF_OSI          AF_ISO          /* OSI is ISO */
+#define AF_ECMA         8               /* european computer manufacturers */
+#define AF_DATAKIT      9               /* datakit protocols */
+#define AF_CCITT        10              /* CCITT protocols, X.25 etc */
+#define AF_SNA          11              /* IBM SNA */
+#define AF_DECnet       12              /* DECnet */
+#define AF_DLI          13              /* Direct data link interface */
+#define AF_LAT          14              /* LAT */
+#define AF_HYLINK       15              /* NSC Hyperchannel */
+#define AF_APPLETALK    16              /* AppleTalk */
+#define AF_NETBIOS      17              /* NetBios-style addresses */
+
+#define AF_MAX          18
+
+/*
+ * Structure used by kernel to store most
+ * addresses.
+ */
+struct sockaddr {
+        u_short sa_family;              /* address family */
+        char    sa_data[14];            /* up to 14 bytes of direct address */
+};
+
+/*
+ * Structure used by kernel to pass protocol
+ * information in raw sockets.
+ */
+struct sockproto {
+        u_short sp_family;              /* address family */
+        u_short sp_protocol;            /* protocol */
+};
+
+/*
+ * Protocol families, same as address families for now.
+ */
+#define PF_UNSPEC       AF_UNSPEC
+#define PF_UNIX         AF_UNIX
+#define PF_INET         AF_INET
+#define PF_IMPLINK      AF_IMPLINK
+#define PF_PUP          AF_PUP
+#define PF_CHAOS        AF_CHAOS
+#define PF_NS           AF_NS
+#define PF_IPX          AF_IPX
+#define PF_ISO          AF_ISO
+#define PF_OSI          AF_OSI
+#define PF_ECMA         AF_ECMA
+#define PF_DATAKIT      AF_DATAKIT
+#define PF_CCITT        AF_CCITT
+#define PF_SNA          AF_SNA
+#define PF_DECnet       AF_DECnet
+#define PF_DLI          AF_DLI
+#define PF_LAT          AF_LAT
+#define PF_HYLINK       AF_HYLINK
+#define PF_APPLETALK    AF_APPLETALK
+
+#define PF_MAX          AF_MAX
+
+/*
+ * Structure used for manipulating linger option.
+ */
+struct  linger {
+        u_short l_onoff;                /* option on/off */
+        u_short l_linger;               /* linger time */
+};
+
+/*
+ * Level number for (get/set)sockopt() to apply to socket itself.
+ */
+#define SOL_SOCKET      0xffff          /* options for socket level */
+
+/*
+ * Maximum queue length specifiable by listen.
+ */
+#define SOMAXCONN       5
+
+#define MSG_OOB         0x1             /* process out-of-band data */
+#define MSG_PEEK        0x2             /* peek at incoming message */
+#define MSG_DONTROUTE   0x4             /* send without using routing tables */
+
+#define MSG_MAXIOVLEN   16
+
+#define        MSG_PARTIAL     0x8000          /* partial send or recv for message xport */
+
+/*
+ * Define constant based on rfc883, used by gethostbyxxxx() calls.
+ */
+#define MAXGETHOSTSTRUCT        1024
+
+/*
+ * Define flags to be used with the WSAAsyncSelect() call.
+ */
+#define FD_READ         0x01
+#define FD_WRITE        0x02
+#define FD_OOB          0x04
+#define FD_ACCEPT       0x08
+#define FD_CONNECT      0x10
+#define FD_CLOSE        0x20
+
+/*
+ * All Windows Sockets error constants are biased by WSABASEERR from
+ * the "normal"
+ */
+#define WSABASEERR              10000
+/*
+ * Windows Sockets definitions of regular Microsoft C error constants
+ */
+#define WSAEINTR                (WSABASEERR+4)
+#define WSAEBADF                (WSABASEERR+9)
+#define WSAEACCES               (WSABASEERR+13)
+#define WSAEFAULT               (WSABASEERR+14)
+#define WSAEINVAL               (WSABASEERR+22)
+#define WSAEMFILE               (WSABASEERR+24)
+
+/*
+ * Windows Sockets definitions of regular Berkeley error constants
+ */
+#define WSAEWOULDBLOCK          (WSABASEERR+35)
+#define WSAEINPROGRESS          (WSABASEERR+36)
+#define WSAEALREADY             (WSABASEERR+37)
+#define WSAENOTSOCK             (WSABASEERR+38)
+#define WSAEDESTADDRREQ         (WSABASEERR+39)
+#define WSAEMSGSIZE             (WSABASEERR+40)
+#define WSAEPROTOTYPE           (WSABASEERR+41)
+#define WSAENOPROTOOPT          (WSABASEERR+42)
+#define WSAEPROTONOSUPPORT      (WSABASEERR+43)
+#define WSAESOCKTNOSUPPORT      (WSABASEERR+44)
+#define WSAEOPNOTSUPP           (WSABASEERR+45)
+#define WSAEPFNOSUPPORT         (WSABASEERR+46)
+#define WSAEAFNOSUPPORT         (WSABASEERR+47)
+#define WSAEADDRINUSE           (WSABASEERR+48)
+#define WSAEADDRNOTAVAIL        (WSABASEERR+49)
+#define WSAENETDOWN             (WSABASEERR+50)
+#define WSAENETUNREACH          (WSABASEERR+51)
+#define WSAENETRESET            (WSABASEERR+52)
+#define WSAECONNABORTED         (WSABASEERR+53)
+#define WSAECONNRESET           (WSABASEERR+54)
+#define WSAENOBUFS              (WSABASEERR+55)
+#define WSAEISCONN              (WSABASEERR+56)
+#define WSAENOTCONN             (WSABASEERR+57)
+#define WSAESHUTDOWN            (WSABASEERR+58)
+#define WSAETOOMANYREFS         (WSABASEERR+59)
+#define WSAETIMEDOUT            (WSABASEERR+60)
+#define WSAECONNREFUSED         (WSABASEERR+61)
+#define WSAELOOP                (WSABASEERR+62)
+#define WSAENAMETOOLONG         (WSABASEERR+63)
+#define WSAEHOSTDOWN            (WSABASEERR+64)
+#define WSAEHOSTUNREACH         (WSABASEERR+65)
+#define WSAENOTEMPTY            (WSABASEERR+66)
+#define WSAEPROCLIM             (WSABASEERR+67)
+#define WSAEUSERS               (WSABASEERR+68)
+#define WSAEDQUOT               (WSABASEERR+69)
+#define WSAESTALE               (WSABASEERR+70)
+#define WSAEREMOTE              (WSABASEERR+71)
+
+#define WSAEDISCON              (WSABASEERR+101)
+
+/*
+ * Extended Windows Sockets error constant definitions
+ */
+#define WSASYSNOTREADY          (WSABASEERR+91)
+#define WSAVERNOTSUPPORTED      (WSABASEERR+92)
+#define WSANOTINITIALISED       (WSABASEERR+93)
+
+/*
+ * Error return codes from gethostbyname() and gethostbyaddr()
+ * (when using the resolver). Note that these errors are
+ * retrieved via WSAGetLastError() and must therefore follow
+ * the rules for avoiding clashes with error numbers from
+ * specific implementations or language run-time systems.
+ * For this reason the codes are based at WSABASEERR+1001.
+ * Note also that [WSA]NO_ADDRESS is defined only for
+ * compatibility purposes.
+ */
+
+#define h_errno         WSAGetLastError()
+
+/* Authoritative Answer: Host not found */
+#define WSAHOST_NOT_FOUND       (WSABASEERR+1001)
+#define HOST_NOT_FOUND          WSAHOST_NOT_FOUND
+
+/* Non-Authoritative: Host not found, or SERVERFAIL */
+#define WSATRY_AGAIN            (WSABASEERR+1002)
+#define TRY_AGAIN               WSATRY_AGAIN
+
+/* Non recoverable errors, FORMERR, REFUSED, NOTIMP */
+#define WSANO_RECOVERY          (WSABASEERR+1003)
+#define NO_RECOVERY             WSANO_RECOVERY
+
+/* Valid name, no data record of requested type */
+#define WSANO_DATA              (WSABASEERR+1004)
+#define NO_DATA                 WSANO_DATA
+
+/* no address, look for MX record */
+#define WSANO_ADDRESS           WSANO_DATA
+#define NO_ADDRESS              WSANO_ADDRESS
+
+/*
+ * Windows Sockets errors redefined as regular Berkeley error constants.
+ * These are commented out in Windows NT to avoid conflicts with errno.h.
+ * Use the WSA constants instead.
+ */
+#if 0
+#define EWOULDBLOCK             WSAEWOULDBLOCK
+#define EINPROGRESS             WSAEINPROGRESS
+#define EALREADY                WSAEALREADY
+#define ENOTSOCK                WSAENOTSOCK
+#define EDESTADDRREQ            WSAEDESTADDRREQ
+#define EMSGSIZE                WSAEMSGSIZE
+#define EPROTOTYPE              WSAEPROTOTYPE
+#define ENOPROTOOPT             WSAENOPROTOOPT
+#define EPROTONOSUPPORT         WSAEPROTONOSUPPORT
+#define ESOCKTNOSUPPORT         WSAESOCKTNOSUPPORT
+#define EOPNOTSUPP              WSAEOPNOTSUPP
+#define EPFNOSUPPORT            WSAEPFNOSUPPORT
+#define EAFNOSUPPORT            WSAEAFNOSUPPORT
+#define EADDRINUSE              WSAEADDRINUSE
+#define EADDRNOTAVAIL           WSAEADDRNOTAVAIL
+#define ENETDOWN                WSAENETDOWN
+#define ENETUNREACH             WSAENETUNREACH
+#define ENETRESET               WSAENETRESET
+#define ECONNABORTED            WSAECONNABORTED
+#define ECONNRESET              WSAECONNRESET
+#define ENOBUFS                 WSAENOBUFS
+#define EISCONN                 WSAEISCONN
+#define ENOTCONN                WSAENOTCONN
+#define ESHUTDOWN               WSAESHUTDOWN
+#define ETOOMANYREFS            WSAETOOMANYREFS
+#define ETIMEDOUT               WSAETIMEDOUT
+#define ECONNREFUSED            WSAECONNREFUSED
+#define ELOOP                   WSAELOOP
+#define ENAMETOOLONG            WSAENAMETOOLONG
+#define EHOSTDOWN               WSAEHOSTDOWN
+#define EHOSTUNREACH            WSAEHOSTUNREACH
+#define ENOTEMPTY               WSAENOTEMPTY
+#define EPROCLIM                WSAEPROCLIM
+#define EUSERS                  WSAEUSERS
+#define EDQUOT                  WSAEDQUOT
+#define ESTALE                  WSAESTALE
+#define EREMOTE                 WSAEREMOTE
+#endif
+
+/* Socket function prototypes */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+SOCKET PASCAL FAR accept (SOCKET s, struct sockaddr FAR *addr,
+                          int FAR *addrlen);
+
+int PASCAL FAR bind (SOCKET s, const struct sockaddr FAR *addr, int namelen);
+
+int PASCAL FAR closesocket (SOCKET s);
+
+int PASCAL FAR connect (SOCKET s, const struct sockaddr FAR *name, int namelen);
+
+int PASCAL FAR ioctlsocket (SOCKET s, long cmd, u_long FAR *argp);
+
+int PASCAL FAR getpeername (SOCKET s, struct sockaddr FAR *name,
+                            int FAR * namelen);
+
+int PASCAL FAR getsockname (SOCKET s, struct sockaddr FAR *name,
+                            int FAR * namelen);
+
+int PASCAL FAR getsockopt (SOCKET s, int level, int optname,
+                           char FAR * optval, int FAR *optlen);
+
+u_long PASCAL FAR htonl (u_long hostlong);
+
+u_short PASCAL FAR htons (u_short hostshort);
+
+unsigned long PASCAL FAR inet_addr (const char FAR * cp);
+
+char FAR * PASCAL FAR inet_ntoa (struct in_addr in);
+
+int PASCAL FAR listen (SOCKET s, int backlog);
+
+u_long PASCAL FAR ntohl (u_long netlong);
+
+u_short PASCAL FAR ntohs (u_short netshort);
+
+int PASCAL FAR recv (SOCKET s, char FAR * buf, int len, int flags);
+
+int PASCAL FAR recvfrom (SOCKET s, char FAR * buf, int len, int flags,
+                         struct sockaddr FAR *from, int FAR * fromlen);
+
+int PASCAL FAR select (int nfds, fd_set FAR *readfds, fd_set FAR *writefds,
+                       fd_set FAR *exceptfds, const struct timeval FAR *timeout);
+
+int PASCAL FAR send (SOCKET s, const char FAR * buf, int len, int flags);
+
+int PASCAL FAR sendto (SOCKET s, const char FAR * buf, int len, int flags,
+                       const struct sockaddr FAR *to, int tolen);
+
+int PASCAL FAR setsockopt (SOCKET s, int level, int optname,
+                           const char FAR * optval, int optlen);
+
+int PASCAL FAR shutdown (SOCKET s, int how);
+
+SOCKET PASCAL FAR socket (int af, int type, int protocol);
+
+/* Database function prototypes */
+
+struct hostent FAR * PASCAL FAR gethostbyaddr(const char FAR * addr,
+                                              int len, int type);
+
+struct hostent FAR * PASCAL FAR gethostbyname(const char FAR * name);
+
+int PASCAL FAR gethostname (char FAR * name, int namelen);
+
+struct servent FAR * PASCAL FAR getservbyport(int port, const char FAR * proto);
+
+struct servent FAR * PASCAL FAR getservbyname(const char FAR * name,
+                                              const char FAR * proto);
+
+struct protoent FAR * PASCAL FAR getprotobynumber(int proto);
+
+struct protoent FAR * PASCAL FAR getprotobyname(const char FAR * name);
+
+/* Microsoft Windows Extension function prototypes */
+
+int PASCAL FAR WSAStartup(WORD wVersionRequired, LPWSADATA lpWSAData);
+
+int PASCAL FAR WSACleanup(void);
+
+void PASCAL FAR WSASetLastError(int iError);
+
+int PASCAL FAR WSAGetLastError(void);
+
+BOOL PASCAL FAR WSAIsBlocking(void);
+
+int PASCAL FAR WSAUnhookBlockingHook(void);
+
+FARPROC PASCAL FAR WSASetBlockingHook(FARPROC lpBlockFunc);
+
+int PASCAL FAR WSACancelBlockingCall(void);
+
+HANDLE PASCAL FAR WSAAsyncGetServByName(HWND hWnd, u_int wMsg,
+                                        const char FAR * name,
+                                        const char FAR * proto,
+                                        char FAR * buf, int buflen);
+
+HANDLE PASCAL FAR WSAAsyncGetServByPort(HWND hWnd, u_int wMsg, int port,
+                                        const char FAR * proto, char FAR * buf,
+                                        int buflen);
+
+HANDLE PASCAL FAR WSAAsyncGetProtoByName(HWND hWnd, u_int wMsg,
+                                         const char FAR * name, char FAR * buf,
+                                         int buflen);
+
+HANDLE PASCAL FAR WSAAsyncGetProtoByNumber(HWND hWnd, u_int wMsg,
+                                           int number, char FAR * buf,
+                                           int buflen);
+
+HANDLE PASCAL FAR WSAAsyncGetHostByName(HWND hWnd, u_int wMsg,
+                                        const char FAR * name, char FAR * buf,
+                                        int buflen);
+
+HANDLE PASCAL FAR WSAAsyncGetHostByAddr(HWND hWnd, u_int wMsg,
+                                        const char FAR * addr, int len, int type,
+                                        char FAR * buf, int buflen);
+
+int PASCAL FAR WSACancelAsyncRequest(HANDLE hAsyncTaskHandle);
+
+int PASCAL FAR WSAAsyncSelect(SOCKET s, HWND hWnd, u_int wMsg,
+                               long lEvent);
+
+int PASCAL FAR WSARecvEx (SOCKET s, char FAR * buf, int len, int FAR *flags);
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Microsoft Windows Extended data types */
+typedef struct sockaddr SOCKADDR;
+typedef struct sockaddr *PSOCKADDR;
+typedef struct sockaddr FAR *LPSOCKADDR;
+
+typedef struct sockaddr_in SOCKADDR_IN;
+typedef struct sockaddr_in *PSOCKADDR_IN;
+typedef struct sockaddr_in FAR *LPSOCKADDR_IN;
+
+typedef struct linger LINGER;
+typedef struct linger *PLINGER;
+typedef struct linger FAR *LPLINGER;
+
+typedef struct in_addr IN_ADDR;
+typedef struct in_addr *PIN_ADDR;
+typedef struct in_addr FAR *LPIN_ADDR;
+
+typedef struct fd_set FD_SET;
+typedef struct fd_set *PFD_SET;
+typedef struct fd_set FAR *LPFD_SET;
+
+typedef struct hostent HOSTENT;
+typedef struct hostent *PHOSTENT;
+typedef struct hostent FAR *LPHOSTENT;
+
+typedef struct servent SERVENT;
+typedef struct servent *PSERVENT;
+typedef struct servent FAR *LPSERVENT;
+
+typedef struct protoent PROTOENT;
+typedef struct protoent *PPROTOENT;
+typedef struct protoent FAR *LPPROTOENT;
+
+typedef struct timeval TIMEVAL;
+typedef struct timeval *PTIMEVAL;
+typedef struct timeval FAR *LPTIMEVAL;
+
+/*
+ * Windows message parameter composition and decomposition
+ * macros.
+ *
+ * WSAMAKEASYNCREPLY is intended for use by the Windows Sockets implementation
+ * when constructing the response to a WSAAsyncGetXByY() routine.
+ */
+#define WSAMAKEASYNCREPLY(buflen,error)     MAKELONG(buflen,error)
+/*
+ * WSAMAKESELECTREPLY is intended for use by the Windows Sockets implementation
+ * when constructing the response to WSAAsyncSelect().
+ */
+#define WSAMAKESELECTREPLY(event,error)     MAKELONG(event,error)
+/*
+ * WSAGETASYNCBUFLEN is intended for use by the Windows Sockets application
+ * to extract the buffer length from the lParam in the response
+ * to a WSAGetXByY().
+ */
+#define WSAGETASYNCBUFLEN(lParam)           LOWORD(lParam)
+/*
+ * WSAGETASYNCERROR is intended for use by the Windows Sockets application
+ * to extract the error code from the lParam in the response
+ * to a WSAGetXByY().
+ */
+#define WSAGETASYNCERROR(lParam)            HIWORD(lParam)
+/*
+ * WSAGETSELECTEVENT is intended for use by the Windows Sockets application
+ * to extract the event code from the lParam in the response
+ * to a WSAAsyncSelect().
+ */
+#define WSAGETSELECTEVENT(lParam)           LOWORD(lParam)
+/*
+ * WSAGETSELECTERROR is intended for use by the Windows Sockets application
+ * to extract the error code from the lParam in the response
+ * to a WSAAsyncSelect().
+ */
+#define WSAGETSELECTERROR(lParam)           HIWORD(lParam)
+
+#endif  /* _WINSOCKAPI_ */
+
+
+\1a
\ No newline at end of file
diff --git a/libraries/msdos/winsock/kerberos.c b/libraries/msdos/winsock/kerberos.c
new file mode 100644 (file)
index 0000000..6229204
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ *  Copyright (c) 1992, 1994 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  kerberos.c - for the windows environment
+ */
+
+#include <msdos.h>
+#include "lber.h"
+#include "ldap.h"
+
+#ifdef KERBEROS
+#ifdef WINSOCK
+#include <winsock.h>
+#endif
+#include <stdio.h>
+
+#ifdef AUTHMAN
+#include <authlib.h>
+
+/*
+ * get_kerberosv4_credentials - obtain kerberos v4 credentials for ldap.
+ * this includes krbtgt, and any service tickets
+ */
+
+/* ARGSUSED */
+char *
+get_kerberosv4_credentials( LDAP *ld, char *who, char *service, int *len )
+{
+    static short    authman_refnum = 0;
+    static          char ticket[ MAX_KTXT_LEN ];
+    short           version, ticketlen, err;
+    AUTH_PTR        ticketStorage = ticket;
+    AUTH_SHORT_PTR  pTicketLen = &ticketlen;
+    AUTH_STR_PTR    pName = service;
+    AUTH_STR_PTR    pInstance;
+    HINSTANCE       instAuthLibDLL = NULL;
+    pfn_openAuthMan fp_openAuthMan = NULL;
+    pfn_closeAuthMan fp_closeAuthMan = NULL;
+    pfn_getV4Ticket fp_getV4Ticket = NULL;
+
+
+#ifdef LDAP_REFERRALS
+       pInstance = ld->ld_defconn->lconn_krbinstance;
+#else /* LDAP_REFERRALS */
+       pInstance = ld->ld_host;
+#endif /* LDAP_REFERRALS */
+
+    if ( !pInstance ) {        // if we don't know name of service host, no chance for service tickets
+        ld->ld_errno = LDAP_LOCAL_ERROR;
+        WSASetLastError(WSANO_ADDRESS);
+       return( NULL );
+    }
+    
+    if ( !instAuthLibDLL )
+    {
+        unsigned int prevMode = SetErrorMode( SEM_NOOPENFILEERRORBOX ); // don't whine at user if you can't find it
+        instAuthLibDLL = LoadLibrary("AuthLib.DLL");
+        SetErrorMode( prevMode );
+
+        if ( instAuthLibDLL < HINSTANCE_ERROR ) // can't find authlib
+        {
+            ld->ld_errno = LDAP_AUTH_UNKNOWN; 
+            return( NULL );
+        }
+        
+        fp_openAuthMan = (pfn_openAuthMan)GetProcAddress( instAuthLibDLL, "openAuthMan" );
+        fp_getV4Ticket = (pfn_getV4Ticket)GetProcAddress( instAuthLibDLL, "getV4Ticket" );
+        fp_closeAuthMan = (pfn_closeAuthMan)GetProcAddress( instAuthLibDLL, "closeAuthMan" );
+
+        // verify that we found all the routines we need
+        if (!(fp_closeAuthMan && fp_getV4Ticket && fp_openAuthMan))
+        {
+               FreeLibrary( instAuthLibDLL ); // free authlib.dll so it gets unloaded
+           instAuthLibDLL = NULL;
+            ld->ld_errno = LDAP_AUTH_UNKNOWN; 
+            return( NULL );
+        }
+        
+    }
+
+    /*
+     * make sure RJC's Authentication Manager version isn't > 4.0
+     */
+     if ( authman_refnum == 0 && (( err = (fp_openAuthMan)( &authman_refnum, &version )) != AUTH_NO_ERROR || AUTH_VERSION_CODE > version )) {
+        ld->ld_errno = LDAP_AUTH_UNKNOWN; 
+        if ( AUTH_VERSION_CODE > version )
+        {
+            ld->ld_errno = LDAP_INAPPROPRIATE_AUTH; // version too old
+        }
+        (fp_closeAuthMan)( authman_refnum );
+        authman_refnum = NULL;
+        FreeLibrary( instAuthLibDLL ); // free authlib.dll so it gets unloaded
+           instAuthLibDLL = NULL;
+        return( NULL );
+    }
+    
+    if (( err = (fp_getV4Ticket)( authman_refnum, ticketStorage, pTicketLen, pName, pInstance,
+            NULL, INFINITE_LIFETIME, 1 )) != AUTH_NO_ERROR ) {
+        
+        ld->ld_errno = AUTH_USER_CANCELED == err ? LDAP_USER_CANCELLED : LDAP_INVALID_CREDENTIALS;
+        (fp_closeAuthMan)( authman_refnum );
+        authman_refnum = NULL;
+        FreeLibrary( instAuthLibDLL ); // free authlib.dll so it gets unloaded
+           instAuthLibDLL = NULL;
+        return( NULL );
+    }
+
+    *len = ticketlen;
+    (fp_closeAuthMan)( authman_refnum ); // open pukes if you call twice with no close in between
+    authman_refnum = NULL;
+    FreeLibrary( instAuthLibDLL ); // free authlib.dll so it gets unloaded
+    instAuthLibDLL = NULL;
+    return( (char *)ticket );
+}
+
+#endif /* AUTHMAN */
+#endif /* KERBEROS */
+
diff --git a/libraries/msdos/winsock/ldap32.def b/libraries/msdos/winsock/ldap32.def
new file mode 100644 (file)
index 0000000..8563777
--- /dev/null
@@ -0,0 +1,166 @@
+LIBRARY         LDAP32\r
+DESCRIPTION     'Lightweight Directory Access Protocol Client API'\r
+CODE            PRELOAD MOVEABLE DISCARDABLE\r
+DATA            PRELOAD MOVEABLE SINGLE\r
+VERSION                        3.2\r
+HEAPSIZE        4096\r
+\r
+EXPORTS\r
+; we need to manually assign ordinal numbers so we can add new routines\r
+; and not disturb the ordinals and thus not require callers to relink.\r
+       ldap_abandon                            @10\r
+       ldap_add                                @11\r
+       ldap_unbind                             @13\r
+       ldap_enable_cache                       @14\r
+       ldap_disable_cache                      @15\r
+       ldap_destroy_cache                      @16\r
+       ldap_flush_cache                        @17\r
+       ldap_uncache_entry                      @18\r
+       ldap_compare                            @19\r
+       ldap_delete                             @20\r
+       ldap_result2error                       @21\r
+       ldap_err2string                 @22\r
+       ldap_modify                             @23\r
+       ldap_modrdn                             @24\r
+       ldap_open                                       @25\r
+       ldap_first_entry                        @26\r
+       ldap_next_entry                 @27\r
+       ldap_delete_result_entry        @28\r
+       ldap_add_result_entry           @29\r
+       ldap_get_dn                             @30\r
+       ldap_dn2ufn                             @31\r
+       ldap_first_attribute            @32\r
+       ldap_next_attribute             @33\r
+       ldap_get_values                 @34\r
+       ldap_get_values_len             @35\r
+       ldap_count_entries                      @36\r
+       ldap_count_values                       @37\r
+       ldap_value_free                 @38\r
+       ldap_explode_dn                 @39\r
+       ldap_result                             @40\r
+       ldap_msgfree                            @41\r
+       ldap_msgdelete                          @42\r
+       ldap_search                             @43\r
+       ldap_add_s                                      @44\r
+       ldap_bind_s                             @45\r
+       ldap_unbind_s                           @46\r
+       ldap_delete_s                           @47\r
+       ldap_modify_s                           @48\r
+       ldap_modrdn_s                           @49\r
+       ldap_search_s                           @50\r
+       ldap_search_st                          @51\r
+       ldap_compare_s                          @52\r
+       ldap_ufn_search_c                       @53\r
+       ldap_ufn_search_s                       @54\r
+       ldap_init_getfilter             @55\r
+       ldap_getfilter_free             @56\r
+       ldap_getfirstfilter             @57\r
+       ldap_getnextfilter                      @58\r
+       ldap_simple_bind                        @59\r
+       ldap_simple_bind_s                      @60\r
+       ldap_bind                                       @61\r
+       ldap_friendly_name                      @62\r
+       ldap_free_friendlymap           @63\r
+       ldap_ufn_search_ct                      @64\r
+       ldap_set_cache_options          @65\r
+       ldap_uncache_request            @66\r
+       ldap_modrdn2                            @67\r
+       ldap_modrdn2_s                          @68\r
+       ldap_ufn_setfilter                      @69\r
+       ldap_ufn_setprefix                      @70\r
+       ldap_ufn_timeout                        @71\r
+       ldap_init_getfilter_buf @72\r
+       ldap_setfilteraffixes           @73\r
+       ldap_sort_entries                       @74\r
+       ldap_sort_values                        @75\r
+       ldap_sort_strcasecmp            @76\r
+       ldap_count_values_len           @77\r
+       ldap_name2template              @78\r
+       ldap_value_free_len             @79\r
+\r
+; manually comment and uncomment these five as necessary\r
+;      ldap_kerberos_bind1             @80\r
+;      ldap_kerberos_bind2             @81\r
+;      ldap_kerberos_bind_s            @82\r
+;      ldap_kerberos_bind1_s           @83\r
+;      ldap_kerberos_bind2_s           @84\r
+\r
+       ldap_init                       @85\r
+       ldap_is_dns_dn                  @86\r
+       ldap_explode_dns                @87\r
+       ldap_mods_free                  @88\r
+\r
+       ldap_is_ldap_url                @89\r
+       ldap_free_urldesc               @90\r
+       ldap_url_parse                  @91\r
+       ldap_url_search                 @92\r
+       ldap_url_search_s               @93\r
+       ldap_url_search_st              @94\r
+       ldap_set_rebind_proc            @95\r
+\r
+       ber_skip_tag                            @100\r
+       ber_peek_tag                            @101\r
+       ber_get_int                             @102\r
+       ber_get_stringb                 @103\r
+       ber_get_stringa                 @104\r
+       ber_get_stringal                        @105\r
+       ber_get_bitstringa                      @106\r
+       ber_get_null                            @107\r
+       ber_get_boolean                 @108\r
+       ber_first_element                       @109\r
+       ber_next_element                        @110\r
+       ber_scanf                                       @111\r
+       ber_bvfree                                      @112\r
+       ber_bvecfree                            @113\r
+       ber_put_int                             @114\r
+       ber_put_ostring                 @115\r
+       ber_put_string                          @116\r
+       ber_put_bitstring                       @117\r
+       ber_put_null                            @118\r
+       ber_put_boolean                 @119\r
+       ber_start_seq                           @120\r
+       ber_start_set                           @121\r
+       ber_put_seq                             @122\r
+       ber_put_set                             @123\r
+       ber_printf                                      @124\r
+       ber_read                                        @125\r
+       ber_write                                       @126\r
+       ber_free                                        @127\r
+       ber_flush                                       @128\r
+       ber_alloc                                       @129\r
+       ber_dup                                 @130\r
+       ber_get_next                            @131\r
+       ber_get_tag                             @132\r
+       ber_put_enum                            @133\r
+       der_alloc                                       @134\r
+       ber_alloc_t                             @135\r
+       ber_bvdup                               @136\r
+       ber_init                                @137\r
+       ber_reset                               @138\r
+\r
+       ldap_memfree                            @200\r
+\r
+       ldap_init_searchprefs           @300\r
+       ldap_init_searchprefs_buf       @301\r
+       ldap_free_searchprefs           @302\r
+       ldap_first_searchobj            @303\r
+       ldap_next_searchobj             @304\r
+       ldap_build_filter                       @305\r
+\r
+       ldap_init_templates             @400\r
+       ldap_init_templates_buf @401\r
+       ldap_free_templates             @402\r
+       ldap_first_disptmpl             @403\r
+       ldap_next_disptmpl                      @404\r
+       ldap_oc2template                        @405\r
+       ldap_tmplattrs                          @406\r
+       ldap_first_tmplrow                      @407\r
+       ldap_next_tmplrow                       @408\r
+       ldap_first_tmplcol                      @409\r
+       ldap_next_tmplcol                       @410\r
+       ldap_entry2text_search          @411\r
+       ldap_entry2text                 @412\r
+       ldap_vals2text                          @413\r
+       ldap_entry2html                 @414\r
+       ldap_entry2html_search                  @415\r
+       ldap_vals2html                          @416\r
diff --git a/libraries/msdos/winsock/ldap32.mak b/libraries/msdos/winsock/ldap32.mak
new file mode 100644 (file)
index 0000000..a8bcf7e
--- /dev/null
@@ -0,0 +1,1632 @@
+# Microsoft Developer Studio Generated NMAKE File, Format Version 4.10\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102\r
+\r
+!IF "$(CFG)" == ""\r
+CFG=libldap - Win32 Debug\r
+!MESSAGE No configuration specified.  Defaulting to libldap - Win32 Debug.\r
+!ENDIF \r
+\r
+!IF "$(CFG)" != "libldap - Win32 Release" && "$(CFG)" !=\\r
+ "libldap - Win32 Debug"\r
+!MESSAGE Invalid configuration "$(CFG)" specified.\r
+!MESSAGE You can specify a configuration when running NMAKE on this makefile\r
+!MESSAGE by defining the macro CFG on the command line.  For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "ldap32.mak" CFG="libldap - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "libldap - Win32 Release" (based on\\r
+ "Win32 (x86) Dynamic-Link Library")\r
+!MESSAGE "libldap - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")\r
+!MESSAGE \r
+!ERROR An invalid configuration is specified.\r
+!ENDIF \r
+\r
+!IF "$(OS)" == "Windows_NT"\r
+NULL=\r
+!ELSE \r
+NULL=nul\r
+!ENDIF \r
+################################################################################\r
+# Begin Project\r
+# PROP Target_Last_Scanned "libldap - Win32 Debug"\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+MTL=mktyplib.exe\r
+\r
+!IF  "$(CFG)" == "libldap - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Target_Dir ""\r
+OUTDIR=.\Release\r
+INTDIR=.\Release\r
+\r
+ALL : "$(OUTDIR)\ldap32.dll" "$(OUTDIR)\ldap32.bsc"\r
+\r
+CLEAN : \r
+       -@erase "$(INTDIR)\abandon.obj"\r
+       -@erase "$(INTDIR)\abandon.sbr"\r
+       -@erase "$(INTDIR)\add.obj"\r
+       -@erase "$(INTDIR)\add.sbr"\r
+       -@erase "$(INTDIR)\addentry.obj"\r
+       -@erase "$(INTDIR)\addentry.sbr"\r
+       -@erase "$(INTDIR)\bind.obj"\r
+       -@erase "$(INTDIR)\bind.sbr"\r
+       -@erase "$(INTDIR)\cache.obj"\r
+       -@erase "$(INTDIR)\cache.sbr"\r
+       -@erase "$(INTDIR)\charset.obj"\r
+       -@erase "$(INTDIR)\charset.sbr"\r
+       -@erase "$(INTDIR)\compare.obj"\r
+       -@erase "$(INTDIR)\compare.sbr"\r
+       -@erase "$(INTDIR)\decode.obj"\r
+       -@erase "$(INTDIR)\decode.sbr"\r
+       -@erase "$(INTDIR)\delete.obj"\r
+       -@erase "$(INTDIR)\delete.sbr"\r
+       -@erase "$(INTDIR)\disptmpl.obj"\r
+       -@erase "$(INTDIR)\disptmpl.sbr"\r
+       -@erase "$(INTDIR)\dsparse.obj"\r
+       -@erase "$(INTDIR)\dsparse.sbr"\r
+       -@erase "$(INTDIR)\encode.obj"\r
+       -@erase "$(INTDIR)\encode.sbr"\r
+       -@erase "$(INTDIR)\error.obj"\r
+       -@erase "$(INTDIR)\error.sbr"\r
+       -@erase "$(INTDIR)\free.obj"\r
+       -@erase "$(INTDIR)\free.sbr"\r
+       -@erase "$(INTDIR)\friendly.obj"\r
+       -@erase "$(INTDIR)\friendly.sbr"\r
+       -@erase "$(INTDIR)\getattr.obj"\r
+       -@erase "$(INTDIR)\getattr.sbr"\r
+       -@erase "$(INTDIR)\getdn.obj"\r
+       -@erase "$(INTDIR)\getdn.sbr"\r
+       -@erase "$(INTDIR)\getentry.obj"\r
+       -@erase "$(INTDIR)\getentry.sbr"\r
+       -@erase "$(INTDIR)\getfilte.obj"\r
+       -@erase "$(INTDIR)\getfilte.sbr"\r
+       -@erase "$(INTDIR)\getvalue.obj"\r
+       -@erase "$(INTDIR)\getvalue.sbr"\r
+       -@erase "$(INTDIR)\io.obj"\r
+       -@erase "$(INTDIR)\io.sbr"\r
+       -@erase "$(INTDIR)\kbind.obj"\r
+       -@erase "$(INTDIR)\kbind.sbr"\r
+       -@erase "$(INTDIR)\kerberos.obj"\r
+       -@erase "$(INTDIR)\kerberos.sbr"\r
+       -@erase "$(INTDIR)\libldap.res"\r
+       -@erase "$(INTDIR)\modify.obj"\r
+       -@erase "$(INTDIR)\modify.sbr"\r
+       -@erase "$(INTDIR)\modrdn.obj"\r
+       -@erase "$(INTDIR)\modrdn.sbr"\r
+       -@erase "$(INTDIR)\msdos.obj"\r
+       -@erase "$(INTDIR)\msdos.sbr"\r
+       -@erase "$(INTDIR)\open.obj"\r
+       -@erase "$(INTDIR)\open.sbr"\r
+       -@erase "$(INTDIR)\regex.obj"\r
+       -@erase "$(INTDIR)\regex.sbr"\r
+       -@erase "$(INTDIR)\request.obj"\r
+       -@erase "$(INTDIR)\request.sbr"\r
+       -@erase "$(INTDIR)\result.obj"\r
+       -@erase "$(INTDIR)\result.sbr"\r
+       -@erase "$(INTDIR)\sbind.obj"\r
+       -@erase "$(INTDIR)\sbind.sbr"\r
+       -@erase "$(INTDIR)\search.obj"\r
+       -@erase "$(INTDIR)\search.sbr"\r
+       -@erase "$(INTDIR)\sort.obj"\r
+       -@erase "$(INTDIR)\sort.sbr"\r
+       -@erase "$(INTDIR)\srchpref.obj"\r
+       -@erase "$(INTDIR)\srchpref.sbr"\r
+       -@erase "$(INTDIR)\tmplout.obj"\r
+       -@erase "$(INTDIR)\tmplout.sbr"\r
+       -@erase "$(INTDIR)\ufn.obj"\r
+       -@erase "$(INTDIR)\ufn.sbr"\r
+       -@erase "$(INTDIR)\unbind.obj"\r
+       -@erase "$(INTDIR)\unbind.sbr"\r
+       -@erase "$(INTDIR)\url.obj"\r
+       -@erase "$(INTDIR)\url.sbr"\r
+       -@erase "$(INTDIR)\wsockip.obj"\r
+       -@erase "$(INTDIR)\wsockip.sbr"\r
+       -@erase "$(OUTDIR)\ldap32.bsc"\r
+       -@erase "$(OUTDIR)\ldap32.dll"\r
+       -@erase "$(OUTDIR)\ldap32.exp"\r
+       -@erase "$(OUTDIR)\ldap32.lib"\r
+\r
+"$(OUTDIR)" :\r
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"\r
+\r
+# ADD BASE CPP /nologo /G3 /MT /W3 /Od /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "WINSOCK" /D "DOS" /D "NEEDPROTOS" /D "NO_USERINTERFACE" /D "KERBEROS" /YX /c\r
+# ADD CPP /nologo /G3 /MT /W3 /Od /I "..\..\include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "WINSOCK" /D "DOS" /D "NEEDPROTOS" /D "NO_USERINTERFACE" /D "_NODLLIMPORT_" /FR /YX /c\r
+CPP_PROJ=/nologo /G3 /MT /W3 /Od /I "..\..\include" /D "NDEBUG" /D "WIN32" /D\\r
+ "_WINDOWS" /D "WINSOCK" /D "DOS" /D "NEEDPROTOS" /D "NO_USERINTERFACE" /D\\r
+ "_NODLLIMPORT_" /FR"$(INTDIR)/" /Fp"$(INTDIR)/ldap32.pch" /YX /Fo"$(INTDIR)/"\\r
+ /c \r
+CPP_OBJS=.\Release/\r
+CPP_SBRS=.\Release/\r
+# ADD BASE MTL /nologo /D "NDEBUG" /win32\r
+# ADD MTL /nologo /D "NDEBUG" /win32\r
+MTL_PROJ=/nologo /D "NDEBUG" /win32 \r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)/libldap.res" /d "NDEBUG" \r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/ldap32.bsc" \r
+BSC32_SBRS= \\r
+       "$(INTDIR)\abandon.sbr" \\r
+       "$(INTDIR)\add.sbr" \\r
+       "$(INTDIR)\addentry.sbr" \\r
+       "$(INTDIR)\bind.sbr" \\r
+       "$(INTDIR)\cache.sbr" \\r
+       "$(INTDIR)\charset.sbr" \\r
+       "$(INTDIR)\compare.sbr" \\r
+       "$(INTDIR)\decode.sbr" \\r
+       "$(INTDIR)\delete.sbr" \\r
+       "$(INTDIR)\disptmpl.sbr" \\r
+       "$(INTDIR)\dsparse.sbr" \\r
+       "$(INTDIR)\encode.sbr" \\r
+       "$(INTDIR)\error.sbr" \\r
+       "$(INTDIR)\free.sbr" \\r
+       "$(INTDIR)\friendly.sbr" \\r
+       "$(INTDIR)\getattr.sbr" \\r
+       "$(INTDIR)\getdn.sbr" \\r
+       "$(INTDIR)\getentry.sbr" \\r
+       "$(INTDIR)\getfilte.sbr" \\r
+       "$(INTDIR)\getvalue.sbr" \\r
+       "$(INTDIR)\io.sbr" \\r
+       "$(INTDIR)\kbind.sbr" \\r
+       "$(INTDIR)\kerberos.sbr" \\r
+       "$(INTDIR)\modify.sbr" \\r
+       "$(INTDIR)\modrdn.sbr" \\r
+       "$(INTDIR)\msdos.sbr" \\r
+       "$(INTDIR)\open.sbr" \\r
+       "$(INTDIR)\regex.sbr" \\r
+       "$(INTDIR)\request.sbr" \\r
+       "$(INTDIR)\result.sbr" \\r
+       "$(INTDIR)\sbind.sbr" \\r
+       "$(INTDIR)\search.sbr" \\r
+       "$(INTDIR)\sort.sbr" \\r
+       "$(INTDIR)\srchpref.sbr" \\r
+       "$(INTDIR)\tmplout.sbr" \\r
+       "$(INTDIR)\ufn.sbr" \\r
+       "$(INTDIR)\unbind.sbr" \\r
+       "$(INTDIR)\url.sbr" \\r
+       "$(INTDIR)\wsockip.sbr"\r
+\r
+"$(OUTDIR)\ldap32.bsc" : "$(OUTDIR)" $(BSC32_SBRS)\r
+    $(BSC32) @<<\r
+  $(BSC32_FLAGS) $(BSC32_SBRS)\r
+<<\r
+\r
+LINK32=link.exe\r
+# ADD BASE LINK32 oldnames.lib ldllcew.lib krbv4win.lib wshelper.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /map:"FULL" /machine:IX86\r
+# ADD LINK32 WSOCK32.LIB oldnames.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:IX86\r
+# SUBTRACT LINK32 /map\r
+LINK32_FLAGS=WSOCK32.LIB oldnames.lib kernel32.lib user32.lib gdi32.lib\\r
+ winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib\\r
+ uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll\\r
+ /incremental:no /pdb:"$(OUTDIR)/ldap32.pdb" /machine:IX86\\r
+ /out:"$(OUTDIR)/ldap32.dll" /implib:"$(OUTDIR)/ldap32.lib" \r
+LINK32_OBJS= \\r
+       "$(INTDIR)\abandon.obj" \\r
+       "$(INTDIR)\add.obj" \\r
+       "$(INTDIR)\addentry.obj" \\r
+       "$(INTDIR)\bind.obj" \\r
+       "$(INTDIR)\cache.obj" \\r
+       "$(INTDIR)\charset.obj" \\r
+       "$(INTDIR)\compare.obj" \\r
+       "$(INTDIR)\decode.obj" \\r
+       "$(INTDIR)\delete.obj" \\r
+       "$(INTDIR)\disptmpl.obj" \\r
+       "$(INTDIR)\dsparse.obj" \\r
+       "$(INTDIR)\encode.obj" \\r
+       "$(INTDIR)\error.obj" \\r
+       "$(INTDIR)\free.obj" \\r
+       "$(INTDIR)\friendly.obj" \\r
+       "$(INTDIR)\getattr.obj" \\r
+       "$(INTDIR)\getdn.obj" \\r
+       "$(INTDIR)\getentry.obj" \\r
+       "$(INTDIR)\getfilte.obj" \\r
+       "$(INTDIR)\getvalue.obj" \\r
+       "$(INTDIR)\io.obj" \\r
+       "$(INTDIR)\kbind.obj" \\r
+       "$(INTDIR)\kerberos.obj" \\r
+       "$(INTDIR)\libldap.res" \\r
+       "$(INTDIR)\modify.obj" \\r
+       "$(INTDIR)\modrdn.obj" \\r
+       "$(INTDIR)\msdos.obj" \\r
+       "$(INTDIR)\open.obj" \\r
+       "$(INTDIR)\regex.obj" \\r
+       "$(INTDIR)\request.obj" \\r
+       "$(INTDIR)\result.obj" \\r
+       "$(INTDIR)\sbind.obj" \\r
+       "$(INTDIR)\search.obj" \\r
+       "$(INTDIR)\sort.obj" \\r
+       "$(INTDIR)\srchpref.obj" \\r
+       "$(INTDIR)\tmplout.obj" \\r
+       "$(INTDIR)\ufn.obj" \\r
+       "$(INTDIR)\unbind.obj" \\r
+       "$(INTDIR)\url.obj" \\r
+       "$(INTDIR)\wsockip.obj" \\r
+       "..\..\..\..\MSDEV\LIB\WSOCK32.LIB"\r
+\r
+"$(OUTDIR)\ldap32.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)\r
+    $(LINK32) @<<\r
+  $(LINK32_FLAGS) $(LINK32_OBJS)\r
+<<\r
+\r
+!ELSEIF  "$(CFG)" == "libldap - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "Debug"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Target_Dir ""\r
+OUTDIR=.\Debug\r
+INTDIR=.\Debug\r
+\r
+ALL : "$(OUTDIR)\ldap32.dll" "$(OUTDIR)\ldap32.bsc"\r
+\r
+CLEAN : \r
+       -@erase "$(INTDIR)\abandon.obj"\r
+       -@erase "$(INTDIR)\abandon.sbr"\r
+       -@erase "$(INTDIR)\add.obj"\r
+       -@erase "$(INTDIR)\add.sbr"\r
+       -@erase "$(INTDIR)\addentry.obj"\r
+       -@erase "$(INTDIR)\addentry.sbr"\r
+       -@erase "$(INTDIR)\bind.obj"\r
+       -@erase "$(INTDIR)\bind.sbr"\r
+       -@erase "$(INTDIR)\cache.obj"\r
+       -@erase "$(INTDIR)\cache.sbr"\r
+       -@erase "$(INTDIR)\charset.obj"\r
+       -@erase "$(INTDIR)\charset.sbr"\r
+       -@erase "$(INTDIR)\compare.obj"\r
+       -@erase "$(INTDIR)\compare.sbr"\r
+       -@erase "$(INTDIR)\decode.obj"\r
+       -@erase "$(INTDIR)\decode.sbr"\r
+       -@erase "$(INTDIR)\delete.obj"\r
+       -@erase "$(INTDIR)\delete.sbr"\r
+       -@erase "$(INTDIR)\disptmpl.obj"\r
+       -@erase "$(INTDIR)\disptmpl.sbr"\r
+       -@erase "$(INTDIR)\dsparse.obj"\r
+       -@erase "$(INTDIR)\dsparse.sbr"\r
+       -@erase "$(INTDIR)\encode.obj"\r
+       -@erase "$(INTDIR)\encode.sbr"\r
+       -@erase "$(INTDIR)\error.obj"\r
+       -@erase "$(INTDIR)\error.sbr"\r
+       -@erase "$(INTDIR)\free.obj"\r
+       -@erase "$(INTDIR)\free.sbr"\r
+       -@erase "$(INTDIR)\friendly.obj"\r
+       -@erase "$(INTDIR)\friendly.sbr"\r
+       -@erase "$(INTDIR)\getattr.obj"\r
+       -@erase "$(INTDIR)\getattr.sbr"\r
+       -@erase "$(INTDIR)\getdn.obj"\r
+       -@erase "$(INTDIR)\getdn.sbr"\r
+       -@erase "$(INTDIR)\getentry.obj"\r
+       -@erase "$(INTDIR)\getentry.sbr"\r
+       -@erase "$(INTDIR)\getfilte.obj"\r
+       -@erase "$(INTDIR)\getfilte.sbr"\r
+       -@erase "$(INTDIR)\getvalue.obj"\r
+       -@erase "$(INTDIR)\getvalue.sbr"\r
+       -@erase "$(INTDIR)\io.obj"\r
+       -@erase "$(INTDIR)\io.sbr"\r
+       -@erase "$(INTDIR)\kbind.obj"\r
+       -@erase "$(INTDIR)\kbind.sbr"\r
+       -@erase "$(INTDIR)\kerberos.obj"\r
+       -@erase "$(INTDIR)\kerberos.sbr"\r
+       -@erase "$(INTDIR)\libldap.res"\r
+       -@erase "$(INTDIR)\modify.obj"\r
+       -@erase "$(INTDIR)\modify.sbr"\r
+       -@erase "$(INTDIR)\modrdn.obj"\r
+       -@erase "$(INTDIR)\modrdn.sbr"\r
+       -@erase "$(INTDIR)\msdos.obj"\r
+       -@erase "$(INTDIR)\msdos.sbr"\r
+       -@erase "$(INTDIR)\open.obj"\r
+       -@erase "$(INTDIR)\open.sbr"\r
+       -@erase "$(INTDIR)\regex.obj"\r
+       -@erase "$(INTDIR)\regex.sbr"\r
+       -@erase "$(INTDIR)\request.obj"\r
+       -@erase "$(INTDIR)\request.sbr"\r
+       -@erase "$(INTDIR)\result.obj"\r
+       -@erase "$(INTDIR)\result.sbr"\r
+       -@erase "$(INTDIR)\sbind.obj"\r
+       -@erase "$(INTDIR)\sbind.sbr"\r
+       -@erase "$(INTDIR)\search.obj"\r
+       -@erase "$(INTDIR)\search.sbr"\r
+       -@erase "$(INTDIR)\sort.obj"\r
+       -@erase "$(INTDIR)\sort.sbr"\r
+       -@erase "$(INTDIR)\srchpref.obj"\r
+       -@erase "$(INTDIR)\srchpref.sbr"\r
+       -@erase "$(INTDIR)\tmplout.obj"\r
+       -@erase "$(INTDIR)\tmplout.sbr"\r
+       -@erase "$(INTDIR)\ufn.obj"\r
+       -@erase "$(INTDIR)\ufn.sbr"\r
+       -@erase "$(INTDIR)\unbind.obj"\r
+       -@erase "$(INTDIR)\unbind.sbr"\r
+       -@erase "$(INTDIR)\url.obj"\r
+       -@erase "$(INTDIR)\url.sbr"\r
+       -@erase "$(INTDIR)\vc40.idb"\r
+       -@erase "$(INTDIR)\vc40.pdb"\r
+       -@erase "$(INTDIR)\wsockip.obj"\r
+       -@erase "$(INTDIR)\wsockip.sbr"\r
+       -@erase "$(OUTDIR)\ldap32.bsc"\r
+       -@erase "$(OUTDIR)\ldap32.dll"\r
+       -@erase "$(OUTDIR)\ldap32.exp"\r
+       -@erase "$(OUTDIR)\ldap32.ilk"\r
+       -@erase "$(OUTDIR)\ldap32.lib"\r
+       -@erase "$(OUTDIR)\ldap32.pdb"\r
+\r
+"$(OUTDIR)" :\r
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"\r
+\r
+# ADD BASE CPP /nologo /MTd /W3 /Gm /Zi /Od /Gf /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "WINSOCK" /D "DOS" /D "NEEDPROTOS" /D "NO_USERINTERFACE" /D "KERBEROS" /FR /YX /c\r
+# ADD CPP /nologo /MTd /W3 /Gm /Zi /Od /Gf /I "..\..\include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "WINSOCK" /D "DOS" /D "NEEDPROTOS" /D "NO_USERINTERFACE" /D "_NODLLIMPORT_" /FR /YX /c\r
+CPP_PROJ=/nologo /MTd /W3 /Gm /Zi /Od /Gf /I "..\..\include" /D "_DEBUG" /D\\r
+ "WIN32" /D "_WINDOWS" /D "WINSOCK" /D "DOS" /D "NEEDPROTOS" /D\\r
+ "NO_USERINTERFACE" /D "_NODLLIMPORT_" /FR"$(INTDIR)/" /Fp"$(INTDIR)/ldap32.pch"\\r
+ /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c \r
+CPP_OBJS=.\Debug/\r
+CPP_SBRS=.\Debug/\r
+# ADD BASE MTL /nologo /D "_DEBUG" /win32\r
+# ADD MTL /nologo /D "_DEBUG" /win32\r
+MTL_PROJ=/nologo /D "_DEBUG" /win32 \r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)/libldap.res" /d "_DEBUG" \r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/ldap32.bsc" \r
+BSC32_SBRS= \\r
+       "$(INTDIR)\abandon.sbr" \\r
+       "$(INTDIR)\add.sbr" \\r
+       "$(INTDIR)\addentry.sbr" \\r
+       "$(INTDIR)\bind.sbr" \\r
+       "$(INTDIR)\cache.sbr" \\r
+       "$(INTDIR)\charset.sbr" \\r
+       "$(INTDIR)\compare.sbr" \\r
+       "$(INTDIR)\decode.sbr" \\r
+       "$(INTDIR)\delete.sbr" \\r
+       "$(INTDIR)\disptmpl.sbr" \\r
+       "$(INTDIR)\dsparse.sbr" \\r
+       "$(INTDIR)\encode.sbr" \\r
+       "$(INTDIR)\error.sbr" \\r
+       "$(INTDIR)\free.sbr" \\r
+       "$(INTDIR)\friendly.sbr" \\r
+       "$(INTDIR)\getattr.sbr" \\r
+       "$(INTDIR)\getdn.sbr" \\r
+       "$(INTDIR)\getentry.sbr" \\r
+       "$(INTDIR)\getfilte.sbr" \\r
+       "$(INTDIR)\getvalue.sbr" \\r
+       "$(INTDIR)\io.sbr" \\r
+       "$(INTDIR)\kbind.sbr" \\r
+       "$(INTDIR)\kerberos.sbr" \\r
+       "$(INTDIR)\modify.sbr" \\r
+       "$(INTDIR)\modrdn.sbr" \\r
+       "$(INTDIR)\msdos.sbr" \\r
+       "$(INTDIR)\open.sbr" \\r
+       "$(INTDIR)\regex.sbr" \\r
+       "$(INTDIR)\request.sbr" \\r
+       "$(INTDIR)\result.sbr" \\r
+       "$(INTDIR)\sbind.sbr" \\r
+       "$(INTDIR)\search.sbr" \\r
+       "$(INTDIR)\sort.sbr" \\r
+       "$(INTDIR)\srchpref.sbr" \\r
+       "$(INTDIR)\tmplout.sbr" \\r
+       "$(INTDIR)\ufn.sbr" \\r
+       "$(INTDIR)\unbind.sbr" \\r
+       "$(INTDIR)\url.sbr" \\r
+       "$(INTDIR)\wsockip.sbr"\r
+\r
+"$(OUTDIR)\ldap32.bsc" : "$(OUTDIR)" $(BSC32_SBRS)\r
+    $(BSC32) @<<\r
+  $(BSC32_FLAGS) $(BSC32_SBRS)\r
+<<\r
+\r
+LINK32=link.exe\r
+# ADD BASE LINK32 oldnames.lib ldllcew.lib krbv4win.lib wshelper.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /map:"FULL" /debug /machine:IX86\r
+# ADD LINK32 WSOCK32.LIB oldnames.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:IX86\r
+# SUBTRACT LINK32 /map\r
+LINK32_FLAGS=WSOCK32.LIB oldnames.lib kernel32.lib user32.lib gdi32.lib\\r
+ winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib\\r
+ uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll\\r
+ /incremental:yes /pdb:"$(OUTDIR)/ldap32.pdb" /debug /machine:IX86\\r
+ /def:".\ldap32.def" /out:"$(OUTDIR)/ldap32.dll" /implib:"$(OUTDIR)/ldap32.lib" \r
+DEF_FILE= \\r
+       ".\ldap32.def"\r
+LINK32_OBJS= \\r
+       "$(INTDIR)\abandon.obj" \\r
+       "$(INTDIR)\add.obj" \\r
+       "$(INTDIR)\addentry.obj" \\r
+       "$(INTDIR)\bind.obj" \\r
+       "$(INTDIR)\cache.obj" \\r
+       "$(INTDIR)\charset.obj" \\r
+       "$(INTDIR)\compare.obj" \\r
+       "$(INTDIR)\decode.obj" \\r
+       "$(INTDIR)\delete.obj" \\r
+       "$(INTDIR)\disptmpl.obj" \\r
+       "$(INTDIR)\dsparse.obj" \\r
+       "$(INTDIR)\encode.obj" \\r
+       "$(INTDIR)\error.obj" \\r
+       "$(INTDIR)\free.obj" \\r
+       "$(INTDIR)\friendly.obj" \\r
+       "$(INTDIR)\getattr.obj" \\r
+       "$(INTDIR)\getdn.obj" \\r
+       "$(INTDIR)\getentry.obj" \\r
+       "$(INTDIR)\getfilte.obj" \\r
+       "$(INTDIR)\getvalue.obj" \\r
+       "$(INTDIR)\io.obj" \\r
+       "$(INTDIR)\kbind.obj" \\r
+       "$(INTDIR)\kerberos.obj" \\r
+       "$(INTDIR)\libldap.res" \\r
+       "$(INTDIR)\modify.obj" \\r
+       "$(INTDIR)\modrdn.obj" \\r
+       "$(INTDIR)\msdos.obj" \\r
+       "$(INTDIR)\open.obj" \\r
+       "$(INTDIR)\regex.obj" \\r
+       "$(INTDIR)\request.obj" \\r
+       "$(INTDIR)\result.obj" \\r
+       "$(INTDIR)\sbind.obj" \\r
+       "$(INTDIR)\search.obj" \\r
+       "$(INTDIR)\sort.obj" \\r
+       "$(INTDIR)\srchpref.obj" \\r
+       "$(INTDIR)\tmplout.obj" \\r
+       "$(INTDIR)\ufn.obj" \\r
+       "$(INTDIR)\unbind.obj" \\r
+       "$(INTDIR)\url.obj" \\r
+       "$(INTDIR)\wsockip.obj" \\r
+       "..\..\..\..\MSDEV\LIB\WSOCK32.LIB"\r
+\r
+"$(OUTDIR)\ldap32.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)\r
+    $(LINK32) @<<\r
+  $(LINK32_FLAGS) $(LINK32_OBJS)\r
+<<\r
+\r
+!ENDIF \r
+\r
+.c{$(CPP_OBJS)}.obj:\r
+   $(CPP) $(CPP_PROJ) $<  \r
+\r
+.cpp{$(CPP_OBJS)}.obj:\r
+   $(CPP) $(CPP_PROJ) $<  \r
+\r
+.cxx{$(CPP_OBJS)}.obj:\r
+   $(CPP) $(CPP_PROJ) $<  \r
+\r
+.c{$(CPP_SBRS)}.sbr:\r
+   $(CPP) $(CPP_PROJ) $<  \r
+\r
+.cpp{$(CPP_SBRS)}.sbr:\r
+   $(CPP) $(CPP_PROJ) $<  \r
+\r
+.cxx{$(CPP_SBRS)}.sbr:\r
+   $(CPP) $(CPP_PROJ) $<  \r
+\r
+################################################################################\r
+# Begin Target\r
+\r
+# Name "libldap - Win32 Release"\r
+# Name "libldap - Win32 Debug"\r
+\r
+!IF  "$(CFG)" == "libldap - Win32 Release"\r
+\r
+!ELSEIF  "$(CFG)" == "libldap - Win32 Debug"\r
+\r
+!ENDIF \r
+\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\abandon.c\r
+DEP_CPP_ABAND=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\sys/time.h"\\r
+       "..\..\include\sys\socket.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       ".\ldap-int.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_ABAND=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       ".\macos.h"\\r
+       \r
+\r
+"$(INTDIR)\abandon.obj" : $(SOURCE) $(DEP_CPP_ABAND) "$(INTDIR)"\r
+\r
+"$(INTDIR)\abandon.sbr" : $(SOURCE) $(DEP_CPP_ABAND) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\add.c\r
+DEP_CPP_ADD_C=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\sys/time.h"\\r
+       "..\..\include\sys\socket.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       ".\ldap-int.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_ADD_C=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       ".\macos.h"\\r
+       \r
+\r
+"$(INTDIR)\add.obj" : $(SOURCE) $(DEP_CPP_ADD_C) "$(INTDIR)"\r
+\r
+"$(INTDIR)\add.sbr" : $(SOURCE) $(DEP_CPP_ADD_C) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\bind.c\r
+DEP_CPP_BIND_=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\sys/time.h"\\r
+       "..\..\include\sys\socket.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_BIND_=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       ".\externs.h"\\r
+       ".\macos.h"\\r
+       \r
+\r
+"$(INTDIR)\bind.obj" : $(SOURCE) $(DEP_CPP_BIND_) "$(INTDIR)"\r
+\r
+"$(INTDIR)\bind.sbr" : $(SOURCE) $(DEP_CPP_BIND_) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\cache.c\r
+DEP_CPP_CACHE=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\sys/time.h"\\r
+       "..\..\include\sys\socket.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       ".\ldap-int.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_CACHE=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       ".\externs.h"\\r
+       ".\macos.h"\\r
+       \r
+\r
+"$(INTDIR)\cache.obj" : $(SOURCE) $(DEP_CPP_CACHE) "$(INTDIR)"\r
+\r
+"$(INTDIR)\cache.sbr" : $(SOURCE) $(DEP_CPP_CACHE) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\compare.c\r
+DEP_CPP_COMPA=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\sys/time.h"\\r
+       "..\..\include\sys\socket.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       ".\ldap-int.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_COMPA=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       ".\macos.h"\\r
+       \r
+\r
+"$(INTDIR)\compare.obj" : $(SOURCE) $(DEP_CPP_COMPA) "$(INTDIR)"\r
+\r
+"$(INTDIR)\compare.sbr" : $(SOURCE) $(DEP_CPP_COMPA) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\delete.c\r
+DEP_CPP_DELET=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\sys/time.h"\\r
+       "..\..\include\sys\socket.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       ".\ldap-int.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_DELET=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       ".\macos.h"\\r
+       \r
+\r
+"$(INTDIR)\delete.obj" : $(SOURCE) $(DEP_CPP_DELET) "$(INTDIR)"\r
+\r
+"$(INTDIR)\delete.sbr" : $(SOURCE) $(DEP_CPP_DELET) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\error.c\r
+DEP_CPP_ERROR=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\sys/time.h"\\r
+       "..\..\include\sys\socket.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_ERROR=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       \r
+\r
+"$(INTDIR)\error.obj" : $(SOURCE) $(DEP_CPP_ERROR) "$(INTDIR)"\r
+\r
+"$(INTDIR)\error.sbr" : $(SOURCE) $(DEP_CPP_ERROR) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\getfilte.c\r
+DEP_CPP_GETFI=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\regex.h"\\r
+       "..\..\include\sys/file.h"\\r
+       "..\..\include\sys/time.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_GETFI=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       ".\macos.h"\\r
+       \r
+\r
+"$(INTDIR)\getfilte.obj" : $(SOURCE) $(DEP_CPP_GETFI) "$(INTDIR)"\r
+\r
+"$(INTDIR)\getfilte.sbr" : $(SOURCE) $(DEP_CPP_GETFI) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\regex.c\r
+DEP_CPP_REGEX=\\r
+       "..\..\include\portable.h"\\r
+       "..\..\include\regex.h"\\r
+       \r
+\r
+"$(INTDIR)\regex.obj" : $(SOURCE) $(DEP_CPP_REGEX) "$(INTDIR)"\r
+\r
+"$(INTDIR)\regex.sbr" : $(SOURCE) $(DEP_CPP_REGEX) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\modify.c\r
+DEP_CPP_MODIF=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\sys/time.h"\\r
+       "..\..\include\sys\socket.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       ".\ldap-int.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_MODIF=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       ".\macos.h"\\r
+       \r
+\r
+"$(INTDIR)\modify.obj" : $(SOURCE) $(DEP_CPP_MODIF) "$(INTDIR)"\r
+\r
+"$(INTDIR)\modify.sbr" : $(SOURCE) $(DEP_CPP_MODIF) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\modrdn.c\r
+DEP_CPP_MODRD=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\sys/time.h"\\r
+       "..\..\include\sys\socket.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       ".\ldap-int.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_MODRD=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       ".\macos.h"\\r
+       \r
+\r
+"$(INTDIR)\modrdn.obj" : $(SOURCE) $(DEP_CPP_MODRD) "$(INTDIR)"\r
+\r
+"$(INTDIR)\modrdn.sbr" : $(SOURCE) $(DEP_CPP_MODRD) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\getdn.c\r
+DEP_CPP_GETDN=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\sys/time.h"\\r
+       "..\..\include\sys\socket.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_GETDN=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       ".\macos.h"\\r
+       \r
+\r
+"$(INTDIR)\getdn.obj" : $(SOURCE) $(DEP_CPP_GETDN) "$(INTDIR)"\r
+\r
+"$(INTDIR)\getdn.sbr" : $(SOURCE) $(DEP_CPP_GETDN) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\getentry.c\r
+DEP_CPP_GETEN=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\sys/time.h"\\r
+       "..\..\include\sys\socket.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_GETEN=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       ".\macos.h"\\r
+       \r
+\r
+"$(INTDIR)\getentry.obj" : $(SOURCE) $(DEP_CPP_GETEN) "$(INTDIR)"\r
+\r
+"$(INTDIR)\getentry.sbr" : $(SOURCE) $(DEP_CPP_GETEN) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\getattr.c\r
+DEP_CPP_GETAT=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\sys/time.h"\\r
+       "..\..\include\sys\socket.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       ".\ldap-int.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_GETAT=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       ".\macos.h"\\r
+       \r
+\r
+"$(INTDIR)\getattr.obj" : $(SOURCE) $(DEP_CPP_GETAT) "$(INTDIR)"\r
+\r
+"$(INTDIR)\getattr.sbr" : $(SOURCE) $(DEP_CPP_GETAT) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\getvalue.c\r
+DEP_CPP_GETVA=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\sys/time.h"\\r
+       "..\..\include\sys\socket.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_GETVA=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       ".\macos.h"\\r
+       \r
+\r
+"$(INTDIR)\getvalue.obj" : $(SOURCE) $(DEP_CPP_GETVA) "$(INTDIR)"\r
+\r
+"$(INTDIR)\getvalue.sbr" : $(SOURCE) $(DEP_CPP_GETVA) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\addentry.c\r
+DEP_CPP_ADDEN=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\sys/time.h"\\r
+       "..\..\include\sys\socket.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_ADDEN=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       ".\macos.h"\\r
+       \r
+\r
+"$(INTDIR)\addentry.obj" : $(SOURCE) $(DEP_CPP_ADDEN) "$(INTDIR)"\r
+\r
+"$(INTDIR)\addentry.sbr" : $(SOURCE) $(DEP_CPP_ADDEN) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\result.c\r
+DEP_CPP_RESUL=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\portable.h"\\r
+       "..\..\include\sys/select.h"\\r
+       "..\..\include\sys/time.h"\\r
+       "..\..\include\sys\socket.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       ".\ldap-int.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_RESUL=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       ".\externs.h"\\r
+       ".\macos.h"\\r
+       ".\ucx_select.h"\\r
+       \r
+\r
+"$(INTDIR)\result.obj" : $(SOURCE) $(DEP_CPP_RESUL) "$(INTDIR)"\r
+\r
+"$(INTDIR)\result.sbr" : $(SOURCE) $(DEP_CPP_RESUL) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\search.c\r
+DEP_CPP_SEARC=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\sys/time.h"\\r
+       "..\..\include\sys\socket.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       ".\ldap-int.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_SEARC=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       ".\macos.h"\\r
+       \r
+\r
+"$(INTDIR)\search.obj" : $(SOURCE) $(DEP_CPP_SEARC) "$(INTDIR)"\r
+\r
+"$(INTDIR)\search.sbr" : $(SOURCE) $(DEP_CPP_SEARC) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\ufn.c\r
+DEP_CPP_UFN_C=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\sys/time.h"\\r
+       "..\..\include\sys\socket.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_UFN_C=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       ".\macos.h"\\r
+       \r
+\r
+"$(INTDIR)\ufn.obj" : $(SOURCE) $(DEP_CPP_UFN_C) "$(INTDIR)"\r
+\r
+"$(INTDIR)\ufn.sbr" : $(SOURCE) $(DEP_CPP_UFN_C) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\msdos.c\r
+DEP_CPP_MSDOS=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\sys/time.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       \r
+NODEP_CPP_MSDOS=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       \r
+\r
+"$(INTDIR)\msdos.obj" : $(SOURCE) $(DEP_CPP_MSDOS) "$(INTDIR)"\r
+\r
+"$(INTDIR)\msdos.sbr" : $(SOURCE) $(DEP_CPP_MSDOS) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\sbind.c\r
+DEP_CPP_SBIND=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\sys/time.h"\\r
+       "..\..\include\sys\socket.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       ".\ldap-int.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_SBIND=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       ".\macos.h"\\r
+       \r
+\r
+"$(INTDIR)\sbind.obj" : $(SOURCE) $(DEP_CPP_SBIND) "$(INTDIR)"\r
+\r
+"$(INTDIR)\sbind.sbr" : $(SOURCE) $(DEP_CPP_SBIND) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\unbind.c\r
+DEP_CPP_UNBIN=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\sys/time.h"\\r
+       "..\..\include\sys\socket.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       ".\ldap-int.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_UNBIN=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       ".\externs.h"\\r
+       ".\macos.h"\\r
+       \r
+\r
+"$(INTDIR)\unbind.obj" : $(SOURCE) $(DEP_CPP_UNBIN) "$(INTDIR)"\r
+\r
+"$(INTDIR)\unbind.sbr" : $(SOURCE) $(DEP_CPP_UNBIN) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\kbind.c\r
+DEP_CPP_KBIND=\\r
+       "..\..\include\conf.h"\\r
+       "..\..\include\des.h"\\r
+       "..\..\include\krb.h"\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\lsh_pwd.h"\\r
+       "..\..\include\mit_copy.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\sys/time.h"\\r
+       "..\..\include\sys\socket.h"\\r
+       ".\..\..\include\conf-pc.h"\\r
+       ".\..\..\include\osconf.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       ".\ldap-int.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_KBIND=\\r
+       ".\..\..\include\conf-bsd386i.h"\\r
+       ".\..\..\include\conf-bsdapollo.h"\\r
+       ".\..\..\include\conf-bsdibm032.h"\\r
+       ".\..\..\include\conf-bsdm68k.h"\\r
+       ".\..\..\include\conf-bsdsparc.h"\\r
+       ".\..\..\include\conf-bsdtahoe.h"\\r
+       ".\..\..\include\conf-bsdvax.h"\\r
+       ".\..\..\include\conf-pyr.h"\\r
+       ".\..\..\include\conf-ultmips2.h"\\r
+       ".\..\..\include\names.h"\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       ".\macos.h"\\r
+       \r
+\r
+"$(INTDIR)\kbind.obj" : $(SOURCE) $(DEP_CPP_KBIND) "$(INTDIR)"\r
+\r
+"$(INTDIR)\kbind.sbr" : $(SOURCE) $(DEP_CPP_KBIND) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\friendly.c\r
+DEP_CPP_FRIEN=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\sys/time.h"\\r
+       "..\..\include\sys\socket.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_FRIEN=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       ".\macos.h"\\r
+       \r
+\r
+"$(INTDIR)\friendly.obj" : $(SOURCE) $(DEP_CPP_FRIEN) "$(INTDIR)"\r
+\r
+"$(INTDIR)\friendly.sbr" : $(SOURCE) $(DEP_CPP_FRIEN) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\disptmpl.c\r
+DEP_CPP_DISPT=\\r
+       "..\..\include\disptmpl.h"\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\sys/file.h"\\r
+       "..\..\include\sys/time.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_DISPT=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       ".\macos.h"\\r
+       \r
+\r
+"$(INTDIR)\disptmpl.obj" : $(SOURCE) $(DEP_CPP_DISPT) "$(INTDIR)"\r
+\r
+"$(INTDIR)\disptmpl.sbr" : $(SOURCE) $(DEP_CPP_DISPT) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\dsparse.c\r
+DEP_CPP_DSPAR=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\sys/file.h"\\r
+       "..\..\include\sys/time.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_DSPAR=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       ".\macos.h"\\r
+       \r
+\r
+"$(INTDIR)\dsparse.obj" : $(SOURCE) $(DEP_CPP_DSPAR) "$(INTDIR)"\r
+\r
+"$(INTDIR)\dsparse.sbr" : $(SOURCE) $(DEP_CPP_DSPAR) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\free.c\r
+DEP_CPP_FREE_=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\sys/time.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_FREE_=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       ".\macos.h"\\r
+       \r
+\r
+"$(INTDIR)\free.obj" : $(SOURCE) $(DEP_CPP_FREE_) "$(INTDIR)"\r
+\r
+"$(INTDIR)\free.sbr" : $(SOURCE) $(DEP_CPP_FREE_) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\sort.c\r
+DEP_CPP_SORT_=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\sys/time.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       \r
+NODEP_CPP_SORT_=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       ".\macos.h"\\r
+       \r
+\r
+"$(INTDIR)\sort.obj" : $(SOURCE) $(DEP_CPP_SORT_) "$(INTDIR)"\r
+\r
+"$(INTDIR)\sort.sbr" : $(SOURCE) $(DEP_CPP_SORT_) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\srchpref.c\r
+DEP_CPP_SRCHP=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\srchpref.h"\\r
+       "..\..\include\sys/file.h"\\r
+       "..\..\include\sys/time.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_SRCHP=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       ".\macos.h"\\r
+       \r
+\r
+"$(INTDIR)\srchpref.obj" : $(SOURCE) $(DEP_CPP_SRCHP) "$(INTDIR)"\r
+\r
+"$(INTDIR)\srchpref.sbr" : $(SOURCE) $(DEP_CPP_SRCHP) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\tmplout.c\r
+DEP_CPP_TMPLO=\\r
+       "..\..\include\disptmpl.h"\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\sys/file.h"\\r
+       "..\..\include\sys/time.h"\\r
+       "..\..\include\sys\socket.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_TMPLO=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       ".\macos.h"\\r
+       \r
+\r
+"$(INTDIR)\tmplout.obj" : $(SOURCE) $(DEP_CPP_TMPLO) "$(INTDIR)"\r
+\r
+"$(INTDIR)\tmplout.sbr" : $(SOURCE) $(DEP_CPP_TMPLO) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\libldap.rc\r
+\r
+"$(INTDIR)\libldap.res" : $(SOURCE) "$(INTDIR)"\r
+   $(RSC) $(RSC_PROJ) $(SOURCE)\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\request.c\r
+DEP_CPP_REQUE=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\portable.h"\\r
+       "..\..\include\sys/select.h"\\r
+       "..\..\include\sys/time.h"\\r
+       "..\..\include\sys\socket.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       ".\ldap-int.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_REQUE=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       ".\externs.h"\\r
+       ".\macos.h"\\r
+       ".\ucx_select.h"\\r
+       \r
+\r
+"$(INTDIR)\request.obj" : $(SOURCE) $(DEP_CPP_REQUE) "$(INTDIR)"\r
+\r
+"$(INTDIR)\request.sbr" : $(SOURCE) $(DEP_CPP_REQUE) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\wsockip.c\r
+DEP_CPP_WSOCK=\\r
+       "..\..\include\_sys/filio.h"\\r
+       "..\..\include\_sys/ioctl.h"\\r
+       "..\..\include\arpa/nameser.h"\\r
+       "..\..\include\hesiod.h"\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\netdb.h"\\r
+       "..\..\include\netinet/in.h"\\r
+       "..\..\include\portable.h"\\r
+       "..\..\include\resolv.h"\\r
+       "..\..\include\sys/filio.h"\\r
+       "..\..\include\sys/ioctl.h"\\r
+       "..\..\include\sys/select.h"\\r
+       "..\..\include\sys/time.h"\\r
+       "..\..\include\sys\socket.h"\\r
+       "..\..\include\wshelper.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_WSOCK=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       \r
+\r
+"$(INTDIR)\wsockip.obj" : $(SOURCE) $(DEP_CPP_WSOCK) "$(INTDIR)"\r
+\r
+"$(INTDIR)\wsockip.sbr" : $(SOURCE) $(DEP_CPP_WSOCK) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\open.c\r
+DEP_CPP_OPEN_=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\netinet/in.h"\\r
+       "..\..\include\sys/param.h"\\r
+       "..\..\include\sys/time.h"\\r
+       "..\..\include\sys\socket.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       ".\ldap-int.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_OPEN_=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       ".\macos.h"\\r
+       \r
+\r
+"$(INTDIR)\open.obj" : $(SOURCE) $(DEP_CPP_OPEN_) "$(INTDIR)"\r
+\r
+"$(INTDIR)\open.sbr" : $(SOURCE) $(DEP_CPP_OPEN_) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\ldap32.def\r
+\r
+!IF  "$(CFG)" == "libldap - Win32 Release"\r
+\r
+# PROP Exclude_From_Build 1\r
+\r
+!ELSEIF  "$(CFG)" == "libldap - Win32 Debug"\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=\MSDEV\LIB\WSOCK32.LIB\r
+\r
+!IF  "$(CFG)" == "libldap - Win32 Release"\r
+\r
+!ELSEIF  "$(CFG)" == "libldap - Win32 Debug"\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\kerberos.c\r
+DEP_CPP_KERBE=\\r
+       "..\..\include\authlib.h"\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\sys/time.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       \r
+NODEP_CPP_KERBE=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       \r
+\r
+"$(INTDIR)\kerberos.obj" : $(SOURCE) $(DEP_CPP_KERBE) "$(INTDIR)"\r
+\r
+"$(INTDIR)\kerberos.sbr" : $(SOURCE) $(DEP_CPP_KERBE) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\url.c\r
+DEP_CPP_URL_C=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\sys/time.h"\\r
+       "..\..\include\sys\socket.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       ".\ldap-int.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_URL_C=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       ".\macos.h"\\r
+       \r
+\r
+"$(INTDIR)\url.obj" : $(SOURCE) $(DEP_CPP_URL_C) "$(INTDIR)"\r
+\r
+"$(INTDIR)\url.sbr" : $(SOURCE) $(DEP_CPP_URL_C) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\charset.c\r
+DEP_CPP_CHARS=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\ldap.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\sys/param.h"\\r
+       "..\..\include\sys/time.h"\\r
+       "..\..\include\sys\socket.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       ".\..\..\include\proto-ld.h"\\r
+       ".\ldap-int.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_CHARS=\\r
+       ".\..\..\include\proto-lber.h"\\r
+       ".\..\..\include\proto-ldap.h"\\r
+       ".\macos.h"\\r
+       \r
+\r
+"$(INTDIR)\charset.obj" : $(SOURCE) $(DEP_CPP_CHARS) "$(INTDIR)"\r
+\r
+"$(INTDIR)\charset.sbr" : $(SOURCE) $(DEP_CPP_CHARS) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE="\src\ldap-3.3b1\libraries\liblber\io.c"\r
+DEP_CPP_IO_C48=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\netinet/in.h"\\r
+       "..\..\include\sys\socket.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_IO_C48=\\r
+       "..\liblber\macos.h"\\r
+       ".\..\..\include\proto-lber.h"\\r
+       \r
+\r
+BuildCmds= \\r
+       $(CPP) $(CPP_PROJ) $(SOURCE) \\r
+       \r
+\r
+"$(INTDIR)\io.obj" : $(SOURCE) $(DEP_CPP_IO_C48) "$(INTDIR)"\r
+   $(BuildCmds)\r
+\r
+"$(INTDIR)\io.sbr" : $(SOURCE) $(DEP_CPP_IO_C48) "$(INTDIR)"\r
+   $(BuildCmds)\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE="\src\ldap-3.3b1\libraries\liblber\encode.c"\r
+DEP_CPP_ENCOD=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\netinet/in.h"\\r
+       "..\..\include\sys\socket.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_ENCOD=\\r
+       "..\liblber\macos.h"\\r
+       ".\..\..\include\proto-lber.h"\\r
+       \r
+\r
+BuildCmds= \\r
+       $(CPP) $(CPP_PROJ) $(SOURCE) \\r
+       \r
+\r
+"$(INTDIR)\encode.obj" : $(SOURCE) $(DEP_CPP_ENCOD) "$(INTDIR)"\r
+   $(BuildCmds)\r
+\r
+"$(INTDIR)\encode.sbr" : $(SOURCE) $(DEP_CPP_ENCOD) "$(INTDIR)"\r
+   $(BuildCmds)\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE="\src\ldap-3.3b1\libraries\liblber\decode.c"\r
+DEP_CPP_DECOD=\\r
+       "..\..\include\lber.h"\\r
+       "..\..\include\msdos.h"\\r
+       "..\..\include\netinet/in.h"\\r
+       "..\..\include\sys\socket.h"\\r
+       ".\..\..\include\proto-lb.h"\\r
+       {$(INCLUDE)}"\sys\TYPES.H"\\r
+       \r
+NODEP_CPP_DECOD=\\r
+       "..\liblber\macos.h"\\r
+       ".\..\..\include\proto-lber.h"\\r
+       \r
+\r
+BuildCmds= \\r
+       $(CPP) $(CPP_PROJ) $(SOURCE) \\r
+       \r
+\r
+"$(INTDIR)\decode.obj" : $(SOURCE) $(DEP_CPP_DECOD) "$(INTDIR)"\r
+   $(BuildCmds)\r
+\r
+"$(INTDIR)\decode.sbr" : $(SOURCE) $(DEP_CPP_DECOD) "$(INTDIR)"\r
+   $(BuildCmds)\r
+\r
+# End Source File\r
+# End Target\r
+# End Project\r
+################################################################################\r
diff --git a/libraries/msdos/winsock/ldap32.mdp b/libraries/msdos/winsock/ldap32.mdp
new file mode 100644 (file)
index 0000000..a3f977e
Binary files /dev/null and b/libraries/msdos/winsock/ldap32.mdp differ
diff --git a/libraries/msdos/winsock/libldap.def b/libraries/msdos/winsock/libldap.def
new file mode 100644 (file)
index 0000000..33f39ed
--- /dev/null
@@ -0,0 +1,165 @@
+LIBRARY         LIBLDAP\r
+DESCRIPTION     'Lightweight Directory Access Protocol Client API'\r
+EXETYPE         WINDOWS\r
+CODE            PRELOAD MOVEABLE DISCARDABLE\r
+DATA            PRELOAD MOVEABLE SINGLE\r
+\r
+HEAPSIZE        4096\r
+\r
+EXPORTS\r
+       _ldap_abandon                           @10\r
+       _ldap_add                                       @11\r
+       _ldap_unbind                            @13\r
+       _ldap_enable_cache                      @14\r
+       _ldap_disable_cache                     @15\r
+       _ldap_destroy_cache                     @16\r
+       _ldap_flush_cache                       @17\r
+       _ldap_uncache_entry                     @18\r
+       _ldap_compare                           @19\r
+       _ldap_delete                            @20\r
+       _ldap_result2error                      @21\r
+       _ldap_err2string                        @22\r
+       _ldap_modify                            @23\r
+       _ldap_modrdn                            @24\r
+       _ldap_open                                      @25\r
+       _ldap_first_entry                       @26\r
+       _ldap_next_entry                        @27\r
+       _ldap_delete_result_entry       @28\r
+       _ldap_add_result_entry          @29\r
+       _ldap_get_dn                            @30\r
+       _ldap_dn2ufn                            @31\r
+       _ldap_first_attribute           @32\r
+       _ldap_next_attribute            @33\r
+       _ldap_get_values                        @34\r
+       _ldap_get_values_len            @35\r
+       _ldap_count_entries                     @36\r
+       _ldap_count_values                      @37\r
+       _ldap_value_free                        @38\r
+       _ldap_explode_dn                        @39\r
+       _ldap_result                            @40\r
+       _ldap_msgfree                           @41\r
+       _ldap_msgdelete                         @42\r
+       _ldap_search                            @43\r
+       _ldap_add_s                                     @44\r
+       _ldap_bind_s                            @45\r
+       _ldap_unbind_s                          @46\r
+       _ldap_delete_s                          @47\r
+       _ldap_modify_s                          @48\r
+       _ldap_modrdn_s                          @49\r
+       _ldap_search_s                          @50\r
+       _ldap_search_st                         @51\r
+       _ldap_compare_s                         @52\r
+       _ldap_ufn_search_c                      @53\r
+       _ldap_ufn_search_s                      @54\r
+       _ldap_init_getfilter            @55\r
+       _ldap_getfilter_free            @56\r
+       _ldap_getfirstfilter            @57\r
+       _ldap_getnextfilter                     @58\r
+       _ldap_simple_bind                       @59\r
+       _ldap_simple_bind_s                     @60\r
+       _ldap_bind                                      @61\r
+       _ldap_friendly_name                     @62\r
+       _ldap_free_friendlymap          @63\r
+       _ldap_ufn_search_ct                     @64\r
+       _ldap_set_cache_options         @65\r
+       _ldap_uncache_request           @66\r
+       _ldap_modrdn2                           @67\r
+       _ldap_modrdn2_s                         @68\r
+       _ldap_ufn_setfilter                     @69\r
+       _ldap_ufn_setprefix                     @70\r
+       _ldap_ufn_timeout                       @71\r
+       _ldap_init_getfilter_buf        @72\r
+       _ldap_setfilteraffixes          @73\r
+       _ldap_sort_entries                      @74\r
+       _ldap_sort_values                       @75\r
+       _ldap_sort_strcasecmp           @76\r
+       _ldap_count_values_len          @77\r
+       _ldap_name2template             @78\r
+       _ldap_value_free_len            @79\r
+\r
+; manually comment and uncomment these five as necessary\r
+       _ldap_kerberos_bind1            @80\r
+       _ldap_kerberos_bind2            @81\r
+       _ldap_kerberos_bind_s           @82\r
+       _ldap_kerberos_bind1_s          @83\r
+       _ldap_kerberos_bind2_s          @84\r
+\r
+       _ldap_init                      @85\r
+       _ldap_is_dns_dn                 @86\r
+       _ldap_explode_dns               @87\r
+       _ldap_mods_free                 @88\r
+\r
+       _ldap_is_ldap_url               @89\r
+       _ldap_free_urldesc              @90\r
+       _ldap_url_parse                 @91\r
+       _ldap_url_search                @92\r
+       _ldap_url_search_s              @93\r
+       _ldap_url_search_st             @94\r
+       _ldap_set_rebind_proc           @95\r
+\r
+       _ber_skip_tag                           @100\r
+       _ber_peek_tag                           @101\r
+       _ber_get_int                            @102\r
+       _ber_get_stringb                        @103\r
+       _ber_get_stringa                        @104\r
+       _ber_get_stringal                       @105\r
+       _ber_get_bitstringa                     @106\r
+       _ber_get_null                           @107\r
+       _ber_get_boolean                        @108\r
+       _ber_first_element                      @109\r
+       _ber_next_element                       @110\r
+       _ber_scanf                                      @111\r
+       _ber_bvfree                                     @112\r
+       _ber_bvecfree                           @113\r
+       _ber_put_int                            @114\r
+       _ber_put_ostring                        @115\r
+       _ber_put_string                         @116\r
+       _ber_put_bitstring                      @117\r
+       _ber_put_null                           @118\r
+       _ber_put_boolean                        @119\r
+       _ber_start_seq                          @120\r
+       _ber_start_set                          @121\r
+       _ber_put_seq                            @122\r
+       _ber_put_set                            @123\r
+       _ber_printf                                     @124\r
+       _ber_read                                       @125\r
+       _ber_write                                      @126\r
+       _ber_free                                       @127\r
+       _ber_flush                                      @128\r
+       _ber_alloc                                      @129\r
+       _ber_dup                                        @130\r
+       _ber_get_next                           @131\r
+       _ber_get_tag                            @132\r
+       _ber_put_enum                           @133\r
+       _der_alloc                                      @134\r
+       _ber_alloc_t                            @135\r
+       _ber_bvdup                              @136\r
+       _ber_init                               @137\r
+       _ber_reset                              @138\r
+\r
+       _ldap_memfree                           @200\r
+\r
+       _ldap_init_searchprefs          @300\r
+       _ldap_init_searchprefs_buf      @301\r
+       _ldap_free_searchprefs          @302\r
+       _ldap_first_searchobj           @303\r
+       _ldap_next_searchobj            @304\r
+       _ldap_build_filter                      @305\r
+\r
+       _ldap_init_templates            @400\r
+       _ldap_init_templates_buf        @401\r
+       _ldap_free_templates            @402\r
+       _ldap_first_disptmpl            @403\r
+       _ldap_next_disptmpl                     @404\r
+       _ldap_oc2template                       @405\r
+       _ldap_tmplattrs                         @406\r
+       _ldap_first_tmplrow                     @407\r
+       _ldap_next_tmplrow                      @408\r
+       _ldap_first_tmplcol                     @409\r
+       _ldap_next_tmplcol                      @410\r
+       _ldap_entry2text_search         @411\r
+       _ldap_entry2text                        @412\r
+       _ldap_vals2text                         @413\r
+       _ldap_entry2html                        @414\r
+       _ldap_entry2html_search                 @415\r
+       _ldap_vals2html                         @416\r
diff --git a/libraries/msdos/winsock/libldap.mak b/libraries/msdos/winsock/libldap.mak
new file mode 100644 (file)
index 0000000..7a6b327
--- /dev/null
@@ -0,0 +1,667 @@
+# Microsoft Visual C++ generated build script - Do not modify\r
+\r
+PROJ = LIBLDAP\r
+DEBUG = 0\r
+PROGTYPE = 1\r
+CALLER = \r
+ARGS = \r
+DLLS = \r
+D_RCDEFINES = /d_DEBUG \r
+R_RCDEFINES = /dNDEBUG \r
+ORIGIN = MSVC\r
+ORIGIN_VER = 1.00\r
+PROJPATH = C:\SRC\LDAP\LIBRAR~1\LIBLDAP\\r
+USEMFC = 0\r
+CC = cl\r
+CPP = cl\r
+CXX = cl\r
+CCREATEPCHFLAG = \r
+CPPCREATEPCHFLAG = \r
+CUSEPCHFLAG = \r
+CPPUSEPCHFLAG = \r
+FIRSTC = ABANDON.C   \r
+FIRSTCPP =             \r
+RC = rc\r
+CFLAGS_D_WDLL = /nologo /G2 /W3 /Gf /Zi /ALu /Od /D "_DEBUG" /D "WINSOCK" /D "DOS" /D "NEEDPROTOS" /D "NO_USERINTERFACE" /D "KERBEROS" /FR /Fd"LIBLDAP.PDB"\r
+CFLAGS_R_WDLL = /nologo /f- /G3 /W3 /Gf /ALu /Od /D "NDEBUG" /D "WINSOCK" /D "DOS" /D "NEEDPROTOS" /D "NO_USERINTERFACE" /D "KERBEROS" \r
+LFLAGS_D_WDLL = /NOLOGO /NOD /NOE /PACKC:61440 /ALIGN:16 /ONERROR:NOEXE /CO /MAP:FULL\r
+LFLAGS_R_WDLL = /NOLOGO /NOD /NOE /PACKC:61440 /ALIGN:16 /ONERROR:NOEXE /MAP:FULL\r
+LIBS_D_WDLL = oldnames libw ldllcew krbv4win commdlg.lib olecli.lib olesvr.lib shell.lib \r
+LIBS_R_WDLL = oldnames libw ldllcew krbv4win commdlg.lib olecli.lib olesvr.lib shell.lib \r
+RCFLAGS = /nologo \r
+RESFLAGS = /nologo \r
+RUNFLAGS = \r
+DEFFILE = LIBLDAP.DEF\r
+OBJS_EXT = \r
+LIBS_EXT = WINSOCK.LIB \r
+!if "$(DEBUG)" == "1"\r
+CFLAGS = $(CFLAGS_D_WDLL)\r
+LFLAGS = $(LFLAGS_D_WDLL)\r
+LIBS = $(LIBS_D_WDLL)\r
+MAPFILE = nul\r
+RCDEFINES = $(D_RCDEFINES)\r
+!else\r
+CFLAGS = $(CFLAGS_R_WDLL)\r
+LFLAGS = $(LFLAGS_R_WDLL)\r
+LIBS = $(LIBS_R_WDLL)\r
+MAPFILE = nul\r
+RCDEFINES = $(R_RCDEFINES)\r
+!endif\r
+!if [if exist MSVC.BND del MSVC.BND]\r
+!endif\r
+SBRS = ABANDON.SBR \\r
+               ADD.SBR \\r
+               BIND.SBR \\r
+               CACHE.SBR \\r
+               COMPARE.SBR \\r
+               DELETE.SBR \\r
+               ERROR.SBR \\r
+               GETFILTE.SBR \\r
+               REGEX.SBR \\r
+               MODIFY.SBR \\r
+               MODRDN.SBR \\r
+               GETDN.SBR \\r
+               GETENTRY.SBR \\r
+               GETATTR.SBR \\r
+               GETVALUE.SBR \\r
+               ADDENTRY.SBR \\r
+               RESULT.SBR \\r
+               SEARCH.SBR \\r
+               UFN.SBR \\r
+               DECODE.SBR \\r
+               ENCODE.SBR \\r
+               IO.SBR \\r
+               MSDOS.SBR \\r
+               SBIND.SBR \\r
+               UNBIND.SBR \\r
+               KBIND.SBR \\r
+               FRIENDLY.SBR \\r
+               DISPTMPL.SBR \\r
+               DSPARSE.SBR \\r
+               FREE.SBR \\r
+               SORT.SBR \\r
+               SRCHPREF.SBR \\r
+               TMPLOUT.SBR \\r
+               REQUEST.SBR \\r
+               WSOCKIP.SBR \\r
+               OPEN.SBR \\r
+               CHARSET.SBR \\r
+               URL.SBR\r
+\r
+\r
+WINSOCK_DEP = \r
+\r
+ABANDON_DEP = c:\src\ldap\include\sys/socket.h \\r
+       c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\proto-ld.h \\r
+       c:\src\ldap\librar~1\libldap\ldap-int.h\r
+\r
+\r
+ADD_DEP = c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\sys/socket.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\proto-ld.h \\r
+       c:\src\ldap\librar~1\libldap\ldap-int.h\r
+\r
+\r
+BIND_DEP = c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\sys/socket.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\proto-ld.h\r
+\r
+\r
+CACHE_DEP = c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\sys/socket.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\proto-ld.h \\r
+       c:\src\ldap\librar~1\libldap\ldap-int.h\r
+\r
+\r
+COMPARE_DEP = c:\src\ldap\include\sys/socket.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\proto-ld.h \\r
+       c:\src\ldap\librar~1\libldap\ldap-int.h\r
+\r
+\r
+DELETE_DEP = c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\sys/socket.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\proto-ld.h \\r
+       c:\src\ldap\librar~1\libldap\ldap-int.h\r
+\r
+\r
+ERROR_DEP = c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\sys/socket.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\proto-ld.h\r
+\r
+\r
+GETFILTE_DEP = c:\src\ldap\include\regex.h \\r
+       c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\sys/file.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\proto-ld.h\r
+\r
+\r
+REGEX_DEP = c:\src\ldap\include\portable.h \\r
+       c:\src\ldap\include\regex.h\r
+\r
+\r
+MODIFY_DEP = c:\src\ldap\include\sys/socket.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\proto-ld.h \\r
+       c:\src\ldap\librar~1\libldap\ldap-int.h\r
+\r
+\r
+MODRDN_DEP = c:\src\ldap\include\sys/socket.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\proto-ld.h \\r
+       c:\src\ldap\librar~1\libldap\ldap-int.h\r
+\r
+\r
+GETDN_DEP = c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\sys/socket.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\proto-ld.h\r
+\r
+\r
+GETENTRY_DEP = c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\sys/socket.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\proto-ld.h\r
+\r
+\r
+GETATTR_DEP = c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\sys/socket.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\proto-ld.h \\r
+       c:\src\ldap\librar~1\libldap\ldap-int.h\r
+\r
+\r
+GETVALUE_DEP = c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\sys/socket.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\proto-ld.h\r
+\r
+\r
+ADDENTRY_DEP = c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\sys/socket.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\proto-ld.h\r
+\r
+\r
+RESULT_DEP = c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\sys/socket.h \\r
+       c:\src\ldap\include\sys/select.h \\r
+       c:\src\ldap\include\portable.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\proto-ld.h \\r
+       c:\src\ldap\librar~1\libldap\ldap-int.h\r
+\r
+\r
+SEARCH_DEP = c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\sys/socket.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\proto-ld.h \\r
+       c:\src\ldap\librar~1\libldap\ldap-int.h\r
+\r
+\r
+UFN_DEP = c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\sys/socket.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\proto-ld.h\r
+\r
+\r
+DECODE_DEP = c:\src\ldap\include\sys/socket.h \\r
+       c:\src\ldap\include\netinet/in.h \\r
+       c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h\r
+\r
+\r
+ENCODE_DEP = c:\src\ldap\include\sys/socket.h \\r
+       c:\src\ldap\include\netinet/in.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h\r
+\r
+\r
+IO_DEP = c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\sys/socket.h \\r
+       c:\src\ldap\include\netinet/in.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h\r
+\r
+\r
+MSDOS_DEP = c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\proto-ld.h\r
+\r
+\r
+SBIND_DEP = c:\src\ldap\include\sys/socket.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\proto-ld.h \\r
+       c:\src\ldap\librar~1\libldap\ldap-int.h\r
+\r
+\r
+UNBIND_DEP = c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\sys/socket.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\proto-ld.h \\r
+       c:\src\ldap\librar~1\libldap\ldap-int.h\r
+\r
+\r
+KBIND_DEP = c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\krb.h \\r
+       c:\src\ldap\include\mit_copy.h \\r
+       c:\src\ldap\include\conf.h \\r
+       c:\src\ldap\include\osconf.h \\r
+       c:\src\ldap\include\conf-pc.h \\r
+       c:\src\ldap\include\des.h \\r
+       c:\src\ldap\include\lsh_pwd.h \\r
+       c:\src\ldap\include\sys/socket.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\proto-ld.h \\r
+       c:\src\ldap\librar~1\libldap\ldap-int.h\r
+\r
+\r
+FRIENDLY_DEP = c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\sys/socket.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\proto-ld.h\r
+\r
+\r
+DISPTMPL_DEP = c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\sys/file.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\proto-ld.h \\r
+       c:\src\ldap\include\disptmpl.h\r
+\r
+\r
+DSPARSE_DEP = c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\sys/file.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\proto-ld.h\r
+\r
+\r
+FREE_DEP = c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\proto-ld.h\r
+\r
+\r
+SORT_DEP = c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\proto-ld.h\r
+\r
+\r
+SRCHPREF_DEP = c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\sys/file.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\proto-ld.h \\r
+       c:\src\ldap\include\srchpref.h\r
+\r
+\r
+TMPLOUT_DEP = c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\sys/file.h \\r
+       c:\src\ldap\include\sys/socket.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\proto-ld.h \\r
+       c:\src\ldap\include\disptmpl.h\r
+\r
+\r
+LIBLDAP_RCDEP = \r
+\r
+REQUEST_DEP = c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\sys/socket.h \\r
+       c:\src\ldap\include\sys/select.h \\r
+       c:\src\ldap\include\portable.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\proto-ld.h \\r
+       c:\src\ldap\librar~1\libldap\ldap-int.h\r
+\r
+\r
+WSOCKIP_DEP = c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\wshelper.h \\r
+       c:\src\ldap\include\resolv.h \\r
+       c:\src\ldap\include\arpa/nameser.h \\r
+       c:\src\ldap\include\hesiod.h \\r
+       c:\src\ldap\include\sys/socket.h \\r
+       c:\src\ldap\include\netinet/in.h \\r
+       c:\src\ldap\include\netdb.h \\r
+       c:\src\ldap\include\sys\socket.h \\r
+       c:\src\ldap\include\sys/select.h \\r
+       c:\src\ldap\include\portable.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\proto-ld.h \\r
+       c:\src\ldap\include\_sys/filio.h \\r
+       c:\src\ldap\include\sys/filio.h \\r
+       c:\src\ldap\include\_sys/ioctl.h \\r
+       c:\src\ldap\include\sys/ioctl.h\r
+\r
+\r
+OPEN_DEP = c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\sys/socket.h \\r
+       c:\src\ldap\include\sys/param.h \\r
+       c:\src\ldap\include\netinet/in.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\proto-ld.h \\r
+       c:\src\ldap\librar~1\libldap\ldap-int.h\r
+\r
+\r
+CHARSET_DEP = c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\sys/socket.h \\r
+       c:\src\ldap\include\sys/param.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\proto-ld.h \\r
+       c:\src\ldap\librar~1\libldap\ldap-int.h\r
+\r
+\r
+URL_DEP = c:\src\ldap\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       c:\src\ldap\include\sys/socket.h \\r
+       c:\src\ldap\include\lber.h \\r
+       c:\src\ldap\include\proto-lb.h \\r
+       c:\src\ldap\include\ldap.h \\r
+       c:\src\ldap\include\proto-ld.h \\r
+       c:\src\ldap\librar~1\libldap\ldap-int.h\r
+\r
+\r
+all:   $(PROJ).DLL\r
+\r
+ABANDON.OBJ:   ABANDON.C $(ABANDON_DEP)\r
+       $(CC) $(CFLAGS) $(CCREATEPCHFLAG) /c ABANDON.C\r
+\r
+ADD.OBJ:       ADD.C $(ADD_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c ADD.C\r
+\r
+BIND.OBJ:      BIND.C $(BIND_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c BIND.C\r
+\r
+CACHE.OBJ:     CACHE.C $(CACHE_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c CACHE.C\r
+\r
+COMPARE.OBJ:   COMPARE.C $(COMPARE_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c COMPARE.C\r
+\r
+DELETE.OBJ:    DELETE.C $(DELETE_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c DELETE.C\r
+\r
+ERROR.OBJ:     ERROR.C $(ERROR_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c ERROR.C\r
+\r
+GETFILTE.OBJ:  GETFILTE.C $(GETFILTE_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c GETFILTE.C\r
+\r
+REGEX.OBJ:     REGEX.C $(REGEX_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c REGEX.C\r
+\r
+MODIFY.OBJ:    MODIFY.C $(MODIFY_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c MODIFY.C\r
+\r
+MODRDN.OBJ:    MODRDN.C $(MODRDN_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c MODRDN.C\r
+\r
+GETDN.OBJ:     GETDN.C $(GETDN_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c GETDN.C\r
+\r
+GETENTRY.OBJ:  GETENTRY.C $(GETENTRY_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c GETENTRY.C\r
+\r
+GETATTR.OBJ:   GETATTR.C $(GETATTR_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c GETATTR.C\r
+\r
+GETVALUE.OBJ:  GETVALUE.C $(GETVALUE_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c GETVALUE.C\r
+\r
+ADDENTRY.OBJ:  ADDENTRY.C $(ADDENTRY_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c ADDENTRY.C\r
+\r
+RESULT.OBJ:    RESULT.C $(RESULT_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c RESULT.C\r
+\r
+SEARCH.OBJ:    SEARCH.C $(SEARCH_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c SEARCH.C\r
+\r
+UFN.OBJ:       UFN.C $(UFN_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c UFN.C\r
+\r
+DECODE.OBJ:    ..\LIBLBER\DECODE.C $(DECODE_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c ..\LIBLBER\DECODE.C\r
+\r
+ENCODE.OBJ:    ..\LIBLBER\ENCODE.C $(ENCODE_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c ..\LIBLBER\ENCODE.C\r
+\r
+IO.OBJ:        ..\LIBLBER\IO.C $(IO_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c ..\LIBLBER\IO.C\r
+\r
+MSDOS.OBJ:     MSDOS.C $(MSDOS_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c MSDOS.C\r
+\r
+SBIND.OBJ:     SBIND.C $(SBIND_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c SBIND.C\r
+\r
+UNBIND.OBJ:    UNBIND.C $(UNBIND_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c UNBIND.C\r
+\r
+KBIND.OBJ:     KBIND.C $(KBIND_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c KBIND.C\r
+\r
+FRIENDLY.OBJ:  FRIENDLY.C $(FRIENDLY_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c FRIENDLY.C\r
+\r
+DISPTMPL.OBJ:  DISPTMPL.C $(DISPTMPL_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c DISPTMPL.C\r
+\r
+DSPARSE.OBJ:   DSPARSE.C $(DSPARSE_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c DSPARSE.C\r
+\r
+FREE.OBJ:      FREE.C $(FREE_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c FREE.C\r
+\r
+SORT.OBJ:      SORT.C $(SORT_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c SORT.C\r
+\r
+SRCHPREF.OBJ:  SRCHPREF.C $(SRCHPREF_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c SRCHPREF.C\r
+\r
+TMPLOUT.OBJ:   TMPLOUT.C $(TMPLOUT_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c TMPLOUT.C\r
+\r
+LIBLDAP.RES:   LIBLDAP.RC $(LIBLDAP_RCDEP)\r
+       $(RC) $(RCFLAGS) $(RCDEFINES) -r LIBLDAP.RC\r
+\r
+REQUEST.OBJ:   REQUEST.C $(REQUEST_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c REQUEST.C\r
+\r
+WSOCKIP.OBJ:   WSOCKIP.C $(WSOCKIP_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c WSOCKIP.C\r
+\r
+OPEN.OBJ:      OPEN.C $(OPEN_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c OPEN.C\r
+\r
+CHARSET.OBJ:   CHARSET.C $(CHARSET_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c CHARSET.C\r
+\r
+URL.OBJ:       URL.C $(URL_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c URL.C\r
+\r
+\r
+$(PROJ).DLL::  LIBLDAP.RES\r
+\r
+$(PROJ).DLL::  ABANDON.OBJ ADD.OBJ BIND.OBJ CACHE.OBJ COMPARE.OBJ DELETE.OBJ ERROR.OBJ \\r
+       GETFILTE.OBJ REGEX.OBJ MODIFY.OBJ MODRDN.OBJ GETDN.OBJ GETENTRY.OBJ GETATTR.OBJ GETVALUE.OBJ \\r
+       ADDENTRY.OBJ RESULT.OBJ SEARCH.OBJ UFN.OBJ DECODE.OBJ ENCODE.OBJ IO.OBJ MSDOS.OBJ \\r
+       SBIND.OBJ UNBIND.OBJ KBIND.OBJ FRIENDLY.OBJ DISPTMPL.OBJ DSPARSE.OBJ FREE.OBJ SORT.OBJ \\r
+       SRCHPREF.OBJ TMPLOUT.OBJ REQUEST.OBJ WSOCKIP.OBJ OPEN.OBJ CHARSET.OBJ URL.OBJ $(OBJS_EXT) $(DEFFILE)\r
+       echo >NUL @<<$(PROJ).CRF\r
+ABANDON.OBJ +\r
+ADD.OBJ +\r
+BIND.OBJ +\r
+CACHE.OBJ +\r
+COMPARE.OBJ +\r
+DELETE.OBJ +\r
+ERROR.OBJ +\r
+GETFILTE.OBJ +\r
+REGEX.OBJ +\r
+MODIFY.OBJ +\r
+MODRDN.OBJ +\r
+GETDN.OBJ +\r
+GETENTRY.OBJ +\r
+GETATTR.OBJ +\r
+GETVALUE.OBJ +\r
+ADDENTRY.OBJ +\r
+RESULT.OBJ +\r
+SEARCH.OBJ +\r
+UFN.OBJ +\r
+DECODE.OBJ +\r
+ENCODE.OBJ +\r
+IO.OBJ +\r
+MSDOS.OBJ +\r
+SBIND.OBJ +\r
+UNBIND.OBJ +\r
+KBIND.OBJ +\r
+FRIENDLY.OBJ +\r
+DISPTMPL.OBJ +\r
+DSPARSE.OBJ +\r
+FREE.OBJ +\r
+SORT.OBJ +\r
+SRCHPREF.OBJ +\r
+TMPLOUT.OBJ +\r
+REQUEST.OBJ +\r
+WSOCKIP.OBJ +\r
+OPEN.OBJ +\r
+CHARSET.OBJ +\r
+URL.OBJ +\r
+$(OBJS_EXT)\r
+$(PROJ).DLL\r
+$(MAPFILE)\r
+c:\msvc\lib\+\r
+c:\msvc\mfc\lib\+\r
+c:\src\lib\+\r
+WINSOCK.LIB+\r
+$(LIBS)\r
+$(DEFFILE);\r
+<<\r
+       link $(LFLAGS) @$(PROJ).CRF\r
+       $(RC) $(RESFLAGS) LIBLDAP.RES $@\r
+       @copy $(PROJ).CRF MSVC.BND\r
+       implib /nowep $(PROJ).LIB $(PROJ).DLL\r
+\r
+$(PROJ).DLL::  LIBLDAP.RES\r
+       if not exist MSVC.BND   $(RC) $(RESFLAGS) LIBLDAP.RES $@\r
+\r
+run: $(PROJ).DLL\r
+       $(PROJ) $(RUNFLAGS)\r
+\r
+\r
+$(PROJ).BSC: $(SBRS)\r
+       bscmake @<<\r
+/o$@ $(SBRS)\r
+<<\r
diff --git a/libraries/msdos/winsock/libldap.rc b/libraries/msdos/winsock/libldap.rc
new file mode 100644 (file)
index 0000000..2c15d8d
--- /dev/null
@@ -0,0 +1,40 @@
+#ifdef APSTUDIO_INVOKED\r
+       #error:  this file is not editable by App Studio; use an editor\r
+#endif //APSTUDIO_INVOKED\r
+\r
+#include "ver.h"\r
+\r
+VS_VERSION_INFO        VERSIONINFO\r
+       FILEVERSION             3,3,0,0         // LIBLDAP version 3.3\r
+       PRODUCTVERSION  3,3,0,0\r
+       FILEFLAGSMASK   VS_FFI_FILEFLAGSMASK\r
+#ifdef _DEBUG\r
+       FILEFLAGS               (VS_FF_DEBUG|VS_FF_PRIVATEBUILD|VS_FF_PRERELEASE)\r
+#else\r
+       FILEFLAGS               VS_FF_PRERELEASE        // beta version\r
+//     FILEFLAGS               0                       // final version\r
+#endif\r
+       FILEOS                  VOS_DOS_WINDOWS16\r
+       FILETYPE                VFT_APP\r
+       FILESUBTYPE             0\r
+BEGIN\r
+       BLOCK "StringFileInfo"\r
+       BEGIN\r
+               BLOCK "040904E4"        // lang=US English, Charset=Windows Multilingual\r
+               BEGIN\r
+                       VALUE   "CompanyName",          "University of Michigan\0"\r
+                       VALUE   "FileDescription",      "Lightweight Directory Access Protocol Library\0"\r
+                       VALUE   "FileVersion",          "3.3b1\0"\r
+                       VALUE   "InternalName",         "LIBLDAP\0"\r
+                       VALUE   "LegalCopyright",       "Copyright (c) 1996 The Regents of The University of Michigan\0"\r
+                       VALUE   "LegalTrademarks",      "None\0"\r
+                       VALUE   "OriginalFileName",     "LIBLDAP.DLL\0"\r
+                       VALUE   "ProductName",          "LIBLDAP\0"\r
+                       VALUE   "ProductVersion",       "3.3b1\0"\r
+               END\r
+       END\r
+       BLOCK "VarFileInfo"\r
+       BEGIN\r
+               VALUE   "Translation",  0x409, 1252     // English + Windows ANSI codepage\r
+       END\r
+END\r
diff --git a/libraries/msdos/winsock/ltest/console.c b/libraries/msdos/winsock/ltest/console.c
new file mode 100644 (file)
index 0000000..2cacc0d
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * console.c -- simple windows console emulator for Winsock testing
+ * 27 June 1993 by Mark C Smith
+ */
+#include <stdio.h>
+#include <winsock.h>
+#include <string.h>
+#include "console.h"
+
+static char *argv[] = { "console", "rearwindow", 0 };  /* */
+char szAppName[20];
+char szLineBuf[512];
+HWND hInst;          
+HWND hWndMain, hWndOutputEdit;
+HANDLE hAccel;
+
+int reg_classes( void );
+void unreg_classes( void );
+
+
+
+int PASCAL
+WinMain( HANDLE hInstance, HANDLE hPrevInst, LPSTR lpszCmdLine, int nCmdShow)
+{
+    MSG msg;
+    int rc;
+
+    strcpy( szAppName, "console");
+
+    hInst = hInstance;
+    if ( !hPrevInst ) {
+       if (( rc = reg_classes()) != 0 ) {
+          MessageBox(0, "Couldn't register window classes", NULL, MB_ICONEXCLAMATION);
+          return( rc );
+       }
+    }
+
+    hWndMain = CreateWindow(
+                szAppName,               /* Window class name           */
+               "Console",              /* Window's title              */
+                WS_CAPTION      |        /* Title and Min/Max           */
+                WS_SYSMENU      |        /* Add system menu box         */
+                WS_MINIMIZEBOX  |        /* Add minimize box            */
+                WS_MAXIMIZEBOX  |        /* Add maximize box            */
+                WS_THICKFRAME   |        /* thick sizeable frame        */
+                WS_CLIPCHILDREN |         /* don't draw in child windows areas */
+                WS_OVERLAPPED,
+                CW_USEDEFAULT, 0,        /* Use default X, Y            */
+                CW_USEDEFAULT, 0,        /* Use default X, Y            */
+               0,                        /* Parent window's handle      */
+               0,                        /* Default to Class Menu       */
+                hInst,                   /* Instance of window          */
+               NULL );                  /* Create struct for WM_CREATE */
+
+    if( !hWndMain ) {
+       MessageBox( 0, "Couldn't create main window", NULL, MB_ICONEXCLAMATION);
+       return( -1 );
+    }
+
+    ShowWindow( hWndMain, nCmdShow );
+
+    hAccel = LoadAccelerators( hInst, szAppName );
+
+    if (( hWndOutputEdit = new_editwindow( hWndMain, "console output" )) == NULL ) {
+       MessageBox( 0, "Couldn't create output window", NULL, MB_ICONEXCLAMATION);
+       return( -1 );
+    }
+
+    while( GetMessage( &msg, 0, 0, 0 )) {
+       if( TranslateAccelerator( hWndMain, hAccel, &msg )) {
+           continue;
+       }
+
+       TranslateMessage(&msg);
+       DispatchMessage(&msg);
+    }
+
+    unreg_classes();
+    return( msg.wParam );
+}
+
+LONG FAR PASCAL
+WndProc( HWND hWnd, WORD msg, WORD wParam, LONG lParam )
+{
+    HDC            hDC;
+    PAINTSTRUCT ps;
+
+    switch( msg ) {
+    case WM_COMMAND:
+       switch( wParam ) {
+       case IDM_F_OPENLDAP:
+           ldapmain( 2, argv );
+           break;
+
+       case IDM_F_EXIT:
+           PostQuitMessage( 0 );
+           break;
+
+       default:
+          return( DefWindowProc( hWnd, msg, wParam, lParam ));
+     }
+
+    case WM_CREATE:
+        break;
+
+    case WM_MOVE:
+         break;
+
+    case WM_SIZE:
+        break;
+
+    case WM_PAINT:
+       memset( &ps, 0x00, sizeof( PAINTSTRUCT ));
+       hDC = BeginPaint( hWnd, &ps );
+       SetBkMode(hDC, TRANSPARENT);
+
+       EndPaint(hWnd, &ps);
+       break;
+
+    case WM_CLOSE:
+       DestroyWindow(hWnd);
+       if ( hWnd == hWndMain ) {
+           PostQuitMessage( 0 );
+       }
+        break;
+
+    default:
+        return( DefWindowProc( hWnd, msg, wParam, lParam ));
+   }
+
+   return( 0L );
+}
+
+int
+reg_classes( void )
+{
+    WNDCLASS   wndclass;
+    memset( &wndclass, 0x00, sizeof( WNDCLASS ));
+
+
+    wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_BYTEALIGNWINDOW;
+    wndclass.lpfnWndProc = WndProc;
+    wndclass.cbClsExtra = 0;
+    wndclass.cbWndExtra = 0;
+    wndclass.hInstance = hInst;
+    wndclass.hIcon = LoadIcon(hInst, "CONSOLE");
+    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
+    wndclass.hbrBackground = (HBRUSH)( COLOR_WINDOW+1 );
+    wndclass.lpszMenuName = szAppName; /* Menu Name is App Name */
+    wndclass.lpszClassName = szAppName; /* Class Name is App Name */
+    if( !RegisterClass( &wndclass )) {
+       return( -1 );
+    }
+
+    return( 0 );
+}
+
+void
+unreg_classes( void )
+{
+    UnregisterClass( szAppName, hInst );
+}
+
+
+char *
+getline( char *line, int len, FILE *s, char *prompt )
+{
+     FARPROC lpfnDlgProc;
+     int       nRc;
+
+     printf( prompt );
+
+     lpfnDlgProc = MakeProcInstance((FARPROC)GetLineDlgProc, hInst);
+     nRc = DialogBox(hInst, MAKEINTRESOURCE(200), hWndMain, lpfnDlgProc);
+     FreeProcInstance(lpfnDlgProc);
+     if ( !nRc ) {
+       return( NULL );
+     }
+     strncpy( line, szLineBuf, len );
+     printf( "%s\n", line );
+     return( line );
+}
+
+
+
+void
+perror( char *msg )
+{
+    printf( "%s: error %d\n", msg, WSAGetLastError());
+}
+
+void
+appexit( int rc )
+{
+    printf( "exit( %d )\n", rc );
+}
+
+int
+fprintf( FILE *f, char *fmt, void *a1, void *a2, void *a3, void *a4,
+    void *a5 )
+{
+    printf( fmt, a1, a2, a3, a4, a5 );
+}
+
+int
+printf( char *fmt, void *a1, void *a2, void *a3, void *a4, void *a5 )
+{
+    char *p, *send, buf[ 1024 ], *crlf = "\r\n";
+
+    sprintf( buf, fmt, a1, a2, a3, a4, a5 );
+
+    send = buf;
+    for ( p = buf; *p != '\0'; ++p ) {
+       if ( *p == '\n' ) {
+           *p = '\0';
+           SendMessage( hWndOutputEdit, EM_REPLACESEL, 0, (long)send );
+           SendMessage( hWndOutputEdit, EM_REPLACESEL, 0, (long)crlf );
+           send = p + 1;
+       }
+    }
+
+    if ( p > send ) {
+       SendMessage( hWndOutputEdit, EM_REPLACESEL, 0, (long)send );
+    }
+}
+
+BOOL FAR PASCAL
+GetLineDlgProc(HWND hWndDlg, WORD Message, WORD wParam, LONG lParam)
+{
+   switch(Message) {
+   case WM_INITDIALOG:
+        /* cwCenter(hWndDlg, 0); */
+        break;
+
+    case WM_CLOSE:
+         /* Closing the Dialog behaves the same as Cancel               */
+         PostMessage(hWndDlg, WM_COMMAND, IDCANCEL, 0L);
+        break;
+
+    case WM_COMMAND:
+        switch(wParam) {
+            case IDOK:
+            SendDlgItemMessage( hWndDlg, DLG_GETLINE_TEXT, WM_GETTEXT, sizeof( szLineBuf),
+               (long)szLineBuf );
+            EndDialog(hWndDlg, TRUE);
+            break;
+        case IDCANCEL:
+            EndDialog(hWndDlg, FALSE);
+            break;
+       }
+       break;
+
+    default:
+        return FALSE;
+    }
+    return TRUE;
+}
diff --git a/libraries/msdos/winsock/ltest/console.h b/libraries/msdos/winsock/ltest/console.h
new file mode 100644 (file)
index 0000000..03f48bf
--- /dev/null
@@ -0,0 +1,19 @@
+/*\r
+ * console.h -- defines for a simple windows console emulator\r
+ * 27 June 1993 by Mark C Smith\r
+ */\r
+\r
+#define IDM_FILE         1000\r
+#define IDM_F_OPENLDAP     1050\r
+#define IDM_F_EXIT         1100\r
+#define DLG_GETLINE_TEXT           102\r
+\r
+#define exit( e )      appexit( e ); return( e )\r
+\r
+void perror( char *msg );\r
+int printf( char *fmt, ... );\r
+int fprintf( FILE *f, char *fmt, ... );\r
+void appexit( int rc );\r
+char *getline( char *line, int len, FILE *s, char *prompt );\r
+LONG FAR PASCAL WndProc( HWND, WORD, WORD, LONG );\r
+BOOL FAR PASCAL GetLineDlgProc(HWND hWndDlg, WORD Message, WORD wParam, LONG lParam);\r
diff --git a/libraries/msdos/winsock/ltest/inpdlg.dlg b/libraries/msdos/winsock/ltest/inpdlg.dlg
new file mode 100644 (file)
index 0000000..de0c641
--- /dev/null
@@ -0,0 +1,14 @@
+DLGINCLUDE RCDATA DISCARDABLE\r
+BEGIN\r
+    "INPDLG.H\0"\r
+END\r
+\r
+200 DIALOG 14, 28, 313, 34\r
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU\r
+CAPTION "Getline"\r
+FONT 8, "MS Sans Serif"\r
+BEGIN\r
+    LTEXT           "Input:", 101, 2, 3, 20, 8\r
+    EDITTEXT        DLG_GETLINE_TEXT, 25, 2, 245, 26, ES_AUTOHSCROLL\r
+    PUSHBUTTON      "Enter", IDOK, 275, 6, 33, 14\r
+END\r
diff --git a/libraries/msdos/winsock/ltest/inpdlg.h b/libraries/msdos/winsock/ltest/inpdlg.h
new file mode 100644 (file)
index 0000000..2838cc5
--- /dev/null
@@ -0,0 +1 @@
+#define DLG_GETLINE_TEXT            102\r
diff --git a/libraries/msdos/winsock/ltest/ltest.def b/libraries/msdos/winsock/ltest/ltest.def
new file mode 100644 (file)
index 0000000..27416cd
--- /dev/null
@@ -0,0 +1,9 @@
+NAME           CONSOLE\r
+EXETYPE         WINDOWS\r
+STUB            'C:\windows\WINSTUB.EXE'\r
+CODE            PRELOAD MOVEABLE\r
+DATA            PRELOAD MOVEABLE MULTIPLE\r
+HEAPSIZE       32768\r
+EXPORTS        WndProc                 @1\r
+               TEditWndProc            @2\r
+               GetLineDlgProc          @3\r
diff --git a/libraries/msdos/winsock/ltest/ltest.mak b/libraries/msdos/winsock/ltest/ltest.mak
new file mode 100644 (file)
index 0000000..df5e9a6
--- /dev/null
@@ -0,0 +1,140 @@
+# Microsoft Visual C++ generated build script - Do not modify\r
+\r
+PROJ = LTEST\r
+DEBUG = 1\r
+PROGTYPE = 0\r
+CALLER = \r
+ARGS = \r
+DLLS = \r
+D_RCDEFINES = -d_DEBUG\r
+R_RCDEFINES = -dNDEBUG\r
+ORIGIN = MSVC\r
+ORIGIN_VER = 1.00\r
+PROJPATH = E:\SRC\LDAP-3.3B1\LIBRAR~1\MSDOS\WINSOCK\LTEST\\r
+USEMFC = 0\r
+CC = cl\r
+CPP = cl\r
+CXX = cl\r
+CCREATEPCHFLAG = \r
+CPPCREATEPCHFLAG = \r
+CUSEPCHFLAG = \r
+CPPUSEPCHFLAG = \r
+FIRSTC = CONSOLE.C   \r
+FIRSTCPP =             \r
+RC = rc\r
+CFLAGS_D_WEXE = /nologo /G2 /W3 /Gf /Zi /AL /Od /D "_DEBUG" /D "DOS" /D "NEEDPROTOS" /D "WINSOCK" /I "..\h" /I "..\winsock" /FR /GA /Fd"LIBLDAP.PDB"\r
+CFLAGS_R_WEXE = /nologo /W3 /AM /O1 /D "NDEBUG" /D "DOS" /D "NEEDPROTOS" /D "WINSOCK" /I "..\winsock" /FR /GA \r
+LFLAGS_D_WEXE = /NOLOGO /NOD /PACKC:61440 /STACK:10240 /ALIGN:16 /ONERROR:NOEXE /CO  \r
+LFLAGS_R_WEXE = /NOLOGO /NOD /PACKC:61440 /STACK:10240 /ALIGN:16 /ONERROR:NOEXE  \r
+LIBS_D_WEXE = oldnames libw llibcew commdlg.lib olecli.lib olesvr.lib shell.lib \r
+LIBS_R_WEXE = oldnames libw mlibcew commdlg.lib olecli.lib olesvr.lib shell.lib \r
+RCFLAGS = /nologo\r
+RESFLAGS = /nologo\r
+RUNFLAGS = \r
+DEFFILE = LTEST.DEF\r
+OBJS_EXT = \r
+LIBS_EXT = ..\..\..\LIBLDAP\LIBLDAP.LIB ..\..\..\LIBLDAP\WINSOCK.LIB \r
+!if "$(DEBUG)" == "1"\r
+CFLAGS = $(CFLAGS_D_WEXE)\r
+LFLAGS = $(LFLAGS_D_WEXE)\r
+LIBS = $(LIBS_D_WEXE)\r
+MAPFILE = nul\r
+RCDEFINES = $(D_RCDEFINES)\r
+!else\r
+CFLAGS = $(CFLAGS_R_WEXE)\r
+LFLAGS = $(LFLAGS_R_WEXE)\r
+LIBS = $(LIBS_R_WEXE)\r
+MAPFILE = nul\r
+RCDEFINES = $(R_RCDEFINES)\r
+!endif\r
+!if [if exist MSVC.BND del MSVC.BND]\r
+!endif\r
+SBRS = CONSOLE.SBR \\r
+               TEXTWIND.SBR \\r
+               GETOPT.SBR \\r
+               TEST.SBR\r
+\r
+\r
+LIBLDAP_DEP = \r
+\r
+WINSOCK_DEP = \r
+\r
+CONSOLE_DEP = c:\msvc\include\winsock.h \\r
+       e:\src\ldap-3.3b1\librar~1\msdos\winsock\ltest\console.h\r
+\r
+\r
+TEXTWIND_DEP = e:\src\ldap-3.3b1\librar~1\msdos\winsock\ltest\console.h \\r
+       e:\src\ldap-3.3b1\librar~1\msdos\winsock\ltest\textwind.h\r
+\r
+\r
+LTEST_RCDEP = e:\src\ldap-3.3b1\librar~1\msdos\winsock\ltest\console.h \\r
+       e:\src\ldap-3.3b1\librar~1\msdos\winsock\ltest\inpdlg.dlg\r
+\r
+\r
+GETOPT_DEP = e:\src\ldap-3.3b1\include\lber.h \\r
+       e:\src\ldap-3.3b1\include\proto-lb.h\r
+\r
+\r
+TEST_DEP = e:\src\ldap-3.3b1\include\msdos.h \\r
+       c:\msvc\include\winsock.h \\r
+       e:\src\ldap-3.3b1\include\sys/socket.h \\r
+       e:\src\ldap-3.3b1\include\sys/file.h \\r
+       e:\src\ldap-3.3b1\include\lber.h \\r
+       e:\src\ldap-3.3b1\include\proto-lb.h \\r
+       e:\src\ldap-3.3b1\include\ldap.h \\r
+       e:\src\ldap-3.3b1\include\proto-ld.h\r
+\r
+\r
+all:   $(PROJ).EXE $(PROJ).BSC\r
+\r
+CONSOLE.OBJ:   CONSOLE.C $(CONSOLE_DEP)\r
+       $(CC) $(CFLAGS) $(CCREATEPCHFLAG) /c CONSOLE.C\r
+\r
+TEXTWIND.OBJ:  TEXTWIND.C $(TEXTWIND_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c TEXTWIND.C\r
+\r
+LTEST.RES:     LTEST.RC $(LTEST_RCDEP)\r
+       $(RC) $(RCFLAGS) $(RCDEFINES) -r LTEST.RC\r
+\r
+GETOPT.OBJ:    ..\..\..\MACINTOS\GETOPT.C $(GETOPT_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c ..\..\..\MACINTOS\GETOPT.C\r
+\r
+TEST.OBJ:      ..\..\..\LIBLDAP\TEST.C $(TEST_DEP)\r
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c ..\..\..\LIBLDAP\TEST.C\r
+\r
+\r
+$(PROJ).EXE::  LTEST.RES\r
+\r
+$(PROJ).EXE::  CONSOLE.OBJ TEXTWIND.OBJ GETOPT.OBJ TEST.OBJ $(OBJS_EXT) $(DEFFILE)\r
+       echo >NUL @<<$(PROJ).CRF\r
+CONSOLE.OBJ +\r
+TEXTWIND.OBJ +\r
+GETOPT.OBJ +\r
+TEST.OBJ +\r
+$(OBJS_EXT)\r
+$(PROJ).EXE\r
+$(MAPFILE)\r
+c:\msvc\lib\+\r
+c:\msvc\mfc\lib\+\r
+c:\src\lib\+\r
+e:.\+\r
+..\..\..\LIBLDAP\LIBLDAP.LIB+\r
+..\..\..\LIBLDAP\WINSOCK.LIB+\r
+$(LIBS)\r
+$(DEFFILE);\r
+<<\r
+       link $(LFLAGS) @$(PROJ).CRF\r
+       $(RC) $(RESFLAGS) LTEST.RES $@\r
+       @copy $(PROJ).CRF MSVC.BND\r
+\r
+$(PROJ).EXE::  LTEST.RES\r
+       if not exist MSVC.BND   $(RC) $(RESFLAGS) LTEST.RES $@\r
+\r
+run: $(PROJ).EXE\r
+       $(PROJ) $(RUNFLAGS)\r
+\r
+\r
+$(PROJ).BSC: $(SBRS)\r
+       bscmake @<<\r
+/o$@ $(SBRS)\r
+<<\r
diff --git a/libraries/msdos/winsock/ltest/ltest.rc b/libraries/msdos/winsock/ltest/ltest.rc
new file mode 100644 (file)
index 0000000..60622a5
--- /dev/null
@@ -0,0 +1,22 @@
+#include <windows.h>
+#include "console.h"
+
+
+CONSOLE MENU
+  BEGIN
+    POPUP  "&File"
+      BEGIN
+       MENUITEM "&Open LDAP", IDM_F_OPENLDAP
+       MENUITEM SEPARATOR
+        MENUITEM "E&xit\tAlt+F4", IDM_F_EXIT
+      END
+ END
+
+               
+CONSOLE ACCELERATORS
+  BEGIN
+    VK_F12, IDM_F_OPENLDAP, VIRTKEY, CONTROL
+    VK_F4, IDM_F_EXIT, ALT, VIRTKEY
+  END
+
+#include "inpdlg.dlg"
diff --git a/libraries/msdos/winsock/ltest/ltest32.mak b/libraries/msdos/winsock/ltest/ltest32.mak
new file mode 100644 (file)
index 0000000..586018c
--- /dev/null
@@ -0,0 +1,348 @@
+# Microsoft Developer Studio Generated NMAKE File, Format Version 4.10\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Application" 0x0101\r
+\r
+!IF "$(CFG)" == ""\r
+CFG=LTEST - Win32 Debug\r
+!MESSAGE No configuration specified.  Defaulting to LTEST - Win32 Debug.\r
+!ENDIF \r
+\r
+!IF "$(CFG)" != "LTEST - Win32 Release" && "$(CFG)" != "LTEST - Win32 Debug"\r
+!MESSAGE Invalid configuration "$(CFG)" specified.\r
+!MESSAGE You can specify a configuration when running NMAKE on this makefile\r
+!MESSAGE by defining the macro CFG on the command line.  For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "LTEST32.MAK" CFG="LTEST - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "LTEST - Win32 Release" (based on "Win32 (x86) Application")\r
+!MESSAGE "LTEST - Win32 Debug" (based on "Win32 (x86) Application")\r
+!MESSAGE \r
+!ERROR An invalid configuration is specified.\r
+!ENDIF \r
+\r
+!IF "$(OS)" == "Windows_NT"\r
+NULL=\r
+!ELSE \r
+NULL=nul\r
+!ENDIF \r
+################################################################################\r
+# Begin Project\r
+# PROP Target_Last_Scanned "LTEST - Win32 Debug"\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+MTL=mktyplib.exe\r
+\r
+!IF  "$(CFG)" == "LTEST - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Target_Dir ""\r
+OUTDIR=.\Release\r
+INTDIR=.\Release\r
+\r
+ALL : "$(OUTDIR)\LTEST32.exe"\r
+\r
+CLEAN : \r
+       -@erase "$(INTDIR)\console.obj"\r
+       -@erase "$(INTDIR)\getopt.obj"\r
+       -@erase "$(INTDIR)\ltest.res"\r
+       -@erase "$(INTDIR)\test.obj"\r
+       -@erase "$(INTDIR)\textwind.obj"\r
+       -@erase "$(OUTDIR)\LTEST32.exe"\r
+\r
+"$(OUTDIR)" :\r
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"\r
+\r
+# ADD BASE CPP /nologo /W3 /O1 /I "..\winsock" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "DOS" /D "NEEDPROTOS" /D "WINSOCK" /FR /YX /c\r
+# ADD CPP /nologo /W3 /O1 /I "..\..\..\..\include" /I "." /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "DOS" /D "NEEDPROTOS" /D "WINSOCK" /YX /c\r
+# SUBTRACT CPP /Fr\r
+CPP_PROJ=/nologo /ML /W3 /O1 /I "..\..\..\..\include" /I "." /D "WIN32" /D\\r
+ "NDEBUG" /D "_WINDOWS" /D "DOS" /D "NEEDPROTOS" /D "WINSOCK"\\r
+ /Fp"$(INTDIR)/LTEST32.pch" /YX /Fo"$(INTDIR)/" /c \r
+CPP_OBJS=.\Release/\r
+CPP_SBRS=.\.\r
+# ADD BASE MTL /nologo /D "NDEBUG" /win32\r
+# ADD MTL /nologo /D "NDEBUG" /win32\r
+MTL_PROJ=/nologo /D "NDEBUG" /win32 \r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)/ltest.res" /d "NDEBUG" \r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/LTEST32.bsc" \r
+BSC32_SBRS= \\r
+       \r
+LINK32=link.exe\r
+# ADD BASE LINK32 oldnames.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /stack:0x2800 /subsystem:windows /machine:IX86\r
+# ADD LINK32 oldnames.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /stack:0x2800 /subsystem:windows /machine:IX86\r
+LINK32_FLAGS=oldnames.lib kernel32.lib user32.lib gdi32.lib winspool.lib\\r
+ comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib\\r
+ odbc32.lib odbccp32.lib /nologo /stack:0x2800 /subsystem:windows\\r
+ /incremental:no /pdb:"$(OUTDIR)/LTEST32.pdb" /machine:IX86 /def:".\ltest.def"\\r
+ /out:"$(OUTDIR)/LTEST32.exe" \r
+DEF_FILE= \\r
+       ".\ltest.def"\r
+LINK32_OBJS= \\r
+       "$(INTDIR)\console.obj" \\r
+       "$(INTDIR)\getopt.obj" \\r
+       "$(INTDIR)\ltest.res" \\r
+       "$(INTDIR)\test.obj" \\r
+       "$(INTDIR)\textwind.obj" \\r
+       "..\..\..\..\..\..\MSDEV\LIB\WSOCK32.LIB" \\r
+       "..\..\..\libldap\Debug\ldap32.lib"\r
+\r
+"$(OUTDIR)\LTEST32.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)\r
+    $(LINK32) @<<\r
+  $(LINK32_FLAGS) $(LINK32_OBJS)\r
+<<\r
+\r
+!ELSEIF  "$(CFG)" == "LTEST - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "Debug"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Target_Dir ""\r
+OUTDIR=.\Debug\r
+INTDIR=.\Debug\r
+\r
+ALL : "$(OUTDIR)\LTEST32.exe"\r
+\r
+CLEAN : \r
+       -@erase "$(INTDIR)\console.obj"\r
+       -@erase "$(INTDIR)\getopt.obj"\r
+       -@erase "$(INTDIR)\ltest.res"\r
+       -@erase "$(INTDIR)\test.obj"\r
+       -@erase "$(INTDIR)\textwind.obj"\r
+       -@erase "$(OUTDIR)\LTEST32.exe"\r
+       -@erase "$(OUTDIR)\LTEST32.ilk"\r
+       -@erase "$(OUTDIR)\LTEST32.pdb"\r
+       -@erase ".\LIBLDAP.IDB"\r
+       -@erase ".\LIBLDAP.PDB"\r
+\r
+"$(OUTDIR)" :\r
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"\r
+\r
+# ADD BASE CPP /nologo /W3 /Gm /Zi /Od /Gf /I "..\h" /I "..\winsock" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "DOS" /D "NEEDPROTOS" /D "WINSOCK" /FR /YX /Fd"LIBLDAP.PDB" /c\r
+# ADD CPP /nologo /W3 /Gm /Zi /Od /Gf /I "..\h" /I "..\..\..\..\include" /I "." /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "DOS" /D "NEEDPROTOS" /D "WINSOCK" /YX /Fd"LIBLDAP.PDB" /c\r
+# SUBTRACT CPP /Fr\r
+CPP_PROJ=/nologo /MLd /W3 /Gm /Zi /Od /Gf /I "..\h" /I "..\..\..\..\include" /I\\r
+ "." /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "DOS" /D "NEEDPROTOS" /D "WINSOCK"\\r
+ /Fp"$(INTDIR)/LTEST32.pch" /YX /Fo"$(INTDIR)/" /Fd"LIBLDAP.PDB" /c \r
+CPP_OBJS=.\Debug/\r
+CPP_SBRS=.\.\r
+# ADD BASE MTL /nologo /D "_DEBUG" /win32\r
+# ADD MTL /nologo /D "_DEBUG" /win32\r
+MTL_PROJ=/nologo /D "_DEBUG" /win32 \r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)/ltest.res" /d "_DEBUG" \r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/LTEST32.bsc" \r
+BSC32_SBRS= \\r
+       \r
+LINK32=link.exe\r
+# ADD BASE LINK32 oldnames.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /stack:0x2800 /subsystem:windows /debug /machine:IX86\r
+# ADD LINK32 oldnames.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /stack:0x2800 /subsystem:windows /debug /machine:IX86\r
+LINK32_FLAGS=oldnames.lib kernel32.lib user32.lib gdi32.lib winspool.lib\\r
+ comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib\\r
+ odbc32.lib odbccp32.lib /nologo /stack:0x2800 /subsystem:windows\\r
+ /incremental:yes /pdb:"$(OUTDIR)/LTEST32.pdb" /debug /machine:IX86\\r
+ /def:".\ltest.def" /out:"$(OUTDIR)/LTEST32.exe" \r
+DEF_FILE= \\r
+       ".\ltest.def"\r
+LINK32_OBJS= \\r
+       "$(INTDIR)\console.obj" \\r
+       "$(INTDIR)\getopt.obj" \\r
+       "$(INTDIR)\ltest.res" \\r
+       "$(INTDIR)\test.obj" \\r
+       "$(INTDIR)\textwind.obj" \\r
+       "..\..\..\..\..\..\MSDEV\LIB\WSOCK32.LIB" \\r
+       "..\..\..\libldap\Debug\ldap32.lib"\r
+\r
+"$(OUTDIR)\LTEST32.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)\r
+    $(LINK32) @<<\r
+  $(LINK32_FLAGS) $(LINK32_OBJS)\r
+<<\r
+\r
+!ENDIF \r
+\r
+.c{$(CPP_OBJS)}.obj:\r
+   $(CPP) $(CPP_PROJ) $<  \r
+\r
+.cpp{$(CPP_OBJS)}.obj:\r
+   $(CPP) $(CPP_PROJ) $<  \r
+\r
+.cxx{$(CPP_OBJS)}.obj:\r
+   $(CPP) $(CPP_PROJ) $<  \r
+\r
+.c{$(CPP_SBRS)}.sbr:\r
+   $(CPP) $(CPP_PROJ) $<  \r
+\r
+.cpp{$(CPP_SBRS)}.sbr:\r
+   $(CPP) $(CPP_PROJ) $<  \r
+\r
+.cxx{$(CPP_SBRS)}.sbr:\r
+   $(CPP) $(CPP_PROJ) $<  \r
+\r
+################################################################################\r
+# Begin Target\r
+\r
+# Name "LTEST - Win32 Release"\r
+# Name "LTEST - Win32 Debug"\r
+\r
+!IF  "$(CFG)" == "LTEST - Win32 Release"\r
+\r
+!ELSEIF  "$(CFG)" == "LTEST - Win32 Debug"\r
+\r
+!ENDIF \r
+\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\console.c\r
+DEP_CPP_CONSO=\\r
+       ".\console.h"\\r
+       \r
+\r
+"$(INTDIR)\console.obj" : $(SOURCE) $(DEP_CPP_CONSO) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\textwind.c\r
+DEP_CPP_TEXTW=\\r
+       ".\console.h"\\r
+       ".\textwind.h"\\r
+       \r
+\r
+"$(INTDIR)\textwind.obj" : $(SOURCE) $(DEP_CPP_TEXTW) "$(INTDIR)"\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\ltest.rc\r
+\r
+!IF  "$(CFG)" == "LTEST - Win32 Release"\r
+\r
+\r
+"$(INTDIR)\ltest.res" : $(SOURCE) "$(INTDIR)"\r
+   $(RSC) $(RSC_PROJ) $(SOURCE)\r
+\r
+\r
+!ELSEIF  "$(CFG)" == "LTEST - Win32 Debug"\r
+\r
+DEP_RSC_LTEST=\\r
+       ".\console.h"\\r
+       ".\inpdlg.dlg"\\r
+       \r
+\r
+"$(INTDIR)\ltest.res" : $(SOURCE) $(DEP_RSC_LTEST) "$(INTDIR)"\r
+   $(RSC) $(RSC_PROJ) $(SOURCE)\r
+\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE="\src\ldap-3.3b1\libraries\macintos\getopt.c"\r
+DEP_CPP_GETOP=\\r
+       "..\..\..\..\include\lber.h"\\r
+       "..\..\..\..\include\proto-lb.h"\\r
+       "..\..\..\..\include\proto-lber.h"\\r
+       \r
+\r
+"$(INTDIR)\getopt.obj" : $(SOURCE) $(DEP_CPP_GETOP) "$(INTDIR)"\r
+   $(CPP) $(CPP_PROJ) $(SOURCE)\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE="\src\ldap-3.3b1\libraries\libldap\test.c"\r
+DEP_CPP_TEST_=\\r
+       "..\..\..\..\include\lber.h"\\r
+       "..\..\..\..\include\ldap.h"\\r
+       "..\..\..\..\include\msdos.h"\\r
+       "..\..\..\..\include\proto-lb.h"\\r
+       "..\..\..\..\include\proto-lber.h"\\r
+       "..\..\..\..\include\proto-ld.h"\\r
+       "..\..\..\..\include\proto-ldap.h"\\r
+       ".\console.h"\\r
+       {$(INCLUDE)}"\sys\stat.h"\\r
+       {$(INCLUDE)}"\sys\types.h"\\r
+       \r
+NODEP_CPP_TEST_=\\r
+       "..\..\..\libldap\macos.h"\\r
+       "..\..\..\libldap\msdos.h"\\r
+       \r
+\r
+"$(INTDIR)\test.obj" : $(SOURCE) $(DEP_CPP_TEST_) "$(INTDIR)"\r
+   $(CPP) $(CPP_PROJ) $(SOURCE)\r
+\r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=.\ltest.def\r
+\r
+!IF  "$(CFG)" == "LTEST - Win32 Release"\r
+\r
+!ELSEIF  "$(CFG)" == "LTEST - Win32 Debug"\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE="\src\ldap-3.3b1\libraries\libldap\Debug\ldap32.lib"\r
+\r
+!IF  "$(CFG)" == "LTEST - Win32 Release"\r
+\r
+!ELSEIF  "$(CFG)" == "LTEST - Win32 Debug"\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+################################################################################\r
+# Begin Source File\r
+\r
+SOURCE=\MSDEV\LIB\WSOCK32.LIB\r
+\r
+!IF  "$(CFG)" == "LTEST - Win32 Release"\r
+\r
+!ELSEIF  "$(CFG)" == "LTEST - Win32 Debug"\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+# End Target\r
+# End Project\r
+################################################################################\r
diff --git a/libraries/msdos/winsock/ltest/ltest32.mdp b/libraries/msdos/winsock/ltest/ltest32.mdp
new file mode 100644 (file)
index 0000000..5cd47fd
Binary files /dev/null and b/libraries/msdos/winsock/ltest/ltest32.mdp differ
diff --git a/libraries/msdos/winsock/ltest/textwind.c b/libraries/msdos/winsock/ltest/textwind.c
new file mode 100644 (file)
index 0000000..80f522f
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * textwind.c
+ */
+#include <windows.h>
+#include <stdio.h>
+#include "console.h"
+#include "textwind.h"
+
+static BOOL windclassreg = FALSE;
+extern HWND hInst;
+
+/*
+ * local prototypes
+ */
+BOOL register_editclass( void );
+
+
+HWND
+new_editwindow( HWND hParent, char *lpszTitle )
+{
+       HWND    hWnd, hEditWnd;
+       RECT    r;
+
+       /*
+        * register text edit window class if we have not already done so
+        */
+       if ( !windclassreg && !register_editclass()) {
+               return( NULL );
+       }
+
+       /*
+        * create an instance of text edit window
+        */
+       hWnd = CreateWindow( WINDCLASS_TEDIT, lpszTitle != NULL ? lpszTitle : "Untitled",
+                       WS_OVERLAPPEDWINDOW,
+                       CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+                       hParent, NULL, hInst, NULL );
+
+       if ( !hWnd ) {
+               return( NULL );
+       }
+
+       /*
+        * create a child Edit controls that fills the text edit window
+        */
+       GetClientRect( hWnd, (LPRECT)&r );
+       hEditWnd = CreateWindow( "Edit", NULL,
+                       WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_MULTILINE,
+                       0, 0, r.right - r.left, r.bottom - r.top, hWnd, IDC_EDIT, hInst, NULL );
+
+       if ( !hEditWnd ) {
+               DestroyWindow( hWnd );
+               return( NULL );
+       }
+
+       /*
+        * add edit control to property list of window
+        */
+       if( !SetProp( hWnd, "hEditWnd", hEditWnd )) {
+               DestroyWindow( hWnd );
+               return( NULL );
+       }
+
+       if ( lpszTitle != NULL ) {
+           SetWindowText( hWnd, lpszTitle );
+       }
+
+       /*
+        * show and draw the new window
+        */
+       ShowWindow( hWnd, SW_SHOWNORMAL );
+       UpdateWindow( hWnd );
+       return( hEditWnd );
+}
+
+
+BOOL
+register_editclass()
+{
+       WNDCLASS        wc;
+
+       memset( &wc, 0x00, sizeof(WNDCLASS) );
+
+       wc.style = CS_HREDRAW | CS_VREDRAW | CS_BYTEALIGNWINDOW;
+       wc.lpfnWndProc = TEditWndProc;
+       wc.hInstance = hInst;
+       wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1 );
+       wc.lpszClassName = WINDCLASS_TEDIT;
+       return( windclassreg = RegisterClass( &wc ));
+}
+
+
+void
+memory_error( void )
+{
+       MessageBox( GetFocus(), "Out of memory", "Sample", MB_ICONHAND | MB_OK );
+}
+
+
+long FAR PASCAL TEditWndProc( HWND hWnd, unsigned message, WORD wParam, LONG lParam )
+{
+       HWND    hEditWnd;
+
+       hEditWnd = GetProp( hWnd, "hEditWnd" );
+
+       switch( message ) {
+       case WM_COMMAND:
+               switch( wParam ) {
+               case IDC_EDIT:
+                       if ( HIWORD( lParam ) == EN_ERRSPACE ) {
+                               memory_error();
+                       }
+                       break;
+               }
+               break;
+
+       case WM_SETFOCUS:
+               SetFocus( hEditWnd );
+               break;
+
+       case WM_SIZE:
+               MoveWindow( hEditWnd, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE );
+               break;
+
+       default:
+               return( DefWindowProc( hWnd, message, wParam, lParam ));
+       }
+
+       return( NULL );
+}
diff --git a/libraries/msdos/winsock/ltest/textwind.h b/libraries/msdos/winsock/ltest/textwind.h
new file mode 100644 (file)
index 0000000..b61cb8a
--- /dev/null
@@ -0,0 +1,13 @@
+/*\r
+ * textwind.h\r
+ */\r
+\r
+#define        WINDCLASS_TEDIT "TextClass"\r
+#define IDC_EDIT               100\r
+\r
+/*\r
+ * prototypes\r
+ */\r
+HWND new_editwindow( HWND hParent, char *lpszTtitle );\r
+void memory_error( void );\r
+long FAR PASCAL TEditWndProc( HWND hWnd, unsigned message, WORD wParam, LONG lParam );\r
diff --git a/libraries/msdos/winsock/makefile b/libraries/msdos/winsock/makefile
new file mode 100644 (file)
index 0000000..9bdb965
--- /dev/null
@@ -0,0 +1,680 @@
+# Microsoft Visual C++ generated build script - Do not modify
+# Microsoft Visual C++ generated build script - Do not modify
+# but due to buffer length limitataions for both preprocessor defines
+# and include paths we went to using this file as an external makefile
+# April 1995 sgr@umich.edu
+
+PROJ = LIBLDAP
+DEBUG = 0
+PROGTYPE = 1
+
+WINSOCK = 1    # want winsock api, no vendor specific calls
+DOS = 1                # windows lives on top of DOS at present
+NEEDPROTOS = 1 # need strict typeing in fcn declarations
+KERBEROS = 1   # Kerberos or no, your choice
+
+#include paths will vary per site,  I've broken them up by function
+INC_MSVC = c:\msvc\include
+INC_LDAP = q:\src\ldap-3.2b1\include
+INC_KERBEROS = q:\src\krb\mit_env\kerberos\include;q:\src\krb\mit_env\kerberos
+INC_WSHELPER = c:\src\mit\wshelper
+INC_AUTHMAN = c:\src\authman\dll
+INC_MITENV = q:\src\krb\mit_env\localh
+
+#order is important
+INCLUDE = $(INC_MSVC);$(INC_LDAP);$(INC_AUTHMAN);$(INC_MITENV);$(INC_KERBEROS);$(INC_WSHELPER)
+
+LDAP_FLAGS = /D "TEMPLATEFILE" ="""ldtmpl.cfg"""\
+       /D "FILTERFILE"="""ldfilter.cfg"""
+
+!if "$(KERBEROS)" == "1"
+# WSHELPER
+# with kerberos, we need to use WSHELPER (Winsock Helper)  to do 
+# gethostbyaddr() calls for us because we can't count on the vendor's 
+# (Novell) tcp/ip stack doing this right.  The real name of the ldap 
+# server is required to get service tickets.
+#
+LDAP_FLAGS = $(LDAP_FLAGS) /D "KERBEROS" /D "WSHELPER" /D "AUTHMAN"
+#      SET INCLUDE=$(INCLUDE), $(INC_KERBEROS), $(INC_WSHELPER), $(INC_AUTHMAN), $(INC_MITENV)
+!endif
+# _WINDOWS
+# authman.h requires _WINDOWS (with a value!), which is set automatically by
+# particular options related to prolog/epilog code generation 
+# which are true for AUTHMAN, but not libldap, so do this manually.
+#
+#
+# __MSDOS__
+# krb.h (well really osconf.h, via conf.h, via krb.h) doesn't recognize
+# microsoft's default "_MSDOS".  It wants __MSDOS__, so provide it.
+#
+# WINDOWS
+# same crap, this time from conf-pc.h, this time with WINDOWS
+#      
+# _WINDLL
+# Wshelper.h requires _WINDLL to be defined.  Default configuration
+# of libldap doesn't use any prolog/epilog optimization, so _WINDLL
+# isn't defined by default.
+#
+!if "$(WINSOCK)"=="1"
+LDAP_FLAGS = $(LDAP_FLAGS)\
+               /D "WINSOCK"\
+               /D "_WINDOWS"\
+               /D "__MSDOS__"\
+               /D "WINDOWS"\
+               /D "_WINDLL"\
+               /D "NO_USERINTERFACE"
+!endif
+!if "$(DOS)"=="1"
+LDAP_FLAGS = $(LDAP_FLAGS) /D "DOS"
+!endif
+!if "$(NEEDPROTOS)"=="1"
+LDAP_FLAGS = $(LDAP_FLAGS) /D "NEEDPROTOS"
+!endif
+
+CALLER = 
+ARGS = 
+DLLS = 
+D_RCDEFINES = /d_DEBUG 
+R_RCDEFINES = /dNDEBUG 
+ORIGIN = MSVC
+ORIGIN_VER = 1.00
+PROJPATH = Q:\SRC\LDAP-3.2B1\LIB\LIBLDAP\
+USEMFC = 0
+CC = cl
+CPP = cl
+CXX = cl
+CCREATEPCHFLAG = 
+CPPCREATEPCHFLAG = 
+CUSEPCHFLAG = 
+CPPUSEPCHFLAG = 
+FIRSTC = ABANDON.C   
+FIRSTCPP =             
+RC = rc
+CFLAGS_D_WDLL = /nologo /G2 /W3 /Gf /Zi /ALu /Od /D "_DEBUG" /FR /Fd"LIBLDAP.PDB"
+CFLAGS_R_WDLL = /nologo /f- /G3 /W3 /Gf /ALu /Od /D "NDEBUG" /FR
+LFLAGS_D_WDLL = /NOLOGO /NOD /NOE /PACKC:61440 /ALIGN:16 /ONERROR:NOEXE /CO /MAP:FULL
+LFLAGS_R_WDLL = /NOLOGO /NOD /NOE /PACKC:61440 /ALIGN:16 /ONERROR:NOEXE /MAP:FULL
+LIBS_D_WDLL = oldnames libw ldllcew authlib krbv4win wshelper commdlg.lib olecli.lib olesvr.lib shell.lib 
+LIBS_R_WDLL = oldnames libw ldllcew authlib krbv4win wshelper commdlg.lib olecli.lib olesvr.lib shell.lib 
+RCFLAGS = /nologo 
+RESFLAGS = /nologo 
+RUNFLAGS = 
+DEFFILE = LIBLDAP.DEF
+OBJS_EXT = 
+LIBS_EXT = WINSOCK.LIB 
+!if "$(DEBUG)" == "1"
+CFLAGS = $(CFLAGS_D_WDLL) $(LDAP_FLAGS)
+LFLAGS = $(LFLAGS_D_WDLL)
+LIBS = $(LIBS_D_WDLL)
+MAPFILE = nul
+RCDEFINES = $(D_RCDEFINES)
+!else
+CFLAGS = $(CFLAGS_R_WDLL) $(LDAP_FLAGS)
+LFLAGS = $(LFLAGS_R_WDLL)
+LIBS = $(LIBS_R_WDLL)
+MAPFILE = nul
+RCDEFINES = $(R_RCDEFINES)
+!endif
+!if [if exist MSVC.BND del MSVC.BND]
+!endif
+SBRS = ABANDON.SBR \
+               ADD.SBR \
+               BIND.SBR \
+               CACHE.SBR \
+               COMPARE.SBR \
+               DELETE.SBR \
+               ERROR.SBR \
+               GETFILTE.SBR \
+               REGEX.SBR \
+               MODIFY.SBR \
+               MODRDN.SBR \
+               GETDN.SBR \
+               GETENTRY.SBR \
+               GETATTR.SBR \
+               ADDENTRY.SBR \
+               RESULT.SBR \
+               SEARCH.SBR \
+               UFN.SBR \
+               OPENWSA.SBR \
+               DECODE.SBR \
+               ENCODE.SBR \
+               IO.SBR \
+               MSDOS.SBR \
+               SBIND.SBR \
+               UNBIND.SBR \
+               KBIND.SBR \
+               FRIENDLY.SBR \
+               DISPTMPL.SBR \
+               DSPARSE.SBR \
+               FREE.SBR \
+               SORT.SBR \
+               SRCHPREF.SBR \
+               TMPLOUT.SBR \
+               KERBEROS.SBR \
+               GETVALUE.SBR
+
+
+WINSOCK_DEP = 
+
+ABANDON_DEP = $(INC_LDAP)\sys\socket.h \
+       $(INC_LDAP)\msdos.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\ldap.h \
+       $(INC_LDAP)\proto-ld.h
+
+
+ADD_DEP = $(INC_LDAP)\msdos.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\sys/socket.h \
+       $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\ldap.h \
+       $(INC_LDAP)\proto-ld.h
+
+
+BIND_DEP = $(INC_LDAP)\msdos.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\sys/socket.h \
+       $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\ldap.h \
+       $(INC_LDAP)\proto-ld.h
+
+
+CACHE_DEP = $(INC_LDAP)\msdos.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\sys/socket.h \
+       $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\ldap.h \
+       $(INC_LDAP)\proto-ld.h
+
+
+COMPARE_DEP = $(INC_LDAP)\sys/socket.h \
+       $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\ldap.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\proto-ld.h
+
+
+DELETE_DEP = $(INC_LDAP)\msdos.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\sys/socket.h \
+       $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\ldap.h \
+       $(INC_LDAP)\proto-ld.h
+
+
+ERROR_DEP = $(INC_LDAP)\msdos.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\sys/socket.h \
+       $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\ldap.h \
+       $(INC_LDAP)\proto-ld.h
+
+
+GETFILTE_DEP = $(INC_LDAP)\regex.h \
+       $(INC_LDAP)\msdos.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\sys/file.h \
+       $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\ldap.h \
+       $(INC_LDAP)\proto-ld.h
+
+
+REGEX_DEP = $(INC_LDAP)\portable.h \
+       $(INC_LDAP)\regex.h
+
+
+MODIFY_DEP = $(INC_LDAP)\sys/socket.h \
+       $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\ldap.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\proto-ld.h
+
+
+MODRDN_DEP = $(INC_LDAP)\sys/socket.h \
+       $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\ldap.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\proto-ld.h
+
+
+GETDN_DEP = $(INC_LDAP)\msdos.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\sys/socket.h \
+       $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\ldap.h \
+       $(INC_LDAP)\proto-ld.h
+
+
+GETENTRY_DEP = $(INC_LDAP)\msdos.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\sys/socket.h \
+       $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\ldap.h \
+       $(INC_LDAP)\proto-ld.h
+
+
+GETATTR_DEP = $(INC_LDAP)\msdos.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\sys/socket.h \
+       $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\ldap.h \
+       $(INC_LDAP)\proto-ld.h
+
+
+ADDENTRY_DEP = $(INC_LDAP)\msdos.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\sys/socket.h \
+       $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\ldap.h \
+       $(INC_LDAP)\proto-ld.h
+
+
+RESULT_DEP = $(INC_LDAP)\msdos.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\sys/socket.h \
+       $(INC_LDAP)\sys/select.h \
+       $(INC_LDAP)\portable.h \
+       $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\ldap.h \
+       $(INC_LDAP)\proto-ld.h
+
+
+SEARCH_DEP = $(INC_LDAP)\sys/socket.h \
+       $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\ldap.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\proto-ld.h \
+       $(INC_LDAP)\msdos.h
+
+
+UFN_DEP = $(INC_LDAP)\msdos.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\sys/socket.h \
+       $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\ldap.h \
+       $(INC_LDAP)\proto-ld.h
+
+
+OPENWSA_DEP = $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\ldap.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\proto-ld.h \
+       $(INC_LDAP)\msdos.h \
+       q:\src\mit\localh\wshelper.h \
+       q:\src\mit\localh\resolv.h \
+       q:\src\mit\localh\arpa/nameser.h \
+       q:\src\mit\localh\hesiod.h
+
+
+DECODE_DEP = $(INC_LDAP)\sys/socket.h \
+       $(INC_LDAP)\netinet/in.h \
+       $(INC_LDAP)\msdos.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h
+
+
+ENCODE_DEP = $(INC_LDAP)\sys/socket.h \
+       $(INC_LDAP)\netinet/in.h \
+       $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\msdos.h \
+       $(INC_LDAP)\winsock.h
+
+
+IO_DEP = $(INC_LDAP)\sys/socket.h \
+       $(INC_LDAP)\netinet/in.h \
+       $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\msdos.h
+
+
+MSDOS_DEP = $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\ldap.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\proto-ld.h \
+       $(INC_LDAP)\msdos.h
+
+
+SBIND_DEP = $(INC_LDAP)\sys/socket.h \
+       $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\ldap.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\proto-ld.h
+
+
+UNBIND_DEP = $(INC_LDAP)\msdos.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\sys/socket.h \
+       $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\ldap.h \
+       $(INC_LDAP)\proto-ld.h
+
+
+KBIND_DEP = $(INC_LDAP)\msdos.h \
+       $(INC_LDAP)\winsock.h \
+       c:\src\h\krbv4\krb.h \
+       q:\src\mit\localh\mit_copy.h \
+       q:\src\mit\localh\conf.h \
+       q:\src\mit\localh\osconf.h \
+       q:\src\mit\localh\conf-pc.h \
+       c:\src\h\krbv4\des.h \
+       q:\src\mit\localh\lsh_pwd.h \
+       $(INC_LDAP)\sys/socket.h \
+       $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\ldap.h \
+       $(INC_LDAP)\proto-ld.h
+
+
+FRIENDLY_DEP = $(INC_LDAP)\msdos.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\sys/socket.h \
+       $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\ldap.h \
+       $(INC_LDAP)\proto-ld.h
+
+
+DISPTMPL_DEP = $(INC_LDAP)\msdos.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\sys/file.h \
+       $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\ldap.h \
+       $(INC_LDAP)\proto-ld.h \
+       $(INC_LDAP)\disptmpl.h
+
+
+DSPARSE_DEP = $(INC_LDAP)\msdos.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\sys/file.h \
+       $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\ldap.h \
+       $(INC_LDAP)\proto-ld.h
+
+
+FREE_DEP = $(INC_LDAP)\msdos.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\ldap.h \
+       $(INC_LDAP)\proto-ld.h
+
+
+SORT_DEP = $(INC_LDAP)\msdos.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\ldap.h \
+       $(INC_LDAP)\proto-ld.h
+
+
+SRCHPREF_DEP = $(INC_LDAP)\msdos.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\sys/file.h \
+       $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\ldap.h \
+       $(INC_LDAP)\proto-ld.h \
+       $(INC_LDAP)\srchpref.h
+
+
+TMPLOUT_DEP = $(INC_LDAP)\msdos.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\sys/file.h \
+       $(INC_LDAP)\sys/socket.h \
+       $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\ldap.h \
+       $(INC_LDAP)\proto-ld.h \
+       $(INC_LDAP)\disptmpl.h
+
+
+LIBLDAP_RCDEP = 
+
+KERBEROS_DEP = $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\ldap.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\proto-ld.h \
+       $(INC_LDAP)\msdos.h \
+       c:\src\authman\dll\authlib.h
+
+
+GETVALUE_DEP = $(INC_LDAP)\msdos.h \
+       $(INC_LDAP)\winsock.h \
+       $(INC_LDAP)\sys/socket.h \
+       $(INC_LDAP)\lber.h \
+       $(INC_LDAP)\proto-lb.h \
+       $(INC_LDAP)\ldap.h \
+       $(INC_LDAP)\proto-ld.h
+
+
+all:   $(PROJ).DLL $(PROJ).BSC
+
+clean:
+       del *.aps
+       del *.bsc 
+       del *.pdb 
+       del *.vcw 
+       del *.res
+       del *.pch
+       del *.obj
+       del *.sbr
+#      del *.map
+
+ABANDON.OBJ:   ABANDON.C $(ABANDON_DEP)
+       $(CC) $(CFLAGS) $(CCREATEPCHFLAG) /c ABANDON.C
+
+ADD.OBJ:       ADD.C $(ADD_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c ADD.C
+
+BIND.OBJ:      BIND.C $(BIND_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c BIND.C
+
+CACHE.OBJ:     CACHE.C $(CACHE_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c CACHE.C
+
+COMPARE.OBJ:   COMPARE.C $(COMPARE_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c COMPARE.C
+
+DELETE.OBJ:    DELETE.C $(DELETE_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c DELETE.C
+
+ERROR.OBJ:     ERROR.C $(ERROR_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c ERROR.C
+
+GETFILTE.OBJ:  GETFILTE.C $(GETFILTE_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c GETFILTE.C
+
+REGEX.OBJ:     REGEX.C $(REGEX_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c REGEX.C
+
+MODIFY.OBJ:    MODIFY.C $(MODIFY_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c MODIFY.C
+
+MODRDN.OBJ:    MODRDN.C $(MODRDN_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c MODRDN.C
+
+GETDN.OBJ:     GETDN.C $(GETDN_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c GETDN.C
+
+GETENTRY.OBJ:  GETENTRY.C $(GETENTRY_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c GETENTRY.C
+
+GETATTR.OBJ:   GETATTR.C $(GETATTR_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c GETATTR.C
+
+ADDENTRY.OBJ:  ADDENTRY.C $(ADDENTRY_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c ADDENTRY.C
+
+RESULT.OBJ:    RESULT.C $(RESULT_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c RESULT.C
+
+SEARCH.OBJ:    SEARCH.C $(SEARCH_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c SEARCH.C
+
+UFN.OBJ:       UFN.C $(UFN_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c UFN.C
+
+OPENWSA.OBJ:   OPENWSA.C $(OPENWSA_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c OPENWSA.C
+
+DECODE.OBJ:    ..\LIBLBER\DECODE.C $(DECODE_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c ..\LIBLBER\DECODE.C
+
+ENCODE.OBJ:    ..\LIBLBER\ENCODE.C $(ENCODE_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c ..\LIBLBER\ENCODE.C
+
+IO.OBJ:        ..\LIBLBER\IO.C $(IO_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c ..\LIBLBER\IO.C
+
+MSDOS.OBJ:     MSDOS.C $(MSDOS_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c MSDOS.C
+
+SBIND.OBJ:     SBIND.C $(SBIND_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c SBIND.C
+
+UNBIND.OBJ:    UNBIND.C $(UNBIND_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c UNBIND.C
+
+KBIND.OBJ:     KBIND.C $(KBIND_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c KBIND.C
+
+FRIENDLY.OBJ:  FRIENDLY.C $(FRIENDLY_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c FRIENDLY.C
+
+DISPTMPL.OBJ:  DISPTMPL.C $(DISPTMPL_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c DISPTMPL.C
+
+DSPARSE.OBJ:   DSPARSE.C $(DSPARSE_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c DSPARSE.C
+
+FREE.OBJ:      FREE.C $(FREE_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c FREE.C
+
+SORT.OBJ:      SORT.C $(SORT_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c SORT.C
+
+SRCHPREF.OBJ:  SRCHPREF.C $(SRCHPREF_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c SRCHPREF.C
+
+TMPLOUT.OBJ:   TMPLOUT.C $(TMPLOUT_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c TMPLOUT.C
+
+LIBLDAP.RES:   LIBLDAP.RC $(LIBLDAP_RCDEP)
+       $(RC) $(RCFLAGS) $(RCDEFINES) -r LIBLDAP.RC
+
+KERBEROS.OBJ:  ..\MSDOS\KERBEROS.C $(KERBEROS_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c ..\MSDOS\KERBEROS.C
+
+GETVALUE.OBJ:  GETVALUE.C $(GETVALUE_DEP)
+       $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c GETVALUE.C
+
+
+$(PROJ).DLL::  LIBLDAP.RES
+
+$(PROJ).DLL::  ABANDON.OBJ ADD.OBJ BIND.OBJ CACHE.OBJ COMPARE.OBJ DELETE.OBJ ERROR.OBJ \
+       GETFILTE.OBJ REGEX.OBJ MODIFY.OBJ MODRDN.OBJ GETDN.OBJ GETENTRY.OBJ GETATTR.OBJ ADDENTRY.OBJ \
+       RESULT.OBJ SEARCH.OBJ UFN.OBJ OPENWSA.OBJ DECODE.OBJ ENCODE.OBJ IO.OBJ MSDOS.OBJ \
+       SBIND.OBJ UNBIND.OBJ KBIND.OBJ FRIENDLY.OBJ DISPTMPL.OBJ DSPARSE.OBJ FREE.OBJ SORT.OBJ \
+       SRCHPREF.OBJ TMPLOUT.OBJ KERBEROS.OBJ GETVALUE.OBJ $(OBJS_EXT) $(DEFFILE)
+       echo >NUL @<<$(PROJ).CRF
+ABANDON.OBJ +
+ADD.OBJ +
+BIND.OBJ +
+CACHE.OBJ +
+COMPARE.OBJ +
+DELETE.OBJ +
+ERROR.OBJ +
+GETFILTE.OBJ +
+REGEX.OBJ +
+MODIFY.OBJ +
+MODRDN.OBJ +
+GETDN.OBJ +
+GETENTRY.OBJ +
+GETATTR.OBJ +
+ADDENTRY.OBJ +
+RESULT.OBJ +
+SEARCH.OBJ +
+UFN.OBJ +
+OPENWSA.OBJ +
+DECODE.OBJ +
+ENCODE.OBJ +
+IO.OBJ +
+MSDOS.OBJ +
+SBIND.OBJ +
+UNBIND.OBJ +
+KBIND.OBJ +
+FRIENDLY.OBJ +
+DISPTMPL.OBJ +
+DSPARSE.OBJ +
+FREE.OBJ +
+SORT.OBJ +
+SRCHPREF.OBJ +
+TMPLOUT.OBJ +
+KERBEROS.OBJ +
+GETVALUE.OBJ +
+$(OBJS_EXT)
+$(PROJ).DLL
+$(MAPFILE)
+c:\msvc\lib\+
+c:\msvc\mfc\lib\+
+c:\src\lib\+
+c:\src\mit\locallib\+
+WINSOCK.LIB+
+$(LIBS)
+$(DEFFILE);
+<<
+       link $(LFLAGS) @$(PROJ).CRF
+       $(RC) $(RESFLAGS) LIBLDAP.RES $@
+       @copy $(PROJ).CRF MSVC.BND
+       implib /nowep $(PROJ).LIB $(PROJ).DLL
+
+$(PROJ).DLL::  LIBLDAP.RES
+       if not exist MSVC.BND   $(RC) $(RESFLAGS) LIBLDAP.RES $@
+
+run: $(PROJ).DLL
+       $(PROJ) $(RUNFLAGS)
+
+#clean:
+#      del *.aps
+#      del *.bsc 
+#      del *.pdb 
+#      del *.vcw 
+#      del *.res
+#      del *.pch
+#      del *.obj
+#      del *.sbr
+#      del *.map
+
+$(PROJ).BSC: $(SBRS)
+       bscmake @<<
+/o$@ $(SBRS)
+<<
+
diff --git a/libraries/msdos/winsock/openwsa.c b/libraries/msdos/winsock/openwsa.c
new file mode 100644 (file)
index 0000000..0137121
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ *  Copyright (c) 1993 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  open-wsa.c -- libldap ldap_open routine that assumes Winsock API
+ */
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1993 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include "lber.h"
+#include "ldap.h"
+#include <stdio.h>
+#include <string.h>
+#include "msdos.h"
+#ifdef WSHELPER
+#include "wshelper.h"
+#endif
+
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK        ((u_long) 0x7f000001)
+#endif
+
+#ifdef LDAP_DEBUG
+int    ldap_debug;
+#endif
+
+/*
+ * ldap_open - initialize and connect to an ldap server.  A magic cookie to
+ * be used for future communication is returned on success, NULL on failure.
+ *
+ * Example:
+ *     LDAP    *ld;
+ *     ld = ldap_open( hostname, port );
+ */
+
+LDAP *ldap_open( host, port )
+char   *host;
+int    port;
+{
+       SOCKET                  s;
+       struct sockaddr_in      sock;
+       struct hostent FAR      *hp;
+       LDAP                    *ld;
+       unsigned long           address;
+       int                     i, connected;
+       char                    *p, hostname[64];
+       WSADATA                 wsadata;
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_open\n", 0, 0, 0 );
+
+       if ( WSAStartup( 0x0101, &wsadata ) != 0 ) {
+           return( NULL );
+       }
+
+       hp = NULL;
+
+       if ( host != NULL ) {
+           if (( address = inet_addr( host )) == INADDR_NONE ) {
+               if (( hp = gethostbyname( host )) == NULL ) {
+                   WSACleanup();
+                   return( NULL );
+               }
+           }
+       } else {
+           address = htonl( INADDR_LOOPBACK );
+       }
+
+       if ( port == 0 )
+               port = LDAP_PORT;
+
+       if ( (s = socket( AF_INET, SOCK_STREAM, 0 )) == INVALID_SOCKET ) {
+               WSACleanup();
+               return( NULL );
+       }
+
+       connected = 0;
+       for ( i = 0; i == 0 || ( hp != NULL && hp->h_addr_list[ i ] != 0L );
+               ++i ) {
+           if ( hp != NULL ) {
+               SAFEMEMCPY( &sock.sin_addr.s_addr, hp->h_addr_list[ i ],
+                   sizeof( sock.sin_addr.s_addr ));
+           } else {
+               sock.sin_addr.s_addr = address;
+           }
+           sock.sin_family = AF_INET;
+           sock.sin_port = htons( port );
+
+           if ( connect( s, (struct sockaddr *) &sock, sizeof(sock) ) != SOCKET_ERROR ) {
+               connected = 1;
+               break;
+           }
+       }
+
+       if ( !connected ) {
+           closesocket( s );
+           WSACleanup();
+           return( NULL );
+       }
+
+       /*
+        * do a reverse lookup on the addr to get the official hostname.
+        * this is necessary for kerberos to work right, since the official
+        * hostname is used as the kerberos instance.
+        */
+
+       hostname[0] = '\0';
+#ifdef WSHELPER
+       if ( (hp = rgethostbyaddr( (char *)&sock.sin_addr.s_addr,
+#else
+       if ( (hp = gethostbyaddr( (char *)&sock.sin_addr.s_addr,
+#endif
+            sizeof(sock.sin_addr.s_addr), AF_INET )) != NULL ) {
+           if ( hp->h_name != NULL ) {
+               if ( (p = strchr( hp->h_name, '.' )) != NULL ) {
+                   *p = '\0';
+               }
+               strcpy( hostname, hp->h_name );
+           }
+       }
+
+       if ( (ld = (LDAP *) calloc( sizeof(LDAP), 1 )) == NULL ) {
+               closesocket( s );
+               WSACleanup();
+               return( NULL );
+       }
+       ld->ld_sb.sb_sd = s;
+       ld->ld_host = strdup( hostname );
+       ld->ld_version = LDAP_VERSION;
+
+       return( ld );
+}
diff --git a/libraries/msdos/winsock/setupwsa.bat b/libraries/msdos/winsock/setupwsa.bat
new file mode 100644 (file)
index 0000000..af86c64
--- /dev/null
@@ -0,0 +1,69 @@
+rem\r
+rem MSDOS batch file to setup LDAP source area for Windows Socket API build\r
+rem This should be run from the ***ROOT*** of the LDAP source tree\r
+rem\r
+rem Updated 4 April 1996 * Steve Rothwell * University of Michigan\r
+rem\r
+\r
+mkdir include\sys\r
+mkdir include\_sys\r
+mkdir include\arpa\r
+mkdir include\netinet\r
+\r
+rem  original set of empty files\r
+copy libraries\msdos\winsock\include\file.h include\sys\r
+copy libraries\msdos\winsock\include\select.h include\sys\r
+copy libraries\msdos\winsock\include\socket.h include\sys\r
+copy libraries\msdos\winsock\include\param.h include\sys\r
+copy libraries\msdos\winsock\include\ioctl.h include\sys\r
+copy libraries\msdos\winsock\include\filio.h include\sys\r
+copy libraries\msdos\winsock\include\time.h include\sys\r
+copy libraries\msdos\winsock\include\in.h include\netinet\r
+\r
+rem  a newer copy\r
+copy libraries\msdos\winsock\include\wsa\winsock.h include\r
+\r
+rem  from MIT's kerberos stuff\r
+copy libraries\msdos\winsock\include\krb\krb.h include\r
+copy libraries\msdos\winsock\include\krb\des.h include\r
+\r
+rem  from MIT's "localh" collection\r
+copy libraries\msdos\winsock\include\krb\mit\mit_copy.h include\r
+copy libraries\msdos\winsock\include\krb\mit\conf.h include\r
+copy libraries\msdos\winsock\include\krb\mit\conf-pc.h include\r
+copy libraries\msdos\winsock\include\krb\mit\osconf.h include\r
+copy libraries\msdos\winsock\include\krb\mit\lsh_pwd.h include\r
+copy libraries\msdos\winsock\include\krb\mit\wshelper.h include\r
+copy libraries\msdos\winsock\include\krb\mit\resolv.h include\r
+copy libraries\msdos\winsock\include\krb\mit\hesiod.h include\r
+copy libraries\msdos\winsock\include\krb\mit\arpa\nameser.h include\arpa\r
+\r
+rem  from Novell's LWP "toolkit" collection\r
+copy libraries\msdos\winsock\include\net\_sys\filio.h include\_sys\r
+copy libraries\msdos\winsock\include\net\_sys\ioctl.h include\_sys\r
+copy libraries\msdos\winsock\include\net\netdb.h include\r
+\r
+copy libraries\msdos\winsock\include\wsa.h include\msdos.h\r
+copy libraries\msdos\winsock\wsa.c libraries\libldap\msdos.c\r
+\r
+copy libraries\msdos\winsock\wsockip.c libraries\libldap\r
+copy libraries\msdos\winsock\kerberos.c libraries\libldap\r
+\r
+rem  the Pieces you need for MSVC 1.52c\r
+copy libraries\msdos\winsock\libldap.def libraries\libldap\r
+copy libraries\msdos\winsock\libldap.mak libraries\libldap\r
+copy libraries\msdos\winsock\libldap.rc libraries\libldap\r
+copy libraries\msdos\winsock\wsa\winsock.def libraries\libldap\r
+\r
+copy libraries\msdos\winsock\ldap32.def libraries\libldap\r
+copy libraries\msdos\winsock\ldap32.mak libraries\libldap\r
+copy libraries\msdos\winsock\ldap32.mdp libraries\libldap\r
+\r
+attrib -r libraries\libldap\getfilter.c\r
+move libraries\libldap\getfilter.c libraries\libldap\getfilte.c\r
+attrib -r  libraries\libldap\getvalues.c\r
+move libraries\libldap\getvalues.c libraries\libldap\getvalue.c\r
+attrib -r  include\proto-ldap.h\r
+move include\proto-ldap.h include\proto-ld.h\r
+attrib -r  include\proto-lber.h\r
+move include\proto-lber.h include\proto-lb.h\r
diff --git a/libraries/msdos/winsock/unsetupwsa.bat b/libraries/msdos/winsock/unsetupwsa.bat
new file mode 100644 (file)
index 0000000..ddef725
--- /dev/null
@@ -0,0 +1,77 @@
+@rem\r
+@rem this is UNsetupwsa.bat  It reverses what setupwsa.bat does.\r
+@rem you SHOULD NOT use this file !!!\r
+@rem MSDOS batch file to setup LDAP source area for Windows Socket API build\r
+@rem This should be run from the ***ROOT*** of the LDAP source tree\r
+@rem\r
+@rem Updated 1 December 1995 * Steve Rothwell * University of Michigan\r
+@rem\r
+\r
+@echo "You SHOULD NOT USE unsetupwsa.bat"\r
+@goto END\r
+\r
+:UNSETUP\r
+\r
+rem  original set of empty files\r
+call copyback libraries\msdos\winsock\include\file.h include\sys\file.h \r
+call copyback libraries\msdos\winsock\include\select.h include\sys\select.h \r
+call copyback libraries\msdos\winsock\include\socket.h include\sys\socket.h \r
+call copyback libraries\msdos\winsock\include\param.h include\sys\param.h \r
+call copyback libraries\msdos\winsock\include\ioctl.h include\sys\ioctl.h \r
+call copyback libraries\msdos\winsock\include\filio.h include\sys\filio.h \r
+call copyback libraries\msdos\winsock\include\time.h include\sys\time.h \r
+call copyback libraries\msdos\winsock\include\in.h include\netinet\in.h \r
+\r
+rem  a newer copy\r
+call copyback libraries\msdos\winsock\include\wsa\winsock.h include\winsock.h \r
+\r
+rem  from MIT's kerberos stuff\r
+call copyback libraries\msdos\winsock\include\krb\krb.h include\krb.h \r
+call copyback libraries\msdos\winsock\include\krb\des.h include\des.h \r
+\r
+rem  from MIT's "localh" collection\r
+call copyback libraries\msdos\winsock\include\krb\mit\mit_copy.h include\mit_copy.h \r
+call copyback libraries\msdos\winsock\include\krb\mit\conf.h include\conf.h \r
+call copyback libraries\msdos\winsock\include\krb\mit\conf-pc.h include\conf-pc.h \r
+call copyback libraries\msdos\winsock\include\krb\mit\osconf.h include\osconf.h \r
+call copyback libraries\msdos\winsock\include\krb\mit\lsh_pwd.h include\lsh_pwd.h \r
+call copyback libraries\msdos\winsock\include\krb\mit\wshelper.h include\wshelper.h \r
+call copyback libraries\msdos\winsock\include\krb\mit\resolv.h include\resolv.h \r
+call copyback libraries\msdos\winsock\include\krb\mit\hesiod.h include\hesiod.h \r
+call copyback libraries\msdos\winsock\include\krb\mit\arpa\nameser.h include\arpa\nameser.h \r
+\r
+rem  from Novell's LWP "toolkit" collection\r
+call copyback libraries\msdos\winsock\include\net\_sys\filio.h include\_sys\filio.h \r
+call copyback libraries\msdos\winsock\include\net\_sys\ioctl.h include\_sys\ioctl.h \r
+call copyback libraries\msdos\winsock\include\net\netdb.h include\netdb.h \r
+\r
+call copyback libraries\msdos\winsock\include\wsa.h include\msdos.h\r
+call copyback libraries\msdos\winsock\wsa.c libraries\libldap\msdos.c\r
+\r
+call copyback libraries\msdos\winsock\wsockip.c libraries\libldap\wsockip.c \r
+call copyback libraries\msdos\winsock\kerberos.c libraries\libldap\kerberos.c \r
+\r
+rem  the Pieces you need for MSVC 1.52c\r
+call copyback libraries\msdos\winsock\libldap.def libraries\libldap\libldap.def \r
+call copyback libraries\msdos\winsock\libldap.mak libraries\libldap\libldap.mak \r
+call copyback libraries\msdos\winsock\libldap.rc libraries\libldap\libldap.rc \r
+call copyback libraries\msdos\winsock\wsa\winsock.def libraries\libldap\winsock.def \r
+\r
+call copyback libraries\msdos\winsock\ldap32.def libraries\libldap\ldap32.def \r
+call copyback libraries\msdos\winsock\ldap32.mak libraries\libldap\ldap32.mak \r
+call copyback libraries\msdos\winsock\ldap32.mdp libraries\libldap\ldap32.mdp\r
+\r
+call copyback libraries\libldap\getfilter.c libraries\libldap\getfilte.c\r
+call copyback libraries\libldap\getvalues.c libraries\libldap\getvalue.c\r
+call copyback include\proto-lber.h include\proto-lb.h\r
+call copyback include\proto-ldap.h include\proto-ld.h\r
+\r
+rmdir include\netinet\r
+rmdir include\arpa\r
+rmdir include\_sys\r
+rmdir include\sys\r
+\r
+goto END\r
+\r
+:END\r
+\r
diff --git a/libraries/msdos/winsock/winkit/help/ldap32.hlp b/libraries/msdos/winsock/winkit/help/ldap32.hlp
new file mode 100644 (file)
index 0000000..f9de544
Binary files /dev/null and b/libraries/msdos/winsock/winkit/help/ldap32.hlp differ
diff --git a/libraries/msdos/winsock/winkit/help/ldap32.hpj b/libraries/msdos/winsock/winkit/help/ldap32.hpj
new file mode 100644 (file)
index 0000000..03b2141
--- /dev/null
@@ -0,0 +1,21 @@
+; This file is maintained by HCW. Do not modify this file directly.\r
+\r
+\r
+[OPTIONS]\r
+HCW=0\r
+COMPRESS=12 Hall Zeck\r
+ERRORLOG=LDAP32.ERR\r
+LCID=0x409 0x0 0x0 ;U.S. English\r
+REPORT=Yes\r
+FTS=1d\r
+CONTENTS=Contents\r
+TITLE=Ldap Client API for Windows\r
+COPYRIGHT=Copyright Â¸ Regents of University of Michigan\r
+CITATION=X.500 Project\r
+HLP=.\Ldap32.hlp\r
+\r
+[FILES]\r
+.\libldap.RTF\r
+\r
+[WINDOWS]\r
+main="",,60416\r
diff --git a/libraries/msdos/winsock/winkit/help/libldap.hlp b/libraries/msdos/winsock/winkit/help/libldap.hlp
new file mode 100644 (file)
index 0000000..981ef71
Binary files /dev/null and b/libraries/msdos/winsock/winkit/help/libldap.hlp differ
diff --git a/libraries/msdos/winsock/winkit/help/libldap.hpj b/libraries/msdos/winsock/winkit/help/libldap.hpj
new file mode 100644 (file)
index 0000000..59ab30d
--- /dev/null
@@ -0,0 +1,14 @@
+\r
+[OPTIONS]\r
+ERRORLOG=$LIBLDAP.ERR\r
+COMPRESS=HIGH\r
+OLDKEYPHRASE=YES\r
+CONTENTS=Contents\r
+TITLE=Ldap API for Windows\r
+COPYRIGHT=Copyright Â¸ Regents of University of Michigan\r
+CITATION=X.500 Project\r
+[WINDOWS]\r
+main=,,0,,,0\r
+\r
+[FILES]\r
+$LIBLDAP.RTF\r
diff --git a/libraries/msdos/winsock/winkit/readme.txt b/libraries/msdos/winsock/winkit/readme.txt
new file mode 100644 (file)
index 0000000..5dffc1c
--- /dev/null
@@ -0,0 +1,182 @@
+
+LDAP (Lightweight Directory Access Protocol) API for Windows/Winsock
+
+The lber and ldap client libraries have been ported to Microsoft Windows
+in the form of Windows Dynamic Link libraries called LIBLDAP.DLL (16Bit)
+and Ldap32.dll (32Bit).  The LTest program is also provided in both
+formats.
+
+A Windows Sockets API (version 1.1 conformant) TCP/IP WINSOCK.DLL or
+WSOCK32.DLL is required for the DLL to run.
+
+Our intent is that this "kit" include everything you'll need to make use
+of the ldap client API from your 16Bit or 32Bit application.  If you
+find something missing or have a suggestion for improvement, send email
+to the "bug reporting" address at the bottom of this file.
+
+To use this "kit"
+
+    1) Get to a DOS prompt
+       
+    2) Create the directory you want this to live in (e.g.  \ldap)
+       and cd into it.  We will refer to that directory simply as
+       "\ldap" from now on, but it could be anywhere and have any name
+       you desire.
+
+    3) Use "pkunzip -d" to extract the files.  The "-d" is NECESSARY to
+       preserve the subdirectories and avoid file name collisions.
+
+    4) We have included only the files you need to use and test
+       libldap.dll and ldap32.dll.  If you want the entire distribution, 
+       with source, you can get it from:
+
+           ftp://terminator.rs.itd.umich.edu/ldap/ldap-3.3.tar.Z
+
+The following files are included in this distribution:
+
+    16Bit binaries and libs
+       BINARIES/DEBUG/LIBLDAP.DLL
+       BINARIES/DEBUG/LIBLDAP.LIB
+       BINARIES/RELEASE/LIBLDAP.DLL
+       BINARIES/RELEASE/LIBLDAP.LIB
+
+       BINARIES/DEBUG/LTEST.EXE
+
+    32Bit binaries and libs
+       BINARIES/DEBUG/LDAP32.DLL
+       BINARIES/DEBUG/LDAP32.LIB
+       BINARIES/RELEASE/LDAP32.DLL
+       BINARIES/RELEASE/LDAP32.LIB
+
+       BINARIES/DEBUG/LTEST32.EXE
+
+    Include files
+       INCKIT/MSDOS.H
+       INCKIT/LBER.H
+       INCKIT/LDAP.H
+       INCKIT/PROTO-LD.H
+       INCKIT/PROTO-LB.H
+       INCKIT/SRCHPREF.H
+       INCKIT/DISPTMPL.H
+
+    Sample Configuration files
+       SRCHPREF.CFG
+       DISPTMPL.CFG
+       LDFRIEND.CFG
+       LDFILTER.CFG
+
+    Man pages in the form of Windows HLP files
+       LIBLDAP.HLP     - old format hlp file
+       LDAP32.HLP      - new format hlp file, both have same content
+
+16Bit versions
+
+    Libldap.dll was compiled with KERBEROS, AUTHMAN, WSHELPER, WIN32,
+    _WINDOWS,& LDAP_REFERRALS defined.  Even if you do not need kerberos
+    authentication, (see below for more information on kerberos) this
+    dll should work correctly for you.
+
+    LDAP_REFERRALS makes libldap.dll capable of handling referrals
+    returned by a slapd server.
+
+32Bit versions
+
+    The 32Bit version is NOT SAFE for MULTIPLE THREADS at this time.
+    Not more than one thread per application may make use of the
+    ldap routines.
+
+    Ldap32.dll was compiled with LDAP_REFERRALS defined and is capable
+    of handling referrals returned by a slapd server.
+
+
+WRITING APPLICATIONS THAT USE LIBLDAP.DLL or LDAP32.DLL
+
+    All of the normal LDAP and LBER calls documented in the help file
+    should work, except for ldap_perror (this is not supported under
+    Windows since you will want to use an application-defined dialog;
+    you can use ldap_err2string to obtain an error string to display in
+    a message box or dialog).  
+
+    The man pages are included in this kit in the form of windows HLP files.
+    The official source man pages are available via the web at:
+
+           http://www.umich.edu/ldap/doc/man/
+
+    Any memory that you obtain as the result of a call to an LIBLDAP.DLL
+    routine should NOT be freed by calling the free() routine in your C
+    library.  Instead, use the the new utility routine ldap_memfree or
+    the appropriate ldap ...free routine.  This is so the malloc/calloc
+    and free routines all come from the same library (the one in
+    libldap) rather than using libldap's malloc/calloc and the calling
+    program's free.  Microsoft's VC++ 4.0 compiler (in debug mode)
+    FORCED me to be compulsive about this for the application I used to
+    test.
+
+    To be friendly under Windows, you should use the asynchronous LDAP
+    calls whenever possible.
+
+    One limitation of the current LIBLDAP.DLL is that each X.500 LDAP
+    result message has to be smaller than 64K bytes.  Ldap32.dll does
+    NOT have this limitation.
+
+    To compile the ldap dlls we define the following preprocessor variables.
+
+        WINSOCK, DOS, NEEDPROTOS, NO_USERINTERFACE, KERBEROS
+    
+    Presumably you don't need KERBEROS.  You may need some/all the others
+    to take the right path through the include files.  Also note that a
+    few more preprocessor variables are defined in msdos.h.  This means that
+    msdos.h must be included before ldap.h or lber.h.
+    
+
+LTest and LTtest32 
+
+    The LTest.exe and LTest32.exe programs are test interfaces to libldap
+    and ldap32 respectively.  By default they connect to the host 
+    "truelies".  This host name is contained in a string resource in the
+    exe file.  You may easily "customize" this to be the name of whatever
+    server you're using with AppStudio or any Windows resource editor.
+
+Kerberos Information
+
+    Libldap.dll was compiled with KERBEROS, AUTHMAN, WSHELPER, &
+    LDAP_REFERRALS defined.  If you do not need kerberos authentication,
+    this dll should still work correctly for you.  Libldap.dll
+    dynamically loads and uses the dlls needed for kerberos
+    authentication (Authlib.dll, Krbv4win.dll, & WSHelper.dll).  If
+    Libldap.dll is unable to load the needed dlls, execution continues
+    without error, but without kerberos authentication capability.
+
+    AUTHMAN allows libldap.dll to make use of Authlib.dll (which
+    requires KrbV4Win.dll & WSHelper.dll) if they are ALL in the "PATH".
+    If these are not available, kerberos authentication can not succede,
+    but libldap.dll will execute without error.
+
+    WSHELPER means that if WSHelper.dll is in the "PATH", it will be
+    dynamically loaded and used to do the gethostbyaddr() call required
+    for kerberos authentication to work.  (This is used because so many
+    vendor implementations of gethostbyaddr return WRONG results.  We
+    are working with all vendors we can get to listen to get these
+    implementations fixed.)  If WSHelper.dll is not in the "PATH"
+    libldap.dll does not fail to execute correctly.
+
+    Ldap32.dll does NOT have the ability to do kerberos authentication
+    because none of Authlib.dll, krbv4win.dll or wshelper.dll have been
+    ported to 32Bits at this time.
+
+    For further information on using kerberos with the ldap DLLs send
+    email to ldap-support@umich.edu.
+
+BUG REPORTING
+
+    Bug reports should be sent to bug-ldap@umich.edu.
+
+
+Miscellaneous
+
+    Build testing was done on Windows NT workstation 3.51 (build 1057
+    service pack 2) on an NTFS file system (which supports long
+    filenames) using Microsoft Visual C++ 1.52c (16 bit) and Visual C++
+    4.0 (32 bit).
+
+README Last updated 11 January 1996 by Steve Rothwell
diff --git a/libraries/msdos/winsock/winkit/windowskit.cmd b/libraries/msdos/winsock/winkit/windowskit.cmd
new file mode 100644 (file)
index 0000000..bcaa227
--- /dev/null
@@ -0,0 +1 @@
+nmake /f WindowsKit.Mak all\r
diff --git a/libraries/msdos/winsock/winkit/windowskit.mak b/libraries/msdos/winsock/winkit/windowskit.mak
new file mode 100644 (file)
index 0000000..7ba8154
--- /dev/null
@@ -0,0 +1,172 @@
+#\r
+# makefile.nmake stub makefile for nmake\r
+# 15 Dec 1995 : sgr\r
+#\r
+#<target> :[:] <dependent> [... <dependent>]\r
+#      <commands>\r
+#      [<commands>]\r
+#\r
+# $@   Current target's full name (path, base, extension)\r
+# $$@  Current target's full name (path, base, extension)\r
+#      (Valid only as a dependent in a dependency.)\r
+# $*   Current target's path & base name minus extension\r
+# $**  All dependents of the current target.\r
+# $?   All dependents with a later timestamp than the current target.\r
+# $<   Dependent file with a later timestamp that the current target.\r
+#      (Valid only in commands in inference rules.)\r
+#\r
+# Modifiers $(@F)\r
+# B    Base name\r
+# F    Base name + extension (Full name)\r
+# D    Drive + directory\r
+# R    Drive + directory + base name (Reusable name)\r
+\r
+ROOT = ..\..\..\..\r
+HELP = $(ROOT)\windows\help\r
+LDAP = $(ROOT)\librar~1\libldap\r
+LTEST = $(ROOT)\librar~1\msdos\winsock\ltest\r
+WINSOCK = $(ROOT)\librar~1\msdos\winsock\r
+MAININC = $(ROOT)\include\r
+LINCL = incKit\r
+BIN = binaries\r
+BINARIES = \\r
+               $(BIN)\debug\libldap.dll \\r
+               $(BIN)\debug\libldap.lib \\r
+               $(BIN)\release\libldap.dll \\r
+               $(BIN)\release\libldap.lib \\r
+               $(BIN)\debug\ltest.exe \\r
+               $(BIN)\debug\ldap32.dll \\r
+               $(BIN)\debug\ldap32.lib \\r
+               $(BIN)\release\ldap32.dll \\r
+               $(BIN)\release\ldap32.lib \\r
+               $(BIN)\debug\ltest32.exe \\r
+               libldap.hlp \\r
+               ldap32.hlp\r
+\r
+all: WinLdap.zip\r
+\r
+WinLdap.zip :  \\r
+               $(BINARIES) \\r
+# Using Wax500 as a test case, only the\r
+# following include files are needed to make\r
+# a non-kerberized ldap32.dll\r
+# or a kerberized libldap.dll\r
+               $(LINCL)\disptmpl.h \\r
+               $(LINCL)\lber.h \\r
+               $(LINCL)\ldap.h \\r
+               $(LINCL)\msdos.h \\r
+               $(LINCL)\proto-ld.h \\r
+               $(LINCL)\proto-lb.h \\r
+               $(LINCL)\srchpref.h \\r
+               srchpref.cfg \\r
+               disptmpl.cfg \\r
+               ldfriend.cfg \\r
+               ldfilter.cfg \\r
+               readme.txt\r
+       -!pkzip -P -u $@ $?\r
+       del *.cfg\r
+\r
+$(BIN)\debug\libldap.dll : $(LDAP)\debug\libldap.dll \r
+       -@md $(@D)\r
+       -copy $? $@\r
+\r
+$(BIN)\debug\libldap.lib : $(LDAP)\debug\libldap.lib \r
+       -@md $(@D)\r
+       -copy $? $@\r
+\r
+$(BIN)\debug\ltest.exe : $(LTEST)\ltest.exe \r
+       -@md $(@D)\r
+       -copy $? $@\r
+\r
+$(BIN)\debug\ldap32.dll : $(LDAP)\debug\ldap32.dll \r
+       -@md $(@D)\r
+       -copy $? $@\r
+\r
+$(BIN)\debug\ldap32.lib : $(LDAP)\debug\ldap32.lib \r
+       -@md $(@D)\r
+       -copy $? $@\r
+\r
+$(BIN)\debug\ltest32.exe : $(LTEST)\debug\ltest32.exe \r
+       -@md $(@D)\r
+       -copy $? $@\r
+\r
+$(BIN)\release\libldap.dll : $(LDAP)\release\libldap.dll \r
+       -@md $(@D)\r
+       -copy $? $@\r
+\r
+$(BIN)\release\libldap.lib : $(LDAP)\release\libldap.lib \r
+       -@md $(@D)\r
+       -copy $? $@\r
+\r
+$(BIN)\release\ldap32.dll : $(LDAP)\release\ldap32.dll \r
+       -@md $(@D)\r
+       -copy $? $@\r
+\r
+$(BIN)\release\ldap32.lib : $(LDAP)\release\ldap32.lib \r
+       -@md $(@D)\r
+       -copy $? $@\r
+\r
+$(LINCL)\disptmpl.h : $(MAININC)\disptmpl.h\r
+       -@md $(@D)\r
+       -copy $? $@\r
+\r
+$(LINCL)\lber.h : $(MAININC)\lber.h\r
+       -@md $(@D)\r
+       -copy $? $@\r
+\r
+$(LINCL)\ldap.h : $(MAININC)\ldap.h\r
+       -@md $(@D)\r
+       -copy $? $@\r
+\r
+$(LINCL)\msdos.h : $(MAININC)\msdos.h\r
+       -@md $(@D)\r
+       -copy $? $@\r
+\r
+$(LINCL)\proto-ld.h : $(MAININC)\proto-ld.h\r
+       -@md $(@D)\r
+       -copy $? $@\r
+\r
+$(LINCL)\proto-lb.h : $(MAININC)\proto-lb.h\r
+       -@md $(@D)\r
+       -copy $? $@\r
+\r
+$(LINCL)\srchpref.h : $(MAININC)\srchpref.h\r
+       -@md $(@D)\r
+       -copy $? $@\r
+\r
+libldap.hlp : $(HELP)\build\libldap.hlp\r
+       -copy $? $@\r
+\r
+ldap32.hlp  : $(HELP)\ldap32.hlp\r
+       -copy $? $@\r
+\r
+srchpref.cfg :         $(LDAP)\ldapsearchprefs.conf\r
+       -copy $** $@ \r
+\r
+ldfilter.cfg :         $(LDAP)\ldapfilter.conf\r
+       -copy $** $@ \r
+\r
+disptmpl.cfg :         $(LDAP)\ldaptemplates.conf\r
+       -copy $** $@ \r
+\r
+ldfriend.cfg :         $(LDAP)\ldapfriendly\r
+       -copy $** $@ \r
+\r
+\r
+$(LDAP)\debug\libldap.dll :\r
+$(LDAP)\debug\libldap.lib :\r
+$(LDAP)\release\libldap.dll :\r
+$(LDAP)\release\libldap.lib :\r
+$(LTEST)\ltest.exe :\r
+$(LDAP)\debug\ldap32.dll :\r
+$(LDAP)\debug\ldap32.lib :\r
+$(LDAP)\release\ldap32.dll :\r
+$(LDAP)\release\ldap32.lib :\r
+$(LTEST)\debug\ltest32.exe :\r
+$(HELP)\build\libldap.hlp :\r
+$(HELP)\ldap32.hlp :\r
+$(LDAP)\ldapsearchprefs.conf :\r
+$(LDAP)\ldapfilter.conf :\r
+$(LDAP)\ldaptemplates.conf :\r
+$(LDAP)\ldapfriendly :\r
+readme.txt :\r
diff --git a/libraries/msdos/winsock/wsa.c b/libraries/msdos/winsock/wsa.c
new file mode 100644 (file)
index 0000000..5ae59f9
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Microsoft Windows specifics for LIBLDAP DLL
+ */
+#include "lber.h"
+#include "ldap.h"
+#include "msdos.h"
+
+
+#ifdef _WIN32
+/* Lifted from Q125688
+ * How to Port a 16-bit DLL to a Win32 DLL
+ * on the MSVC 4.0 CD
+ */
+BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
+{
+       switch (fdwReason)
+       {
+       case DLL_PROCESS_ATTACH:
+                /* Code from LibMain inserted here.  Return TRUE to keep the
+                   DLL loaded or return FALSE to fail loading the DLL.
+
+                   You may have to modify the code in your original LibMain to
+                   account for the fact that it may be called more than once.
+                   You will get one DLL_PROCESS_ATTACH for each process that
+                   loads the DLL. This is different from LibMain which gets
+                   called only once when the DLL is loaded. The only time this
+                   is critical is when you are using shared data sections.
+                   If you are using shared data sections for statically
+                   allocated data, you will need to be careful to initialize it
+                   only once. Check your code carefully.
+
+                   Certain one-time initializations may now need to be done for
+                   each process that attaches. You may also not need code from
+                   your original LibMain because the operating system may now
+                   be doing it for you.
+                */
+               /*
+                * 16 bit code calls UnlockData()
+                * which is mapped to UnlockSegment in windows.h
+                * in 32 bit world UnlockData is not defined anywhere
+                * UnlockSegment is mapped to GlobalUnfix in winbase.h
+                * and the docs for both UnlockSegment and GlobalUnfix say 
+                * ".. function is oboslete.  Segments have no meaning 
+                *  in the 32-bit environment".  So we do nothing here.
+                */
+               break;
+
+       case DLL_THREAD_ATTACH:
+               /* Called each time a thread is created in a process that has
+                  already loaded (attached to) this DLL. Does not get called
+                  for each thread that exists in the process before it loaded
+                  the DLL.
+
+                  Do thread-specific initialization here.
+               */
+               break;
+
+       case DLL_THREAD_DETACH:
+               /* Same as above, but called when a thread in the process
+                  exits.
+
+                  Do thread-specific cleanup here.
+               */
+               break;
+
+       case DLL_PROCESS_DETACH:
+               /* Code from _WEP inserted here.  This code may (like the
+                  LibMain) not be necessary.  Check to make certain that the
+                  operating system is not doing it for you.
+               */
+               break;
+       }
+       /* The return value is only used for DLL_PROCESS_ATTACH; all other
+       conditions are ignored.  */
+       return TRUE;   // successful DLL_PROCESS_ATTACH
+}
+#else
+int CALLBACK
+LibMain( HINSTANCE hinst, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine )
+{
+       UnlockData( 0 );
+       return( 1 );
+}
+#endif
+
+
+void
+ldap_memfree( void *p )
+{
+       free( p );
+}
diff --git a/libraries/msdos/winsock/wsa/errno.c b/libraries/msdos/winsock/wsa/errno.c
new file mode 100644 (file)
index 0000000..cb49c5f
--- /dev/null
@@ -0,0 +1,21 @@
+#include <winsock.h>
+
+/* Copies string corresponding to the error code provided    */
+/* into buf, maximum length len. Returns length actually     */
+/* copied to buffer, or zero if error code is unknown.       */
+/* String resources should be present for each error code    */
+/* using the value of the code as the string ID (except for  */
+/* error = 0, which is mapped to WSABASEERR to keep it with  */
+/* the others). The DLL is free to use any string IDs that   */
+/* are less than WSABASEERR for its own use. The LibMain     */
+/* procedure of the DLL is presumed to have saved its        */
+/* HINSTANCE in the global variable hInst.                   */
+
+int PASCAL FAR WSAsperror (int errorcode, char far * buf, int len)
+{
+        if (errorcode == 0)
+                errorcode = WSABASEERR;
+        if (errorcode < WSABASEERR)
+                return 0;
+        return LoadString(hInst,errorcode,buf,len);
+}
diff --git a/libraries/msdos/winsock/wsa/errno.rc b/libraries/msdos/winsock/wsa/errno.rc
new file mode 100644 (file)
index 0000000..1252957
--- /dev/null
@@ -0,0 +1,57 @@
+#include <winsock.h>
+
+STRINGTABLE
+BEGIN
+  WSABASEERR,         "[0] No Error"
+  WSAEINTR,           "[10004] Interrupted system call"
+  WSAEBADF,           "[10009] Bad file number"
+  WSAEACCES,          "[10013] Permission denied"
+  WSAEFAULT,          "[10014] Bad address"
+  WSAEINVAL,          "[10022] Invalid argument"
+  WSAEMFILE,          "[10024] Too many open files"
+  WSAEWOULDBLOCK,     "[10035] Operation would block"
+  WSAEINPROGRESS,     "[10036] Operation now in progress"
+  WSAEALREADY,        "[10037] Operation already in progress"
+  WSAENOTSOCK,        "[10038] Socket operation on non-socket"
+  WSAEDESTADDRREQ,    "[10039] Destination address required"
+  WSAEMSGSIZE,        "[10040] Message too long"
+  WSAEPROTOTYPE,      "[10041] Protocol wrong type for socket"
+  WSAENOPROTOOPT,     "[10042] Bad protocol option"
+  WSAEPROTONOSUPPORT, "[10043] Protocol not supported"
+  WSAESOCKTNOSUPPORT, "[10044] Socket type not supported"
+  WSAEOPNOTSUPP,      "[10045] Operation not supported on socket"
+  WSAEPFNOSUPPORT,    "[10046] Protocol family not supported"
+  WSAEAFNOSUPPORT,    "[10047] Address family not supported by protocol family"
+  WSAEADDRINUSE,      "[10048] Address already in use"
+  WSAEADDRNOTAVAIL,   "[10049] Can't assign requested address"
+  WSAENETDOWN,        "[10050] Network is down"
+  WSAENETUNREACH,     "[10051] Network is unreachable"
+  WSAENETRESET,       "[10052] Net dropped connection or reset"
+  WSAECONNABORTED,    "[10053] Software caused connection abort"
+  WSAECONNRESET,      "[10054] Connection reset by peer"
+  WSAENOBUFS,         "[10055] No buffer space available"
+  WSAEISCONN,         "[10056] Socket is already connected"
+  WSAENOTCONN,        "[10057] Socket is not connected"
+  WSAESHUTDOWN,       "[10058] Can't send after socket shutdown"
+  WSAETOOMANYREFS,    "[10059] Too many references, can't splice"
+  WSAETIMEDOUT,       "[10060] Connection timed out"
+  WSAECONNREFUSED,    "[10061] Connection refused"
+  WSAELOOP,           "[10062] Too many levels of symbolic links"
+  WSAENAMETOOLONG,    "[10063] File name too long"
+  WSAEHOSTDOWN,       "[10064] Host is down"
+  WSAEHOSTUNREACH,    "[10065] No Route to Host"
+  WSAENOTEMPTY,       "[10066] Directory not empty"
+  WSAEPROCLIM,        "[10067] Too many processes"
+  WSAEUSERS,          "[10068] Too many users"
+  WSAEDQUOT,          "[10069] Disc Quota Exceeded"
+  WSAESTALE,          "[10070] Stale NFS file handle"
+  WSAEREMOTE,         "[10071] Too many levels of remote in path"
+  WSASYSNOTREADY,     "[10091] Network SubSystem is unavailable"
+  WSAVERNOTSUPPORTED, "[10092] WINSOCK DLL Version out of range"
+  WSANOTINITIALIZED,  "[10093] Successful WSASTARTUP not yet performed"
+  WSAHOST_NOT_FOUND,  "[11001] Host not found"
+  WSATRY_AGAIN,       "[11002] Non-Authoritative Host not found"
+  WSANO_RECOVERY,     "[11003] Non-Recoverable errors: FORMERR, REFUSED, NOTIMP"
+  WSANO_DATA,         "[11004] Valid name, no data record of requested 
+type"
+END
diff --git a/libraries/msdos/winsock/wsa/winsock.def b/libraries/msdos/winsock/wsa/winsock.def
new file mode 100644 (file)
index 0000000..0aa0953
--- /dev/null
@@ -0,0 +1,84 @@
+;  
+;         File: winsock.def 
+;       System: MS-Windows 3.x 
+;      Summary: Module definition file for Windows Sockets DLL.  
+;  
+
+LIBRARY         WINSOCK         ; Application's module name 
+
+DESCRIPTION     'BSD Socket API for Windows' 
+
+EXETYPE         WINDOWS         ; required for all windows applications 
+
+STUB            'WINSTUB.EXE'   ; generates error message if application 
+                                ; is run without Windows 
+
+;CODE can be FIXED in memory because of potential upcalls 
+CODE            PRELOAD         FIXED 
+
+;DATA must be SINGLE and at a FIXED location since this is a DLL 
+DATA            PRELOAD         FIXED           SINGLE
+
+HEAPSIZE        1024 
+STACKSIZE       16384 
+
+; All functions that will be called by any Windows routine 
+; must be exported.  Any additional exports beyond those defined
+; here must have ordinal numbers 1000 or above. 
+
+EXPORTS 
+        accept                         @1 
+        bind                           @2 
+        closesocket                    @3 
+        connect                        @4 
+        getpeername                    @5 
+        getsockname                    @6 
+        getsockopt                     @7 
+        htonl                          @8 
+        htons                          @9 
+        inet_addr                      @10 
+        inet_ntoa                      @11 
+        ioctlsocket                    @12 
+        listen                         @13 
+        ntohl                          @14 
+        ntohs                          @15 
+        recv                           @16 
+        recvfrom                       @17 
+        select                         @18 
+        send                           @19 
+        sendto                         @20 
+        setsockopt                     @21 
+        shutdown                       @22 
+        socket                         @23 
+
+        gethostbyaddr                  @51 
+        gethostbyname                  @52 
+        getprotobyname                 @53 
+        getprotobynumber               @54 
+        getservbyname                  @55 
+        getservbyport                  @56 
+        gethostname                    @57
+
+        WSAAsyncSelect                 @101 
+        WSAAsyncGetHostByAddr          @102 
+        WSAAsyncGetHostByName          @103 
+        WSAAsyncGetProtoByNumber       @104 
+        WSAAsyncGetProtoByName         @105 
+        WSAAsyncGetServByPort          @106 
+        WSAAsyncGetServByName          @107 
+        WSACancelAsyncRequest          @108 
+        WSASetBlockingHook             @109 
+        WSAUnhookBlockingHook          @110 
+        WSAGetLastError                @111 
+        WSASetLastError                @112 
+        WSACancelBlockingCall          @113 
+        WSAIsBlocking                  @114 
+        WSAStartup                     @115 
+        WSACleanup                     @116 
+
+        __WSAFDIsSet                   @151 
+
+        WEP                            @500    RESIDENTNAME 
+
+;eof 
+
diff --git a/libraries/msdos/winsock/wsa/winsock.h b/libraries/msdos/winsock/wsa/winsock.h
new file mode 100644 (file)
index 0000000..13eb70a
--- /dev/null
@@ -0,0 +1,826 @@
+/* WINSOCK.H--definitions to be used with the WINSOCK.DLL
+ *
+ * This header file corresponds to version 1.1 of the Windows Sockets specification.
+ *
+ * This file includes parts which are Copyright (c) 1982-1986 Regents
+ * of the University of California.  All rights reserved.  The
+ * Berkeley Software License Agreement specifies the terms and
+ * conditions for redistribution.
+ */
+
+#ifndef _WINSOCKAPI_
+#define _WINSOCKAPI_
+
+/*
+ * Pull in WINDOWS.H if necessary
+ */
+#ifndef _INC_WINDOWS
+#include <windows.h>
+#endif /* _INC_WINDOWS */
+
+/*
+ * Basic system type definitions, taken from the BSD file sys/types.h.
+ */
+typedef unsigned char   u_char;
+typedef unsigned short  u_short;
+typedef unsigned int    u_int;
+typedef unsigned long   u_long;
+
+/*
+ * The new type to be used in all
+ * instances which refer to sockets.
+ */
+typedef u_int           SOCKET;
+
+/*
+ * Select uses arrays of SOCKETs.  These macros manipulate such
+ * arrays.  FD_SETSIZE may be defined by the user before including
+ * this file, but the default here should be >= 64.
+ *
+ * CAVEAT IMPLEMENTOR and USER: THESE MACROS AND TYPES MUST BE
+ * INCLUDED IN WINSOCK.H EXACTLY AS SHOWN HERE.
+ */
+#ifndef FD_SETSIZE
+#define FD_SETSIZE      64
+#endif /* FD_SETSIZE */
+
+typedef struct fd_set {
+        u_short fd_count;               /* how many are SET? */
+        SOCKET  fd_array[FD_SETSIZE];   /* an array of SOCKETs */
+} fd_set;
+
+extern int PASCAL FAR __WSAFDIsSet(SOCKET, fd_set FAR *);
+
+#define FD_CLR(fd, set) do { \
+    u_int __i; \
+    for (__i = 0; __i < ((fd_set FAR *)(set))->fd_count ; __i++) { \
+        if (((fd_set FAR *)(set))->fd_array[__i] == fd) { \
+            while (__i < ((fd_set FAR *)(set))->fd_count-1) { \
+                ((fd_set FAR *)(set))->fd_array[__i] = \
+                    ((fd_set FAR *)(set))->fd_array[__i+1]; \
+                __i++; \
+            } \
+            ((fd_set FAR *)(set))->fd_count--; \
+            break; \
+        } \
+    } \
+} while(0)
+
+#define FD_SET(fd, set) do { \
+    if (((fd_set FAR *)(set))->fd_count < FD_SETSIZE) \
+        ((fd_set FAR *)(set))->fd_array[((fd_set FAR *)(set))->fd_count++]=fd;\
+} while(0)
+
+#define FD_ZERO(set) (((fd_set FAR *)(set))->fd_count=0)
+
+#define FD_ISSET(fd, set) __WSAFDIsSet((SOCKET)fd, (fd_set FAR *)set)
+
+/*
+ * Structure used in select() call, taken from the BSD file sys/time.h.
+ */
+struct timeval {
+        long    tv_sec;         /* seconds */
+        long    tv_usec;        /* and microseconds */
+};
+
+/*
+ * Operations on timevals.
+ *
+ * NB: timercmp does not work for >= or <=.
+ */
+#define timerisset(tvp)         ((tvp)->tv_sec || (tvp)->tv_usec)
+#define timercmp(tvp, uvp, cmp) \
+        ((tvp)->tv_sec cmp (uvp)->tv_sec || \
+         (tvp)->tv_sec == (uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec)
+#define timerclear(tvp)         (tvp)->tv_sec = (tvp)->tv_usec = 0
+
+/*
+ * Commands for ioctlsocket(),  taken from the BSD file fcntl.h.
+ *
+ *
+ * Ioctl's have the command encoded in the lower word,
+ * and the size of any in or out parameters in the upper
+ * word.  The high 2 bits of the upper word are used
+ * to encode the in/out status of the parameter; for now
+ * we restrict parameters to at most 128 bytes.
+ */
+#define IOCPARM_MASK    0x7f            /* parameters must be < 128 bytes */
+#define IOC_VOID        0x20000000      /* no parameters */
+#define IOC_OUT         0x40000000      /* copy out parameters */
+#define IOC_IN          0x80000000      /* copy in parameters */
+#define IOC_INOUT       (IOC_IN|IOC_OUT)
+                                        /* 0x20000000 distinguishes new &
+                                           old ioctl's */
+#define _IO(x,y)        (IOC_VOID|(x<<8)|y)
+
+#define _IOR(x,y,t)     (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y)
+
+#define _IOW(x,y,t)     (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y)
+
+#define FIONREAD    _IOR('f', 127, u_long) /* get # bytes to read */
+#define FIONBIO     _IOW('f', 126, u_long) /* set/clear non-blocking i/o */
+#define FIOASYNC    _IOW('f', 125, u_long) /* set/clear async i/o */
+
+/* Socket I/O Controls */
+#define SIOCSHIWAT  _IOW('s',  0, u_long)  /* set high watermark */
+#define SIOCGHIWAT  _IOR('s',  1, u_long)  /* get high watermark */
+#define SIOCSLOWAT  _IOW('s',  2, u_long)  /* set low watermark */
+#define SIOCGLOWAT  _IOR('s',  3, u_long)  /* get low watermark */
+#define SIOCATMARK  _IOR('s',  7, u_long)  /* at oob mark? */
+
+/*
+ * Structures returned by network data base library, taken from the
+ * BSD file netdb.h.  All addresses are supplied in host order, and
+ * returned in network order (suitable for use in system calls).
+ */
+
+struct  hostent {
+        char    FAR * h_name;           /* official name of host */
+        char    FAR * FAR * h_aliases;  /* alias list */
+        short   h_addrtype;             /* host address type */
+        short   h_length;               /* length of address */
+        char    FAR * FAR * h_addr_list; /* list of addresses */
+#define h_addr  h_addr_list[0]          /* address, for backward compat */
+};
+
+/*
+ * It is assumed here that a network number
+ * fits in 32 bits.
+ */
+struct  netent {
+        char    FAR * n_name;           /* official name of net */
+        char    FAR * FAR * n_aliases;  /* alias list */
+        short   n_addrtype;             /* net address type */
+        u_long  n_net;                  /* network # */
+};
+
+struct  servent {
+        char    FAR * s_name;           /* official service name */
+        char    FAR * FAR * s_aliases;  /* alias list */
+        short   s_port;                 /* port # */
+        char    FAR * s_proto;          /* protocol to use */
+};
+
+struct  protoent {
+        char    FAR * p_name;           /* official protocol name */
+        char    FAR * FAR * p_aliases;  /* alias list */
+        short   p_proto;                /* protocol # */
+};
+
+/*
+ * Constants and structures defined by the internet system,
+ * Per RFC 790, September 1981, taken from the BSD file netinet/in.h.
+ */
+
+/*
+ * Protocols
+ */
+#define IPPROTO_IP              0               /* dummy for IP */
+#define IPPROTO_ICMP            1               /* control message protocol */
+#define IPPROTO_GGP             2               /* gateway^2 (deprecated) */
+#define IPPROTO_TCP             6               /* tcp */
+#define IPPROTO_PUP             12              /* pup */
+#define IPPROTO_UDP             17              /* user datagram protocol */
+#define IPPROTO_IDP             22              /* xns idp */
+#define IPPROTO_ND              77              /* UNOFFICIAL net disk proto */
+
+#define IPPROTO_RAW             255             /* raw IP packet */
+#define IPPROTO_MAX             256
+
+/*
+ * Port/socket numbers: network standard functions
+ */
+#define IPPORT_ECHO             7
+#define IPPORT_DISCARD          9
+#define IPPORT_SYSTAT           11
+#define IPPORT_DAYTIME          13
+#define IPPORT_NETSTAT          15
+#define IPPORT_FTP              21
+#define IPPORT_TELNET           23
+#define IPPORT_SMTP             25
+#define IPPORT_TIMESERVER       37
+#define IPPORT_NAMESERVER       42
+#define IPPORT_WHOIS            43
+#define IPPORT_MTP              57
+
+/*
+ * Port/socket numbers: host specific functions
+ */
+#define IPPORT_TFTP             69
+#define IPPORT_RJE              77
+#define IPPORT_FINGER           79
+#define IPPORT_TTYLINK          87
+#define IPPORT_SUPDUP           95
+
+/*
+ * UNIX TCP sockets
+ */
+#define IPPORT_EXECSERVER       512
+#define IPPORT_LOGINSERVER      513
+#define IPPORT_CMDSERVER        514
+#define IPPORT_EFSSERVER        520
+
+/*
+ * UNIX UDP sockets
+ */
+#define IPPORT_BIFFUDP          512
+#define IPPORT_WHOSERVER        513
+#define IPPORT_ROUTESERVER      520
+                                        /* 520+1 also used */
+
+/*
+ * Ports < IPPORT_RESERVED are reserved for
+ * privileged processes (e.g. root).
+ */
+#define IPPORT_RESERVED         1024
+
+/*
+ * Link numbers
+ */
+#define IMPLINK_IP              155
+#define IMPLINK_LOWEXPER        156
+#define IMPLINK_HIGHEXPER       158
+
+/*
+ * Internet address (old style... should be updated)
+ */
+struct in_addr {
+        union {
+                struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
+                struct { u_short s_w1,s_w2; } S_un_w;
+                u_long S_addr;
+        } S_un;
+#define s_addr  S_un.S_addr
+                                /* can be used for most tcp & ip code */
+#define s_host  S_un.S_un_b.s_b2
+                                /* host on imp */
+#define s_net   S_un.S_un_b.s_b1
+                                /* network */
+#define s_imp   S_un.S_un_w.s_w2
+                                /* imp */
+#define s_impno S_un.S_un_b.s_b4
+                                /* imp # */
+#define s_lh    S_un.S_un_b.s_b3
+                                /* logical host */
+};
+
+/*
+ * Definitions of bits in internet address integers.
+ * On subnets, the decomposition of addresses to host and net parts
+ * is done according to subnet mask, not the masks here.
+ */
+#define IN_CLASSA(i)            (((long)(i) & 0x80000000) == 0)
+#define IN_CLASSA_NET           0xff000000
+#define IN_CLASSA_NSHIFT        24
+#define IN_CLASSA_HOST          0x00ffffff
+#define IN_CLASSA_MAX           128
+
+#define IN_CLASSB(i)            (((long)(i) & 0xc0000000) == 0x80000000)
+#define IN_CLASSB_NET           0xffff0000
+#define IN_CLASSB_NSHIFT        16
+#define IN_CLASSB_HOST          0x0000ffff
+#define IN_CLASSB_MAX           65536
+
+#define IN_CLASSC(i)            (((long)(i) & 0xc0000000) == 0xc0000000)
+#define IN_CLASSC_NET           0xffffff00
+#define IN_CLASSC_NSHIFT        8
+#define IN_CLASSC_HOST          0x000000ff
+
+#define INADDR_ANY              (u_long)0x00000000
+#define INADDR_LOOPBACK         0x7f000001
+#define INADDR_BROADCAST        (u_long)0xffffffff    
+#define INADDR_NONE             0xffffffff
+
+/*
+ * Socket address, internet style.
+ */
+struct sockaddr_in {
+        short   sin_family;
+        u_short sin_port;
+        struct  in_addr sin_addr;
+        char    sin_zero[8];
+};
+
+#define WSADESCRIPTION_LEN      256
+#define WSASYS_STATUS_LEN       128
+
+typedef struct WSAData {
+        WORD                    wVersion;
+        WORD                    wHighVersion;
+        char                    szDescription[WSADESCRIPTION_LEN+1];
+        char                    szSystemStatus[WSASYS_STATUS_LEN+1];
+        unsigned short          iMaxSockets;
+        unsigned short          iMaxUdpDg;
+        char FAR *              lpVendorInfo;
+} WSADATA;
+
+typedef WSADATA FAR *LPWSADATA;
+
+/*
+ * Options for use with [gs]etsockopt at the IP level.
+ */
+#define IP_OPTIONS      1               /* set/get IP per-packet options */
+
+/*
+ * Definitions related to sockets: types, address families, options,
+ * taken from the BSD file sys/socket.h.
+ */
+
+/*
+ * This is used instead of -1, since the
+ * SOCKET type is unsigned.
+ */
+#define INVALID_SOCKET  (SOCKET)(~0)
+#define SOCKET_ERROR            (-1)
+
+/*
+ * Types
+ */
+#define SOCK_STREAM     1               /* stream socket */
+#define SOCK_DGRAM      2               /* datagram socket */
+#define SOCK_RAW        3               /* raw-protocol interface */
+#define SOCK_RDM        4               /* reliably-delivered message */
+#define SOCK_SEQPACKET  5               /* sequenced packet stream */
+
+/*
+ * Option flags per-socket.
+ */
+#define SO_DEBUG        0x0001          /* turn on debugging info recording */
+#define SO_ACCEPTCONN   0x0002          /* socket has had listen() */
+#define SO_REUSEADDR    0x0004          /* allow local address reuse */
+#define SO_KEEPALIVE    0x0008          /* keep connections alive */
+#define SO_DONTROUTE    0x0010          /* just use interface addresses */
+#define SO_BROADCAST    0x0020          /* permit sending of broadcast msgs */
+#define SO_USELOOPBACK  0x0040          /* bypass hardware when possible */
+#define SO_LINGER       0x0080          /* linger on close if data present */
+#define SO_OOBINLINE    0x0100          /* leave received OOB data in line */
+
+#define SO_DONTLINGER   (u_int)(~SO_LINGER)
+
+/*
+ * Additional options.
+ */
+#define SO_SNDBUF       0x1001          /* send buffer size */
+#define SO_RCVBUF       0x1002          /* receive buffer size */
+#define SO_SNDLOWAT     0x1003          /* send low-water mark */
+#define SO_RCVLOWAT     0x1004          /* receive low-water mark */
+#define SO_SNDTIMEO     0x1005          /* send timeout */
+#define SO_RCVTIMEO     0x1006          /* receive timeout */
+#define SO_ERROR        0x1007          /* get error status and clear */
+#define SO_TYPE         0x1008          /* get socket type */
+
+/*
+ * TCP options.
+ */
+#define TCP_NODELAY     0x0001
+
+/*
+ * Address families.
+ */
+#define AF_UNSPEC       0               /* unspecified */
+#define AF_UNIX         1               /* local to host (pipes, portals) */
+#define AF_INET         2               /* internetwork: UDP, TCP, etc. */
+#define AF_IMPLINK      3               /* arpanet imp addresses */
+#define AF_PUP          4               /* pup protocols: e.g. BSP */
+#define AF_CHAOS        5               /* mit CHAOS protocols */
+#define AF_NS           6               /* XEROX NS protocols */
+#define AF_ISO          7               /* ISO protocols */
+#define AF_OSI          AF_ISO          /* OSI is ISO */
+#define AF_ECMA         8               /* european computer manufacturers */
+#define AF_DATAKIT      9               /* datakit protocols */
+#define AF_CCITT        10              /* CCITT protocols, X.25 etc */
+#define AF_SNA          11              /* IBM SNA */
+#define AF_DECnet       12              /* DECnet */
+#define AF_DLI          13              /* Direct data link interface */
+#define AF_LAT          14              /* LAT */
+#define AF_HYLINK       15              /* NSC Hyperchannel */
+#define AF_APPLETALK    16              /* AppleTalk */
+#define AF_NETBIOS      17              /* NetBios-style addresses */
+
+#define AF_MAX          18
+
+/*
+ * Structure used by kernel to store most
+ * addresses.
+ */
+struct sockaddr {
+        u_short sa_family;              /* address family */
+        char    sa_data[14];            /* up to 14 bytes of direct address */
+};
+
+/*
+ * Structure used by kernel to pass protocol
+ * information in raw sockets.
+ */
+struct sockproto {
+        u_short sp_family;              /* address family */
+        u_short sp_protocol;            /* protocol */
+};
+
+/*
+ * Protocol families, same as address families for now.
+ */
+#define PF_UNSPEC       AF_UNSPEC
+#define PF_UNIX         AF_UNIX
+#define PF_INET         AF_INET
+#define PF_IMPLINK      AF_IMPLINK
+#define PF_PUP          AF_PUP
+#define PF_CHAOS        AF_CHAOS
+#define PF_NS           AF_NS
+#define PF_ISO          AF_ISO
+#define PF_OSI          AF_OSI
+#define PF_ECMA         AF_ECMA
+#define PF_DATAKIT      AF_DATAKIT
+#define PF_CCITT        AF_CCITT
+#define PF_SNA          AF_SNA
+#define PF_DECnet       AF_DECnet
+#define PF_DLI          AF_DLI
+#define PF_LAT          AF_LAT
+#define PF_HYLINK       AF_HYLINK
+#define PF_APPLETALK    AF_APPLETALK
+
+#define PF_MAX          AF_MAX
+
+/*
+ * Structure used for manipulating linger option.
+ */
+struct  linger {
+        u_short l_onoff;                /* option on/off */
+        u_short l_linger;               /* linger time */
+};
+
+/*
+ * Level number for (get/set)sockopt() to apply to socket itself.
+ */
+#define SOL_SOCKET      0xffff          /* options for socket level */
+
+/*
+ * Maximum queue length specifiable by listen.
+ */
+#define SOMAXCONN       5
+
+#define MSG_OOB         0x1             /* process out-of-band data */
+#define MSG_PEEK        0x2             /* peek at incoming message */
+#define MSG_DONTROUTE   0x4             /* send without using routing tables */
+
+#define MSG_MAXIOVLEN   16
+
+/*
+ * Define constant based on rfc883, used by gethostbyxxxx() calls.
+ */
+#define MAXGETHOSTSTRUCT        1024
+
+/*
+ * Define flags to be used with the WSAAsyncSelect() call.
+ */
+#define FD_READ         0x01
+#define FD_WRITE        0x02
+#define FD_OOB          0x04
+#define FD_ACCEPT       0x08
+#define FD_CONNECT      0x10
+#define FD_CLOSE        0x20
+
+/*
+ * All Windows Sockets error constants are biased by WSABASEERR from
+ * the "normal"
+ */
+#define WSABASEERR              10000
+/*
+ * Windows Sockets definitions of regular Microsoft C error constants
+ */
+#define WSAEINTR                (WSABASEERR+4)
+#define WSAEBADF                (WSABASEERR+9)
+#define WSAEACCES               (WSABASEERR+13)
+#define WSAEFAULT               (WSABASEERR+14)
+#define WSAEINVAL               (WSABASEERR+22)
+#define WSAEMFILE               (WSABASEERR+24)
+
+/*
+ * Windows Sockets definitions of regular Berkeley error constants
+ */
+#define WSAEWOULDBLOCK          (WSABASEERR+35)
+#define WSAEINPROGRESS          (WSABASEERR+36)
+#define WSAEALREADY             (WSABASEERR+37)
+#define WSAENOTSOCK             (WSABASEERR+38)
+#define WSAEDESTADDRREQ         (WSABASEERR+39)
+#define WSAEMSGSIZE             (WSABASEERR+40)
+#define WSAEPROTOTYPE           (WSABASEERR+41)
+#define WSAENOPROTOOPT          (WSABASEERR+42)
+#define WSAEPROTONOSUPPORT      (WSABASEERR+43)
+#define WSAESOCKTNOSUPPORT      (WSABASEERR+44)
+#define WSAEOPNOTSUPP           (WSABASEERR+45)
+#define WSAEPFNOSUPPORT         (WSABASEERR+46)
+#define WSAEAFNOSUPPORT         (WSABASEERR+47)
+#define WSAEADDRINUSE           (WSABASEERR+48)
+#define WSAEADDRNOTAVAIL        (WSABASEERR+49)
+#define WSAENETDOWN             (WSABASEERR+50)
+#define WSAENETUNREACH          (WSABASEERR+51)
+#define WSAENETRESET            (WSABASEERR+52)
+#define WSAECONNABORTED         (WSABASEERR+53)
+#define WSAECONNRESET           (WSABASEERR+54)
+#define WSAENOBUFS              (WSABASEERR+55)
+#define WSAEISCONN              (WSABASEERR+56)
+#define WSAENOTCONN             (WSABASEERR+57)
+#define WSAESHUTDOWN            (WSABASEERR+58)
+#define WSAETOOMANYREFS         (WSABASEERR+59)
+#define WSAETIMEDOUT            (WSABASEERR+60)
+#define WSAECONNREFUSED         (WSABASEERR+61)
+#define WSAELOOP                (WSABASEERR+62)
+#define WSAENAMETOOLONG         (WSABASEERR+63)
+#define WSAEHOSTDOWN            (WSABASEERR+64)
+#define WSAEHOSTUNREACH         (WSABASEERR+65)
+#define WSAENOTEMPTY            (WSABASEERR+66)
+#define WSAEPROCLIM             (WSABASEERR+67)
+#define WSAEUSERS               (WSABASEERR+68)
+#define WSAEDQUOT               (WSABASEERR+69)
+#define WSAESTALE               (WSABASEERR+70)
+#define WSAEREMOTE              (WSABASEERR+71)
+
+/*
+ * Extended Windows Sockets error constant definitions
+ */
+#define WSASYSNOTREADY          (WSABASEERR+91)
+#define WSAVERNOTSUPPORTED      (WSABASEERR+92)
+#define WSANOTINITIALISED       (WSABASEERR+93)
+
+/*
+ * Error return codes from gethostbyname() and gethostbyaddr()
+ * (when using the resolver). Note that these errors are
+ * retrieved via WSAGetLastError() and must therefore follow
+ * the rules for avoiding clashes with error numbers from
+ * specific implementations or language run-time systems.
+ * For this reason the codes are based at WSABASEERR+1001.
+ * Note also that [WSA]NO_ADDRESS is defined only for
+ * compatibility purposes.
+ */
+
+#define h_errno         WSAGetLastError()
+
+/* Authoritative Answer: Host not found */
+#define WSAHOST_NOT_FOUND       (WSABASEERR+1001)
+#define HOST_NOT_FOUND          WSAHOST_NOT_FOUND
+
+/* Non-Authoritative: Host not found, or SERVERFAIL */
+#define WSATRY_AGAIN            (WSABASEERR+1002)
+#define TRY_AGAIN               WSATRY_AGAIN
+
+/* Non recoverable errors, FORMERR, REFUSED, NOTIMP */
+#define WSANO_RECOVERY          (WSABASEERR+1003)
+#define NO_RECOVERY             WSANO_RECOVERY
+
+/* Valid name, no data record of requested type */
+#define WSANO_DATA              (WSABASEERR+1004)
+#define NO_DATA                 WSANO_DATA
+
+/* no address, look for MX record */
+#define WSANO_ADDRESS           WSANO_DATA
+#define NO_ADDRESS              WSANO_ADDRESS
+
+/*
+ * Windows Sockets errors redefined as regular Berkeley error constants
+ */
+#define EWOULDBLOCK             WSAEWOULDBLOCK
+#define EINPROGRESS             WSAEINPROGRESS
+#define EALREADY                WSAEALREADY
+#define ENOTSOCK                WSAENOTSOCK
+#define EDESTADDRREQ            WSAEDESTADDRREQ
+#define EMSGSIZE                WSAEMSGSIZE
+#define EPROTOTYPE              WSAEPROTOTYPE
+#define ENOPROTOOPT             WSAENOPROTOOPT
+#define EPROTONOSUPPORT         WSAEPROTONOSUPPORT
+#define ESOCKTNOSUPPORT         WSAESOCKTNOSUPPORT
+#define EOPNOTSUPP              WSAEOPNOTSUPP
+#define EPFNOSUPPORT            WSAEPFNOSUPPORT
+#define EAFNOSUPPORT            WSAEAFNOSUPPORT
+#define EADDRINUSE              WSAEADDRINUSE
+#define EADDRNOTAVAIL           WSAEADDRNOTAVAIL
+#define ENETDOWN                WSAENETDOWN
+#define ENETUNREACH             WSAENETUNREACH
+#define ENETRESET               WSAENETRESET
+#define ECONNABORTED            WSAECONNABORTED
+#define ECONNRESET              WSAECONNRESET
+#define ENOBUFS                 WSAENOBUFS
+#define EISCONN                 WSAEISCONN
+#define ENOTCONN                WSAENOTCONN
+#define ESHUTDOWN               WSAESHUTDOWN
+#define ETOOMANYREFS            WSAETOOMANYREFS
+#define ETIMEDOUT               WSAETIMEDOUT
+#define ECONNREFUSED            WSAECONNREFUSED
+#define ELOOP                   WSAELOOP
+#define ENAMETOOLONG            WSAENAMETOOLONG
+#define EHOSTDOWN               WSAEHOSTDOWN
+#define EHOSTUNREACH            WSAEHOSTUNREACH
+#define ENOTEMPTY               WSAENOTEMPTY
+#define EPROCLIM                WSAEPROCLIM
+#define EUSERS                  WSAEUSERS
+#define EDQUOT                  WSAEDQUOT
+#define ESTALE                  WSAESTALE
+#define EREMOTE                 WSAEREMOTE
+
+/* Socket function prototypes */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+SOCKET PASCAL FAR accept (SOCKET s, struct sockaddr FAR *addr,
+                          int FAR *addrlen);
+
+int PASCAL FAR bind (SOCKET s, const struct sockaddr FAR *addr, int namelen);
+
+int PASCAL FAR closesocket (SOCKET s);
+
+int PASCAL FAR connect (SOCKET s, const struct sockaddr FAR *name, int namelen);
+
+int PASCAL FAR ioctlsocket (SOCKET s, long cmd, u_long FAR *argp);
+
+int PASCAL FAR getpeername (SOCKET s, struct sockaddr FAR *name,
+                            int FAR * namelen);
+
+int PASCAL FAR getsockname (SOCKET s, struct sockaddr FAR *name,
+                            int FAR * namelen);
+
+int PASCAL FAR getsockopt (SOCKET s, int level, int optname,
+                           char FAR * optval, int FAR *optlen);
+
+u_long PASCAL FAR htonl (u_long hostlong);
+
+u_short PASCAL FAR htons (u_short hostshort);
+
+unsigned long PASCAL FAR inet_addr (const char FAR * cp);
+
+char FAR * PASCAL FAR inet_ntoa (struct in_addr in);
+
+int PASCAL FAR listen (SOCKET s, int backlog);
+
+u_long PASCAL FAR ntohl (u_long netlong);
+
+u_short PASCAL FAR ntohs (u_short netshort);
+
+int PASCAL FAR recv (SOCKET s, char FAR * buf, int len, int flags);
+
+int PASCAL FAR recvfrom (SOCKET s, char FAR * buf, int len, int flags,
+                         struct sockaddr FAR *from, int FAR * fromlen);
+
+int PASCAL FAR select (int nfds, fd_set FAR *readfds, fd_set FAR *writefds,
+                       fd_set FAR *exceptfds, const struct timeval FAR *timeout);
+
+int PASCAL FAR send (SOCKET s, const char FAR * buf, int len, int flags);
+
+int PASCAL FAR sendto (SOCKET s, const char FAR * buf, int len, int flags,
+                       const struct sockaddr FAR *to, int tolen);
+
+int PASCAL FAR setsockopt (SOCKET s, int level, int optname,
+                           const char FAR * optval, int optlen);
+
+int PASCAL FAR shutdown (SOCKET s, int how);
+
+SOCKET PASCAL FAR socket (int af, int type, int protocol);
+
+/* Database function prototypes */
+
+struct hostent FAR * PASCAL FAR gethostbyaddr(const char FAR * addr,
+                                              int len, int type);
+
+struct hostent FAR * PASCAL FAR gethostbyname(const char FAR * name);
+
+int PASCAL FAR gethostname (char FAR * name, int namelen);
+
+struct servent FAR * PASCAL FAR getservbyport(int port, const char FAR * proto);
+
+struct servent FAR * PASCAL FAR getservbyname(const char FAR * name,
+                                              const char FAR * proto);
+
+struct protoent FAR * PASCAL FAR getprotobynumber(int proto);
+
+struct protoent FAR * PASCAL FAR getprotobyname(const char FAR * name);
+
+/* Microsoft Windows Extension function prototypes */
+
+int PASCAL FAR WSAStartup(WORD wVersionRequired, LPWSADATA lpWSAData);
+
+int PASCAL FAR WSACleanup(void);
+
+void PASCAL FAR WSASetLastError(int iError);
+
+int PASCAL FAR WSAGetLastError(void);
+
+BOOL PASCAL FAR WSAIsBlocking(void);
+
+int PASCAL FAR WSAUnhookBlockingHook(void);
+
+FARPROC PASCAL FAR WSASetBlockingHook(FARPROC lpBlockFunc);
+
+int PASCAL FAR WSACancelBlockingCall(void);
+
+HANDLE PASCAL FAR WSAAsyncGetServByName(HWND hWnd, u_int wMsg,
+                                        const char FAR * name, 
+                                        const char FAR * proto,
+                                        char FAR * buf, int buflen);
+
+HANDLE PASCAL FAR WSAAsyncGetServByPort(HWND hWnd, u_int wMsg, int port,
+                                        const char FAR * proto, char FAR * buf,
+                                        int buflen);
+
+HANDLE PASCAL FAR WSAAsyncGetProtoByName(HWND hWnd, u_int wMsg,
+                                         const char FAR * name, char FAR * buf,
+                                         int buflen);
+
+HANDLE PASCAL FAR WSAAsyncGetProtoByNumber(HWND hWnd, u_int wMsg,
+                                           int number, char FAR * buf,
+                                           int buflen);
+
+HANDLE PASCAL FAR WSAAsyncGetHostByName(HWND hWnd, u_int wMsg,
+                                        const char FAR * name, char FAR * buf,
+                                        int buflen);
+
+HANDLE PASCAL FAR WSAAsyncGetHostByAddr(HWND hWnd, u_int wMsg,
+                                        const char FAR * addr, int len, int type,
+                                        const char FAR * buf, int buflen);
+
+int PASCAL FAR WSACancelAsyncRequest(HANDLE hAsyncTaskHandle);
+
+int PASCAL FAR WSAAsyncSelect(SOCKET s, HWND hWnd, u_int wMsg,
+                               long lEvent);
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Microsoft Windows Extended data types */
+typedef struct sockaddr SOCKADDR;
+typedef struct sockaddr *PSOCKADDR;
+typedef struct sockaddr FAR *LPSOCKADDR;
+
+typedef struct sockaddr_in SOCKADDR_IN;
+typedef struct sockaddr_in *PSOCKADDR_IN;
+typedef struct sockaddr_in FAR *LPSOCKADDR_IN;
+
+typedef struct linger LINGER;
+typedef struct linger *PLINGER;
+typedef struct linger FAR *LPLINGER;
+
+typedef struct in_addr IN_ADDR;
+typedef struct in_addr *PIN_ADDR;
+typedef struct in_addr FAR *LPIN_ADDR;
+
+typedef struct fd_set FD_SET;
+typedef struct fd_set *PFD_SET;
+typedef struct fd_set FAR *LPFD_SET;
+
+typedef struct hostent HOSTENT;
+typedef struct hostent *PHOSTENT;
+typedef struct hostent FAR *LPHOSTENT;
+
+typedef struct servent SERVENT;
+typedef struct servent *PSERVENT;
+typedef struct servent FAR *LPSERVENT;
+
+typedef struct protoent PROTOENT;
+typedef struct protoent *PPROTOENT;
+typedef struct protoent FAR *LPPROTOENT;
+
+typedef struct timeval TIMEVAL;
+typedef struct timeval *PTIMEVAL;
+typedef struct timeval FAR *LPTIMEVAL;
+
+/*
+ * Windows message parameter composition and decomposition
+ * macros.
+ *
+ * WSAMAKEASYNCREPLY is intended for use by the Windows Sockets implementation
+ * when constructing the response to a WSAAsyncGetXByY() routine.
+ */
+#define WSAMAKEASYNCREPLY(buflen,error)     MAKELONG(buflen,error)
+/*
+ * WSAMAKESELECTREPLY is intended for use by the Windows Sockets implementation
+ * when constructing the response to WSAAsyncSelect().
+ */
+#define WSAMAKESELECTREPLY(event,error)     MAKELONG(event,error)
+/*
+ * WSAGETASYNCBUFLEN is intended for use by the Windows Sockets application
+ * to extract the buffer length from the lParam in the response
+ * to a WSAGetXByY().
+ */
+#define WSAGETASYNCBUFLEN(lParam)           LOWORD(lParam)
+/*
+ * WSAGETASYNCERROR is intended for use by the Windows Sockets application
+ * to extract the error code from the lParam in the response
+ * to a WSAGetXByY().
+ */
+#define WSAGETASYNCERROR(lParam)            HIWORD(lParam)
+/*
+ * WSAGETSELECTEVENT is intended for use by the Windows Sockets application
+ * to extract the event code from the lParam in the response
+ * to a WSAAsyncSelect().
+ */
+#define WSAGETSELECTEVENT(lParam)           LOWORD(lParam)
+/*
+ * WSAGETSELECTERROR is intended for use by the Windows Sockets application
+ * to extract the error code from the lParam in the response
+ * to a WSAAsyncSelect().
+ */
+#define WSAGETSELECTERROR(lParam)           HIWORD(lParam)
+
+#endif  /* _WINSOCKAPI_ */
+
diff --git a/libraries/msdos/winsock/wsockip.c b/libraries/msdos/winsock/wsockip.c
new file mode 100644 (file)
index 0000000..307541c
--- /dev/null
@@ -0,0 +1,467 @@
+/*
+ *  Copyright (c) 1995 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  os-ip.c -- platform-specific TCP & UDP related code
+ */
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1995 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#if defined(WINSOCK) || defined(_WIN32)
+#include <io.h>
+#include "msdos.h"
+#include "stdarg.h"
+#ifdef          KERBEROS
+#include "wshelper.h"
+#endif  /* KERBEROS */
+#endif          /* WINSOCK */
+#include <errno.h>
+
+#ifdef          _WIN32
+#include <io.h>
+#else   /* _WIN32 */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#endif          /* _WIN32 */
+#ifdef          _AIX
+#include <sys/select.h>
+#endif          /* _AIX */
+#include "portable.h"
+#include "lber.h"
+#include "ldap.h"
+
+#ifdef          NEED_FILIO
+#ifdef          WINSOCK
+#include <_sys/filio.h>
+#else           /* WINSOCK */
+#include <sys/filio.h>
+#endif          /* WINSOCK */
+#else   /* NEED_FILIO */
+#ifdef          WINSOCK
+#include <_sys/ioctl.h>
+#else   /* WINSOCK */
+#include <sys/ioctl.h>
+#endif          /* WINSOCK */
+#endif          /* NEED_FILIO */
+#ifdef          USE_SYSCONF
+#include <unistd.h>
+#endif          /* USE_SYSCONF */
+
+
+#ifdef MACOS
+#define tcp_close( s )         tcpclose( s )
+#else /* MACOS */
+#ifdef DOS
+#ifdef PCNFS
+#define tcp_close( s )         close( s )
+#endif /* PCNFS */
+#ifdef NCSA
+#define tcp_close( s )         netclose( s ); netshut()
+#endif /* NCSA */
+#ifdef WINSOCK
+#define tcp_close( s )         closesocket( s ); WSACleanup();
+#endif /* WINSOCK */
+#else /* DOS */
+#define tcp_close( s )         close( s )
+#endif /* DOS */
+#endif /* MACOS */
+
+
+#ifdef WINSOCK
+       static WSADATA          wsadata;
+       
+#ifdef LDAP_DEBUG
+void
+Debug( int level, char* fmt, ... )
+{
+       char buf[BUFSIZ];
+       va_list DbgArgs;
+       int i = 0;
+       char* arg[3] = { NULL, NULL, NULL };
+
+       va_start( DbgArgs, fmt );
+       for ( i= 0; i < 3; i++ )
+       {
+               arg[i] = va_arg( DbgArgs, va_list );
+       }
+       va_end( DbgArgs );              /* Reset variable arguments.      */
+
+
+       wsprintf( buf, fmt, arg[0], arg[1], arg[2] );
+       OutputDebugString( buf );
+}
+
+#define BPLEN  48
+#include <ctype.h>
+
+void
+lber_bprint( char *data, int len )
+{
+    static char        hexdig[] = "0123456789abcdef";
+    char       out[ BPLEN ];
+    int                i = 0;
+    char       buf[BUFSIZ];
+
+    memset( out, 0, BPLEN );
+    buf[0] = '\0';
+    for ( ;; ) {
+       if ( len < 1 ) {
+           wsprintf( buf, "\t%s\n", ( i == 0 ) ? "(end)" : out );
+           OutputDebugString( buf );
+           break;
+       }
+
+#ifndef HEX
+       if ( isgraph( (unsigned char)*data )) {
+           out[ i ] = ' ';
+           out[ i+1 ] = *data;
+       } else {
+#endif
+           out[ i ] = hexdig[ ( *data & 0xf0 ) >> 4 ];
+           out[ i+1 ] = hexdig[ *data & 0x0f ];
+#ifndef HEX
+       }
+#endif
+       i += 2;
+       len--;
+       data++;
+
+       if ( i > BPLEN - 2 ) {
+           wsprintf( buf, "\t%s\n", out );
+           OutputDebugString( buf );
+           memset( out, 0, BPLEN );
+           i = 0;
+           continue;
+       }
+       out[ i++ ] = ' ';
+    }
+}
+#endif /* LDAP_DEBUG */
+#endif /* WINSOCK */
+
+int
+connect_to_host( Sockbuf *sb, char *host, unsigned long address,
+       int port, int async )
+/*
+ * if host == NULL, connect using address
+ * "address" and "port" must be in network byte order
+ * zero is returned upon success, -1 if fatal error, -2 EINPROGRESS
+ * async is only used ifdef LDAP_REFERRALS (non-0 means don't wait for connect)
+ * XXX async is not used yet!
+ */
+{
+       int                     rc, i, s, connected, use_hp;
+       struct sockaddr_in      sin;
+       struct hostent          *hp;
+
+#ifdef notyet
+#ifdef LDAP_REFERRALS
+       int                     status; /* for ioctl call */
+#endif /* LDAP_REFERRALS */
+#endif /* notyet */
+
+       Debug( LDAP_DEBUG_TRACE, "connect_to_host: %s:%d\n",
+           ( host == NULL ) ? "(by address)" : host, ntohs( port ), 0 );
+
+#ifdef WINSOCK
+       if ( WSAStartup( 0x0101, &wsadata ) != 0 ) {
+           return( (int)NULL );
+       }
+#endif
+
+       hp = NULL;
+       connected = use_hp = 0;
+
+       if ( host != NULL && ( address = inet_addr( host )) == -1 ) {
+               if ( (hp = gethostbyname( host )) == NULL ) {
+#ifdef WINSOCK
+                       errno = WSAGetLastError();
+#else
+                       errno = EHOSTUNREACH;   /* not exactly right, but... */
+#endif
+                       return( -1 );
+               }
+               use_hp = 1;
+       }
+
+       rc = -1;
+       for ( i = 0; !use_hp || ( hp->h_addr_list[ i ] != 0 ); i++ ) {
+               if (( s = socket( AF_INET, SOCK_STREAM, 0 )) < 0 ) {
+                       return( -1 );
+               }
+#ifdef notyet
+#ifdef LDAP_REFERRALS
+               status = 1;
+               if ( async && ioctl( s, FIONBIO, (caddr_t)&status ) == -1 ) {
+                       Debug( LDAP_DEBUG_ANY, "FIONBIO ioctl failed on %d\n",
+                           s, 0, 0 );
+               }
+#endif /* LDAP_REFERRALS */
+#endif /* notyet */
+               (void)memset( (char *)&sin, 0, sizeof( struct sockaddr_in ));
+               sin.sin_family = AF_INET;
+               sin.sin_port = port;
+               SAFEMEMCPY( (char *) &sin.sin_addr.s_addr,
+                   ( use_hp ? (char *) hp->h_addr_list[ i ] :
+                   (char *) &address ), sizeof( sin.sin_addr.s_addr) );
+
+               if ( connect( s, (struct sockaddr *)&sin,
+                   sizeof( struct sockaddr_in )) >= 0 ) {
+                       connected = 1;
+                       rc = 0;
+                       break;
+               } else {
+#ifdef notyet
+#ifdef LDAP_REFERRALS
+#ifdef EAGAIN
+                       if ( errno == EINPROGRESS || errno == EAGAIN ) {
+#else /* EAGAIN */
+                       if ( errno == EINPROGRESS ) {
+#endif /* EAGAIN */
+                               Debug( LDAP_DEBUG_TRACE,
+                                       "connect would block...\n", 0, 0, 0 );
+                               rc = -2;
+                               break;
+                       }
+#endif /* LDAP_REFERRALS */
+#endif /* notyet */
+
+                       Debug( LDAP_DEBUG_TRACE, "%s", (char *)inet_ntoa( sin.sin_addr ), 0, 0 );
+
+                       close( s );
+                       if ( !use_hp ) {
+                               break;
+                       }
+               }
+       }
+
+       sb->sb_sd = s;
+
+       if ( connected ) {
+#ifdef notyet
+#ifdef LDAP_REFERRALS
+               status = 0;
+               if ( !async && ioctl( s, FIONBIO, (caddr_t)&on ) == -1 ) {
+                       Debug( LDAP_DEBUG_ANY, "FIONBIO ioctl failed on %d\n",
+                           s, 0, 0 );
+               }
+#endif /* LDAP_REFERRALS */
+#endif /* notyet */
+
+               Debug( LDAP_DEBUG_TRACE, "sd %d connected to: %s\n",
+                   s, inet_ntoa( sin.sin_addr ), 0 );
+       }
+    
+       return( rc );   /* Do NOT call WSACleanup. We want to use socket and various routines */
+}
+
+
+void
+close_connection( Sockbuf *sb )
+{
+    tcp_close( sb->sb_sd );
+}
+
+
+#ifdef KERBEROS
+char *
+host_connected_to( Sockbuf *sb )
+{
+       struct hostent          *hp = NULL;
+       int                     len;
+       struct sockaddr_in      sin;
+
+#ifdef WINSOCK
+       struct hostent          lhp;
+       char hName[BUFSIZ/2];
+    unsigned int prevMode;
+
+       // Create a function pointer type that can be type-checked
+       // by an ANSI-C compiler.
+       typedef struct hostent FAR * (PASCAL FAR * LPGHBA)(const char FAR * addr, int len, int type);
+       HINSTANCE hDLLInst;
+       LPGHBA ghba = NULL;    // Declare pointer to functions that can be type-checked.
+
+       memset(&lhp, 0x00, sizeof(struct hostent));
+       hName[0] = '\0';
+#endif 
+       (void)memset( (char *)&sin, 0, sizeof( struct sockaddr_in ));
+       len = sizeof( sin );
+       if ( getpeername( sb->sb_sd, (struct sockaddr*) &sin, &len ) == -1 ) {
+               return( NULL );
+       }
+
+       /*
+        * do a reverse lookup on the addr to get the official hostname.
+        * this is necessary for kerberos to work right, since the official
+        * hostname is used as the kerberos instance.
+        */
+#ifdef WINSOCK
+       /*
+        * Dynamically detect and use wshelper.dll if available. If not use 
+        * winsock's gethostbyaddr and cross your fingers.
+        */
+    prevMode = SetErrorMode( SEM_NOOPENFILEERRORBOX );
+       hDLLInst = LoadLibrary ("WSHELPER.DLL");
+       SetErrorMode( prevMode );
+       if (hDLLInst >= HINSTANCE_ERROR) {
+            ghba = (LPGHBA)GetProcAddress (hDLLInst, "rgethostbyaddr");
+       
+            if (ghba) {
+                       hp = (*ghba)( (char *)&sin.sin_addr, 
+                               sizeof( sin.sin_addr.s_addr ), AF_INET );
+                       if ( hp && hp->h_name ) {
+                               /* copy name, put in our fake hp, make hp point to it
+                                * because this hp disappears when FreeLibrary is called */
+                               strcpy(hName, hp->h_name);
+                               lhp.h_name = &hName;
+                               hp = &lhp;
+                       }
+            } else {
+                       hp = gethostbyaddr( (char *)&sin.sin_addr,
+                       sizeof( sin.sin_addr.s_addr ), AF_INET );
+            }
+            FreeLibrary (hDLLInst);
+       } else {
+               hp = gethostbyaddr( (char *)&sin.sin_addr,
+               sizeof( sin.sin_addr.s_addr ), AF_INET );
+       }
+#else
+       hp = gethostbyaddr( (char *)&sin.sin_addr,
+               sizeof( sin.sin_addr.s_addr ), AF_INET );
+#endif
+       if ( hp != NULL ) {
+               if ( hp->h_name != NULL ) {
+                       return( strdup( hp->h_name ));
+               }
+       }
+
+       return( NULL );
+}
+#endif /* KERBEROS */
+
+
+#ifdef LDAP_REFERRALS
+/* for UNIX */
+struct selectinfo {
+       fd_set  si_readfds;
+       fd_set  si_writefds;
+       fd_set  si_use_readfds;
+       fd_set  si_use_writefds;
+};
+
+
+void
+mark_select_write( LDAP *ld, Sockbuf *sb )
+{
+       struct selectinfo       *sip;
+
+       sip = (struct selectinfo *)ld->ld_selectinfo;
+
+       if ( !FD_ISSET( sb->sb_sd, &sip->si_writefds ))
+               FD_SET( sb->sb_sd, &sip->si_writefds );
+}
+
+
+void
+mark_select_read( LDAP *ld, Sockbuf *sb )
+{
+       struct selectinfo       *sip;
+
+       sip = (struct selectinfo *)ld->ld_selectinfo;
+
+       if ( !FD_ISSET( sb->sb_sd, &sip->si_readfds ))
+               FD_SET( sb->sb_sd, &sip->si_readfds );
+}
+
+
+void
+mark_select_clear( LDAP *ld, Sockbuf *sb )
+{
+       struct selectinfo       *sip;
+
+       sip = (struct selectinfo *)ld->ld_selectinfo;
+
+       FD_CLR( sb->sb_sd, &sip->si_writefds );
+       FD_CLR( sb->sb_sd, &sip->si_readfds );
+}
+
+
+int
+is_write_ready( LDAP *ld, Sockbuf *sb )
+{
+       struct selectinfo       *sip;
+
+       sip = (struct selectinfo *)ld->ld_selectinfo;
+
+       return( FD_ISSET( sb->sb_sd, &sip->si_use_writefds ));
+}
+
+
+int
+is_read_ready( LDAP *ld, Sockbuf *sb )
+{
+       struct selectinfo       *sip;
+
+       sip = (struct selectinfo *)ld->ld_selectinfo;
+
+       return( FD_ISSET( sb->sb_sd, &sip->si_use_readfds ));
+}
+
+
+void *
+new_select_info()
+{
+       struct selectinfo       *sip;
+
+       if (( sip = (struct selectinfo *)calloc( 1,
+           sizeof( struct selectinfo ))) != NULL ) {
+               FD_ZERO( &sip->si_readfds );
+               FD_ZERO( &sip->si_writefds );
+       }
+
+       return( (void *)sip );
+}
+
+
+void
+free_select_info( void *sip )
+{
+       free( sip );
+}
+
+
+int
+do_ldap_select( LDAP *ld, struct timeval *timeout )
+{
+       struct selectinfo       *sip;
+       static int              tblsize;
+
+       Debug( LDAP_DEBUG_TRACE, "do_ldap_select\n", 0, 0, 0 );
+
+       if ( tblsize == 0 ) {
+#ifdef USE_SYSCONF
+               tblsize = sysconf( _SC_OPEN_MAX );
+#else /* USE_SYSCONF */
+#ifdef WINSOCK
+               tblsize = FD_SETSIZE;
+#else
+               tblsize = getdtablesize();
+#endif
+#endif /* USE_SYSCONF */
+       }
+
+       sip = (struct selectinfo *)ld->ld_selectinfo;
+       sip->si_use_readfds = sip->si_readfds;
+       sip->si_use_writefds = sip->si_writefds;
+       
+       return( select( tblsize, &sip->si_use_readfds, &sip->si_use_writefds,
+           NULL, timeout ));
+}
+#endif /* LDAP_REFERRALS */
diff --git a/libraries/vms/Make-template b/libraries/vms/Make-template
new file mode 100644 (file)
index 0000000..2d7ef4e
--- /dev/null
@@ -0,0 +1,48 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1994 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP libraries/vms Makefile
+#
+#-----------------------------------------------------------------------------
+
+############################################################################
+#                                                                          #
+# You should not have to edit anything below this point                    #
+#                                                                          #
+############################################################################
+
+#
+# rules to make the software
+#
+
+all:   FORCE
+
+#
+# rules to install the software
+#
+
+install:       all
+
+#
+# rules to make clean
+#
+
+clean: FORCE
+
+veryclean:     clean
+
+#
+# rules to make depend
+#
+#
+depend:        FORCE
+
+links:
diff --git a/libraries/vms/README.VMS b/libraries/vms/README.VMS
new file mode 100644 (file)
index 0000000..4cb3b6a
--- /dev/null
@@ -0,0 +1,16 @@
+LDAP VMS README
+
+The lber and ldap client libraries and the ldap server ldapd have been
+ported to VMS.   While we at the University of Michigan have no way to
+test under VMS, the necessary code changes have been incorporated.
+
+Please see the file ldap/build/platforms/vms/make.com for some very basic
+build instructions.
+
+
+BUG REPORTING
+
+    Bug reports should be sent to bug-ldap@umich.edu.  They will be
+    passed on to those who did the LDAP VMS port.
+
+README Last updated 15 December 1994 Mark Smith
diff --git a/libraries/vms/getopt.c b/libraries/vms/getopt.c
new file mode 100644 (file)
index 0000000..814ab18
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 1987 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[] = "@(#)getopt.c    4.12 (Berkeley) 6/1/90";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+#include <string.h>
+#include "lber.h"
+#define index strchr
+#define rindex strrchr
+
+/*
+ * get option letter from argument vector
+ */
+int     opterr = 1,             /* if error message should be printed */
+       optind = 1,             /* index into parent argv vector */
+       optopt;                 /* character checked for validity */
+char    *optarg;                /* argument associated with option */
+
+#define BADCH   (int)'?'
+#define EMSG    ""
+
+getopt(nargc, nargv, ostr)
+       int nargc;
+       char **nargv, *ostr;
+{
+       static char *place = EMSG;              /* option letter processing */
+       register char *oli;                     /* option letter list index */
+       char *p;
+
+       if (!*place) {                          /* update scanning pointer */
+               if (optind >= nargc || *(place = nargv[optind]) != '-') {
+                       place = EMSG;
+                       return(EOF);
+               }
+               if (place[1] && *++place == '-') {      /* found "--" */
+                       ++optind;
+                       place = EMSG;
+                       return(EOF);
+               }
+       }                                       /* option letter okay? */
+       if ((optopt = (int)*place++) == (int)':' ||
+           !(oli = index(ostr, optopt))) {
+               /*
+                * if the user didn't specify '-' as an option,
+                * assume it means EOF.
+                */
+               if (optopt == (int)'-')
+                       return(EOF);
+               if (!*place)
+                       ++optind;
+               if (opterr) {
+                       if (!(p = rindex(*nargv, '/')))
+                               p = *nargv;
+                       else
+                               ++p;
+                       (void)fprintf(stderr, "%s: illegal option -- %c\n",
+                           p, optopt);
+               }
+               return(BADCH);
+       }
+       if (*++oli != ':') {                    /* don't need argument */
+               optarg = NULL;
+               if (!*place)
+                       ++optind;
+       }
+       else {                                  /* need an argument */
+               if (*place)                     /* no white space */
+                       optarg = place;
+               else if (nargc <= ++optind) {   /* no arg */
+                       place = EMSG;
+                       if (!(p = rindex(*nargv, '/')))
+                               p = *nargv;
+                       else
+                               ++p;
+                       if (opterr)
+                               (void)fprintf(stderr,
+                                   "%s: option requires an argument -- %c\n",
+                                   p, optopt);
+                       return(BADCH);
+               }
+               else                            /* white space */
+                       optarg = nargv[optind];
+               place = EMSG;
+               ++optind;
+       }
+       return(optopt);                         /* dump back option letter */
+}
diff --git a/libraries/vms/strings.c b/libraries/vms/strings.c
new file mode 100644 (file)
index 0000000..e96ceb3
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * strings.c
+ */
+#include <string.h>
+#include <stdlib.h>
+
+
+#ifndef NO_GLOBALS
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.  The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+/*
+ * This array is designed for mapping upper and lower case letter
+ * together for a case independent comparison.  The mappings are
+ * based upon ascii character sequences.
+ */
+static char charmap[] = {
+       '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+       '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+       '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+       '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+       '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+       '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+       '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+       '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+       '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+       '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+       '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+       '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+       '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+       '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+       '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+       '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+       '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+       '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+       '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+       '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+       '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+       '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+       '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+       '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+       '\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+       '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+       '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+       '\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337',
+       '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+       '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+       '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+       '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
+};
+
+int
+strcasecmp(s1, s2)
+       register char *s1, *s2;
+{
+       register char *cm = charmap;
+
+       while (cm[*s1] == cm[*s2++])
+               if (*s1++ == '\0')
+                       return(0);
+       return(cm[*s1] - cm[*--s2]);
+}
+
+int
+strncasecmp(s1, s2, n)
+       register char *s1, *s2;
+       register long n;
+{
+       register char *cm = charmap;
+
+       while (--n >= 0 && cm[*s1] == cm[*s2++])
+               if (*s1++ == '\0')
+                       return(0);
+       return(n < 0 ? 0 : cm[*s1] - cm[*--s2]);
+}
+#endif NO_GLOBALS
+
+
+char *
+strdup( p )
+       char    *p;
+{
+       char    *r;
+
+       r = (char *) malloc( strlen( p ) + 1 );
+       if ( r != NULL ) {
+               strcpy( r, p );
+       }
+
+       return( r );
+}
+
+void bcopy (void * src, void *dest, int n) {
+       memmove(dest, src, n);
+}
diff --git a/libraries/vms/ucx_select.h b/libraries/vms/ucx_select.h
new file mode 100644 (file)
index 0000000..a45e3ab
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Select uses bit masks of file descriptors in longs.  These macros
+ * manipulate such bit fields.
+ *
+ * FD_SETSIZE is the number file descriptors select() is able to
+ * deal with.  For DEC TCP/IP on VMS this is currently 32.
+ */
+#define        FD_SETSIZE      32
+#define        NBBY    8               /* number of bits in a byte */
+
+typedef long   fd_mask;
+#define NFDBITS        (sizeof(fd_mask) * NBBY)        /* bits per mask */
+
+#ifndef howmany
+#define        howmany(x, y)   (((x)+((y)-1))/(y))
+#endif
+
+typedef        struct fd_set {
+       fd_mask fds_bits[howmany(FD_SETSIZE, NFDBITS)];
+} fd_set;
+
+#define        FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
+#define        FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
+#define        FD_ISSET(n, p)  ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
+#define        FD_ZERO(p)      memset((char *)(p), 0, sizeof(*(p)))
+
+#define getdtablesize()        FD_SETSIZE
+
diff --git a/servers/Make-template b/servers/Make-template
new file mode 100644 (file)
index 0000000..39eb124
--- /dev/null
@@ -0,0 +1,88 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1994 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP servers Makefile
+#
+#-----------------------------------------------------------------------------
+
+############################################################################
+#                                                                          #
+# You should not have to edit anything below this point                    #
+#                                                                          #
+############################################################################
+
+#
+# rules to make the software
+#
+
+all:   FORCE
+       @echo "making all in `$(PWD)`"
+       @for i in *; do \
+           if [ -d $$i -a $$i != "RCS" ]; then \
+               echo "  cd $$i; $(MAKE) $(MFLAGS) all"; \
+               ( cd $$i; $(MAKE) $(MFLAGS) all ); \
+           fi; \
+       done
+
+
+#
+# rules to install the software
+#
+
+install:       FORCE
+       @echo "making install in `$(PWD)`"
+       @for i in *; do \
+           if [ -d $$i -a $$i != "RCS" ]; then \
+               echo "  cd $$i; $(MAKE) $(MFLAGS) install"; \
+               ( cd $$i; $(MAKE) $(MFLAGS) install ); \
+           fi; \
+       done
+
+#
+# rules to make clean
+#
+
+clean: FORCE
+       @echo "making clean in `$(PWD)`"
+       @for i in *; do \
+           if [ -d $$i -a $$i != "RCS" ]; then \
+               echo "  cd $$i; $(MAKE) $(MFLAGS) clean"; \
+               ( cd $$i; $(MAKE) $(MFLAGS) clean ); \
+           fi; \
+       done
+
+veryclean:     clean
+
+#
+# rules to make depend
+#
+#
+
+depend:        FORCE
+       @echo "making depend in `$(PWD)`"
+       @for i in *; do \
+           if [ -d $$i -a $$i != "RCS" ]; then \
+               echo "  cd $$i; $(MAKE) $(MFLAGS) depend"; \
+               ( cd $$i; $(MAKE) $(MFLAGS) depend ); \
+           fi; \
+       done
+
+links:
+       @echo "making links in `$(PWD)`"; \
+       for i in .src/*; do \
+           if [ -d $$i -a $$i != ".src/RCS" ]; then \
+               d=`basename $$i`; \
+               ( $(MKDIR) $$d; cd $$d; $(LN) ../.src/$$d .src; \
+                 $(LN) ../.src/$$d/Make-template . ; \
+                 $(MAKE) $(MFLAGS) MKDIR="$(MKDIR)" LN="$(LN)" \
+                   -f Make-template links ) ; \
+           fi; \
+       done
diff --git a/servers/ldapd/Make-template b/servers/ldapd/Make-template
new file mode 100644 (file)
index 0000000..f8781c5
--- /dev/null
@@ -0,0 +1,122 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1990 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP server daemon makefile
+#
+#-----------------------------------------------------------------------------
+LDAPSRC        = ../..
+HDIR   = $(LDAPSRC)/include
+LDIR   = $(LDAPSRC)/libraries
+VERSIONFILE = $(LDAPSRC)/build/version
+
+SRCS   = main.c detach.c setproctitle.c request.c bind.c result.c error.c \
+       search.c util.c compare.c message.c add.c delete.c modrdn.c modify.c \
+       abandon.c syntax.c association.c kerberos.c certificate.c
+OBJS   = main.o detach.o setproctitle.o request.o bind.o result.o error.o \
+       search.o util.o compare.o message.o add.o delete.o modrdn.o modify.o \
+       abandon.o syntax.o association.o kerberos.o LDAP_tables.o \
+       certificate.o
+
+INCLUDES= -I. -I$(HDIR) $(ISODEINCLUDEFLAG) $(KRBINCLUDEFLAG)
+DEFINES = $(DEFS) $(SERVERDEFS)
+CFLAGS = $(INCLUDES) $(DEFINES) $(ACFLAGS)
+LDFLAGS        = -L$(LDIR) $(ISODELIBFLAG) $(KRBLIBFLAG)
+LIBS   = -llber $(ISODELIBS) $(KRBLIBS) $(ALIBS)
+
+all:   FORCE
+       @if [ "$(HAVEISODE)" = "yes" ]; then \
+            $(MAKE) $(MFLAGS) CC=$(CC) ldapd; \
+       else \
+           echo "uncomment the HAVEISODE=yes line in the Make-common file to build ldapd"; \
+        fi
+
+
+ldapd: version.o
+       $(CC) $(ALDFLAGS) -o $@ $(OBJS) version.o $(LDFLAGS) $(LIBS)
+
+sldapd:        version.o
+       $(CC) $(ALDFLAGS) -static -o $@ $(OBJS) version.o $(LDFLAGS) $(LIBS) -lresolv
+
+version.c: $(OBJS) $(LDIR)/liblber/liblber.a
+       $(RM) $@
+       (u=$${USER-root} v=`$(CAT) $(VERSIONFILE)` d=`$(PWD)` h=`$(HOSTNAME)` \
+        t=`$(DATE)`; $(SED) -e "s|%WHEN%|$${t}|" \
+       -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+       -e "s|%VERSION%|$${v}|" \
+       < Version.c > $@)
+
+request.o:     LDAP-types.h
+
+LDAP_tables.c: ldap.py
+       @if [ ! -z "$(PEPSY)" ]; then \
+           $(PEPSY) -A ldap.py; \
+       else \
+           touch LDAP_tables.c LDAP-types.h; \
+       fi
+
+LDAP-types.h: LDAP_tables.c
+
+install:       FORCE
+       @if [ "$(HAVEISODE)" = "yes" ]; then \
+            $(MAKE) $(MFLAGS) CC=$(CC) install-ldapd; \
+       else \
+           echo "uncomment the HAVEISODE=yes line in the Make-common file to build and install ldapd"; \
+        fi
+
+install-ldapd: $(ETCDIR) $(ETCDIR)/ldapd
+
+$(ETCDIR)/ldapd:       ldapd
+       $(INSTALL) $(INSTALLFLAGS) -m 755 ldapd $(ETCDIR)
+
+lint:  FORCE
+       $(LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+5lint: FORCE
+       $(5LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+clean: FORCE
+       $(RM) ldapd sldapd *.o core a.out version.c LDAP*
+
+depend:        FORCE
+       @if [ ! -z "$(HAVEISODE)" ]; then \
+           $(MKDEP) $(INCLUDES) $(DEFINES) $(SRCS); \
+       else \
+           echo "uncomment the HAVEISODE=yes line in the Make-common file to build ldapd"; \
+       fi
+
+links:
+       @$(LN) .src/*.py .src/*.[ch] .
+# DO NOT DELETE THIS LINE -- mkdep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+main.o: main.c ../../include/portable.h ../../include/lber.h
+main.o: ../../include/ldap.h common.h
+detach.o: detach.c ../../include/portable.h
+setproctitle.o: setproctitle.c
+request.o: request.c ../../include/lber.h ../../include/ldap.h common.h
+bind.o: bind.c ../../include/lber.h ../../include/ldap.h common.h
+result.o: result.c ../../include/lber.h ../../include/ldap.h common.h
+error.o: error.c ../../include/lber.h ../../include/ldap.h
+search.o: search.c ../../include/lber.h ../../include/ldap.h common.h
+util.o: util.c ../../include/lber.h ../../include/ldap.h common.h
+compare.o: compare.c ../../include/lber.h ../../include/ldap.h common.h
+message.o: message.c ../../include/lber.h ../../include/ldap.h common.h
+add.o: add.c ../../include/lber.h ../../include/ldap.h common.h
+delete.o: delete.c ../../include/lber.h ../../include/ldap.h common.h
+modrdn.o: modrdn.c ../../include/lber.h ../../include/ldap.h common.h
+modify.o: modify.c ../../include/lber.h ../../include/ldap.h common.h
+abandon.o: abandon.c ../../include/lber.h ../../include/ldap.h common.h
+syntax.o: syntax.c ../../include/lber.h ../../include/ldap.h common.h
+association.o: association.c ../../include/lber.h ../../include/ldap.h common.h
+kerberos.o: kerberos.c ../../include/lber.h ../../include/ldap.h common.h
+certificate.o: certificate.c ../../include/lber.h ../../include/ldap.h common.h
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/servers/ldapd/Version.c b/servers/ldapd/Version.c
new file mode 100644 (file)
index 0000000..52afd69
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 1991 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+char Versionstr[] = "  ldapd %VERSION% (%WHEN%)\n\t%WHOANDWHERE%\n";
diff --git a/servers/ldapd/abandon.c b/servers/ldapd/abandon.c
new file mode 100644 (file)
index 0000000..3e51192
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <quipu/commonarg.h>
+#include <quipu/attrvalue.h>
+#include <quipu/ds_error.h>
+#include <quipu/abandon.h>
+#include <quipu/dap2.h>
+#include <quipu/dua.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "lber.h"
+#include "ldap.h"
+#include "common.h"
+
+do_abandon(
+    struct conn        *dsaconn,
+    BerElement *ber,
+    int                msgid
+)
+{
+       int                     id;
+       struct ds_abandon_arg   aa;
+       struct DAPindication    di;
+
+       Debug( LDAP_DEBUG_TRACE, "do_abandon\n", 0, 0 ,0 );
+
+       /*
+        * Parse the abandon request.  It looks like this:
+        *      AbandonRequest := MessageID
+        */
+
+       if ( ber_scanf( ber, "i", &id ) == LBER_ERROR ) {
+               Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0 ,0 );
+               return( 0 );
+       }
+
+       Debug( LDAP_DEBUG_ARGS, "do_abandin: id %d\n", id, 0 ,0 );
+
+       aa.aba_invokeid = id;
+
+       Debug( LDAP_DEBUG_TRACE, "DapAbandon...\n", 0, 0 ,0 );
+       if ( DapAbandon( dsaconn->c_ad, msgid, &aa, &di, ROS_ASYNC )
+           == NOTOK ) {
+               Debug( LDAP_DEBUG_ANY, "DapAbandon failed\n", 0, 0 ,0 );
+               return( 0 );
+       }
+       Debug( LDAP_DEBUG_TRACE, "DapAbandon completed\n", 0, 0 ,0 );
+
+       return( 0 );
+}
diff --git a/servers/ldapd/add.c b/servers/ldapd/add.c
new file mode 100644 (file)
index 0000000..cc76223
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <quipu/commonarg.h>
+#include <quipu/attrvalue.h>
+#include <quipu/ds_error.h>
+#include <quipu/add.h>
+#include <quipu/dap2.h>
+#include <quipu/dua.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "lber.h"
+#include "ldap.h"
+#include "common.h"
+
+#ifdef COMPAT20
+extern int     ldap_compat;
+#define ADDTAG (ldap_compat == 20 ? OLD_LDAP_RES_ADD : LDAP_RES_ADD)
+#else
+#define ADDTAG LDAP_RES_ADD
+#endif
+
+int
+do_add(
+    Sockbuf    *clientsb,
+    struct msg *m,
+    BerElement *ber
+)
+{
+       char                            *dn;
+       char                            *type, *last;
+       struct berval                   **bvals;
+       int                             rc;
+       unsigned long                   tag, len;
+       struct ds_addentry_arg          aa;
+       static CommonArgs               common = default_common_args;
+       extern DN                       ldap_str2dn();
+
+       Debug( LDAP_DEBUG_TRACE, "do_add\n", 0, 0, 0 );
+
+       /*
+        * Parse the add request.  It looks like this:
+        *      AddRequest := [APPLICATION 14] SEQUENCE {
+        *              name    DistinguishedName,
+        *              attrs   SEQUENCE OF SEQUENCE {
+        *                      type    AttributeType,
+        *                      values  SET OF AttributeValue
+        *              }
+        *      }
+        */
+
+#if ISODEPACKAGE == IC
+#if ICRELEASE > 2
+       DAS_AddEntryArgument_INIT ( &aa );
+#endif
+#endif
+
+       if ( ber_scanf( ber, "{a", &dn ) == LBER_ERROR ) {
+               Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
+               send_ldap_msgresult( clientsb, ADDTAG, m,
+                   LDAP_PROTOCOL_ERROR, NULL, "" );
+               return( 0 );
+       }
+
+       Debug( LDAP_DEBUG_ARGS, "do_add: dn (%s)\n", dn, 0, 0 );
+
+       aa.ada_object = ldap_str2dn( dn );
+       free( dn );
+       if ( aa.ada_object == NULLDN ) {
+               Debug( LDAP_DEBUG_ANY, "ldap_str2dn failed\n", 0, 0, 0 );
+               send_ldap_msgresult( clientsb, ADDTAG, m,
+                   LDAP_INVALID_DN_SYNTAX, NULL, "" );
+               return( 0 );
+       }
+
+       /* break out once we read them all, or return out on error */
+       aa.ada_entry = NULLATTR;
+       for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
+           tag = ber_next_element( ber, &len, last ) ) {
+               Attr_Sequence   as, get_as();
+
+               if ( ber_scanf( ber, "{a{V}}", &type, &bvals ) == LBER_ERROR )
+                       break;
+
+               if ( (as = get_as( clientsb, LDAP_RES_ADD, m, type,
+                   bvals )) == NULLATTR )
+                       return( 0 );
+
+               aa.ada_entry = as_merge( aa.ada_entry, as );
+       }
+
+       aa.ada_common = common; /* struct copy */
+
+       rc = initiate_dap_operation( OP_ADDENTRY, m, &aa );
+
+       dn_free( aa.ada_object );
+       as_free( aa.ada_entry );
+
+       if ( rc != 0 ) {
+               send_ldap_msgresult( clientsb, ADDTAG, m, rc, NULL, "" );
+               return( 0 );
+       }
+
+       return( 1 );
+}
+
+void
+add_result(
+    Sockbuf    *sb,
+    struct msg *m
+)
+{
+       send_ldap_msgresult( sb, ADDTAG, m, LDAP_SUCCESS, NULL, "" );
+
+       return;
+}
diff --git a/servers/ldapd/association.c b/servers/ldapd/association.c
new file mode 100644 (file)
index 0000000..ab15d04
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <quipu/commonarg.h>
+#include <quipu/ds_error.h>
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include "lber.h"
+#include "ldap.h"
+#if ISODEPACKAGE == IC
+#include <ll/isoaddrs.h>
+#else
+#include <isoaddrs.h>
+#endif
+#include "common.h"
+#ifdef SVR4
+#if !defined(_AIX) && !defined(__osf__)
+#include <sys/filio.h>
+#endif
+#endif
+
+#ifdef __hpux
+#define FIOGETOWN      FIOGSAIOOWN
+#endif
+
+struct conn    *conns;
+
+struct conn *conn_dup( struct conn *cn )
+{
+       struct conn     *new;
+       struct PSAPaddr *psap_cpy();
+
+       if ( (new = (struct conn *) malloc( sizeof(struct conn) )) == NULL )
+               return( NULL );
+
+       *new = *cn;
+       new->c_next = NULL;
+       new->c_time = 0L;
+       new->c_paddr = psap_cpy( cn->c_paddr );
+       new->c_dn = strdup( cn->c_dn );
+       if ( new->c_credlen > 0 ) {
+               new->c_cred = (char *) malloc( cn->c_credlen );
+               SAFEMEMCPY( new->c_cred, cn->c_cred, cn->c_credlen );
+       } else {
+               new->c_cred = "";
+       }
+       new->c_credlen = cn->c_credlen;
+       new->c_refcnt = 1;
+
+       return( new );
+}
+
+int
+conn_init()
+{
+       extern char     *dsa_address;
+       struct PSAPaddr *addr, *psap_cpy();
+
+       if ( (conns = (struct conn *) malloc( sizeof(struct conn) )) == NULL ) {
+               Debug( LDAP_DEBUG_ANY, "conn_init: malloc failed\n", 0, 0, 0 );
+               return( -1 );
+       }
+
+       conns->c_ad = -1;
+       conns->c_dn = NULL;
+       conns->c_cred = NULL;
+       conns->c_credlen = 0;
+
+       if ( dsa_address == NULL || (addr = str2paddr( dsa_address ))
+           == NULLPA ) {
+               conns->c_paddr = NULLPA;
+               Debug( LDAP_DEBUG_ANY, "conn_init: bad DSA address (%s)\n",
+                   dsa_address ? dsa_address : "NULL", 0, 0 );
+       } else {
+           conns->c_paddr = psap_cpy( addr );
+       }
+
+       conns->c_refcnt = 1;    /* this conn is never deleted */
+       conns->c_next = NULL;
+
+       return( 0 );
+}
+
+void
+conn_free( struct conn *conn )
+{
+       struct timeval  tv;
+       extern int      referral_connection_timeout;
+
+       Debug( LDAP_DEBUG_TRACE, "conn_free (%s): refcnt is %d\n",
+           paddr2str( conn->c_paddr, NULLNA ), conn->c_refcnt, 0 );
+
+       if ( --conn->c_refcnt > 0 )
+               return;
+
+       gettimeofday( &tv, (struct timezone *)NULL );
+       if ( conn->c_time != 0L && (tv.tv_sec - conn->c_time)
+           < referral_connection_timeout ) {
+               Debug( LDAP_DEBUG_TRACE, "conn_free: referral conn ttl is %d\n",
+                   referral_connection_timeout - (tv.tv_sec - conn->c_time),
+                   0, 0 );
+               return;
+       }
+
+
+       conn_del( conn );
+
+       if ( conn->c_paddr )
+               free( (char *) conn->c_paddr );
+       if ( conn->c_dn )
+               free( conn->c_dn );
+       if ( conn->c_credlen > 0 )
+               free( conn->c_cred );
+       free( conn );
+}
+
+void
+conn_del( struct conn *conn )
+{
+       struct conn     *tmp, *prev;
+
+       Debug( LDAP_DEBUG_TRACE, "conn_del (%s)\n",
+           paddr2str( conn->c_paddr, NULLNA ), 0, 0 );
+
+       prev = NULL;
+       for ( tmp = conns; tmp != NULL; tmp = tmp->c_next ) {
+               if ( tmp == conn )
+                       break;
+               prev = tmp;
+       }
+
+       if ( tmp == NULL ) {
+               Debug( LDAP_DEBUG_ANY, "conn_del: cannot find conn\n", 0, 0,
+                   0 );
+               return;
+       }
+
+       if ( prev == NULL ) {
+               conns = conns->c_next;  /* delete head of list */
+       } else {
+               prev->c_next = tmp->c_next;
+       }
+}
+
+void
+conn_setfds( fd_set *fds )
+{
+       struct conn     *tmp;
+
+       for ( tmp = conns; tmp != NULL; tmp = tmp->c_next ) {
+               if ( tmp->c_ad != -1 )
+                       FD_SET( tmp->c_ad, fds );
+       }
+}
+
+void
+conn_badfds()
+{
+       struct conn     *tmp;
+
+       for ( tmp = conns; tmp != NULL; tmp = tmp->c_next ) {
+               if ( isclosed( tmp->c_ad ) ) {
+                       Debug( LDAP_DEBUG_ANY, "conn_badfds: fd %d is bad\n",
+                           tmp->c_ad, 0, 0 );
+                       tmp->c_ad = -1;
+               }
+       }
+}
+
+struct conn *conn_getfd( fd_set *fds )
+{
+       struct conn     *tmp;
+
+       for ( tmp = conns; tmp != NULL; tmp = tmp->c_next ) {
+               if ( tmp->c_ad != -1 )
+                       if ( FD_ISSET( tmp->c_ad, fds ) )
+                               return( tmp );
+       }
+
+       return( NULL );
+}
+
+void
+conn_add( struct conn *new )
+{
+       struct timeval  tv;
+
+#ifdef LDAP_DEBUG
+       if ( ldap_debug & LDAP_DEBUG_CONNS ) {
+               char    *str;
+
+               str = paddr2str( new->c_paddr, NULLNA );
+               Debug( LDAP_DEBUG_CONNS, "conn_add: (%s)\n", str, 0, 0 );
+       }
+#endif
+
+       gettimeofday( &tv, (struct timezone *)NULL );
+       new->c_time = tv.tv_sec;
+       new->c_next = conns;
+       new->c_refcnt = 1;
+       conns = new;
+}
+
+static psap_cmp( struct PSAPaddr *a, struct PSAPaddr *b )
+{
+       return( bcmp( (char *) a, (char *) b, sizeof(struct PSAPaddr) ) );
+}
+
+struct conn *conn_find( struct conn *c )
+{
+       struct conn     *tmp;
+
+#ifdef LDAP_DEBUG
+       if ( ldap_debug & LDAP_DEBUG_CONNS ) {
+               char    *str;
+
+               str = paddr2str( c->c_paddr, NULLNA );
+               Debug( LDAP_DEBUG_CONNS, "conn_find: (%s)\n", str, 0, 0 );
+       }
+#endif
+       for ( tmp = conns; tmp != NULL; tmp = tmp->c_next ) {
+#ifdef LDAP_DEBUG
+               if ( ldap_debug & LDAP_DEBUG_CONNS ) {
+                       char    *str;
+
+                       str = paddr2str( tmp->c_paddr, NULLNA );
+                       Debug( LDAP_DEBUG_CONNS, "conn_find: compare to (%s)\n",
+                           str, 0, 0 );
+               }
+#endif
+               if ( psap_cmp( tmp->c_paddr, c->c_paddr ) == 0
+                   && strcmp( tmp->c_dn, c->c_dn ) == 0
+                   && tmp->c_credlen == c->c_credlen
+                   && bcmp( tmp->c_cred, c->c_cred, c->c_credlen ) == 0 ) {
+                       Debug( LDAP_DEBUG_CONNS, "conn_find: found\n", 0,
+                           0, 0 );
+                       return( tmp );
+               }
+       }
+
+       Debug( LDAP_DEBUG_CONNS, "conn_find: not found\n", 0, 0, 0 );
+       return( NULL );
+}
+
+void
+conn_close()
+{
+       struct conn     *tmp;
+
+       for ( tmp = conns; tmp != NULL; tmp = tmp->c_next ) {
+               if ( tmp->c_ad != -1 )
+                       dap_unbind( tmp->c_ad );
+       }
+}
+
+int
+isclosed( int ad )
+{
+       int             o;
+       extern int      errno;
+
+       if ( ioctl( ad, FIOGETOWN, &o ) < 0 )
+               return( errno == EBADF ? 1 : 0 );
+       else
+               return( 0 );
+}
diff --git a/servers/ldapd/bind.c b/servers/ldapd/bind.c
new file mode 100644 (file)
index 0000000..db76ff0
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <quipu/commonarg.h>
+#include <quipu/attrvalue.h>
+#include <quipu/ds_error.h>
+#include <quipu/bind.h>
+#include <quipu/compare.h>
+#include "lber.h"
+#include "ldap.h"
+#include "common.h"
+
+#ifdef COMPAT20
+extern int     ldap_compat;
+#define BINDTAG        (ldap_compat == 20 ? OLD_LDAP_RES_BIND : LDAP_RES_BIND)
+#else
+#define BINDTAG        LDAP_RES_BIND
+#endif
+
+/*
+ * do_bind - perform an X.500 bind operation.  Since we always respond
+ * to the request in here, always return 0 to signify the incoming message
+ * can be discarded.
+ */
+
+int
+do_bind( 
+    Sockbuf    *clientsb,
+    struct msg *m,
+    BerElement *ber,
+    int                *bound
+)
+{
+       int             err;
+       unsigned long   method;
+       unsigned long   len;
+       char            *dn, *pw;
+       char            *matched;
+       struct PSAPaddr *addr, *psap_cpy();
+       extern char     *dsa_address;
+       extern int      version;
+
+       Debug( LDAP_DEBUG_TRACE, "do_bind\n", 0, 0, 0 );
+
+       /*
+        * Parse the bind request.  It looks like this:
+        *      BindRequest ::= SEQUENCE {
+        *              version         INTEGER,                 -- version
+        *              name            DistinguishedName,       -- dn
+        *              authentication  CHOICE {
+        *                      simple          [0] OCTET STRING -- passwd
+        *                      krbv42ldap      [1] OCTET STRING
+        *                      krbv42dsa       [1] OCTET STRING
+        *              }
+        *      }
+        */
+
+       if ( ber_scanf( ber, "{ia", &version, &dn ) == LBER_ERROR ) {
+               Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
+               send_ldap_msgresult( clientsb, BINDTAG, m,
+                   LDAP_PROTOCOL_ERROR, NULL, "Decoding error" );
+               return( 0 );
+       }
+#ifdef COMPAT30
+       if ( ldap_compat == 30 )
+               method = ber_skip_tag( ber, &len );
+       else
+#endif
+               method = ber_peek_tag( ber, &len );
+
+       if ( ber_scanf( ber, "la}", &len, &pw ) == LBER_ERROR ) {
+               Debug( LDAP_DEBUG_ANY, "ber_scanf2 failed\n", 0, 0, 0 );
+               send_ldap_msgresult( clientsb, BINDTAG, m,
+                   LDAP_PROTOCOL_ERROR, NULL, "Decoding error" );
+               return( 0 );
+       }
+
+       if ( version != LDAP_VERSION1 && version != LDAP_VERSION2 ) {
+               Debug( LDAP_DEBUG_ANY, "unknown version %d\n", version, 0, 0 );
+               send_ldap_msgresult( clientsb, BINDTAG, m,
+                   LDAP_PROTOCOL_ERROR, NULL, "Version not supported" );
+               return( 0 );
+       }
+
+       Debug( LDAP_DEBUG_ARGS, "do_bind: version %d dn (%s) method %d\n",
+           version, dn, method );
+
+       if ( m->m_conn->c_paddr == NULLPA ) {
+               char    buf[256];
+
+               sprintf( buf, "Bad DSA address (%s)", dsa_address ?
+                   dsa_address : "NULL" );
+               send_ldap_msgresult( clientsb, BINDTAG, m,
+                   LDAP_OPERATIONS_ERROR, NULL, buf );
+               return( 0 );
+       }
+
+       if ( m->m_conn->c_dn )
+               free( m->m_conn->c_dn );
+       if ( m->m_conn->c_cred )
+               free( m->m_conn->c_cred );
+       m->m_conn->c_dn = dn;
+       m->m_conn->c_cred = pw;
+       m->m_conn->c_credlen = len;
+       m->m_conn->c_method = method;
+
+       err = do_bind_real( m->m_conn, bound, &matched );
+
+       send_ldap_msgresult( clientsb, BINDTAG, m, err, matched, "" );
+
+       if ( matched != NULL )
+               free( matched );
+
+       return( 0 );
+}
+
+int
+do_bind_real(
+    struct conn        *dsaconn,
+    int                *bound,
+    char       **matched
+)
+{
+       struct ds_bind_arg      ba;
+       struct ds_bind_arg      br;
+       struct ds_bind_error    be;
+       struct DSError          dse;
+       char                    *dn = dsaconn->c_dn;
+       int                     err;
+#ifdef KERBEROS
+       u_long                  nonce;
+#endif
+       extern DN               ldap_str2dn();
+
+       Debug( LDAP_DEBUG_TRACE, "do_bind_real\n", 0, 0, 0 );
+
+       *matched = NULL;
+       if ( (ba.dba_dn = ldap_str2dn( dn )) == NULLDN && *dn != '\0' ) {
+               Debug( LDAP_DEBUG_ANY, "ldap_str2dn (%s) failed\n", dn, 0, 0 );
+               return( LDAP_INVALID_DN_SYNTAX );
+       }
+
+       switch ( dsaconn->c_method ) {
+#ifdef COMPAT20
+       case OLD_LDAP_AUTH_SIMPLE:
+#endif
+#ifdef COMPAT30
+       case LDAP_AUTH_SIMPLE_30:
+#endif
+       case LDAP_AUTH_SIMPLE:  /* x.500 simple authentication */
+               if ( dsaconn->c_credlen > DBA_MAX_PASSWD_LEN ) {
+                       Debug( LDAP_DEBUG_ANY, "Password too long\n", 0, 0, 0 );
+                       return( LDAP_INAPPROPRIATE_AUTH );
+               }
+               if (( ba.dba_passwd_len = dsaconn->c_credlen ) > 0 ) {
+                       SAFEMEMCPY( ba.dba_passwd, dsaconn->c_cred,
+                           ba.dba_passwd_len );
+                       ba.dba_auth_type = DBA_AUTH_SIMPLE;
+               } else {
+                       ba.dba_auth_type = DBA_AUTH_NONE;
+               }
+               ba.dba_version = DBA_VERSION_V1988;
+               break;
+
+#ifdef KERBEROS
+#ifdef COMPAT20
+       case OLD_LDAP_AUTH_KRBV4:
+#endif
+#ifdef COMPAT30
+       case LDAP_AUTH_KRBV41_30:
+#endif
+       case LDAP_AUTH_KRBV41:  /* kerberos authentication to ldap server */
+               return( kerberosv4_ldap_auth( dsaconn->c_cred,
+                   dsaconn->c_credlen ) );
+               break;
+
+#ifdef COMPAT20
+       case OLD_LDAP_AUTH_KRBV42:
+#endif
+#ifdef COMPAT30
+       case LDAP_AUTH_KRBV42_30:
+#endif
+       case LDAP_AUTH_KRBV42:  /* kerberos authentication to x500 dsa */
+               if ( (err = kerberosv4_bindarg( &ba, ba.dba_dn, dsaconn->c_cred,
+                   dsaconn->c_credlen, &nonce )) != 0 )
+                       return( err );
+               break;
+#endif
+
+       default:
+               return( LDAP_PROTOCOL_ERROR );
+               break;
+       }
+
+       if ( dsaconn->c_ad != -1 )
+               dap_unbind( dsaconn->c_ad );
+
+       Debug( LDAP_DEBUG_TRACE, "dap_bind to dsa (%s)...\n", paddr2str(
+           dsaconn->c_paddr, NULLNA ), 0, 0 );
+
+       err = dap_bind( &dsaconn->c_ad, &ba, &be, &br, dsaconn->c_paddr );
+
+       if ( err != DS_OK && ba.dba_dn != NULLDN && ba.dba_auth_type
+           == DBA_AUTH_NONE && be.dbe_type == DBE_TYPE_SECURITY ) {
+               /* if doing a NULL bind, retry with a NULL dn */
+               Debug( LDAP_DEBUG_TRACE, "retring NULL dap_bind\n", 0, 0, 0 );
+               dn_free( ba.dba_dn );
+               ba.dba_dn = NULLDN;
+               err = dap_bind( &dsaconn->c_ad, &ba, &be, &br,
+                   dsaconn->c_paddr );
+       }
+
+       if ( err != DS_OK ) {
+               if ( ba.dba_dn != NULLDN )
+                       dn_free( ba.dba_dn );
+
+               if ( be.dbe_type == DBE_TYPE_SERVICE ) {
+                       dse.dse_type = DSE_SERVICEERROR;
+                       dse.ERR_SERVICE.DSE_sv_problem = be.dbe_value;
+               } else if ( be.dbe_type == DBE_TYPE_SECURITY ) {
+                       dse.dse_type = DSE_SECURITYERROR;
+                       dse.ERR_SECURITY.DSE_sc_problem = be.dbe_value;
+               } else {
+                       dse.dse_type = DSE_REMOTEERROR;
+               }
+               err = x500err2ldaperr( &dse, matched );
+
+#ifdef LDAP_DEBUG
+               if ( ldap_debug )
+                       print_error( &dse );    /* prints and then frees */
+               else
+#endif
+                       ds_error_free( &dse );
+
+               dsaconn->c_ad = -1;
+
+               return( err );
+       }
+       bind_arg_free( &br );
+
+       Debug( LDAP_DEBUG_TRACE, "dap_bind successful\n", 0, 0, 0 );
+
+#ifdef KERBEROS
+/* XXX why doesn't this work??
+       if ( dsaconn->c_method == LDAP_AUTH_KRBV42 &&
+           kerberos_check_mutual( &br, nonce ) != 0 ) {
+               Debug( LDAP_DEBUG_ANY, "Mutual authentication failed\n", 0, 0,
+                   0 );
+               return( LDAP_INVALID_CREDENTIALS );
+       }
+*/
+#endif
+
+       *bound = 1;
+
+       return( LDAP_SUCCESS );
+}
diff --git a/servers/ldapd/certificate.c b/servers/ldapd/certificate.c
new file mode 100644 (file)
index 0000000..228d65a
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+ * certificate.c - ldap version of quipu certificate syntax handler
+ *                donated by Eric Rosenquist and BNR
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <quipu/commonarg.h>
+#include <quipu/attrvalue.h>
+#include <quipu/ds_error.h>
+#include <quipu/ds_search.h>
+#include <quipu/dap2.h>
+#include <quipu/dua.h>
+#include "lber.h"
+#include "ldap.h"
+#include "common.h"
+
+int ldap_certif_print( PS ps, struct certificate *parm, int format )
+{
+       Debug( LDAP_DEBUG_TRACE, "ldap_certif_print()\n", 0, 0, 0 );
+
+/*
+ *     An ldap certificate looks like this:
+ *
+ *     <certificate> ::= <version> '#' <serial> '#' <signature-algorithm-id>
+ *                  '#' <issuer> '#' <validity> '#' <subject>
+ *                  '#' <public-key-info> '#' <encrypted-sign-value>
+ *     <version> ::= <integervalue>
+ *     <serial> ::= <integervalue>
+ *     <signature-algorithm-id> ::= <algorithm-id>
+ *     <issuer> ::= an encoded Distinguished Name
+ *     <validity> ::= <not-before-time> '#' <not-after-time>
+ *     <not-before-time> ::= <utc-time>
+ *     <not-after-time> ::= <utc-time>
+ *     <algorithm-parameters> ::=  <null> | <integervalue> |
+ *                              '{ASN}' <hex-string>
+ *     <subject> ::= an encoded Distinguished Name
+ *     <public-key-info> ::= <algorithm-id> '#' <encrypted-sign-value>
+ *     <encrypted-sign-value> ::= <hex-string> | <hex-string> '-' <d>
+ *     <algorithm-id> ::= <oid> '#' <algorithm-parameters>
+ *     <utc-time> ::= an encoded UTCTime value
+ *     <hex-string> ::= <hex-digit> | <hex-digit> <hex-string>
+ */
+
+        ps_printf(ps, "%d#%d#", parm->version, parm->serial);
+
+        ldap_print_algid(ps, &(parm->sig.alg), format);
+
+        dn_print_real(ps, parm->issuer, format);
+        ps_printf(ps, "#");
+
+        utcprint(ps, parm->valid.not_before, format);
+        ps_printf(ps, "#");
+        utcprint(ps, parm->valid.not_after, format);
+        ps_printf(ps, "#");
+
+        dn_print_real(ps, parm->subject, format);
+        ps_printf(ps, "#");
+
+        ldap_print_algid(ps, &(parm->key.alg), format);
+        print_encrypted(ps, parm->key.value, parm->key.n_bits, format);
+
+        print_encrypted(ps, parm->sig.encrypted, parm->sig.n_bits, format);
+}
+
+void
+ldap_print_algid( PS ps, struct alg_id *parm, int format )
+{
+  ps_printf(ps, "%s#", oid2name (parm->algorithm, OIDPART));
+
+  switch(parm->p_type) {
+     case ALG_PARM_ABSENT:
+       if(parm->asn != NULLPE)
+             pe_print(ps, parm->asn, format);
+       ps_printf(ps, "#");
+       break;
+     case ALG_PARM_NUMERIC:
+       if (format == READOUT)
+         ps_printf(ps, "%d#", parm->un.numeric);
+       else
+         ps_printf(ps, "%d#", parm->un.numeric);
+       break;
+      default:
+       if (format == READOUT)
+       {
+         if ((parm->asn->pe_class == PE_CLASS_UNIV)
+           &&(parm->asn->pe_form  == PE_FORM_PRIM)
+           &&(parm->asn->pe_id    == PE_PRIM_INT))
+           ps_printf(ps, "%d", prim2num(parm->asn));
+         else if ((parm->asn->pe_class == PE_CLASS_UNIV)
+           &&(parm->asn->pe_form  == PE_FORM_PRIM)
+           &&(parm->asn->pe_id    == PE_PRIM_NULL))
+           ps_printf(ps, "NULL");
+         else
+         {
+           vpushquipu (ps);
+           vunknown(parm->asn);
+           vpopquipu ();
+         }
+       }
+       else
+       {
+        /* This routine will print a {ASN} prefix */
+         pe_print(ps, parm->asn, format);
+       }
+       ps_printf(ps, "#");
+   }
+}
+
+struct certificate *ldap_str2cert( char *str )
+{
+struct certificate *result;
+char *ptr;
+OID oid;
+
+  Debug( LDAP_DEBUG_TRACE, "ldap_str2cert(%s)\n", str, 0, 0 );
+
+  result = (struct certificate *) calloc(1, sizeof(*result));
+
+  /* version */
+  ptr = strchr(str, '#');
+  if (ptr == NULLCP)
+  {
+    parse_error("version not present",NULLCP);
+    cert_free(result);
+    return (struct certificate *) 0;
+  }
+  *ptr++ = '\0';
+  result->version = atoi(str);
+
+  /* serial number */
+  str = ptr;
+  ptr = strchr(str, '#');
+  if (ptr == NULLCP)
+  {
+    parse_error("serial number not present",NULLCP);
+    cert_free(result);
+    return (struct certificate *) 0;
+  }
+  *ptr++ = '\0';
+  result->serial = atoi(str);
+
+  /* signature algorithm id - oid */
+  str = ptr;
+  ptr = strchr(str, '#');
+  if (ptr == NULLCP)
+  {
+    parse_error("signature algorithm id not present",NULLCP);
+    cert_free(result);
+    return (struct certificate *) 0;
+  }
+  *ptr++ = '\0';
+  oid = name2oid(SkipSpace(str));
+  if (oid == NULLOID)
+  {
+    parse_error("Bad algorithm identifier (SIGNED Value)",NULLCP);
+    cert_free(result);
+    return (struct certificate *) 0;
+  }
+  result->sig.alg.algorithm = oid;
+  result->alg.algorithm     = oid_cpy(oid);
+
+  /* signature algorithm id - parameters */
+  str = ptr;
+  ptr = strchr(str, '#');
+  if (ptr == NULLCP)
+  {
+    parse_error("algorithm id parameters not present",NULLCP);
+    cert_free(result);
+    return (struct certificate *) 0;
+  }
+  *ptr++ = '\0';
+  ldap_str2alg(str, &(result->sig.alg));
+  ldap_str2alg(str, &(result->alg));
+
+  /* issuer */
+  str = ptr;
+  ptr = strchr(str, '#');
+  if (ptr == NULLCP)
+  {
+    parse_error("Issuer not present",NULLCP);
+    cert_free(result);
+    return (struct certificate *) 0;
+  }
+  *ptr++ = '\0';
+  result->issuer = ldap_str2dn(str);
+
+  /* validity - not before */
+  str = ptr;
+  ptr = strchr(str, '#');
+  if (ptr == NULLCP)
+  {
+    parse_error("Start time not present",NULLCP);
+    cert_free(result);
+    return (struct certificate *) 0;
+  }
+  *ptr++ = '\0';
+  result->valid.not_before = strdup(str);
+
+  /* validity - not after */
+  str = ptr;
+  ptr = strchr(str, '#');
+  if (ptr == NULLCP)
+  {
+    parse_error("End time not present",NULLCP);
+    cert_free(result);
+    return (struct certificate *) 0;
+  }
+  *ptr++ = '\0';
+  result->valid.not_after = strdup(str);
+
+  /* subject */
+  str = ptr;
+  ptr = strchr(str, '#');
+  if (ptr == NULLCP)
+  {
+    parse_error("Subject not present",NULLCP);
+    cert_free(result);
+    return (struct certificate *) 0;
+  }
+  *ptr++ = '\0';
+  result->subject = ldap_str2dn(str);
+
+  /* public key info - algorithm id - oid */
+  str = ptr;
+  ptr = strchr(str, '#');
+  if (ptr == NULLCP)
+  {
+    parse_error("public key info algid oid not present",NULLCP);
+    cert_free(result);
+    return (struct certificate *) 0;
+  }
+  *ptr++ = '\0';
+  oid = name2oid(SkipSpace(str));
+  if (oid == NULLOID)
+  {
+    free((char*)result);
+    return (struct certificate *) 0;
+  }
+  result->key.alg.algorithm = oid;
+
+  /* public key info - algorithm id - parameters */
+  str = ptr;
+  ptr = strchr(str, '#');
+  if (ptr == NULLCP)
+  {
+    parse_error("Parameters not present (SIGNED Value)",NULLCP);
+    cert_free(result);
+    return (struct certificate *) 0;
+  }
+  *ptr++ = '\0';
+  ldap_str2alg(str, &(result->key.alg));
+
+  /* public key info - encrypted sign value */
+  str = ptr;
+  ptr = strchr(str, '#');
+  if (ptr == NULLCP)
+  {
+    parse_error("Signature not present",NULLCP);
+    cert_free(result);
+    return (struct certificate *) 0;
+  }
+  *ptr++ = '\0';
+  str2encrypted(str, &(result->key.value), &(result->key.n_bits));
+
+  /* encrypted sign value */
+  str = ptr;
+  str2encrypted(str, &(result->sig.encrypted), &(result->sig.n_bits));
+
+  return (result);
+}
+
+void
+ldap_str2alg( char *str, struct alg_id *alg )
+{
+PE asn2pe();
+
+  if ((str == NULLCP) || (*str == '\0'))
+   {
+     alg->asn = NULLPE;
+     alg->p_type = ALG_PARM_ABSENT;
+   }
+  else if (strncmp(str,"{ASN}", 5) == 0)
+    {
+      alg->asn = asn2pe((char*)str+5);
+      alg->p_type = ALG_PARM_UNKNOWN;
+    }
+  else if (strncmp(str, "NULL", 4) == 0)
+    {
+      alg->asn = asn2pe((char*)"0500");
+      alg->p_type = ALG_PARM_UNKNOWN;
+    }
+  else
+    {
+      alg->asn=NULLPE;
+      alg->p_type = ALG_PARM_NUMERIC;
+      alg->un.numeric = atoi(str);
+    }
+}
+
+void certif_init()
+{
+       extern short    ldap_certif_syntax;
+       sntx_table      *syntax_table;
+       extern sntx_table *get_syntax_table();
+
+       if (syntax_table = get_syntax_table(ldap_certif_syntax)) {
+               syntax_table->s_print = (void *) ldap_certif_print;
+               syntax_table->s_parse = (void *) ldap_str2cert;
+       } else
+               fprintf(stderr, "error getting sntx table in certif_init()\n");
+}
diff --git a/servers/ldapd/common.h b/servers/ldapd/common.h
new file mode 100644 (file)
index 0000000..9239a72
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+/*
+ * This structure represents an association to a dsa.  There is one of
+ * these for each association open (a new association is made for each
+ * new dsa, and for each dn).
+ */
+
+struct conn {
+       int             c_ad;           /* association descriptor */
+       char            *c_dn;          /* the dn this asoc is bound as */
+       char            *c_cred;        /* corresponding pw */
+       long            c_credlen;
+       unsigned long   c_method;
+       struct PSAPaddr *c_paddr;       /* the dsa address */
+       int             c_time;         /* time this association inited */
+       int             c_refcnt;       /* number of ops referencing this ad */
+       struct conn     *c_next;
+};
+
+/*
+ * This structure represents an outstanding request.  There is one of
+ * these for each client request for which we have not yet received a
+ * response from a dsa.
+ */
+
+struct msg {
+       int             m_msgid;        /* the message id */
+       int             m_uniqid;       /* unique id for this message */
+       int             m_msgtype;      /* the ldap operation type */
+       LDAPMod         *m_mods;        /* for modify operations only */
+       BerElement      *m_ber;         /* the unparsed ber for the op */
+       struct conn     *m_conn;        /* connection structure */
+#ifdef CLDAP
+       int             m_cldap;        /* connectionless transport? (CLDAP) */
+       struct sockaddr m_clientaddr;   /* client address (if using CLDAP) */
+       DN              m_searchbase;   /* base used in search */
+#endif /* CLDAP */
+       struct msg      *m_next;
+};
+
+#define DEFAULT_TIMEOUT                        3600    /* idle client connections */
+#define DEFAULT_REFERRAL_TIMEOUT       900     /* DSA connections */
+
+#ifdef NEEDPROTOS
+#include "proto-ldapd.h"
+#else
+extern struct msg *add_msg();
+extern struct msg *get_msg();
+extern struct msg *get_cldap_msg();
+extern int       del_msg();
+
+extern struct conn *conn_getfd();
+extern struct conn *conn_find();
+extern struct conn *conn_dup();
+extern void conn_del();
+
+extern AttributeValue ldap_str2AttrV();
+extern DN ldap_str2dn();
+extern void ldap_str2alg();
+extern void ldap_print_algid();
+#endif /* don't need protos */
diff --git a/servers/ldapd/compare.c b/servers/ldapd/compare.c
new file mode 100644 (file)
index 0000000..88ac160
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <quipu/commonarg.h>
+#include <quipu/attrvalue.h>
+#include <quipu/ds_error.h>
+#include <quipu/compare.h>
+#include <quipu/dap2.h>
+#include <quipu/dua.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "lber.h"
+#include "ldap.h"
+#include "common.h"
+
+#ifdef COMPAT20
+extern int     ldap_compat;
+#define COMPTAG        (ldap_compat == 20 ? OLD_LDAP_RES_COMPARE : LDAP_RES_COMPARE)
+#else
+#define COMPTAG        LDAP_RES_COMPARE
+#endif
+
+int
+do_compare( 
+    Sockbuf    *clientsb,
+    struct msg *m,
+    BerElement *ber
+)
+{
+       char                    *dn, *attr, *value;
+       int                     rc;
+       struct ds_compare_arg   ca;
+       AttributeType           type;
+       static CommonArgs       common = default_common_args;
+       extern short            ldap_dn_syntax;
+
+       Debug( LDAP_DEBUG_TRACE, "do_compare\n", 0, 0, 0 );
+
+       /*
+        * Parse the compare request.  It looks like this:
+        *      CompareRequest := [APPLICATION 14] SEQUENCE {
+        *              entry   DistinguishedName,
+        *              ava     SEQUENCE {
+        *                      type    AttributeType,
+        *                      value   AttributeValue
+        *              }
+        *      }
+        */
+
+#if ISODEPACKAGE == IC
+#if ICRELEASE > 2
+       DAS_CompareArgument_INIT ( &ca );
+#endif
+#endif
+
+       if ( ber_scanf( ber, "{a{aa}}", &dn, &attr, &value ) == LBER_ERROR ) {
+               Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
+               send_ldap_msgresult( clientsb, COMPTAG, m,
+                   LDAP_PROTOCOL_ERROR, NULL, "" );
+               return( 0 );
+       }
+
+       Debug( LDAP_DEBUG_ARGS, "do_compare: dn (%s) attr (%s) value (%s)\n",
+           dn, attr, value );
+
+       ca.cma_object = ldap_str2dn( dn );
+       free( dn );
+       if ( ca.cma_object == NULLDN ) {
+               Debug( LDAP_DEBUG_ANY, "ldap_str2dn failed\n", 0, 0, 0 );
+               send_ldap_msgresult( clientsb, COMPTAG, m,
+                   LDAP_INVALID_DN_SYNTAX, NULL, "" );
+               return( 0 );
+       }
+
+       type = str2AttrT( attr );
+       if ( type == NULLAttrT ) {
+               Debug( LDAP_DEBUG_ANY, "str2AttrT failed\n", 0, 0, 0 );
+               send_ldap_msgresult( clientsb, COMPTAG, m,
+                   LDAP_UNDEFINED_TYPE, NULL, attr );
+               free( attr );
+               return( 0 );
+       }
+       free( attr );
+       ca.cma_purported.ava_type = type;
+
+       ca.cma_purported.ava_value = ldap_str2AttrV( value, type->oa_syntax );
+       free( value );
+       if ( ca.cma_purported.ava_value == NULLAttrV ) {
+               Debug( LDAP_DEBUG_ANY, "str2AttrV failed\n", 0, 0, 0 );
+               send_ldap_msgresult( clientsb, COMPTAG, m,
+                   LDAP_INVALID_SYNTAX, NULL, "" );
+               return( 0 );
+       }
+
+       ca.cma_common = common; /* struct copy */
+
+       rc = initiate_dap_operation( OP_COMPARE, m, &ca );
+
+       dn_free( ca.cma_object );
+       AttrV_free( ca.cma_purported.ava_value );
+
+       if ( rc != 0 ) {
+               send_ldap_msgresult( clientsb, COMPTAG, m, rc, NULL, "" );
+               return( 0 );
+       }
+
+       return( 1 );
+}
+
+void
+compare_result( 
+    Sockbuf                    *sb,
+    struct msg                 *m,
+    struct ds_compare_result   *cr
+)
+{
+       send_ldap_msgresult( sb, COMPTAG, m, cr->cmr_matched ?
+           LDAP_COMPARE_TRUE : LDAP_COMPARE_FALSE, NULL, "" );
+
+       return;
+}
diff --git a/servers/ldapd/delete.c b/servers/ldapd/delete.c
new file mode 100644 (file)
index 0000000..57fe76e
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <quipu/commonarg.h>
+#include <quipu/attrvalue.h>
+#include <quipu/ds_error.h>
+#include <quipu/remove.h>
+#include <quipu/dap2.h>
+#include <quipu/dua.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "lber.h"
+#include "ldap.h"
+#include "common.h"
+
+#ifdef COMPAT20
+extern int     ldap_compat;
+#define DELTAG (ldap_compat == 20 ? OLD_LDAP_RES_DELETE : LDAP_RES_DELETE)
+#else
+#define DELTAG LDAP_RES_DELETE
+#endif
+
+/*
+ * do_delete - Initiate an X.500 remove entry operation.  Returns 1 if
+ * the operation was initiated successfully, and thus a response will be
+ * coming back from the DSA.  Returns 0 if there was trouble and thus no
+ * DSA response is expected.
+ */
+
+int
+do_delete( 
+    Sockbuf    *clientsb,
+    struct msg *m,
+    BerElement *ber
+)
+{
+       char                            *dn;
+       int                             rc;
+       struct ds_removeentry_arg       ra;
+       static CommonArgs               common = default_common_args;
+       extern DN                       ldap_str2dn();
+
+       Debug( LDAP_DEBUG_TRACE, "do_delete\n", 0, 0, 0 );
+
+       /*
+        * Parse the delete request.  It looks like this:
+        *      DelRequest := DistinguishedName
+        */
+
+#if ISODEPACKAGE == IC
+#if ICRELEASE > 2
+       DAS_RemoveEntryArgument_INIT( &ra );
+#endif
+#endif
+
+       if ( ber_scanf( ber, "a", &dn ) == LBER_ERROR ) {
+               Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
+               send_ldap_msgresult( clientsb, DELTAG, m,
+                   LDAP_PROTOCOL_ERROR, NULL, "" );
+               return( 0 );
+       }
+
+       Debug( LDAP_DEBUG_ARGS, "do_delete: dn (%s)\n", dn, 0, 0 );
+
+       ra.rma_object = ldap_str2dn( dn );
+       free( dn );
+       if ( ra.rma_object == NULLDN ) {
+               Debug( LDAP_DEBUG_ANY, "ldap_str2dn failed\n", 0, 0, 0 );
+               send_ldap_msgresult( clientsb, DELTAG, m,
+                   LDAP_INVALID_DN_SYNTAX, NULL, "" );
+               return( 0 );
+       }
+
+       ra.rma_common = common; /* struct copy */
+
+       rc = initiate_dap_operation( OP_REMOVEENTRY, m, &ra );
+
+       dn_free( ra.rma_object );
+
+       if ( rc != 0 ) {
+               send_ldap_msgresult( clientsb, DELTAG, m, rc, NULL, "" );
+               return( 0 );
+       }
+
+       return( 1 );
+}
+
+void
+delete_result(
+    Sockbuf    *sb,
+    struct msg *m
+)
+{
+       send_ldap_msgresult( sb, DELTAG, m, LDAP_SUCCESS, NULL, "" );
+
+       return;
+}
diff --git a/servers/ldapd/detach.c b/servers/ldapd/detach.c
new file mode 100644 (file)
index 0000000..ff435ee
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 1990, 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef SVR4
+#include <sys/stat.h>
+#endif /* svr4 */
+#include <fcntl.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <signal.h>
+#include "portable.h"
+
+#ifdef USE_SYSCONF
+#include <unistd.h>
+#endif /* USE_SYSCONF */
+
+
+detach()
+{
+       int             i, sd, nbits;
+#ifdef LDAP_DEBUG
+       extern int      ldap_debug;
+#endif
+
+#ifdef USE_SYSCONF
+       nbits = sysconf( _SC_OPEN_MAX );
+#else /* USE_SYSCONF */
+       nbits = getdtablesize();
+#endif /* USE_SYSCONF */
+
+#ifdef LDAP_DEBUG
+       if ( ldap_debug == 0 ) {
+#endif
+               for ( i = 0; i < 5; i++ ) {
+                       switch ( fork() ) {
+                       case -1:
+                               sleep( 5 );
+                               continue;
+
+                       case 0:
+                               break;
+
+                       default:
+                               _exit( 0 );
+                       }
+                       break;
+               }
+
+               for ( i = 3; i < nbits; i++ )
+                       close( i );
+
+               (void) chdir( "/" );
+
+               if ( (sd = open( "/dev/null", O_RDWR )) == -1 ) {
+                       perror( "/dev/null" );
+                       exit( 1 );
+               }
+               if ( isatty( 0 ) )
+                       (void) dup2( sd, 0 );
+               if ( isatty( 1 ) )
+                       (void) dup2( sd, 1 );
+               if ( isatty(2) )
+                       (void) dup2( sd, 2 );
+               close( sd );
+
+#ifdef USE_SETSID
+               setsid();
+#else /* USE_SETSID */
+               if ( (sd = open( "/dev/tty", O_RDWR )) != -1 ) {
+                       (void) ioctl( sd, TIOCNOTTY, NULL );
+                       (void) close( sd );
+               }
+#endif /* USE_SETSID */
+#ifdef LDAP_DEBUG
+       } 
+#endif
+
+       (void) signal( SIGPIPE, SIG_IGN );
+}
diff --git a/servers/ldapd/error.c b/servers/ldapd/error.c
new file mode 100644 (file)
index 0000000..e35448c
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <quipu/ds_error.h>
+#include <quipu/attrvalue.h>
+#include <quipu/name.h>
+#include <quipu/commonarg.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <ctype.h>
+#include "lber.h"
+#include "ldap.h"
+
+void
+print_error( struct DSError *e )
+{
+       PS      ps;
+
+        if ( (ps = ps_alloc( std_open )) == NULLPS ) {
+                fprintf( stderr, "error in ps_alloc\n" );
+                return;
+        }
+        if ( std_setup( ps, stderr ) == NOTOK ) {
+                fprintf( stderr, "error in std_setup = %d", ps->ps_errno );
+                return;
+        }
+
+       ds_error( ps, e );
+
+       ps_flush( ps );
+       ps_free( ps );
+}
+
+int
+x500err2ldaperr( struct DSError *e, char **matched )
+{
+       int             ldaperr = LDAP_OTHER;
+       static PS       ps;
+
+       Debug( LDAP_DEBUG_TRACE, "x500err2ldaperr\n", 0, 0, 0 );
+
+       *matched = NULL;
+       switch ( e->dse_type ) {
+       case DSE_ATTRIBUTEERROR:
+#if ISODEPACKAGE == IC || ISODEPACKAGE == XT
+               switch ( e->ERR_ATTRIBUTE.DSE_at_plist->DSE_at_what ) {
+#else
+               switch ( e->ERR_ATTRIBUTE.DSE_at_plist.DSE_at_what ) {
+#endif
+               case DSE_AT_NOSUCHATTRIBUTE:
+                       ldaperr = LDAP_NO_SUCH_ATTRIBUTE;
+                       break;
+               case DSE_AT_INVALIDATTRIBUTESYNTAX:
+                       ldaperr = LDAP_INVALID_SYNTAX;
+                       break;
+               case DSE_AT_UNDEFINEDATTRIBUTETYPE:
+                       ldaperr = LDAP_UNDEFINED_TYPE;
+                       break;
+               case DSE_AT_INAPPROPRIATEMATCHING:
+                       ldaperr = LDAP_INAPPROPRIATE_MATCHING;
+                       break;
+               case DSE_AT_CONSTRAINTVIOLATION:
+                       ldaperr = LDAP_CONSTRAINT_VIOLATION;
+                       break;
+               case DSE_AT_TYPEORVALUEEXISTS:
+                       ldaperr = LDAP_TYPE_OR_VALUE_EXISTS;
+                       break;
+               default:
+                       break;
+               }
+               break;
+
+       case DSE_NAMEERROR:
+               switch( e->ERR_NAME.DSE_na_problem ) {
+               case DSE_NA_NOSUCHOBJECT:
+                       ldaperr = LDAP_NO_SUCH_OBJECT;
+                       break;
+               case DSE_NA_ALIASPROBLEM:
+                       ldaperr = LDAP_ALIAS_PROBLEM;
+                       break;
+               case DSE_NA_INVALIDATTRIBUTESYNTAX:
+                       ldaperr = LDAP_INVALID_SYNTAX;
+                       break;
+               case DSE_NA_ALIASDEREFERENCE:
+                       ldaperr = LDAP_ALIAS_DEREF_PROBLEM;
+                       break;
+               default:
+                       break;
+               }
+
+               if ( e->ERR_NAME.DSE_na_matched == NULLDN ) {
+                       break;
+               }
+
+               if ( ps == NULL ) {
+                       ps = ps_alloc( str_open );
+                       str_setup( ps, NULLCP, 0, 0 );
+               }
+               ldap_dn_print( ps, e->ERR_NAME.DSE_na_matched, NULLDN, EDBOUT );
+               *ps->ps_ptr = '\0';
+
+               *matched = (char *) strdup( ps->ps_base );
+
+               ps->ps_ptr = ps->ps_base;
+               ps->ps_cnt = ps->ps_bufsiz;
+               break;
+
+       case DSE_SERVICEERROR:
+               switch( e->ERR_SERVICE.DSE_sv_problem ) {
+               case DSE_SV_BUSY:
+                       ldaperr = LDAP_BUSY;
+                       break;
+               case DSE_SV_UNAVAILABLE:
+                       ldaperr = LDAP_UNAVAILABLE;
+                       break;
+               case DSE_SV_UNWILLINGTOPERFORM:
+                       ldaperr = LDAP_UNWILLING_TO_PERFORM;
+                       break;
+               case DSE_SV_TIMELIMITEXCEEDED:
+                       ldaperr = LDAP_TIMELIMIT_EXCEEDED;
+                       break;
+               case DSE_SV_ADMINLIMITEXCEEDED:
+                       ldaperr = LDAP_SIZELIMIT_EXCEEDED;
+                       break;
+               case DSE_SV_LOOPDETECT:
+                       ldaperr = LDAP_LOOP_DETECT;
+                       break;
+               default:
+                       break;
+               }
+               break;
+
+       case DSE_SECURITYERROR:
+               switch( e->ERR_SECURITY.DSE_sc_problem ) {
+               case DSE_SC_AUTHENTICATION:
+                       ldaperr = LDAP_INAPPROPRIATE_AUTH;
+                       break;
+               case DSE_SC_INVALIDCREDENTIALS:
+                       ldaperr = LDAP_INVALID_CREDENTIALS;
+                       break;
+               case DSE_SC_ACCESSRIGHTS:
+                       ldaperr = LDAP_INSUFFICIENT_ACCESS;
+                       break;
+               default:
+                       break;
+               }
+               break;
+
+       case DSE_UPDATEERROR:
+               switch( e->ERR_UPDATE.DSE_up_problem ) {
+               case DSE_UP_NAMINGVIOLATION:
+                       ldaperr = LDAP_NAMING_VIOLATION;
+                       break;
+               case DSE_UP_OBJECTCLASSVIOLATION:
+                       ldaperr = LDAP_OBJECT_CLASS_VIOLATION;
+                       break;
+               case DSE_UP_NOTONNONLEAF:
+                       ldaperr = LDAP_NOT_ALLOWED_ON_NONLEAF;
+                       break;
+               case DSE_UP_NOTONRDN:
+                       ldaperr = LDAP_NOT_ALLOWED_ON_RDN;
+                       break;
+               case DSE_UP_ALREADYEXISTS:
+                       ldaperr = LDAP_ALREADY_EXISTS;
+                       break;
+               case DSE_UP_NOOBJECTCLASSMODS:
+                       ldaperr = LDAP_NO_OBJECT_CLASS_MODS;
+                       break;
+               default:
+                       break;
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       return( ldaperr );
+}
diff --git a/servers/ldapd/kerberos.c b/servers/ldapd/kerberos.c
new file mode 100644 (file)
index 0000000..937236e
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#ifdef KERBEROS
+
+#include <stdio.h>
+#include <sys/types.h>
+#include "krb.h"
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <quipu/bind.h>
+#if ISODEPACKAGE == IC
+#include <quipu/DAS-types.h>
+#else
+#include <pepsy/DAS-types.h>
+#endif
+#include "lber.h"
+#include "ldap.h"
+#include "common.h"
+
+int
+kerberosv4_ldap_auth( char *cred, long len )
+{
+       KTEXT_ST        k;
+       KTEXT           ktxt = &k;
+       char            instance[INST_SZ];
+       int             err;
+       AUTH_DAT        ad;
+       extern char     *krb_ldap_service;
+       extern char     *kerberos_keyfile;
+
+       Debug( LDAP_DEBUG_TRACE, "kerberosv4_ldap_auth\n", 0, 0, 0 );
+
+       SAFEMEMCPY( ktxt->dat, cred, len );
+       ktxt->length = len;
+
+       strcpy( instance, "*" );
+       if ( (err = krb_rd_req( ktxt, krb_ldap_service, instance, 0L,
+           &ad, kerberos_keyfile )) != KSUCCESS ) {
+               Debug( LDAP_DEBUG_ANY, "krb_rd_req failed (%s)\n",
+                   krb_err_txt[err], 0, 0 );
+               return( LDAP_INVALID_CREDENTIALS );
+       }
+
+       return( LDAP_SUCCESS );
+}
+
+int
+kerberosv4_bindarg( 
+    struct ds_bind_arg *ba,
+    DN                 dn,
+    char               *cred,
+    long               len,
+    u_long             *nonce
+)
+{
+       struct type_UNIV_EXTERNAL       *e;
+       struct kerberos_parms           kp;
+       PE                              pe;
+       struct timeval                  tv;
+       char                            realm[REALM_SZ];
+       int                             err;
+       extern char                     *krb_x500_service;
+       extern char                     *krb_x500_instance;
+
+       Debug( LDAP_DEBUG_TRACE, "kerberosv4_bindarg\n", 0, 0, 0 );
+
+       e = (struct type_UNIV_EXTERNAL *) calloc( 1,
+           sizeof(struct type_UNIV_EXTERNAL) );
+       e->encoding = (struct choice_UNIV_0 *) calloc( 1,
+           sizeof(struct choice_UNIV_0) );
+       ba->dba_external = e;
+       ba->dba_version = DBA_VERSION_V1988;
+       ba->dba_auth_type = DBA_AUTH_EXTERNAL;
+
+       e->indirect__reference = AUTH_TYPE_KERBEROS_V4;
+       e->direct__reference = NULLOID;
+       e->data__value__descriptor = str2qb( "KRBv4 client credentials",
+           24, 1 );
+
+       kp.kp_dn = dn;
+       kp.kp_version = AUTH_TYPE_KERBEROS_V4;
+
+       if ( (err = krb_get_lrealm( realm, 1 )) != KSUCCESS ) {
+               Debug( LDAP_DEBUG_ANY, "krb_get_lrealm failed (%s)\n",
+                   krb_err_txt[err], 0, 0 );
+               return( LDAP_OPERATIONS_ERROR );
+       }
+
+       gettimeofday( &tv, NULL );
+       *nonce = tv.tv_sec;
+       SAFEMEMCPY( kp.kp_ktxt.dat, cred, len );
+       kp.kp_ktxt.length = len;
+       if ( encode_kerberos_parms( &pe, &kp ) == NOTOK ) {
+               Debug( LDAP_DEBUG_ANY, "kerberos parms encoding failed\n", 0,
+                   0, 0 );
+               return( LDAP_OPERATIONS_ERROR );
+       }
+
+       e->encoding->offset = choice_UNIV_0_single__ASN1__type;
+       e->encoding->un.single__ASN1__type = pe;
+
+       return( 0 );
+}
+
+int
+kerberos_check_mutual(
+    struct ds_bind_arg *res,
+    u_long             nonce
+)
+{
+       struct type_UNIV_EXTERNAL       *e = res->dba_external;
+       struct kerberos_parms           *kp;
+       int                             ret;
+
+       Debug( LDAP_DEBUG_TRACE, "kerberos_check_mutual\n", 0, 0, 0 );
+
+       if ( decode_kerberos_parms( e->encoding->un.single__ASN1__type, &kp )
+           == NOTOK )
+               return( NOTOK );
+       ret = ((kp->kp_nonce == (nonce + 1)) ? OK : NOTOK );
+
+       Debug( LDAP_DEBUG_TRACE, "expecting %d got %d\n", nonce, kp->kp_nonce,
+           0 );
+
+       pe_free( e->encoding->un.single__ASN1__type );
+       dn_free( kp->kp_dn );
+       free( (char *) kp );
+
+       return( ret );
+}
+
+#endif
diff --git a/servers/ldapd/ldap.py b/servers/ldapd/ldap.py
new file mode 100644 (file)
index 0000000..c578caa
--- /dev/null
@@ -0,0 +1,231 @@
+LDAP DEFINITIONS IMPLICIT TAGS ::=
+
+PREFIXES encode decode print
+
+BEGIN
+
+LDAPMessage ::=
+    SEQUENCE {
+         messageID      MessageID,
+                        -- unique id in request,
+                        -- to be echoed in response(s)
+         protocolOp     CHOICE {
+                             searchRequest       SearchRequest,
+                             searchResponse      SearchResponse,
+                             modifyRequest       ModifyRequest,
+                             modifyResponse      ModifyResponse,
+                             addRequest          AddRequest,
+                             addResponse         AddResponse,
+                             delRequest          DelRequest,
+                             delResponse         DelResponse,
+                             modifyDNRequest     ModifyRDNRequest,
+                             modifyDNResponse    ModifyRDNResponse,
+                             compareDNRequest    CompareRequest,
+                             compareDNResponse   CompareResponse,
+                             bindRequest         BindRequest,
+                             bindResponse        BindResponse,
+                             abandonRequest      AbandonRequest,
+                             unbindRequest       UnbindRequest
+                        }
+    }
+
+BindRequest ::=
+    [APPLICATION 0] SEQUENCE {
+         version        INTEGER (1 .. 127),
+                        -- current version is 2
+         name           LDAPDN,
+                        -- null name implies an anonymous bind
+         authentication CHOICE {
+                             simple        [0] OCTET STRING,
+                                       -- a zero length octet string
+                                       -- implies an unauthenticated
+                                       -- bind.
+                             krbv42LDAP    [1] OCTET STRING,
+                             krbv42DSA     [2] OCTET STRING
+                                       -- values as returned by
+                                       -- krb_mk_req()
+                                       -- Other values in later
+                                       -- versions of this protocol.
+                        }
+    }
+
+BindResponse ::= [APPLICATION 1] LDAPResult
+
+UnbindRequest ::= [APPLICATION 2] NULL
+
+SearchRequest ::=
+    [APPLICATION 3] SEQUENCE {
+         baseObject     LDAPDN,
+         scope          ENUMERATED {
+                             baseObject            (0),
+                             singleLevel           (1),
+                             wholeSubtree          (2)
+                        },
+         derefAliases   ENUMERATED {
+                             neverDerefAliases     (0),
+                             derefInSearching      (1),
+                             derefFindingBaseObj   (2),
+                             alwaysDerefAliases    (3)
+                        },
+         sizeLimit      INTEGER (0 .. maxInt),
+                        -- value of 0 implies no sizelimit
+         timeLimit      INTEGER (0 .. maxInt),
+                        -- value of 0 implies no timelimit
+         attrsOnly     BOOLEAN,
+                        -- TRUE, if only attributes (without values)
+                        -- to be returned.
+         filter         Filter,
+         attributes     SEQUENCE OF AttributeType
+    }
+
+SearchResponse ::=
+    CHOICE {
+         entry          [APPLICATION 4] SEQUENCE {
+                             objectName     LDAPDN,
+                             attributes     SEQUENCE OF SEQUENCE {
+                                              AttributeType,
+                                              SET OF
+                                                AttributeValue
+                                            }
+                        },
+         resultCode     [APPLICATION 5] LDAPResult
+    }
+
+ModifyRequest ::=
+    [APPLICATION 6] SEQUENCE {
+         object         LDAPDN,
+         modifications  SEQUENCE OF SEQUENCE {
+                             operation     ENUMERATED {
+                                             add      (0),
+                                             delete   (1),
+                                             replace  (2)
+                                           },
+                             modification  SEQUENCE {
+                                             type     AttributeType,
+                                             values   SET OF
+                                                        AttributeValue
+                                           }
+                        }
+    }
+
+
+ModifyResponse ::= [APPLICATION 7] LDAPResult
+
+AddRequest ::=
+    [APPLICATION 8] SEQUENCE {
+         entry          LDAPDN,
+         attrs          SEQUENCE OF SEQUENCE {
+                             type          AttributeType,
+                             values        SET OF AttributeValue
+                        }
+    }
+
+AddResponse ::= [APPLICATION 9] LDAPResult
+
+DelRequest ::= [APPLICATION 10] LDAPDN
+
+DelResponse ::= [APPLICATION 11] LDAPResult
+
+ModifyRDNRequest ::=
+    [APPLICATION 12] SEQUENCE {
+         entry          LDAPDN,
+         newrdn         RelativeLDAPDN -- old RDN always deleted
+    }
+
+ModifyRDNResponse ::= [APPLICATION 13] LDAPResult
+
+CompareRequest ::=
+    [APPLICATION 14] SEQUENCE {
+         entry          LDAPDN,
+         ava            AttributeValueAssertion
+    }
+
+CompareResponse ::= [APPLICATION 15] LDAPResult
+
+AbandonRequest ::= [APPLICATION 16] MessageID
+
+MessageID ::= INTEGER (0 .. maxInt)
+
+LDAPDN ::= OCTET STRING
+
+RelativeLDAPDN ::= OCTET STRING
+
+Filter ::=
+    CHOICE {
+        and            [0] SET OF Filter,
+        or             [1] SET OF Filter,
+        not            [2] Filter,
+        equalityMatch  [3] AttributeValueAssertion,
+        substrings     [4] SubstringFilter,
+        greaterOrEqual [5] AttributeValueAssertion,
+        lessOrEqual    [6] AttributeValueAssertion,
+        present        [7] AttributeType,
+        approxMatch    [8] AttributeValueAssertion
+    }
+
+LDAPResult ::=
+    SEQUENCE {
+        resultCode    ENUMERATED {
+                        success                      (0),
+                        operationsError              (1),
+                        protocolError                (2),
+                        timeLimitExceeded            (3),
+                        sizeLimitExceeded            (4),
+                        compareFalse                 (5),
+                        compareTrue                  (6),
+                        authMethodNotSupported       (7),
+                        strongAuthRequired           (8),
+                        noSuchAttribute              (16),
+                        undefinedAttributeType       (17),
+                        inappropriateMatching        (18),
+                        constraintViolation          (19),
+                        attributeOrValueExists       (20),
+                        invalidAttributeSyntax       (21),
+                        noSuchObject                 (32),
+                        aliasProblem                 (33),
+                        invalidDNSyntax              (34),
+                        isLeaf                       (35),
+                        aliasDereferencingProblem    (36),
+                        inappropriateAuthentication  (48),
+                        invalidCredentials           (49),
+                        insufficientAccessRights     (50),
+                        busy                         (51),
+                        unavailable                  (52),
+                        unwillingToPerform           (53),
+                        loopDetect                   (54),
+                        namingViolation              (64),
+                        objectClassViolation         (65),
+                        notAllowedOnNonLeaf          (66),
+                        notAllowedOnRDN              (67),
+                        entryAlreadyExists           (68),
+                        objectClassModsProhibited    (69),
+                        other                        (80)
+                      },
+        matchedDN     LDAPDN,
+        errorMessage  OCTET STRING
+    }
+
+AttributeType ::= OCTET STRING
+                -- text name of the attribute, or dotted
+                -- OID representation
+
+AttributeValue ::= OCTET STRING
+
+AttributeValueAssertion ::=
+    SEQUENCE {
+        attributeType        AttributeType,
+        attributeValue       AttributeValue
+    }
+
+SubstringFilter ::=
+    SEQUENCE {
+        type               AttributeType,
+        SEQUENCE OF CHOICE {
+          initial          [0] OCTET STRING,
+          any              [1] OCTET STRING,
+          final            [2] OCTET STRING
+      }
+    }
+
+maxInt INTEGER ::= 65535
+END
diff --git a/servers/ldapd/main.c b/servers/ldapd/main.c
new file mode 100644 (file)
index 0000000..5626a34
--- /dev/null
@@ -0,0 +1,691 @@
+/*
+ * Copyright (c) 1990-1996 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+/*
+ * Some code fragments to run from inetd stolen from the University
+ * of Minnesota gopher distribution, which had this copyright on it:
+ *
+ * Part of the Internet Gopher program, copyright (C) 1991
+ * University of Minnesota Microcomputer Workstation and Networks Center
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/wait.h>
+#include <signal.h>
+#ifdef _AIX
+#include <sys/select.h>
+#endif
+#include <syslog.h>
+#include <quipu/commonarg.h>
+#include <quipu/ds_error.h>
+#include "portable.h"
+#include "lber.h"
+#include "ldap.h"
+#include "common.h"
+
+#ifdef USE_SYSCONF
+#include <unistd.h>
+#endif /* USE_SYSCONF */
+
+void log_and_exit();
+static set_socket();
+static do_queries();
+static SIG_FN wait4child();
+#ifdef CLDAP
+static udp_init();
+#endif
+
+#ifdef LDAP_DEBUG
+int    ldap_debug;
+#endif
+int    version;
+#ifdef COMPAT
+int    ldap_compat;
+#endif
+int    dosyslog;
+int    do_tcp = 1;
+#ifdef CLDAP
+int    do_udp = 0;
+#endif
+int    idletime = DEFAULT_TIMEOUT;
+int    referral_connection_timeout = DEFAULT_REFERRAL_TIMEOUT;
+struct timeval conn_start_tv;
+#ifdef KERBEROS
+char   *krb_ldap_service = "ldapserver";
+char   *krb_x500_service = "x500dsa";
+char   *krb_x500_instance;
+char   *krb_x500_nonce;
+char   *kerberos_keyfile;
+#endif
+
+int    dtblsize;
+int    RunFromInetd = 0;
+
+extern char Versionstr[];
+
+static usage( name )
+char   *name;
+{
+       fprintf( stderr, "usage: %s [-d debuglvl] [-p port] [-l] [-c dsa] [-r referraltimeout]", name );
+#ifdef CLDAP
+       fprintf( stderr, " [ -U | -t timeout ]" );
+#else
+       fprintf( stderr, " [ -t timeout ]" );
+#endif
+       fprintf( stderr, " [-I]" );
+#ifdef KERBEROS
+       fprintf( stderr, " [-i dsainstance]" );
+#endif
+       fprintf( stderr, "\n" );
+}
+
+main (argc, argv)
+int    argc;
+char   **argv;
+{
+       int                     tcps, ns;
+#ifdef CLDAP
+       int                     udps;
+#endif
+       int                     myport = LDAP_PORT;
+       int                     i, pid, socktype;
+       char                    *myname;
+       fd_set                  readfds;
+       struct hostent          *hp;
+       struct sockaddr_in      from;
+       int                     len;
+       int                     dsapargc;
+       char                    **dsapargv;
+       SIG_FN                  wait4child();
+#ifndef NOSETPROCTITLE
+       char                    title[80];
+       extern char             **Argv;
+       extern int              Argc;
+#endif
+       extern char             *optarg;
+       extern int              optind;
+
+#ifdef VMS
+       /* Pick up socket from inetd-type server on VMS */
+       if ( (ns = socket_from_server( NULL )) > 0 )
+               RunFromInetd = 1;
+#else
+        /* Socket from inetd is usually 0 */
+        ns = 0;
+#endif
+
+       /* for dsap_init */
+        if ( (dsapargv = (char **) malloc( 4 * sizeof(char *) )) == NULL ) {
+                perror( "malloc" );
+                exit( 1 );
+        }
+        dsapargv[0] = argv[0];
+        dsapargv[1] = 0;
+        dsapargv[2] = 0;
+        dsapargv[3] = 0;
+        dsapargc = 1;
+#ifdef KERBEROS
+       kerberos_keyfile = "";
+#endif
+
+       /* process command line arguments */
+       while ( (i = getopt( argc, argv, "d:lp:f:i:c:r:t:IuU" )) != EOF ) {
+               switch ( i ) {
+               case 'c':       /* specify dsa to contact */
+                       dsapargv[1] = "-call";
+                       dsapargv[2] = strdup( optarg );
+                       dsapargc = 3;
+                       break;
+
+               case 'd':       /* turn on debugging */
+#ifdef LDAP_DEBUG
+                       ldap_debug = atoi( optarg );
+                       if ( ldap_debug & LDAP_DEBUG_PACKETS )
+                               lber_debug = ldap_debug;
+#else
+                       fprintf( stderr, "Not compiled with -DLDAP_DEBUG!\n" );
+#endif
+                       break;
+
+               case 'l':       /* do syslogging */
+                       dosyslog = 1;
+                       break;
+
+               case 'p':       /* specify port number */
+                       myport = atoi( optarg );
+                       break;
+
+               case 'r':       /* timeout for referral connections */
+                       referral_connection_timeout = atoi( optarg );
+                       break;
+
+               case 't':       /* timeout for idle connections */
+                       idletime = atoi( optarg );
+                       break;
+
+#ifdef KERBEROS
+               case 'f':       /* kerberos key file */
+                       kerberos_keyfile = strdup( optarg );
+                       break;
+
+               case 'i':       /* x500 dsa kerberos instance */
+                       if ( krb_x500_instance != NULL )
+                               free( krb_x500_instance );
+                       krb_x500_instance = strdup( optarg );
+                       break;
+#endif
+
+               case 'I':       /* Run from inetd */
+                       RunFromInetd = 1;
+                       break;
+
+#ifdef CLDAP
+               case 'U':       /* UDP only (no TCP) */
+                       do_tcp = 0;
+                       do_udp = 1;
+                       break;
+
+#ifdef NOTYET
+               case 'u':       /* allow UDP requests (CLDAP) */
+                       do_udp = 1;
+                       break;
+#endif /* NOTYET */
+
+#endif /* CLDAP */
+
+               default:
+                       usage( argv[0] );
+                       exit( 1 );
+               }
+       }
+
+       if ( optind < argc ) {
+               usage( argv[ 0 ] );
+               exit( 1 );
+       }
+
+#ifdef CLDAP
+       if ( do_udp && !do_tcp && idletime != DEFAULT_TIMEOUT ) {
+               usage( argv[ 0 ] );
+               exit( 1 );
+       }
+#endif
+
+       Debug( LDAP_DEBUG_TRACE, "%s", Versionstr, 0, 0 );
+
+#ifdef USE_SYSCONF
+       dtblsize = sysconf( _SC_OPEN_MAX );
+#else /* USE_SYSCONF */
+       dtblsize = getdtablesize();
+#endif /* USE_SYSCONF */
+
+#ifndef NOSETPROCTITLE
+       /* for setproctitle */
+       Argv = argv;
+       Argc = argc;
+#endif
+
+       if ( (myname = strrchr( argv[0], '/' )) == NULL )
+               myname = strdup( argv[0] );
+       else
+               myname = strdup( myname + 1 );
+
+       /* 
+        * detach from the terminal if stderr is redirected or no
+        * debugging is wanted, and then arrange to reap children
+        * that have exited
+        */
+       if (!RunFromInetd) {
+#ifndef NOSETPROCTITLE
+               setproctitle( "initializing" );
+#endif
+#ifndef VMS
+               (void) detach();
+#endif
+               (void) SIGNAL( SIGCHLD, (void *) wait4child );
+               (void) SIGNAL( SIGINT, (void *) log_and_exit );
+       }
+
+       /* 
+        * set up syslogging (if desired)
+        */
+       if ( dosyslog ) {
+#ifdef LOG_LOCAL4
+               openlog( myname, OPENLOG_OPTIONS, LOG_LOCAL4 );
+#else
+               openlog( myname, OPENLOG_OPTIONS );
+#endif
+       }
+
+       /* 
+        * load the syntax handlers, oidtables, and initialize some stuff,
+        * then start listening
+        */
+
+       (void) quipu_syntaxes();
+#ifdef LDAP_USE_PP
+       (void) pp_quipu_init( argv[0] );
+#endif
+#if ISODEPACKAGE == IC
+#if ICRELEASE > 2
+       dsa_operation_syntaxes();
+#endif
+#endif
+       (void) dsap_init( &dsapargc, &dsapargv );
+       (void) get_syntaxes();
+       if (RunFromInetd) {
+               len = sizeof( socktype );
+               getsockopt( ns, SOL_SOCKET, SO_TYPE, &socktype, &len );
+               if ( socktype == SOCK_DGRAM ) {
+#ifdef CLDAP
+                       Debug( LDAP_DEBUG_ARGS,
+                           "CLDAP request from unknown (%s)\n",
+                           inet_ntoa( from.sin_addr ), 0, 0 );
+                       conn_start_tv.tv_sec = 0;
+                       udp_init( 0, 0 );
+                       do_queries( ns, 1 );
+#else /* CLDAP */
+                       Debug( LDAP_DEBUG_ARGS,
+                           "Compile with -DCLDAP for UDP support\n",0,0,0 );
+#endif /* CLDAP */
+                       exit( 0 );
+               }
+
+               len = sizeof(from);
+               if ( getpeername( ns, (struct sockaddr *) &from, &len )
+                   == 0 ) {
+                       hp = gethostbyaddr( (char *) &(from.sin_addr.s_addr),
+                       sizeof(from.sin_addr.s_addr), AF_INET );
+                       Debug( LDAP_DEBUG_ARGS, "connection from %s (%s)\n",
+                           (hp == NULL) ? "unknown" : hp->h_name,
+                           inet_ntoa( from.sin_addr ), 0 );
+
+                       if ( dosyslog ) {
+                               syslog( LOG_INFO, "connection from %s (%s)",
+                                   (hp == NULL) ? "unknown" : hp->h_name,
+                                   inet_ntoa( from.sin_addr ) );
+                       }
+
+#ifndef NOSETPROCTITLE
+                       sprintf( title, "%s %d\n", hp == NULL ?
+                           inet_ntoa( from.sin_addr ) : hp->h_name, myport );
+                       setproctitle( title );
+#endif
+               }
+               gettimeofday( &conn_start_tv, (struct timezone *) NULL );
+               do_queries( ns, 0 );
+
+               exit( 0 );
+       }
+
+       if ( do_tcp )
+           tcps = set_socket( myport, 0 );
+
+#ifdef CLDAP
+       if ( do_udp )
+               udps = udp_init( myport, 1 );
+#endif
+
+       /*
+        * loop, wait for a connection, then fork off a child to handle it
+        * if we are doing CLDAP as well, handle those requests on the fly
+        */
+
+#ifndef NOSETPROCTITLE
+#ifdef CLDAP
+        sprintf( title, "listening %s/%s %d", do_tcp ? "tcp" : "",
+            do_udp ? "udp" : "", myport );
+#else
+        sprintf( title, "listening %s %d", do_tcp ? "tcp" : "", myport );
+#endif
+       setproctitle( title );
+#endif
+
+       for ( ;; ) {
+               FD_ZERO( &readfds );
+               if ( do_tcp )
+                       FD_SET( tcps, &readfds );
+#ifdef CLDAP
+               if ( do_udp )
+                       FD_SET( udps, &readfds );
+#endif
+
+               if ( select( dtblsize, &readfds, 0, 0, 0 ) < 1 ) {
+#ifdef LDAP_DEBUG
+                       if ( ldap_debug ) perror( "main select" );
+#endif
+                       continue;
+               }
+
+#ifdef CLDAP
+               if ( do_udp && FD_ISSET( udps, &readfds ) ) {
+                       do_queries( udps, 1 );
+               }
+#endif
+
+               if ( !do_tcp || ! FD_ISSET( tcps, &readfds ) ) {
+                       continue;
+               }
+
+               len = sizeof(from);
+               if ( (ns = accept( tcps, (struct sockaddr *) &from, &len ))
+                   == -1 ) {
+#ifdef LDAP_DEBUG
+                       if ( ldap_debug ) perror( "accept" );
+#endif
+                       continue;
+               }
+
+               hp = gethostbyaddr( (char *) &(from.sin_addr.s_addr),
+                   sizeof(from.sin_addr.s_addr), AF_INET );
+               Debug( LDAP_DEBUG_ARGS, "connection from %s (%s)\n",
+                   (hp == NULL) ? "unknown" : hp->h_name,
+                   inet_ntoa( from.sin_addr ), 0 );
+
+               if ( dosyslog ) {
+                       syslog( LOG_INFO, "connection from %s (%s)",
+                           (hp == NULL) ? "unknown" : hp->h_name,
+                           inet_ntoa( from.sin_addr ) );
+               }
+
+#ifdef VMS
+               /* This is for debug on terminal on VMS */
+               close( tcps );
+#ifndef NOSETPROCTITLE
+               setproctitle( hp == NULL ? inet_ntoa( from.sin_addr ) :
+                   hp->h_name );
+#endif
+               gettimeofday( &conn_start_tv, (struct timezone *) NULL );
+               (void) SIGNAL( SIGPIPE, (void *) log_and_exit );
+
+               do_queries( ns, 0 );
+               /* NOT REACHED */
+#endif
+
+               switch( pid = fork() ) {
+               case 0:         /* child */
+                       close( tcps );
+#ifndef NOSETPROCTITLE
+                        sprintf( title, "%s (%d)\n", hp == NULL ?
+                               inet_ntoa( from.sin_addr ) : hp->h_name,
+                               myport );
+                       setproctitle( title );
+#endif
+                       gettimeofday( &conn_start_tv, (struct timezone *) NULL );
+                       (void) SIGNAL( SIGPIPE, (void *) log_and_exit );
+
+                       do_queries( ns, 0 );
+                       break;
+
+               case -1:        /* failed */
+#ifdef LDAP_DEBUG
+                       if ( ldap_debug ) perror( "fork" );
+#endif
+                       close( ns );
+                       syslog( LOG_ERR, "fork failed %m" );
+                       /* let things cool off */
+                       sleep( 15 );
+                       break;
+
+               default:        /* parent */
+                       close( ns );
+                       Debug( LDAP_DEBUG_TRACE, "forked child %d\n", pid, 0,
+                           0 );
+                       break;
+               }
+       }
+       /* NOT REACHED */
+}
+
+static
+do_queries(
+    int        clientsock,
+    int        udp             /* is this a UDP (CLDAP) request? */
+)
+{
+       fd_set          readfds;
+       int             rc, i;
+       struct timeval  timeout;
+       Sockbuf         sb;
+#ifdef CLDAP
+       struct sockaddr saddr, faddr;
+       struct sockaddr *saddrlist[ 1 ];
+#endif /* CLDAP */
+
+       Debug( LDAP_DEBUG_TRACE, "do_queries%s\n",
+           udp ? " udp" : "", 0, 0 );
+
+       /*
+        * Loop, wait for a request from the client or a response from
+        * a dsa, then handle it.  Dsap_ad is always a connection to the
+        * "default" dsa.  Other connections can be made as a result of
+        * a referral being chased down.  These association descriptors
+        * are kept track of with the message that caused the referral.
+        * The set_dsa_fds() routine traverses the list of outstanding
+        * messages, setting the appropriate bits in readfds.
+        */
+
+       if ( !udp ) {
+               conn_init();
+       }
+
+       (void) memset( (void *) &sb, '\0', sizeof( sb ) );
+       sb.sb_sd = clientsock;
+       sb.sb_naddr = ( udp ) ? 1 : 0;
+#ifdef CLDAP
+       sb.sb_addrs = (void **)saddrlist;
+       sb.sb_fromaddr = &faddr;
+       sb.sb_useaddr = saddrlist[ 0 ] = &saddr;
+#endif
+       sb.sb_ber.ber_buf = NULL;
+       sb.sb_ber.ber_ptr = NULL;
+       sb.sb_ber.ber_end = NULL;
+
+       timeout.tv_sec = idletime;
+       timeout.tv_usec = 0;
+       for ( ;; ) {
+               struct conn             *dsaconn;
+               extern struct conn      *conns;
+
+               FD_ZERO( &readfds );
+               FD_SET( clientsock, &readfds );
+               conn_setfds( &readfds );
+
+#ifdef LDAP_DEBUG
+               if ( ldap_debug & LDAP_DEBUG_CONNS ) {
+                       Debug( LDAP_DEBUG_CONNS, "FDLIST:", 0, 0, 0 );
+                       for ( i = 0; i < dtblsize; i++ ) {
+                               if ( FD_ISSET( i, &readfds ) ) {
+                                       Debug( LDAP_DEBUG_CONNS, " %d", i, 0,
+                                           0);
+                               }
+                       }
+                       Debug( LDAP_DEBUG_CONNS, "\n", 0, 0, 0 );
+               }
+#endif
+
+               /* 
+                * hack - because of lber buffering, there might be stuff
+                * already waiting for us on the client sock.
+                */
+
+               if ( sb.sb_ber.ber_ptr >= sb.sb_ber.ber_end ) {
+                       if ( (rc = select( dtblsize, &readfds, 0, 0,
+                           udp ? 0 : &timeout )) < 1 ) {
+#ifdef LDAP_DEBUG
+                               if ( ldap_debug ) perror( "do_queries select" );
+#endif
+                               if ( rc == 0 )
+                                       log_and_exit( 0 ); /* idle timeout */
+
+                               Debug( LDAP_DEBUG_ANY, "select returns %d!\n",
+                                   rc, 0, 0 );
+
+                               /* client gone away - we can too */
+                               if ( isclosed( clientsock ) )
+                                       log_and_exit( 0 );
+
+                               /*
+                                * check if a dsa conn has gone away -
+                                * mark it bad if so
+                                */
+                               conn_badfds();
+
+                               continue;
+                       }
+               }
+
+               if ( sb.sb_ber.ber_ptr < sb.sb_ber.ber_end ||
+                   FD_ISSET( clientsock, &readfds ) ) {
+                       client_request( &sb, conns, udp );
+               } else {
+                       if ( (dsaconn = conn_getfd( &readfds )) == NULL ) {
+                               Debug( LDAP_DEBUG_ANY, "No DSA activity!\n",
+                                   0, 0, 0 );
+                               continue;
+                       }
+
+                       dsa_response( dsaconn, &sb );
+               }
+       }
+       /* NOT REACHED */
+}
+
+static set_socket(
+    int        port,
+    int        udp     /* UDP port? */
+)
+{
+       int                     s, i;
+       struct sockaddr_in      addr;
+
+       if ( (s = socket( AF_INET, udp ? SOCK_DGRAM:SOCK_STREAM, 0 )) == -1 ) {
+                perror( "socket" );
+                exit( 1 );
+        }
+
+        /* set option so clients can't keep us from coming back up */
+       i = 1;
+        if ( setsockopt( s, SOL_SOCKET, SO_REUSEADDR, (void *) &i, sizeof(i) )
+           < 0 ) {
+                perror( "setsockopt" );
+                exit( 1 );
+        }
+
+        /* bind to a name */
+       (void)memset( (void *)&addr, '\0', sizeof( addr ));
+        addr.sin_family = AF_INET;
+        addr.sin_addr.s_addr = INADDR_ANY;
+        addr.sin_port = htons( port );
+        if ( bind( s, (struct sockaddr *) &addr, sizeof(addr) ) ) {
+                perror( "bind" );
+                exit( 1 );
+        }
+
+       if ( !udp ) {
+               /* listen for connections */
+               if ( listen( s, 5 ) == -1 ) {
+                       perror( "listen" );
+                       exit( 1 );
+               }
+       }
+       Debug( LDAP_DEBUG_TRACE, "listening on %s port %d\n",
+               udp ? "udp" : "tcp", port, 0 );
+
+       return( s );
+}
+
+static SIG_FN wait4child()
+{
+        WAITSTATUSTYPE     status;
+
+       Debug( LDAP_DEBUG_TRACE, "parent: catching child status\n", 0, 0, 0 );
+
+#ifdef USE_WAITPID
+       while( waitpid( (pid_t) -1, 0, WAIT_FLAGS ) > 0 )
+               ;       /* NULL */
+#else
+        while ( wait3( &status, WAIT_FLAGS, 0 ) > 0 )
+                ;       /* NULL */
+#endif
+
+       (void) SIGNAL( SIGCHLD, (void *) wait4child );
+}
+
+
+void
+log_and_exit( int exitcode )
+{
+       struct timeval  tv;
+
+       if ( dosyslog ) {
+               if ( conn_start_tv.tv_sec == 0 ) {
+                       syslog( LOG_INFO, "UDP exit(%d)", exitcode );
+               } else {
+                       gettimeofday( &tv, (struct timezone *)NULL );
+                       syslog( LOG_INFO, "TCP closed %d seconds,  exit(%d)",
+                           tv.tv_sec - conn_start_tv.tv_sec, exitcode );
+               }
+       }
+
+       exit( exitcode );
+}
+
+
+#ifdef CLDAP
+static int
+udp_init(
+    int        port,
+    int        createsocket
+)
+{
+       int     s, bound;
+       char    *matched;
+       extern char             *dsa_address;
+       extern struct PSAPaddr  *psap_cpy();
+       extern struct conn      *conns;
+
+       if ( createsocket )
+               s = set_socket( port, 1 );
+
+       conn_init();
+       conns->c_dn = strdup("");
+       conns->c_cred = strdup("");
+       conns->c_credlen = 0;
+       conns->c_method = LDAP_AUTH_SIMPLE;
+
+       if ( dsa_address == NULL || (conns->c_paddr = str2paddr( dsa_address ))
+            == NULLPA ) {
+                fprintf(stderr, "Bad DSA address (%s)\n", dsa_address ?
+                    dsa_address : "NULL" );
+                exit( 1 );
+        } else {
+                conns->c_paddr = psap_cpy(conns->c_paddr);
+       }
+
+        if ( do_bind_real(conns, &bound, &matched) != LDAP_SUCCESS) {
+                fprintf(stderr, "Cannot bind to directory\n");
+                exit( 1 );
+        }
+        if ( matched != NULL )
+                free( matched );
+
+       return( createsocket ? s : 0 );
+}
+#endif
diff --git a/servers/ldapd/message.c b/servers/ldapd/message.c
new file mode 100644 (file)
index 0000000..19e07f6
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <quipu/commonarg.h>
+#include <quipu/ds_error.h>
+#include "lber.h"
+#include "ldap.h"
+#include "common.h"
+
+static struct msg      *messages;
+
+struct msg *add_msg(
+    int                        msgid,
+    int                        msgtype,
+    BerElement         *ber,
+    struct conn                *dsaconn,
+    int                        udp,
+    struct sockaddr    *clientaddr
+)
+{
+       struct msg              *new;
+       static int              uniqid = 0;
+
+       /* make a new message */
+       if ( (new = (struct msg *) malloc( sizeof(struct msg) )) == NULL ) {
+               Debug( LDAP_DEBUG_ANY, "addmsg: malloc failed\n", 0, 0, 0 );
+               return( NULL );
+       }
+       new->m_msgid = msgid;
+       new->m_uniqid = ++uniqid;
+       new->m_msgtype = msgtype;
+       new->m_ber = ber;
+       new->m_mods = NULL;
+       new->m_conn = dsaconn;
+       new->m_conn->c_refcnt++;
+       new->m_next = NULL;
+
+#ifdef CLDAP
+       new->m_cldap = udp;
+       new->m_searchbase = NULLDN;
+
+       if ( udp ) {
+               new->m_clientaddr = *clientaddr;
+               Debug( LDAP_DEBUG_TRACE, "udp message from %s port %d\n", 
+                   inet_ntoa( ((struct sockaddr_in *)clientaddr)->sin_addr ),
+                   ((struct sockaddr_in *)clientaddr)->sin_port, 0 );
+       }
+#endif
+
+       /* add it to the front of the queue */
+       new->m_next = messages;
+       messages = new;
+
+       return( new );
+}
+
+struct msg *get_msg( int uniqid )
+{
+       struct msg      *tmp;
+
+       for ( tmp = messages; tmp != NULL; tmp = tmp->m_next ) {
+               if ( tmp->m_uniqid == uniqid )
+                       return( tmp );
+       }
+
+       return( NULL );
+}
+
+int
+del_msg( struct msg *m )
+{
+       struct msg      *cur, *prev;
+
+       prev = NULL;
+       for ( cur = messages; cur != NULL; cur = cur->m_next ) {
+               if ( cur == m )
+                       break;
+               prev = cur;
+       }
+
+       if ( cur == NULL ) {
+               Debug( LDAP_DEBUG_ANY, "delmsg: cannot find msg %x\n", m,
+                   0, 0 );
+               return( -1 );
+       }
+
+       if ( prev == NULL ) {
+               messages = cur->m_next;
+       } else {
+               prev->m_next = cur->m_next;
+       }
+       conn_free( cur->m_conn );
+       modlist_free( cur->m_mods );
+       ber_free( cur->m_ber, 1 );
+#ifdef CLDAP
+       if ( cur->m_searchbase != NULLDN ) {
+           dn_free( cur->m_searchbase );
+       }
+#endif /* CLDAP */
+       free( (char *) cur );
+
+       return( 0 );
+}
+
+/*
+ * send_msg - Send a messge in response to every outstanding request on
+ * a given connection.  This is used, for example, when an association to
+ * a dsa fails.  It deletes messages to which it responds.
+ */
+
+void
+send_msg(
+    struct conn        *conn,
+    Sockbuf    *clientsb,
+    int                err,
+    char       *str
+)
+{
+       struct msg      *tmp, *next;
+
+       next = NULL;
+       for ( tmp = messages; tmp != NULL; tmp = next ) {
+               next = tmp->m_next;
+
+               if ( tmp->m_conn == conn ) {
+                       send_ldap_msgresult( clientsb, tmp->m_msgtype, tmp,
+                           err, NULL, str );
+               }
+
+               del_msg( tmp );
+       }
+}
+
+
+#ifdef CLDAP
+struct msg *
+get_cldap_msg(
+    int                        msgid,
+    int                        msgtype,
+    struct sockaddr    *fromaddr
+)
+{
+       struct msg      *tmp;
+
+       for ( tmp = messages; tmp != NULL; tmp = tmp->m_next ) {
+               if ( tmp->m_cldap && tmp->m_msgid == msgid &&
+                   tmp->m_msgtype == msgtype &&
+                   ((struct sockaddr_in *)&tmp->m_clientaddr)->sin_port ==
+                   ((struct sockaddr_in *)fromaddr)->sin_port &&
+                   ((struct sockaddr_in *)&tmp->m_clientaddr)->sin_addr.s_addr
+                   == ((struct sockaddr_in *)fromaddr)->sin_addr.s_addr ) {
+                       break;
+               }
+       }
+
+       return( tmp );
+}
+#endif /* CLDAP */
diff --git a/servers/ldapd/modify.c b/servers/ldapd/modify.c
new file mode 100644 (file)
index 0000000..bbfd5ed
--- /dev/null
@@ -0,0 +1,645 @@
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <quipu/commonarg.h>
+#include <quipu/attrvalue.h>
+#include <quipu/ds_error.h>
+#include <quipu/modify.h>
+#include <quipu/dap2.h>
+#include <quipu/dua.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "lber.h"
+#include "ldap.h"
+#include "common.h"
+
+static CommonArgs      common = default_common_args;
+
+extern short   ldap_photo_syntax;
+extern short   ldap_jpeg_syntax;
+extern short   ldap_jpeg_nonfile_syntax;
+extern short   ldap_audio_syntax;
+extern short   ldap_dn_syntax;
+extern short   ldap_postaladdress_syntax;
+extern short   ldap_acl_syntax;
+extern short   ldap_mtai_syntax;
+extern short   ldap_rts_cred_syntax;
+extern short   ldap_rtl_syntax;
+extern short   ldap_octetstring_syntax;
+
+
+#ifdef COMPAT20
+extern int     ldap_compat;
+#define MODTAG (ldap_compat == 20 ? OLD_LDAP_RES_MODIFY : LDAP_RES_MODIFY)
+#else
+#define MODTAG LDAP_RES_MODIFY
+#endif
+
+int
+do_modify(
+    Sockbuf    *clientsb,
+    struct msg *m,
+    BerElement *ber
+)
+{
+       char                    *dn;
+       char                    *last;
+       int                     rc;
+       unsigned long           tag, len;
+       LDAPMod                 *mods, *modtail;
+       struct ds_read_arg      ra;
+       extern DN               ldap_str2dn();
+
+       Debug( LDAP_DEBUG_TRACE, "do_modify\n", 0, 0, 0 );
+
+       /*
+        * Parse the modify request.  It looks like this:
+        *      ModifyRequest := [APPLICATION 6] SEQUENCE {
+        *              name    DistinguishedName,
+        *              mods    SEQUENCE OF SEQUENCE {
+        *                      operation       ENUMERATED {
+        *                              add     (0),
+        *                              delete  (1),
+        *                              replace (2)
+        *                      },
+        *                      modification    SEQUENCE {
+        *                              type    AttributeType,
+        *                              values  SET OF AttributeValue
+        *                      }
+        *              }
+        *      }
+        * We then have to initiate a read of the entry to be modified.
+        * The actual modification is done by do_modify2(), after the
+        * read completes.
+        */
+
+#if ISODEPACKAGE == IC
+#if ICRELEASE > 2
+       DAS_ReadArgument_INIT( &ra );
+#endif
+#endif
+
+       if ( ber_scanf( ber, "{a", &dn ) == LBER_ERROR ) {
+               Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
+               send_ldap_msgresult( clientsb, MODTAG, m,
+                   LDAP_PROTOCOL_ERROR, NULL, "" );
+               return( 0 );
+       }
+
+       Debug( LDAP_DEBUG_ARGS, "do_modify: dn (%s)\n", dn, 0, 0 );
+
+       ra.rda_object = ldap_str2dn( dn );
+       free( dn );
+       if ( ra.rda_object == NULLDN ) {
+               Debug( LDAP_DEBUG_ANY, "ldap_str2dn failed\n", 0, 0, 0 );
+               send_ldap_msgresult( clientsb, MODTAG, m,
+                   LDAP_INVALID_DN_SYNTAX, NULL, "" );
+               return( 0 );
+       }
+       ra.rda_eis.eis_allattributes = TRUE;
+       ra.rda_eis.eis_infotypes = EIS_ATTRIBUTESANDVALUES;
+       ra.rda_eis.eis_select = NULLATTR;
+
+       /* collect modifications & save for later */
+       mods = modtail = NULL;
+       for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
+           tag = ber_next_element( ber, &len, last ) ) {
+               LDAPMod *tmp;
+
+               if ( (tmp = (LDAPMod *) calloc( 1, sizeof(LDAPMod) ))
+                   == NULL ) {
+                       send_ldap_msgresult( clientsb, MODTAG, m,
+                           LDAP_OPERATIONS_ERROR, NULL, "Malloc error" );
+                       return( 0 );
+               }
+                       
+               if ( ber_scanf( ber, "{i{a[V]}}", &tmp->mod_op, &tmp->mod_type,
+                   &tmp->mod_bvalues ) == LBER_ERROR ) {
+                       send_ldap_msgresult( clientsb, MODTAG, m,
+                           LDAP_PROTOCOL_ERROR, NULL, "" );
+                       return( 0 );
+               }
+
+               if ( mods == NULL ) {
+                       mods = tmp;
+               } else {
+                       modtail->mod_next = tmp;
+               }
+               modtail = tmp;
+       }
+       m->m_mods = mods;
+
+       ra.rda_common = common; /* struct copy */
+
+       rc = initiate_dap_operation( OP_READ, m, &ra );
+
+       dn_free( ra.rda_object );
+
+       if ( rc != 0 ) {
+               send_ldap_msgresult( clientsb, MODTAG, m, rc, NULL, "" );
+               return( 0 );
+       }
+
+       return( 1 );
+}
+
+int
+do_modify2(
+    Sockbuf                    *clientsb,
+    struct msg                 *m,
+    struct ds_read_result      *rr
+)
+{
+       struct ds_modifyentry_arg       ma;
+       struct entrymod                 *changetail = NULLMOD;
+       int                             rc;
+       LDAPMod                         *mods;
+
+       Debug( LDAP_DEBUG_TRACE, "do_modify2\n", 0, 0, 0 );
+
+#if ISODEPACKAGE == IC
+#if ICRELEASE > 2
+       DAS_ModifyEntryArgument_INIT( &ma );
+#endif
+#endif
+
+       ma.mea_changes = NULLMOD;
+       for ( mods = m->m_mods; mods != NULL; mods = mods->mod_next ) {
+               struct entrymod *em;
+               Attr_Sequence   as, new, get_as();
+
+               if ( (em = (struct entrymod *) calloc( 1,
+                   sizeof(struct entrymod) )) == NULLMOD ) {
+                       send_ldap_msgresult( clientsb, MODTAG, m,
+                           LDAP_OPERATIONS_ERROR, NULL, "Malloc error" );
+                       return( 0 );
+               }
+               em->em_next = NULLMOD;
+
+               if ( (new = get_as( clientsb, MODTAG, m,
+                   mods->mod_type, mods->mod_bvalues )) == NULLATTR )
+                       return( 0 );
+               em->em_what = new;
+
+               for ( as = rr->rdr_entry.ent_attr; as != NULLATTR;
+                   as = as->attr_link ) {
+                       if ( AttrT_cmp( new->attr_type, as->attr_type ) == 0 )
+                               break;
+               }
+
+               if ( new->attr_value == NULLAV &&
+                   mods->mod_op != LDAP_MOD_DELETE ) {
+                       send_ldap_msgresult( clientsb, MODTAG, m,
+                           LDAP_INVALID_SYNTAX, NULL, "No values specified" );
+                       return( 0 );
+               }
+
+               switch ( mods->mod_op ) {
+               case LDAP_MOD_ADD:
+                       Debug( LDAP_DEBUG_ARGS, "ADD:\n", 0, 0, 0 );
+
+                       if ( as == NULLATTR ) {
+                               Debug( LDAP_DEBUG_ARGS, "\tattribute\n", 0, 0,
+                                   0 );
+                               em->em_type = EM_ADDATTRIBUTE;
+                       } else {
+                               Debug( LDAP_DEBUG_ARGS, "\tvalues\n", 0, 0, 0 );
+                               em->em_type = EM_ADDVALUES;
+                       }
+                       break;
+
+               case LDAP_MOD_DELETE:
+                       Debug( LDAP_DEBUG_ARGS, "DELETE:\n", 0, 0, 0 );
+
+                       if ( as == NULLATTR ) {
+                               Debug( LDAP_DEBUG_ARGS,
+                                   "\tno existing attribute\n", 0, 0, 0 );
+                               send_ldap_msgresult( clientsb, MODTAG,
+                                   m, LDAP_NO_SUCH_ATTRIBUTE, NULL, "" );
+                               ems_free( em );
+                               return( 0 );
+                       } else {
+                               if ( new->attr_value == NULLAV ) {
+                                       Debug( LDAP_DEBUG_ARGS, "\tattribute\n",
+                                           0, 0, 0 );
+                                       em->em_type = EM_REMOVEATTRIBUTE;
+                               } else {
+                                       if ( avs_cmp( new->attr_value,
+                                           as->attr_value ) == 0 ) {
+                                               Debug( LDAP_DEBUG_ARGS,
+                                                   "\tattribute\n", 0, 0, 0 );
+                                               em->em_type =
+                                                   EM_REMOVEATTRIBUTE;
+                                       } else {
+                                               Debug( LDAP_DEBUG_ARGS,
+                                                   "\tvalues\n", 0, 0, 0 );
+                                               em->em_type = EM_REMOVEVALUES;
+                                       }
+                               }
+                       }
+                       break;
+
+               case LDAP_MOD_REPLACE:
+                       Debug( LDAP_DEBUG_ARGS, "REPLACE:\n", 0, 0, 0 );
+
+                       if ( as == NULLATTR ) {
+                               Debug( LDAP_DEBUG_ARGS, "\tattribute\n", 0, 0,
+                                   0 );
+                               em->em_type = EM_ADDATTRIBUTE;
+                       } else {
+                               if ( replace_mod( em, as, new ) < 0 ) {
+                                       return( 0 );
+                               }
+                       }
+                       break;
+
+               default:
+                       Debug( LDAP_DEBUG_ARGS, "UNKNOWN MOD:\n", 0, 0, 0 );
+
+                       send_ldap_msgresult( clientsb, MODTAG, m,
+                           LDAP_PROTOCOL_ERROR, NULL, "" );
+                       return( 0 );
+                       break;
+               }
+
+               if ( em->em_what == NULL ) {    /* ignore this mod */
+                       free( em );
+               } else {
+                       if ( ma.mea_changes == NULLMOD ) {
+                               ma.mea_changes = em;
+                       } else {
+                               changetail->em_next = em;
+                       }
+                       changetail = em->em_next == NULLMOD ? em : em->em_next;
+               }
+       }
+
+#ifdef LDAP_DEBUG
+       if ( ldap_debug & LDAP_DEBUG_ARGS ) {
+                struct entrymod *e;
+                Attr_Sequence   as;
+                AV_Sequence     val;
+               PS              ps;
+
+               ps = ps_alloc( std_open );
+               std_setup( ps, stderr );
+
+                fprintf( stderr, "Modify changes are:\n");
+                for (e = ma.mea_changes; e; e = e->em_next) {
+                        switch (e->em_type) {
+                        case EM_ADDATTRIBUTE:
+                                fprintf( stderr, "\tADD ATTRIBUTE\n");
+                                break;
+                        case EM_REMOVEATTRIBUTE:
+                                fprintf( stderr, "\tREMOVE ATTRIBUTE\n");
+                                break;
+                        case EM_ADDVALUES:
+                                fprintf( stderr, "\tADD VALUES\n");
+                                break;
+                        case EM_REMOVEVALUES:
+                                fprintf( stderr, "\tREMOVE VALUES\n");
+                                break;
+                        default:
+                                fprintf( stderr, "\tUNKNOWN\n");
+                                break;
+                        }
+
+                        as = e->em_what;
+                        fprintf( stderr, "\t\ttype (" );
+                       AttrT_print( ps, as->attr_type, EDBOUT );
+                       fprintf( stderr, ")" );
+                        if ( e->em_type == EM_REMOVEATTRIBUTE ) {
+                                fprintf( stderr, "\n" );
+                                continue;
+                        }
+                        fprintf( stderr, " values" );
+                        for (val = as->attr_value; val; val = val->avseq_next) {
+                                ps_print( ps, " (" );
+                               AttrV_print( ps, &val->avseq_av, EDBOUT );
+                               ps_print( ps, ")" );
+                       }
+                        fprintf( stderr, "\n" );
+                }
+               ps_free( ps );
+       }
+#endif
+
+       if ( ma.mea_changes == NULLMOD ) {      /* nothing to do */
+               send_ldap_msgresult( clientsb, MODTAG, m,
+                   LDAP_SUCCESS, NULL, "" );
+               return( 0 );
+       }
+
+       ma.mea_object = rr->rdr_entry.ent_dn;
+       ma.mea_common = common; /* struct copy */
+
+       rc = initiate_dap_operation( OP_MODIFYENTRY, m, &ma );
+
+       ems_free( ma.mea_changes );
+
+       if ( rc != 0 ) {
+               send_ldap_msgresult( clientsb, MODTAG, m, rc, NULL, "" );
+               return( 0 );
+       }
+
+       return( 1 );
+}
+
+Attr_Sequence
+get_as(
+    Sockbuf            *clientsb,
+    unsigned long      op,
+    struct msg         *m,
+    char               *type,
+    struct berval      **bvals
+)
+{
+       Attr_Sequence   as;
+       int             i;
+       short           syntax;
+
+       Debug( LDAP_DEBUG_TRACE, "get_as\n", 0, 0, 0 );
+
+       if ( (as = as_comp_new( NULLAttrT, NULLAV, NULLACL_INFO ))
+           == NULLATTR ) {
+               send_ldap_msgresult( clientsb, op, m,
+                   LDAP_OPERATIONS_ERROR, NULL, "Malloc error" );
+               return( NULLATTR );
+       }
+       as->attr_link = NULLATTR;
+       as->attr_value = NULLAV;
+       as->attr_acl = NULLACL_INFO;
+
+       if ( (as->attr_type = str2AttrT( type )) == NULLAttrT ) {
+              send_ldap_msgresult( clientsb, op, m, LDAP_UNDEFINED_TYPE,
+                  NULL, type );
+               return( NULLATTR );
+       }
+
+       if ( bvals == NULL )
+               return( as );
+
+       syntax = as->attr_type->oa_syntax;
+       for ( i = 0; bvals[i] != NULL; i++ ) {
+               AttributeValue  av;
+               int             t61str, ncomp;
+               char            *sval, *s, *news, *n;
+               extern IFP      merge_acl;
+               extern AttributeValue   bv_asn2AttrV(), ldap_strdn2AttrV();
+               extern AttributeValue   ldap_str_at2AttrV(), bv_octet2AttrV();
+
+               if ( syntax == ldap_jpeg_syntax ||
+                   syntax == ldap_jpeg_nonfile_syntax ||
+                   syntax == ldap_octetstring_syntax ||
+                   syntax == ldap_audio_syntax ) {
+                       if (( av = bv_octet2AttrV( bvals[i] )) == NULLAttrV ) {
+                               send_ldap_msgresult( clientsb, op, m,
+                                   LDAP_INVALID_SYNTAX, NULL, type );
+                               as_free( as );
+                               return( NULLATTR );
+                       }
+               } else if ( syntax == ldap_photo_syntax ) {
+                       if (( av = bv_asn2AttrV( bvals[i] )) == NULLAttrV ) {
+                               send_ldap_msgresult( clientsb, op, m,
+                                   LDAP_INVALID_SYNTAX, NULL, type );
+                               as_free( as );
+                               return( NULLATTR );
+                       }
+               } else {
+
+                       if (( sval = malloc( bvals[i]->bv_len + 1 )) == NULL ) {
+                               send_ldap_msgresult( clientsb, op, m,
+                                   LDAP_OPERATIONS_ERROR, NULL,
+                                  "Malloc error" );
+                               return( NULLATTR );
+                       }
+                       SAFEMEMCPY( sval, bvals[i]->bv_val, bvals[i]->bv_len );
+                       sval[ bvals[i]->bv_len ] = '\0';
+
+                       /* dang quipu - there's no need for this! */
+                       if ( syntax == ldap_postaladdress_syntax ) {
+                               t61str = 0;
+                               ncomp = 1;
+                               for ( s = sval; *s; s++ ) {
+                                       if ( *s == '$' ) {
+                                               ncomp++;
+                                               continue;
+                                       }
+#define ist61(c)  (!isascii(c) || !isalnum(c) \
+                         && c != 047 && c != '(' && c != ')' \
+                         && c != '+' && c != '-' && c != '.' && c != ',' \
+                         && c != '/' && c != ':' && c != '=' && c != '?' \
+                         && c != ' ')
+                                       if ( ist61( *s ) )
+                                               t61str = 1;
+                               }
+#define T61MARK                "{T.61}"
+#define T61MARKLEN     6
+                               if ( t61str ) {
+                                       news = malloc( strlen(sval) +
+                                           ncomp * T61MARKLEN + 1 );
+                                       strcpy( news, T61MARK );
+                                       for ( n = news + T61MARKLEN, s = sval;
+                                           *s; n++, s++ ) {
+                                               *n = *s;
+                                               if ( *s == '$' ) {
+                                                       strcpy( ++n, T61MARK );
+                                                       n += T61MARKLEN - 1;
+                                               }
+                                       }
+                                       *n = '\0';
+                                       free( sval );
+                                       sval = news;
+                               }
+
+                               av = str_at2AttrV( sval, as->attr_type );
+                       } else if ( syntax == ldap_dn_syntax ) {
+                               av = ldap_strdn2AttrV( sval );
+                       } else if ( i != 0 && syntax == ldap_acl_syntax ) {
+                               (void) (*merge_acl)( as->attr_value, sval );
+                               free( sval );
+                               continue;
+                       } else {
+                               av = ldap_str_at2AttrV( sval, as->attr_type );
+                       }
+
+                       if ( av == NULLAttrV ) {
+                               send_ldap_msgresult( clientsb, op, m,
+                                   LDAP_INVALID_SYNTAX, NULL, sval );
+                               free( sval );
+                               as_free( as );
+                               return( NULLATTR );
+                       }
+
+                       free( sval );
+               }
+               as->attr_value = avs_merge( as->attr_value,
+                   avs_comp_new( av ) );
+       }
+
+       return( as );
+}
+
+void
+modify_result( Sockbuf *sb, struct msg *m )
+{
+       send_ldap_msgresult( sb, MODTAG, m, LDAP_SUCCESS, NULL, "" );
+
+       return;
+}
+
+void
+modlist_free( LDAPMod *mods )
+{
+       LDAPMod *next = NULL;
+
+       for ( ; mods != NULL; mods = next ) {
+               free( mods->mod_type );
+               if ( mods->mod_bvalues != NULL )
+                       ber_bvecfree( mods->mod_bvalues );
+               free( mods );
+       }
+}
+
+/*
+ * called when mod is replace to optimize by only deleting old values
+ * that are not in the new set and by only adding what isn't in old set
+ */
+
+int
+replace_mod(
+    struct entrymod    *rem,
+    Attr_Sequence      oas,
+    Attr_Sequence      nas
+)
+{
+       AV_Sequence     oavs, navs, davs, prev_navs, tmp;
+#ifdef LDAP_DEBUG
+       PS              ps;
+
+       ps = ps_alloc( std_open );
+       std_setup( ps, stderr );
+
+       if ( ldap_debug & LDAP_DEBUG_ARGS ) {
+               ps_print( ps, "replace_mod(" );
+               AttrT_print( ps, oas->attr_type, EDBOUT );
+               ps_print( ps, ")\n" );
+       }
+#endif
+
+       davs = NULL;
+       for ( oavs = oas->attr_value; oavs != NULL; oavs = oavs->avseq_next ) {
+#ifdef LDAP_DEBUG
+               if ( ldap_debug & LDAP_DEBUG_ARGS ) {
+                       ps_print( ps, "old value " );
+                       AttrV_print( ps, &oavs->avseq_av, EDBOUT );
+                       ps_print( ps, "\n" );
+               }
+#endif
+
+               prev_navs = NULL;
+               for ( navs = nas->attr_value; navs != NULL;
+                   prev_navs = navs, navs = navs->avseq_next ) {
+#ifdef LDAP_DEBUG
+                       if ( ldap_debug & LDAP_DEBUG_ARGS ) {
+                               ps_print( ps, "\tnew value " );
+                               AttrV_print( ps, &navs->avseq_av, EDBOUT );
+                               ps_print( ps, "\n" );
+                       }
+#endif
+                       if ( AttrV_cmp( &oavs->avseq_av, &navs->avseq_av)
+                           == 0) {
+                               break;
+                       }
+               }
+
+               if ( navs == NULL ) {   /* value to delete */
+#ifdef LDAP_DEBUG
+                       if ( ldap_debug & LDAP_DEBUG_ARGS ) {
+                               ps_print( ps, "value to delete " );
+                               AttrV_print( ps, &oavs->avseq_av, EDBOUT );
+                               ps_print( ps, "\n" );
+                       }
+#endif
+                       if ( davs == NULL ) {
+                           davs = avs_comp_cpy( oavs );
+                       } else {
+                           tmp = avs_comp_cpy( oavs );
+                           tmp->avseq_next = davs;
+                           davs = tmp;
+                       }
+               } else {                /* value to keep */
+#ifdef LDAP_DEBUG
+                       if ( ldap_debug & LDAP_DEBUG_ARGS ) {
+                               ps_print( ps, "value to leave alone " );
+                               AttrV_print( ps, &oavs->avseq_av, EDBOUT );
+                               ps_print( ps, "\n" );
+                       }
+#endif
+                       if ( prev_navs == NULL ) {
+                           nas->attr_value = navs->avseq_next;
+                       } else {
+                           prev_navs->avseq_next = navs->avseq_next;
+                       }
+                       avs_comp_free( navs );
+               }
+       }
+
+       if ( davs == NULL && nas->attr_value == NULL ) {
+#ifdef LDAP_DEBUG
+               if ( ldap_debug & LDAP_DEBUG_ARGS ) {
+                       ps_print( ps, "  nothing to do" );
+               }
+#endif
+               rem->em_what = NULL;
+       } else {
+            /*  Must add new values before removing old values.
+             *  Otherwise, removing all existing values causes the
+             *  attribute to be removed such that subsequent add values
+             *  fail.
+             */
+               if ( nas->attr_value != NULL ) {        /* add new values */
+#ifdef LDAP_DEBUG
+                       if ( ldap_debug & LDAP_DEBUG_ARGS ) {
+                               AttrT_print( ps, nas->attr_type, EDBOUT );
+                               ps_print( ps, ": some to add\n" );
+                       }
+#endif
+                       rem->em_type = EM_ADDVALUES;
+                       rem->em_what = nas;
+                       rem->em_next = NULLMOD;
+               }
+
+               if ( davs != NULL ) {   /* delete old values */
+#ifdef LDAP_DEBUG
+                       if ( ldap_debug & LDAP_DEBUG_ARGS ) {
+                               AttrT_print( ps, nas->attr_type, EDBOUT );
+                               ps_print( ps, ": some to delete\n" );
+                       }
+#endif
+                       if ( nas->attr_value != NULL ) {
+                               rem->em_next = (struct entrymod *) calloc( 1,
+                                   sizeof(struct entrymod) );
+                               rem = rem->em_next;
+                       }
+                       rem->em_type = EM_REMOVEVALUES;
+                       rem->em_what = as_comp_new( NULLAttrT, NULLAV,
+                           NULLACL_INFO );
+                       rem->em_what->attr_type = AttrT_cpy( nas->attr_type );
+                       rem->em_what->attr_value = davs;
+               }
+       }
+
+       return( 0 );
+}
diff --git a/servers/ldapd/modrdn.c b/servers/ldapd/modrdn.c
new file mode 100644 (file)
index 0000000..d3d939e
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <quipu/commonarg.h>
+#include <quipu/attrvalue.h>
+#include <quipu/ds_error.h>
+#include <quipu/modifyrdn.h>
+#include <quipu/dap2.h>
+#include <quipu/dua.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "lber.h"
+#include "ldap.h"
+#include "common.h"
+
+#ifdef COMPAT20
+extern int     ldap_compat;
+#define MODRDNTAG      (ldap_compat == 20 ? OLD_LDAP_RES_MODRDN : LDAP_RES_MODRDN)
+#else
+#define MODRDNTAG      LDAP_RES_MODRDN
+#endif
+
+int
+do_modrdn(
+    Sockbuf    *clientsb,
+    struct msg *m,
+    BerElement *ber
+)
+{
+       char                    *dn, *newrdn;
+       int                     rc, deleteoldrdn;
+       struct ds_modifyrdn_arg ma;
+       static CommonArgs       common = default_common_args;
+       extern DN               ldap_str2dn();
+       extern RDN              ldap_str2rdn();
+
+       Debug( LDAP_DEBUG_TRACE, "do_modrdn\n", 0, 0, 0 );
+
+       /*
+        * Parse the modrdn request.  It looks like this:
+        *      ModifyRDNRequest := SEQUENCE {
+        *              entry   DistinguishedName,
+        *              newrdn  RelativeDistinguishedName
+        *      }
+        */
+
+#if ISODEPACKAGE == IC
+#if ICRELEASE > 2
+       DAS_ModifyDnArgument_INIT( &ma );
+#endif
+#endif
+
+       if ( ber_scanf( ber, "{aa", &dn, &newrdn ) == LBER_ERROR ) {
+               Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
+               send_ldap_msgresult( clientsb, MODRDNTAG, m,
+                   LDAP_PROTOCOL_ERROR, NULL, "" );
+               return( 0 );
+       }
+
+       deleteoldrdn = 1;
+       if ( ber_scanf( ber, "b", &deleteoldrdn ) == LBER_ERROR ) {
+               Debug( LDAP_DEBUG_ANY, "found old modrdn\n", 0, 0, 0 );
+       }
+
+       Debug( LDAP_DEBUG_ARGS,
+           "do_modrdn: dn (%s) newrdn (%s) deleteoldrdn (%d)\n", dn, newrdn,
+           deleteoldrdn );
+
+       ma.mra_object = ldap_str2dn( dn );
+       free( dn );
+       if ( ma.mra_object == NULLDN ) {
+               Debug( LDAP_DEBUG_ANY, "ldap_str2dn failed\n", 0, 0, 0 );
+               send_ldap_msgresult( clientsb, MODRDNTAG, m,
+                   LDAP_INVALID_DN_SYNTAX, NULL, "" );
+               return( 0 );
+       }
+
+       ma.mra_newrdn = ldap_str2rdn( newrdn );
+       free( newrdn );
+       if ( ma.mra_newrdn == NULLRDN ) {
+               Debug( LDAP_DEBUG_ANY, "str2rdn failed\n", 0, 0, 0 );
+               send_ldap_msgresult( clientsb, MODRDNTAG, m,
+                   LDAP_INVALID_DN_SYNTAX, NULL, "Bad RDN" );
+               return( 0 );
+       }
+       ma.deleterdn = (deleteoldrdn ? 1 : 0);
+
+       ma.mra_common = common; /* struct copy */
+
+       rc = initiate_dap_operation( OP_MODIFYRDN, m, &ma );
+
+       dn_free( ma.mra_object );
+       rdn_free( ma.mra_newrdn );
+
+       if ( rc != 0 ) {
+               send_ldap_msgresult( clientsb, MODRDNTAG, m, rc, NULL, "" );
+               return( 0 );
+       }
+
+       return( 1 );
+}
+
+void
+modrdn_result( Sockbuf *sb, struct msg *m )
+{
+       send_ldap_msgresult( sb, MODRDNTAG, m, LDAP_SUCCESS, NULL, "" );
+
+       return;
+}
diff --git a/servers/ldapd/proto-ldapd.h b/servers/ldapd/proto-ldapd.h
new file mode 100644 (file)
index 0000000..9556c84
--- /dev/null
@@ -0,0 +1,158 @@
+#ifndef _PROTO_LDAPD
+#define _PROTO_LDAPD
+
+/*
+ * abandon.c
+ */
+
+int do_abandon( struct conn *dsaconn, BerElement *ber, int msgid );
+
+/*
+ * add.c
+ */
+
+int do_add( Sockbuf *clientsb, struct msg *m, BerElement *ber );
+
+/*
+ * association.c
+ */
+
+struct conn *conn_dup( struct conn *cn );
+int conn_init();
+void conn_free( struct conn *conn );
+void conn_del( struct conn *conn );
+void conn_badfds();
+struct conn *conn_getfd( fd_set *fds );
+void conn_add( struct conn *new );
+struct conn *conn_find( struct conn *c );
+void conn_add( struct conn *new );
+void conn_close();
+int isclosed( int ad );
+
+/*
+ * bind.c
+ */
+
+int do_bind( Sockbuf *clientsb, struct msg *m, BerElement *ber, int *bound );
+int do_bind_real( struct conn *dsaconn, int *bound, char **matched );
+
+/*
+ * certificate.c
+ */
+
+int ldap_certif_print( PS ps, struct certificate *parm, int format );
+void ldap_print_algid( PS ps, struct alg_id *parm, int format );
+struct certificate *ldap_str2cert( char *str );
+void ldap_str2alg( char *str, struct alg_id *alg );
+void certif_init();
+
+/*
+ * compare.c
+ */
+
+int do_compare( Sockbuf *clientsb, struct msg *m, BerElement *ber );
+
+/*
+ * delete.c
+ */
+
+int do_delete( Sockbuf *clientsb, struct msg *m, BerElement *ber );
+
+/*
+ * error.c
+ */
+
+void print_error( struct DSError *e );
+int x500err2ldaperr( struct DSError *e, char **matched );
+
+/*
+ * kerberos.c
+ */
+
+int kerberosv4_ldap_auth( char *cred, long len );
+
+/*
+ * main.c
+ */
+
+void log_and_exit( int exitcode );
+
+/*
+ * message.c
+ */
+
+struct msg *add_msg( int msgid, int msgtype, BerElement *ber,
+       struct conn *dsaconn, int udp, struct sockaddr *clientaddr );
+struct msg *get_msg( int uniqid );
+int del_msg( struct msg *m );
+void send_msg( struct conn *conn, Sockbuf *clientsb, int err, char *str );
+struct msg * get_cldap_msg( int msgid, int msgtype, struct sockaddr *fromaddr );
+
+/*
+ * modify.c
+ */
+
+int do_modify( Sockbuf *clientsb, struct msg *m, BerElement *ber );
+Attr_Sequence get_as( Sockbuf *clientsb, unsigned long op, struct msg *m,
+       char *type, struct berval **bvals );
+void modlist_free( LDAPMod *mods );
+
+/*
+ * modrdn.c
+ */
+
+int do_modrdn( Sockbuf *clientsb, struct msg *m, BerElement *ber );
+
+/*
+ * request.c
+ */
+
+void client_request( Sockbuf *clientsb, struct conn *dsaconn, int  udp );
+int do_request( Sockbuf *clientsb, struct msg *m, BerElement *ber,
+       int *bound );
+int initiate_dap_operation( int op, struct msg *m, void *arg );
+
+/*
+ * result.c
+ */
+
+void dsa_response( struct conn *dsaconn, Sockbuf *clientsb );
+int send_ldap_msgresult( Sockbuf *sb, unsigned long tag, struct msg *m,
+       int err, char *matched, char *text );
+int send_ldap_result( Sockbuf *sb, unsigned long tag, int msgid, int err,
+       char *matched, char *text );
+
+/*
+ * search.c
+ */
+
+int do_search( Sockbuf *clientsb, struct msg *m, BerElement *ber );
+
+/*
+ * syntax.c
+ */
+
+void get_syntaxes();
+int dn_print_real( PS ps, DN dn, int format);
+void ldap_dn_print( PS ps, DN dn, DN base, int format);
+int encode_dn( BerElement *ber, DN dn, DN base);
+int encode_attrs( BerElement *ber, Attr_Sequence as );
+AttributeValue bv_octet2AttrV( struct berval *bv );
+AttributeValue bv_asn2AttrV( struct berval *bv );
+AttributeValue ldap_strdn2AttrV( char *dnstr );
+DN ldap_str2dn( char *str );
+RDN ldap_str2rdn( char *rdnstr );
+AttributeValue ldap_str_at2AttrV( char *str, AttributeType type );
+AttributeValue ldap_str2AttrV( char *value, short syntax );
+
+/*
+ * util.c
+ */
+
+void bprint( char *data, int len );
+void charlist_free( char **cl );
+int get_ava( BerElement *ber, AVA *tava );
+int chase_referral( Sockbuf *clientsb, struct msg *m, struct DSError *err,
+       char **matched );
+
+#endif /* _proto_ldapd */
diff --git a/servers/ldapd/request.c b/servers/ldapd/request.c
new file mode 100644 (file)
index 0000000..51b1d13
--- /dev/null
@@ -0,0 +1,518 @@
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <quipu/commonarg.h>
+#include <quipu/ds_error.h>
+#include <quipu/dap2.h>
+#include <quipu/dua.h>
+#ifdef __hpux
+#include <syslog.h>
+#else
+#include <sys/syslog.h>
+#endif
+#include "lber.h"
+#include "ldap.h"
+#include "common.h"
+
+extern int     dosyslog;
+
+#ifdef PEPSY_DUMP
+#ifndef DEBUG
+#define DEBUG
+#endif
+#include "LDAP-types.h"
+#if ISODEPACKAGE == IC
+#include <compat/logger.h>
+#else
+#include <logger.h>
+#endif
+#endif
+
+/*
+ * client_request - called by do_queries() when there is activity on the
+ * client socket.  It expects to be able to get an LDAP message from the
+ * client socket, parses the first couple of fields, and then calls
+ * do_request() to handle the request.  If do_request() (or something
+ * called by it) returns a response to the client (e.g., in the case of
+ * an error), then client_request() is done.  If the request is not
+ * responded to (and needs a response), it is added to the queue of
+ * outstanding requests.  It will be responded to later via dsa_response(),
+ * once the DSA operation completes.
+ */
+
+void
+client_request(
+    Sockbuf    *clientsb,
+    struct conn        *dsaconn,
+    int        udp
+)
+{
+       unsigned long   tag;
+       unsigned long   len;
+       long            msgid;
+       BerElement      ber, *copyofber;
+       struct msg      *m;
+       static int      bound;
+       extern char     *bound_dn, *bound_pw;
+       struct PSAPaddr *psap_cpy();
+#ifdef COMPAT
+       extern int      ldap_compat;
+#endif
+
+       Debug( LDAP_DEBUG_TRACE, "client_request%s\n",
+           udp ? " udp" : "", 0, 0 );
+
+       /*
+        * Get the ldap message, which is a sequence of message id
+        * and then the actual request choice.
+        */
+
+       ber_init( &ber, 0 );
+       if ( (tag = ber_get_next( clientsb, &len, &ber )) == LBER_DEFAULT ) {
+               Debug( LDAP_DEBUG_ANY, "ber_get_next failed\n", 0, 0, 0 );
+               log_and_exit( 1 );
+       }
+
+#ifdef CLDAP
+       if ( udp && dosyslog ) {
+               syslog( LOG_INFO, "UDP request from unknown (%s)",
+                   inet_ntoa( ((struct sockaddr_in *)
+                   clientsb->sb_fromaddr)->sin_addr ));
+       }
+#endif
+
+#ifdef LDAP_DEBUG
+       if ( ldap_debug & LDAP_DEBUG_BER )
+               trace_ber( tag, len, ber.ber_buf, stderr, 1, 1 );
+#endif
+
+#ifdef COMPAT
+       /*
+        * This tag should be a normal SEQUENCE tag.  In release 2.0 this
+        * tag is 0x10.  In the new stuff this is 0x30.  To distinguish
+        * between 3.0 and the "correct" stuff, we look for an extra
+        * sequence tag after the bind tag.
+        */
+
+       Debug( LDAP_DEBUG_ANY, "bound %d\n", bound, 0, 0 );
+       if ( bound == 0 ) {
+               /* check for 2.0 */
+               if ( tag == OLD_LDAP_TAG_MESSAGE ) {
+                       Debug( LDAP_DEBUG_ANY, "version 2.0 detected\n", 0,
+                           0, 0 );
+                       if ( dosyslog ) {
+                               syslog( LOG_INFO, "old version 2.0 detected" );
+                       }
+                       ldap_compat = 20;
+               /* check for 3.0 */
+               } else {
+                       BerElement      tber;
+                       unsigned long   tlen;
+                       unsigned long   ttag;
+
+                       tber = ber;     /* struct copy */
+                       /* msgid */
+                       ttag = ber_skip_tag( &tber, &tlen );
+                       tber.ber_ptr += tlen;
+                       /* bind sequence header */
+                       ttag = ber_skip_tag( &tber, &tlen );
+                       ttag = ber_peek_tag( &tber, &tlen );
+
+                       Debug( LDAP_DEBUG_ANY, "checking for 3.0 tag 0x%x\n",
+                           ttag, 0, 0 );
+                       if ( ttag == LBER_SEQUENCE ) {
+                               Debug( LDAP_DEBUG_ANY, "version 3.0 detected\n",
+                                   0, 0, 0 );
+                               if ( dosyslog ) {
+                                       syslog( LOG_INFO,
+                                           "old version 3.0 detected" );
+                               }
+                               ldap_compat = 30;
+                       }
+               }
+       }
+#endif
+
+       if ( ber_get_int( &ber, &msgid ) != LDAP_TAG_MSGID ) {
+               send_ldap_result( clientsb, LBER_DEFAULT, msgid,
+                   LDAP_PROTOCOL_ERROR, NULL, "Not an LDAP message" );
+               free( ber.ber_buf );
+               return;
+       }
+
+#ifdef CLDAP
+       if ( udp ) {
+               char    *logdn = NULL;
+
+               ber_get_stringa( &ber, &logdn );
+               if ( logdn != NULL ) {
+                   if ( dosyslog ) {
+                           syslog( LOG_INFO, "UDP requestor: %s", logdn );
+                   }
+                   Debug( LDAP_DEBUG_ANY, "UDP requestor: %s\n", logdn, 0, 0 );
+                   free( logdn );
+               }
+       }
+#endif /* CLDAP */
+
+#ifdef COMPAT30
+       if ( ldap_compat == 30 )
+               tag = ber_skip_tag( &ber, &len );
+       else
+#endif
+               tag = ber_peek_tag( &ber, &len );
+       if ( !udp && bound == 0 && tag != LDAP_REQ_BIND
+#ifdef COMPAT20
+           && tag != OLD_LDAP_REQ_BIND
+#endif
+           ) {
+               send_ldap_result( clientsb, tag, msgid, LDAP_OPERATIONS_ERROR,
+                   NULL, "Bind operation must come first" );
+               free( ber.ber_buf );
+               return;
+       }
+
+#ifdef CLDAP
+       if (udp && tag != LDAP_REQ_SEARCH && tag != LDAP_REQ_ABANDON ) {
+               send_ldap_result( clientsb, tag, msgid, LDAP_OPERATIONS_ERROR,
+                   NULL, "Only search is supported over UDP/CLDAP" );
+               free( ber.ber_buf );
+               return;
+       }
+
+       if ( get_cldap_msg( msgid, tag,
+           (struct sockaddr *)clientsb->sb_fromaddr ) != NULL ) {
+               /*
+                * duplicate request: toss this one
+                */
+               Debug( LDAP_DEBUG_TRACE,
+                   "client_request tossing dup request id %d from %s\n",
+                   msgid, inet_ntoa( ((struct sockaddr_in *)
+                   clientsb->sb_fromaddr)->sin_addr ), 0 );
+               free( ber.ber_buf );
+               return;
+       }
+#endif
+
+       copyofber = ber_dup( &ber );
+
+       m = add_msg( msgid, tag, copyofber, dsaconn, udp,
+#ifdef CLDAP
+               (struct sockaddr *)clientsb->sb_fromaddr );
+#else
+               NULL );
+#endif
+
+       /* 
+        * Call the appropriate routine to handle the request.  If it
+        * returns a nonzero result, the message requires a response, and
+        * so it's left in the queue of outstanding requests, otherwise
+        * it's deleted.
+        */
+
+       if ( do_request( clientsb, m, &ber, &bound ) == 0 ) {
+               del_msg( m );
+       }
+
+       return;
+}
+
+/*
+ * do_request - called when a client makes a request, or when a referral
+ * error is returned.  In the latter case, a connection is made to the
+ * referred to DSA, and do_request() is called to retry the operation over
+ * that connection.  In the former case, do_request() is called to try
+ * the operation over the default association.
+ */
+
+int
+do_request(
+    Sockbuf    *clientsb,
+    struct msg *m,
+    BerElement *ber,
+    int                *bound
+)
+{
+       int             resp_required = 0;
+
+       Debug( LDAP_DEBUG_TRACE, "do_request\n", 0, 0, 0 );
+
+       switch ( m->m_msgtype ) {
+#ifdef COMPAT20
+       case OLD_LDAP_REQ_BIND:
+#endif
+       case LDAP_REQ_BIND:
+               resp_required = do_bind( clientsb, m, ber, bound );
+               break;
+
+#ifdef COMPAT20
+       case OLD_LDAP_REQ_UNBIND:
+#endif
+#ifdef COMPAT30
+       case LDAP_REQ_UNBIND_30:
+#endif
+       case LDAP_REQ_UNBIND:
+               conn_close();
+               log_and_exit( 0 );
+               break;
+
+#ifdef COMPAT20
+       case OLD_LDAP_REQ_ADD:
+#endif
+       case LDAP_REQ_ADD:
+               resp_required = do_add( clientsb, m, ber );
+               break;
+
+#ifdef COMPAT20
+       case OLD_LDAP_REQ_DELETE:
+#endif
+#ifdef COMPAT30
+       case LDAP_REQ_DELETE_30:
+#endif
+       case LDAP_REQ_DELETE:
+               resp_required = do_delete( clientsb, m, ber );
+               break;
+
+#ifdef COMPAT20
+       case OLD_LDAP_REQ_MODRDN:
+#endif
+       case LDAP_REQ_MODRDN:
+               resp_required = do_modrdn( clientsb, m, ber );
+               break;
+
+#ifdef COMPAT20
+       case OLD_LDAP_REQ_MODIFY:
+#endif
+       case LDAP_REQ_MODIFY:
+               resp_required = do_modify( clientsb, m, ber );
+               break;
+
+#ifdef COMPAT20
+       case OLD_LDAP_REQ_COMPARE:
+#endif
+       case LDAP_REQ_COMPARE:
+               resp_required = do_compare( clientsb, m, ber );
+               break;
+
+#ifdef COMPAT20
+       case OLD_LDAP_REQ_SEARCH:
+#endif
+       case LDAP_REQ_SEARCH:
+               resp_required = do_search( clientsb, m, ber );
+               break;
+
+#ifdef COMPAT20
+       case OLD_LDAP_REQ_ABANDON:
+#endif
+#ifdef COMPAT30
+       case LDAP_REQ_ABANDON_30:
+#endif
+       case LDAP_REQ_ABANDON:
+               resp_required = do_abandon( m->m_conn, ber, m->m_uniqid );
+               break;
+
+       default:
+               Debug( LDAP_DEBUG_ANY, "unknown operation %d\n", m->m_msgtype,
+                   0, 0 );
+
+               send_ldap_msgresult( clientsb, m->m_msgtype, m,
+                   LDAP_PROTOCOL_ERROR, NULL, "Unknown request type" );
+               break;
+       }
+
+       return( resp_required );
+}
+
+/* 
+ * initiate_dap_operation - initiate a dap operation, rebinding and retrying
+ * the request if necessary.  If the request is successfully initiated, 0 is
+ * returned.  Otherwise, an indication of the error is returned.
+ */
+
+int
+initiate_dap_operation(
+    int                op,
+    struct msg *m,
+    void       *arg
+)
+{
+       char                    *matched;
+       int                     i, rc, bound = 0;
+       struct DAPindication    di;
+
+       Debug( LDAP_DEBUG_TRACE, "initiate_dap_operation\n", 0, 0, 0 );
+
+       if ( m->m_conn->c_ad == -1 && do_bind_real( m->m_conn, &bound,
+           &matched ) != LDAP_SUCCESS )
+               return( LDAP_UNAVAILABLE );
+
+       for ( i = 0; i < 2; i++ ) {
+               switch ( op ) {
+               case OP_COMPARE:
+                       rc = DapCompare( m->m_conn->c_ad, m->m_uniqid,
+                           (struct ds_compare_arg *) arg, &di, ROS_ASYNC );
+                       break;
+
+               case OP_SEARCH:
+                       rc = DapSearch( m->m_conn->c_ad, m->m_uniqid,
+                           (struct ds_search_arg *) arg, &di, ROS_ASYNC );
+                       break;
+
+               case OP_ADDENTRY:
+                       rc = DapAddEntry( m->m_conn->c_ad, m->m_uniqid,
+                           (struct ds_addentry_arg *) arg, &di, ROS_ASYNC );
+                       break;
+
+               case OP_REMOVEENTRY:
+                       rc = DapRemoveEntry( m->m_conn->c_ad, m->m_uniqid,
+                           (struct ds_removeentry_arg *) arg, &di, ROS_ASYNC );
+                       break;
+
+               case OP_MODIFYENTRY:
+                       rc = DapModifyEntry( m->m_conn->c_ad, m->m_uniqid,
+                           (struct ds_modifyentry_arg *) arg, &di, ROS_ASYNC );
+                       break;
+
+               case OP_READ:
+                       rc = DapRead( m->m_conn->c_ad, m->m_uniqid,
+                           (struct ds_read_arg *) arg, &di, ROS_ASYNC );
+                       break;
+
+               case OP_MODIFYRDN:
+                       rc = DapModifyRDN( m->m_conn->c_ad, m->m_uniqid,
+                           (struct ds_modifyrdn_arg *) arg, &di, ROS_ASYNC );
+                       break;
+
+               default:
+                       break;
+               }
+
+               Debug( LDAP_DEBUG_TRACE, "operation initiated %d\n", rc, 0,
+                   0 );
+
+               if ( rc == OK )
+                       return( 0 );
+
+               /* 
+                * the operation was not invoked - try rebinding, then 
+                * try it again.
+                */
+
+               (void) dap_unbind( m->m_conn->c_ad );
+
+               if ( do_bind_real( m->m_conn, &bound, &matched )
+                   != LDAP_SUCCESS )
+                       break;
+       }
+
+       m->m_conn->c_ad = -1;
+
+       return( LDAP_UNAVAILABLE );     /* DSA was unreachable */
+}
+
+#ifdef LDAP_DEBUG
+int
+trace_ber(
+    int   tag,
+    int   len,
+    char  *ber,
+    FILE  *trace_file,
+    int          prepend,
+    int   read_pdu     /* If non-zero, PDU was read from client.  0 == PDU is being written */
+)
+{
+       unsigned char   *buf;
+       PS              input_ps  = NULLPS;
+       PE              pe;
+       int             result = -1;
+
+       Debug( LDAP_DEBUG_TRACE, "trace_ber(tag=%#x, ber=%#lx, len=%d)\n", tag,
+           (unsigned long) ber, len );
+
+       if ( (buf = (unsigned char *) malloc( len + 6 )) == NULL ) {
+               fprintf( trace_file, "Unable to allocate memory\n" );
+       } else {
+               if ( prepend ) {
+                       buf[0] = tag;
+                       buf[1] = 0x84;
+                       buf[2] = len >> 24;
+                       buf[3] = len >> 16;
+                       buf[4] = len >> 8;
+                       buf[5] = len;
+                       SAFEMEMCPY( buf + 6, ber, len );
+               } else {
+                       SAFEMEMCPY( buf, ber, len );
+               }
+               if ( (input_ps = ps_alloc( str_open )) == NULLPS )
+                       fprintf( trace_file, "ps_alloc failed\n" );
+               else if ( str_setup( input_ps, (char *)buf, len + 6, 1 ) != OK )
+                       fprintf( trace_file, "str_setup\n" );
+               else if ( (pe = ps2pe( input_ps )) == NULLPE ) {
+                       fprintf(trace_file, "ps2pe: %s\n",
+                           ps_error( input_ps->ps_errno ) );
+                       lber_bprint( (char *) buf, len + 6 );
+               } else {
+#ifdef PEPSY_DUMP
+                       int                             failed = 0;
+                       static LLog                     log = {
+                               "-", NULLCP, NULLCP, LLOG_PDUS,
+                               LLOG_NONE, -1, 0, NOTOK
+                       };
+                       struct type_LDAP_LDAPMessage    *ldap_msg = NULL;
+
+                       if ( decode_LDAP_LDAPMessage(pe, 1, 0, NULL, &ldap_msg)
+                           == -1 ) {
+                               failed = 1;
+                               fprintf( trace_file,
+                                   "Error decoding LDAPMessage:\n  [%s]\n",
+                                   PY_pepy );
+                               fprintf( trace_file, "Here is the PDU:\n" );
+                               vsetfp( trace_file, NULL );
+                               vunknown( pe );
+                       }
+                       if (log.ll_events & LLOG_PDUS) {
+                               pvpdu (&log, print_LDAP_LDAPMessage_P, pe,
+                                   failed ?
+                                   "<Bad LDAPMessage>" : "<LDAPMessage>",
+                                   read_pdu);
+                       }
+/*
+                       PLOGP(&log, LDAP_LDAPMessage, pe, failed ? "<Bad LDAPMessage>" : "<LDAPMessage>", read_pdu);
+*/
+                       if (ldap_msg)
+                               free_LDAP_LDAPMessage(ldap_msg);
+#else
+                       vsetfp( trace_file, NULL );
+                       vunknown( pe );
+#endif
+                       pe_free( pe );
+                       result = 0;
+               }
+               free( buf );
+       }
+
+      if ( input_ps )
+              ps_free( input_ps );
+
+      return( result );
+}
+#endif
diff --git a/servers/ldapd/result.c b/servers/ldapd/result.c
new file mode 100644 (file)
index 0000000..3f77032
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <quipu/dsap.h>
+#include <quipu/dap2.h>
+#include <quipu/dua.h>
+#ifdef __hpux
+#include <syslog.h>
+#else
+#include <sys/syslog.h>
+#endif
+#include "lber.h"
+#include "ldap.h"
+#include "common.h"
+
+extern int     dosyslog;
+#ifdef COMPAT
+extern int     ldap_compat;
+#endif
+
+/*
+ * dsa_response - called by do_queries() when there is activity on one of
+ * the DSA associations.  It is passed the association descriptor on which
+ * the activity occurred, and the client socket.  It figures out what kind
+ * of activity it was (e.g., result of a previously initiated operation,
+ * error return, etc), and calls the appropriate routine to send a response
+ * to the client, or to continue the operation in some cases (e.g., modify),
+ * or to chase a referral and retry an operation.
+ *
+ * If the client is actually given a response, dsa_response() removes the
+ * corresponding request from the queue of outstanding requests.  If the
+ * activity was an error referral, a connection is made to the referred to
+ * DSA (if possible), and do_request() is called to retry the request.
+ */
+
+void
+dsa_response(
+    struct conn        *dsaconn,
+    Sockbuf    *clientsb
+)
+{
+       struct DAPindication    di;
+       struct DSResult         *dr;
+       struct DSError          *de;
+       struct DAPpreject       *dp;
+       struct DAPabort         *da;
+       struct msg              *m = NULL;
+       BerElement              *bercopy;
+       char                    *matched;
+       int                     incr, delete, rc, ldaperr;
+
+       Debug( LDAP_DEBUG_TRACE, "dsa_response on ad %d\n", dsaconn->c_ad, 0,
+           0 );
+       di.di_type = -1;
+       if ( (rc = DapInitWaitRequest( dsaconn->c_ad, OK, &di )) == DONE ) {
+               Debug( LDAP_DEBUG_ANY, "DapInitWaitRequest: DONE\n", 0, 0, 0 );
+               return;
+       }
+
+       Debug( LDAP_DEBUG_ARGS, "DapInitWaitRequest: result %d type %d\n", rc,
+           di.di_type, 0 );
+
+       delete = 1;
+       switch ( di.di_type ) {
+       case DI_RESULT:
+               dr = &di.di_result.dr_res;
+               if ( (m = get_msg( di.di_result.dr_id )) == NULL ) {
+                       Debug( LDAP_DEBUG_ANY, "DI_RESULT: can't find msg %d\n",
+                           di.di_result.dr_id, 0, 0 );
+                       return;
+               }
+
+               Debug( LDAP_DEBUG_ARGS, "DI_RESULT: type %d\n",
+                   dr->result_type, 0, 0 );
+
+               switch ( dr->result_type ) {
+               case OP_COMPARE:
+                       compare_result( clientsb, m, &dr->res_cm );
+                       break;
+
+               case OP_SEARCH:
+                       search_result( clientsb, m, &dr->res_sr );
+                       break;
+
+               case OP_ADDENTRY:
+                       add_result( clientsb, m );
+                       break;
+
+               case OP_REMOVEENTRY:
+                       delete_result( clientsb, m );
+                       break;
+
+               case OP_MODIFYENTRY:
+                       modify_result( clientsb, m );
+                       break;
+
+               case OP_READ:
+                       if ( do_modify2( clientsb, m, &dr->res_rd ) != 0 )
+                               delete = 0;
+                       break;
+
+               case OP_MODIFYRDN:
+                       modrdn_result( clientsb, m );
+                       break;
+
+               default:
+                       break;
+               }
+               ds_res_free( dr );
+               break;
+
+       case DI_ERROR:
+               de = &di.di_error.de_err;
+               if ( (m = get_msg( di.di_error.de_id )) == NULL ) {
+                       Debug( LDAP_DEBUG_ANY, "DI_ERROR: can't find msg %d\n",
+                           di.di_error.de_id, 0, 0 );
+                       return;
+               }
+               if ( m->m_msgtype == LDAP_REQ_SEARCH 
+#ifdef COMPAT20
+                   || m->m_msgtype == OLD_LDAP_REQ_SEARCH
+#endif
+                   )
+                       incr = 2;
+               else if ( m->m_msgtype == LDAP_REQ_DELETE )
+                       incr = (LDAP_RES_DELETE - LDAP_REQ_DELETE);
+               else
+                       incr = 1;
+
+               Debug( LDAP_DEBUG_ARGS, "DI_ERROR\n", 0, 0, 0 );
+
+               /* 
+                * chase down referrals, retry operation there.  only do
+                * this for modify-like operations, since we assume the
+                * dsa should have been able to chase anything else that
+                * wasn't really down.
+                */
+
+               if ( de->dse_type == DSE_REFERRAL ) {
+                       int     bound, rc;
+
+                       switch ( m->m_msgtype ) {
+#ifdef COMPAT20
+                       case OLD_LDAP_REQ_ADD:
+                       case OLD_LDAP_REQ_MODIFY:
+                       case OLD_LDAP_REQ_MODRDN:
+                       case OLD_LDAP_REQ_DELETE:
+                       case OLD_LDAP_REQ_COMPARE:
+                       case OLD_LDAP_REQ_SEARCH:
+#endif
+#ifdef COMPAT30
+                       case LDAP_REQ_DELETE_30:
+#endif
+                       case LDAP_REQ_ADD:
+                       case LDAP_REQ_MODIFY:
+                       case LDAP_REQ_MODRDN:
+                       case LDAP_REQ_DELETE:
+                       case LDAP_REQ_COMPARE:
+                       case LDAP_REQ_SEARCH:
+                               /* chase down the referral */
+                               if ( (rc = chase_referral( clientsb, m, de,
+                                   &matched )) != LDAP_SUCCESS ) {
+                                       send_ldap_msgresult( clientsb,
+                                           m->m_msgtype + incr, m, rc,
+                                           matched, "Can't chase referral" );
+                                       free( matched );
+                                       break;
+                               }
+
+                               /* now retry the operation */
+                               bercopy = ber_dup( m->m_ber );
+                               if ( do_request( clientsb, m, bercopy, &bound )
+                                   == 0 ) {
+                                       del_msg( m );
+                               }
+                               ber_free( bercopy, 0 );
+                               return;
+                               break;
+
+                       default:
+                               send_ldap_msgresult( clientsb, m->m_msgtype +
+                                   incr, m, LDAP_UNAVAILABLE, NULL, "" );
+                               break;
+                       }
+                       break;
+               } else if ( de->dse_type == DSE_ABANDONED ) {
+                       return;
+               }
+               
+
+               /* not a referral - convert the error and return to client */
+               ldaperr = x500err2ldaperr( de, &matched );
+#ifdef LDAP_DEBUG
+               if ( ldap_debug )
+                       print_error( de );      /* prints, then calls free */
+               else
+#endif
+                       ds_error_free( de );
+
+               send_ldap_msgresult( clientsb, m->m_msgtype + incr, m,
+                   ldaperr, matched, "" );
+               free( matched );
+               break;
+
+       case DI_PREJECT:
+               dp = &di.di_preject;
+               if ( (m = get_msg( dp->dp_id )) == NULL ) {
+                       Debug(LDAP_DEBUG_ANY, "DI_PREJECT: can't find msg %d\n",
+                           dp->dp_id, 0, 0 );
+                       return;
+               }
+
+               Debug( LDAP_DEBUG_ARGS, "DI_PREJECT src %d rson %d inf (%s)\n",
+                   dp->dp_source, dp->dp_reason, dp->dp_cc ? dp->dp_data
+                   : "" );
+
+               send_ldap_msgresult( clientsb, m->m_msgtype, m,
+                   LDAP_UNAVAILABLE, NULL, "Got PREJECT from X.500" );
+
+               dsaconn->c_ad = -1;
+               break;
+
+       case DI_ABORT:
+               da = &di.di_abort;
+
+               Debug( LDAP_DEBUG_ARGS, "DI_ABORT src %d rson %d inf (%s)\n",
+                   da->da_source, da->da_reason, da->da_cc ? da->da_data
+                   : "" );
+
+               /* assume this always means more stuff coming... */
+               if ( da->da_reason == DA_ROS )
+                       return;
+
+               /* moby hack - but how else do you tell the difference? */
+               if ( isclosed( dsaconn->c_ad ) ) {
+                       send_msg( dsaconn, clientsb, LDAP_UNAVAILABLE,
+                           "Got ABORT from X.500" );
+                       return;
+               }
+
+               /* notify outstanding requests of the failure */
+               send_msg( dsaconn, clientsb, LDAP_OPERATIONS_ERROR,
+                   "Got unknown ABORT from X.500" );
+
+               dsaconn->c_ad = -1;
+               return;
+               break;
+
+       default:
+               Debug( LDAP_DEBUG_ANY, "unknown result type %d\n", di.di_type,
+                   0, 0 );
+
+               dsaconn->c_ad = -1;     /* better safe... */
+               return;
+               break;
+       }
+
+       if ( delete && m != NULL )
+               del_msg( m );
+}
+
+int
+send_ldap_msgresult(
+    Sockbuf            *sb,
+    unsigned long      tag,
+    struct msg         *m,
+    int                        err,
+    char               *matched,
+    char               *text
+)
+{
+#ifdef CLDAP
+       if ( m->m_cldap ) {
+               SAFEMEMCPY( (char *)sb->sb_useaddr, &m->m_clientaddr,
+                   sizeof( struct sockaddr ));
+               Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
+                   inet_ntoa(((struct sockaddr_in *)
+                   sb->sb_useaddr)->sin_addr ),
+                   ((struct sockaddr_in *)sb->sb_useaddr)->sin_port, 0 );
+       }
+#endif
+       return( send_ldap_result( sb, tag, m->m_msgid, err, matched, text ) );
+}
+
+int
+send_ldap_result(
+    Sockbuf            *sb,
+    unsigned long      tag,
+    int                        msgid,
+    int                        err,
+    char               *matched,
+    char               *text
+)
+{
+       BerElement      *ber;
+       int             rc;
+#ifdef CLDAP
+       int             cldap;
+#endif
+       extern int      version;
+
+#ifdef CLDAP
+       cldap = ( sb->sb_naddr > 0 );
+#endif
+
+       Debug( LDAP_DEBUG_TRACE, "send_ldap_result\n", 0, 0, 0 );
+
+       if ( tag == LBER_DEFAULT )
+#ifdef COMPAT20
+               tag = ldap_compat == 20 ? OLD_LBER_SEQUENCE : LBER_SEQUENCE;
+#else
+               tag = LBER_SEQUENCE;
+#endif
+
+       if ( (ber = der_alloc()) == NULLBER ) {
+               Debug( LDAP_DEBUG_ANY, "der_alloc failed\n", 0, 0, 0 );
+               return( -1 );
+       }
+
+       if ( version != 1 ) {
+#ifdef COMPAT20
+               if ( ldap_compat == 20 ) {
+                       rc = ber_printf( ber, "t{it{tess}}", OLD_LBER_SEQUENCE,
+                           msgid, tag, LBER_INTEGER, err,
+                           matched ? matched : "", text );
+               } else
+#endif
+#ifdef COMPAT30
+               if ( ldap_compat == 30 ) {
+                       rc = ber_printf( ber, "{it{{ess}}}", msgid, tag, err,
+                           matched ? matched : "", text );
+               } else
+#endif
+#ifdef CLDAP
+               if ( cldap ) {
+                       rc = ber_printf( ber, "{is{t{ess}}}", msgid, "", tag,
+                           err, matched ? matched : "", text );
+               } else
+#endif
+               rc = ber_printf( ber, "{it{ess}}", msgid, tag, err, matched ?
+                   matched : "", text );
+       } else {
+               /* version 1 always uses the broken stuff */
+               rc = ber_printf( ber, "t{it{is}}", OLD_LBER_SEQUENCE, msgid,
+                   tag, err, text );
+       }
+
+       if ( rc == -1 ) {
+               Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
+               return( -1 );
+       }
+
+#ifdef LDAP_DEBUG
+       if ( ldap_debug & LDAP_DEBUG_BER )
+               trace_ber( 0, ber->ber_ptr - ber->ber_buf, ber->ber_buf,
+                   stderr, 0, 0 );
+#endif
+
+       if ( ber_flush( sb, ber, 1 ) != 0 ) {
+               Debug( LDAP_DEBUG_ANY, "ber_flush failed\n", 0, 0, 0 );
+               return( -1 );
+       }
+
+       return( 0 );
+}
diff --git a/servers/ldapd/search.c b/servers/ldapd/search.c
new file mode 100644 (file)
index 0000000..b250d63
--- /dev/null
@@ -0,0 +1,710 @@
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <quipu/commonarg.h>
+#include <quipu/attrvalue.h>
+#include <quipu/ds_error.h>
+#include <quipu/ds_search.h>
+#include <quipu/dap2.h>
+#include <quipu/dua.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "lber.h"
+#include "ldap.h"
+#include "common.h"
+
+static get_filter();
+static get_filter_list();
+static get_substring_filter();
+
+#ifdef COMPAT
+extern int     version;
+extern int     ldap_compat;
+#define SEARCHRESTAG   (ldap_compat == 20 ? OLD_LDAP_RES_SEARCH_RESULT : LDAP_RES_SEARCH_RESULT)
+#else
+#define SEARCHRESTAG   LDAP_RES_SEARCH_RESULT
+#endif
+
+int
+do_search(
+    Sockbuf    *clientsb,
+    struct msg *m,
+    BerElement *ber
+)
+{
+       int                     rc, err;
+       int                     deref, attrsonly;
+       int                     sizelimit, timelimit;
+       char                    *base;
+       char                    **attrs;
+       struct ds_search_arg    sa;
+       static CommonArgs       common = default_common_args;
+       extern DN               ldap_str2dn();
+
+       Debug( LDAP_DEBUG_TRACE, "do_search\n", 0, 0, 0 );
+
+       /*
+        * Parse the search request.  It looks like this:
+        *      SearchRequest := [APPLICATION 3] SEQUENCE {
+        *              baseObject      DistinguishedName,
+        *              scope           ENUMERATED {
+        *                      baseObject      (0),
+        *                      singleLevel     (1),
+        *                      wholeSubtree    (2)
+        *              },
+        *              derefAliases    ENUMERATED {
+        *                      neverDerefaliases       (0),
+        *                      derefInSearching        (1),
+        *                      derefFindingBaseObj     (2),
+        *                      alwaysDerefAliases      (3)
+        *              },
+        *              sizelimit       INTEGER (0 .. 65535),
+        *              timelimit       INTEGER (0 .. 65535),
+        *              attrsOnly       BOOLEAN,
+        *              filter          Filter,
+        *              attributes      SEQUENCE OF AttributeType
+        *      }
+        */
+
+#if ISODEPACKAGE == IC
+#if ICRELEASE > 2
+       DAS_SearchArgument_INIT( &sa );
+#endif
+#endif
+
+       if ( ber_scanf( ber, "{aiiiib", &base, &sa.sra_subset, &deref,
+           &sizelimit, &timelimit, &attrsonly ) == LBER_ERROR ) {
+               send_ldap_msgresult( clientsb, SEARCHRESTAG, m,
+                   LDAP_PROTOCOL_ERROR, NULL, "" );
+               return( 0 );
+       }
+
+       sa.sra_baseobject = ldap_str2dn( base );
+       if ( sa.sra_baseobject == NULLDN && *base != '\0' ) {
+               free( base );
+               send_ldap_msgresult( clientsb, SEARCHRESTAG, m,
+                   LDAP_INVALID_DN_SYNTAX, NULL, "" );
+               return( 0 );
+       }
+       free( base );
+
+       sa.sra_common = common; /* struct copy */
+       sa.sra_searchaliases = (deref == LDAP_DEREF_SEARCHING ||
+           deref == LDAP_DEREF_ALWAYS);
+       if ( deref == LDAP_DEREF_NEVER || deref == LDAP_DEREF_SEARCHING )
+               sa.sra_common.ca_servicecontrol.svc_options |=
+                   SVC_OPT_DONTDEREFERENCEALIAS;
+
+       sa.sra_common.ca_servicecontrol.svc_sizelimit = (sizelimit == 0 ?
+           SVC_NOSIZELIMIT : sizelimit);
+
+       sa.sra_common.ca_servicecontrol.svc_timelimit = (timelimit == 0 ?
+           SVC_NOTIMELIMIT : timelimit);
+
+       sa.sra_eis.eis_infotypes = (attrsonly ? EIS_ATTRIBUTETYPESONLY :
+           EIS_ATTRIBUTESANDVALUES);
+
+       /* search filter */
+       if ( (err = get_filter( ber, &sa.sra_filter )) != 0 ) {
+               send_ldap_msgresult( clientsb, SEARCHRESTAG, m,
+                   err, NULL, "Bad search filter" );
+               return( 0 );
+       }
+
+#ifdef LDAP_DEBUG
+       if ( ldap_debug & LDAP_DEBUG_ARGS ) {
+               PS      ps;
+
+               ps = ps_alloc( std_open );
+               std_setup( ps, stderr );
+               ps_print( ps, "Filter: " );
+               fi_print( ps, sa.sra_filter, EDBOUT );
+               ps_print( ps, "\n" );
+               ps_free( ps );
+       }
+#endif
+
+       /* attrs to return */
+       attrs = NULL;
+       if ( ber_scanf( ber, "{v}}", &attrs ) == LBER_ERROR ) {
+               send_ldap_msgresult( clientsb, SEARCHRESTAG, m,
+                   LDAP_PROTOCOL_ERROR, NULL, "" );
+               return( 0 );
+       }
+       sa.sra_eis.eis_select = NULLATTR;
+       if ( attrs == NULL ) {
+               sa.sra_eis.eis_allattributes = 1;
+       } else {
+               Attr_Sequence   as;
+               int             i;
+
+               sa.sra_eis.eis_allattributes = 0;
+               for ( i = 0; attrs[i] != NULL; i++ ) {
+                       AttributeType   type;
+
+                       if ( (type = AttrT_new( attrs[i] )) == NULLAttrT ) {
+                               Debug( LDAP_DEBUG_TRACE, "unknown attr (%s)\n",
+                                   attrs[i], 0, 0 );
+                               continue;
+                       }
+
+                       as = as_comp_alloc();
+                       as->attr_type = type;
+                       as->attr_acl = NULLACL_INFO;
+                       as->attr_link = NULLATTR;
+                       as->attr_value = NULLAV;
+
+                       sa.sra_eis.eis_select = as_merge( as,
+                           sa.sra_eis.eis_select );
+               }
+
+               /* complain only if we know about none of the attrs */
+               if ( sa.sra_eis.eis_select == NULLATTR ) {
+                       send_ldap_msgresult( clientsb, SEARCHRESTAG,
+                           m, LDAP_UNDEFINED_TYPE, NULL, attrs[0] );
+                       charlist_free( attrs );
+                       return( 0 );
+               }
+
+               charlist_free( attrs );
+       }
+
+       rc = initiate_dap_operation( OP_SEARCH, m, &sa );
+
+#ifdef CLDAP
+       if (  m->m_cldap )
+               m->m_searchbase = sa.sra_baseobject;
+       else
+#endif /* CLDAP */
+               dn_free( sa.sra_baseobject );
+
+       filter_free( sa.sra_filter );
+       as_free( sa.sra_eis.eis_select );
+
+       if ( rc != 0 ) {
+               send_ldap_msgresult( clientsb, SEARCHRESTAG, m,
+                   rc, NULL, "" );
+               return( 0 );
+       }
+
+       return( 1 );
+}
+
+static get_filter( BerElement *ber, Filter *filt )
+{
+       unsigned long   tag, len;
+       int             err;
+       char            typestr[64];
+       Filter          f;
+
+       Debug( LDAP_DEBUG_TRACE, "get_filter\n", 0, 0, 0 );
+
+       /*
+        * A filter looks like this coming in:
+        *      Filter ::= CHOICE {
+        *              and             [0]     SET OF Filter,
+        *              or              [1]     SET OF Filter,
+        *              not             [2]     Filter,
+        *              equalityMatch   [3]     AttributeValueAssertion,
+        *              substrings      [4]     SubstringFilter,
+        *              greaterOrEqual  [5]     AttributeValueAssertion,
+        *              lessOrEqual     [6]     AttributeValueAssertion,
+        *              present         [7]     AttributeType,,
+        *              approxMatch     [8]     AttributeValueAssertion
+        *      }
+        *
+        *      SubstringFilter ::= SEQUENCE {
+        *              type               AttributeType,
+        *              SEQUENCE OF CHOICE {
+        *                      initial          [0] IA5String,
+        *                      any              [1] IA5String,
+        *                      final            [2] IA5String
+        *              }
+        *      }
+        */
+
+       f = filter_alloc();
+       *filt = f;
+       f->flt_next = NULLFILTER;
+
+       err = 0;
+       switch (tag = ber_peek_tag( ber, &len )) {
+#ifdef COMPAT20
+       case OLD_LDAP_FILTER_EQUALITY:
+#endif
+       case LDAP_FILTER_EQUALITY:
+               Debug( LDAP_DEBUG_ARGS, "EQUALITY\n", 0, 0, 0 );
+               f->flt_type = FILTER_ITEM;
+               f->FUITEM.fi_type = FILTERITEM_EQUALITY;
+#ifdef COMPAT30
+               if ( ldap_compat == 30 )
+                       (void) ber_skip_tag( ber, &len );
+#endif
+
+               if ( (err = get_ava( ber, &f->FUITEM.UNAVA )) != 0 ) {
+                       free( f );
+                       return( err );
+               }
+               break;
+
+#ifdef COMPAT20
+       case OLD_LDAP_FILTER_SUBSTRINGS:
+#endif
+       case LDAP_FILTER_SUBSTRINGS:
+               Debug( LDAP_DEBUG_ARGS, "SUBSTRINGS\n", 0, 0, 0 );
+               err = get_substring_filter( ber, f );
+               break;
+
+#ifdef COMPAT20
+       case OLD_LDAP_FILTER_GE:
+#endif
+       case LDAP_FILTER_GE:
+               Debug( LDAP_DEBUG_ARGS, "GE\n", 0, 0, 0 );
+               f->flt_type = FILTER_ITEM;
+               f->FUITEM.fi_type = FILTERITEM_GREATEROREQUAL;
+#ifdef COMPAT30
+               if ( ldap_compat == 30 )
+                       (void) ber_skip_tag( ber, &len );
+#endif
+               if ( (err = get_ava( ber, &f->FUITEM.UNAVA )) != 0 ) {
+                       free( f );
+                       return( err );
+               }
+               break;
+
+#ifdef COMPAT20
+       case OLD_LDAP_FILTER_LE:
+#endif
+       case LDAP_FILTER_LE:
+               Debug( LDAP_DEBUG_ARGS, "LE\n", 0, 0, 0 );
+               f->flt_type = FILTER_ITEM;
+               f->FUITEM.fi_type = FILTERITEM_LESSOREQUAL;
+#ifdef COMPAT30
+               if ( ldap_compat == 30 )
+                       (void) ber_skip_tag( ber, &len );
+#endif
+
+               if ( (err = get_ava( ber, &f->FUITEM.UNAVA )) != 0 ) {
+                       free( f );
+                       return( err );
+               }
+               break;
+
+#ifdef COMPAT20
+       case OLD_LDAP_FILTER_PRESENT:
+#endif
+#ifdef COMPAT30
+       case LDAP_FILTER_PRESENT_30:
+#endif
+       case LDAP_FILTER_PRESENT:
+               Debug( LDAP_DEBUG_ARGS, "PRESENT\n", 0, 0, 0 );
+               f->flt_type = FILTER_ITEM;
+               f->FUITEM.fi_type = FILTERITEM_PRESENT;
+               len = sizeof(typestr);
+#ifdef COMPAT30
+               if ( ldap_compat == 30 )
+                       (void) ber_skip_tag( ber, &len );
+#endif
+
+               if ( ber_scanf( ber, "s", typestr, &len ) == LBER_ERROR )
+                       return( LDAP_PROTOCOL_ERROR );
+               if ( (f->FUITEM.UNTYPE = str2AttrT( typestr )) == NULLAttrT )
+                       return( LDAP_UNDEFINED_TYPE );
+               break;
+
+#ifdef COMPAT20
+       case OLD_LDAP_FILTER_APPROX:
+#endif
+       case LDAP_FILTER_APPROX:
+               Debug( LDAP_DEBUG_ARGS, "APPROX\n", 0, 0, 0 );
+               f->flt_type = FILTER_ITEM;
+               f->FUITEM.fi_type = FILTERITEM_APPROX;
+#ifdef COMPAT30
+               if ( ldap_compat == 30 )
+                       (void) ber_skip_tag( ber, &len );
+#endif
+
+               if ( (err = get_ava( ber, &f->FUITEM.UNAVA )) != 0 ) {
+                       free( f );
+                       return( err );
+               }
+               break;
+
+#ifdef COMPAT20
+       case OLD_LDAP_FILTER_AND:
+#endif
+       case LDAP_FILTER_AND:
+               Debug( LDAP_DEBUG_ARGS, "AND\n", 0, 0, 0 );
+               f->flt_type = FILTER_AND;
+               err = get_filter_list( ber, f );
+               break;
+
+#ifdef COMPAT20
+       case OLD_LDAP_FILTER_OR:
+#endif
+       case LDAP_FILTER_OR:
+               Debug( LDAP_DEBUG_ARGS, "OR\n", 0, 0, 0 );
+               f->flt_type = FILTER_OR;
+               err = get_filter_list( ber, f );
+               break;
+
+#ifdef COMPAT20
+       case OLD_LDAP_FILTER_NOT:
+#endif
+       case LDAP_FILTER_NOT:
+               Debug( LDAP_DEBUG_ARGS, "NOT\n", 0, 0, 0 );
+               f->flt_type = FILTER_NOT;
+               (void) ber_skip_tag( ber, &len );
+               err = get_filter( ber, &f->FUFILT );
+               break;
+
+       default:
+               Debug( LDAP_DEBUG_ANY, "unknown filter type %d\n", tag, 0, 0 );
+               free( f );
+               return( LDAP_PROTOCOL_ERROR );
+               break;
+       }
+
+       Debug( LDAP_DEBUG_TRACE, "end get_filter\n", 0, 0, 0 );
+       return( err );
+}
+
+static get_filter_list( BerElement *ber, Filter f )
+{
+       Filter          new, tail;
+       int             err;
+       unsigned long   tag, len;
+       char            *last;
+
+       Debug( LDAP_DEBUG_TRACE, "get_filter_list\n", 0, 0, 0 );
+
+#ifdef COMPAT30
+       if ( ldap_compat == 30 )
+               (void) ber_skip_tag( ber, &len );
+#endif
+       f->FUFILT = tail = NULLFILTER;
+       for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
+           tag = ber_next_element( ber, &len, last ) ) {
+               if ( (err = get_filter( ber, &new )) != 0 )
+                       return( err );
+
+               if ( f->FUFILT == NULLFILTER ) {
+                       f->FUFILT = new;
+               } else {
+                       tail->flt_next = new;
+               }
+               tail = new;
+       }
+
+       Debug( LDAP_DEBUG_TRACE, "end get_filter_list\n", 0, 0, 0 );
+       return( 0 );
+}
+
+static get_substring_filter( BerElement *ber, Filter f )
+{
+       unsigned long   tag, len;
+       char            typestr[64];
+       AttributeType   type;
+       char            *valstr, *last;
+       AttributeValue  value;
+       extern short    ldap_dn_syntax;
+
+       Debug( LDAP_DEBUG_TRACE, "get_substring_filter\n", 0, 0, 0 );
+
+#ifdef COMPAT30
+       if ( ldap_compat == 30 )
+               (void) ber_skip_tag( ber, &len );
+#endif
+
+       f->flt_type = FILTER_ITEM;
+       f->FUITEM.fi_type = FILTERITEM_SUBSTRINGS;
+       len = sizeof(typestr);
+       if ( ber_scanf( ber, "{s", typestr, &len ) == LBER_ERROR ) {
+               return( LDAP_PROTOCOL_ERROR );
+       }
+       if ( (type = str2AttrT( typestr )) == NULLAttrT ) {
+               return( LDAP_UNDEFINED_TYPE );
+       }
+       f->FUITEM.UNSUB.fi_sub_type = type;
+       f->FUITEM.UNSUB.fi_sub_initial = NULLAV;
+       f->FUITEM.UNSUB.fi_sub_any = NULLAV;
+       f->FUITEM.UNSUB.fi_sub_final = NULLAV;
+       for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
+           tag = ber_next_element( ber, &len, last ) ) {
+               AV_Sequence     avs, any_end;
+
+#ifdef COMPAT30
+               if ( ldap_compat == 30 ) {
+                       if ( ber_scanf( ber, "{a}", &valstr ) == LBER_ERROR ) {
+                               return( LDAP_PROTOCOL_ERROR );
+                       }
+               } else
+#endif
+                       if ( ber_scanf( ber, "a", &valstr ) == LBER_ERROR ) {
+                               return( LDAP_PROTOCOL_ERROR );
+                       }
+
+               value = ldap_str2AttrV( valstr, type->oa_syntax );
+               free( valstr );
+
+               if ( value == NULLAttrV ) {
+                       return( LDAP_INVALID_SYNTAX );
+               }
+
+               if ( (avs = avs_comp_new( value )) == NULLAV )
+                       return( LDAP_OPERATIONS_ERROR );
+
+               switch ( tag ) {
+#ifdef COMPAT20
+               case OLD_LDAP_SUBSTRING_INITIAL:
+#endif
+#ifdef COMPAT30
+               case LDAP_SUBSTRING_INITIAL_30:
+#endif
+               case LDAP_SUBSTRING_INITIAL:
+                       Debug( LDAP_DEBUG_ARGS, "  INITIAL\n", 0, 0, 0 );
+                       if ( f->FUITEM.UNSUB.fi_sub_initial != NULLAV
+                           && f->FUITEM.UNSUB.fi_sub_initial->avseq_next
+                           != NULLAV ) {
+                               return( LDAP_PROTOCOL_ERROR );
+                       }
+                       f->FUITEM.UNSUB.fi_sub_initial = avs;
+                       break;
+
+#ifdef COMPAT20
+               case OLD_LDAP_SUBSTRING_ANY:
+#endif
+#ifdef COMPAT30
+               case LDAP_SUBSTRING_ANY_30:
+#endif
+               case LDAP_SUBSTRING_ANY:
+                       Debug( LDAP_DEBUG_ARGS, "  ANY\n", 0, 0, 0 );
+       
+                       if (f->FUITEM.UNSUB.fi_sub_any != NULLAV) {
+                               any_end->avseq_next = avs;
+                       } else {
+                               f->FUITEM.UNSUB.fi_sub_any = avs;
+                       }
+
+                       any_end = avs;
+                       break;
+
+#ifdef COMPAT20
+               case OLD_LDAP_SUBSTRING_FINAL:
+#endif
+#ifdef COMPAT30
+               case LDAP_SUBSTRING_FINAL_30:
+#endif
+               case LDAP_SUBSTRING_FINAL:
+                       Debug( LDAP_DEBUG_ARGS, "  FINAL\n", 0, 0, 0 );
+                       if ( f->FUITEM.UNSUB.fi_sub_final != NULLAV
+                           && f->FUITEM.UNSUB.fi_sub_final->avseq_next
+                           != NULLAV ) {
+                               return( LDAP_PROTOCOL_ERROR );
+                       }
+                       f->FUITEM.UNSUB.fi_sub_final = avs;
+                       break;
+
+               default:
+                       Debug( LDAP_DEBUG_ARGS, "  unknown type\n", tag, 0, 0 );
+                       return( LDAP_PROTOCOL_ERROR );
+               }
+       }
+
+       Debug( LDAP_DEBUG_TRACE, "end get_substring_filter\n", 0, 0, 0 );
+       return( 0 );
+}
+
+void
+search_result(
+    Sockbuf                    *sb,
+    struct msg                 *m,
+    struct ds_search_result    *sr
+)
+{
+       EntryInfo       *e;
+       BerElement      *ber;
+       int             rc;
+
+       Debug( LDAP_DEBUG_TRACE, "search_result\n", 0, 0, 0 );
+
+       ber = NULL;
+
+       if ( ! sr->srr_correlated ) {
+               Debug( LDAP_DEBUG_ARGS, "correlating results\n", 0, 0, 0 );
+               correlate_search_results( sr );
+       }
+
+#ifdef CLDAP
+       if ( m->m_cldap ) {
+               if ((ber = der_alloc()) == NULLBER ) {
+                       send_ldap_msgresult( sb, SEARCHRESTAG, m,
+                           LDAP_OPERATIONS_ERROR, NULL, "der_alloc" );
+                       return;
+               }
+               if ( ber_printf( ber, "t{is{", LBER_SEQUENCE, m->m_msgid,
+                   "" ) == -1 ) {
+                       send_ldap_msgresult( sb, SEARCHRESTAG, m,
+                           LDAP_OPERATIONS_ERROR, NULL, "ber_printf" );
+                       return;
+               }
+       }
+#endif
+
+       for ( e = sr->CSR_entries; e != NULLENTRYINFO; e = e->ent_next ) {
+               Debug( LDAP_DEBUG_ARGS, "\tentry:\n", 0, 0, 0 );
+
+#ifdef CLDAP
+               if ( !m->m_cldap )
+#endif /* CLDAP */
+
+                       if ( (ber = der_alloc()) == NULLBER ) {
+                               send_ldap_msgresult( sb, SEARCHRESTAG, m,
+                                   LDAP_OPERATIONS_ERROR, NULL, "der_alloc" );
+                               return;
+                       }
+
+#ifdef COMPAT20
+               if ( version == 1 ) {
+                       if ( ber_printf( ber, "t{it{", OLD_LBER_SEQUENCE,
+                           m->m_msgid, OLD_LDAP_RES_SEARCH_ENTRY ) == -1 ) {
+                               send_ldap_msgresult( sb, SEARCHRESTAG, m,
+                                   LDAP_OPERATIONS_ERROR, NULL, "ber_printf" );
+                               return;
+                       }
+               } else
+#endif
+#ifdef COMPAT30
+               if ( ldap_compat == 30 ) {
+                       if ( ber_printf( ber, "{it{{", m->m_msgid,
+                           LDAP_RES_SEARCH_ENTRY ) == -1 ) {
+                               send_ldap_msgresult( sb, SEARCHRESTAG, m,
+                                   LDAP_OPERATIONS_ERROR, NULL, "ber_printf" );
+                               return;
+                       }
+               } else
+#endif
+#ifdef CLDAP
+               if ( m->m_cldap )
+                       rc = ber_printf( ber, "t{", LDAP_RES_SEARCH_ENTRY );
+               else
+#endif /* CLDAP */
+                       rc = ber_printf( ber, "{it{", m->m_msgid,
+                           LDAP_RES_SEARCH_ENTRY );
+
+               if ( rc == -1 ) {
+                       send_ldap_msgresult( sb, SEARCHRESTAG, m,
+                           LDAP_OPERATIONS_ERROR, NULL, "ber_printf" );
+                       return;
+               }
+
+#ifdef CLDAP
+               if (  m->m_cldap )
+                       rc = encode_dn( ber, e->ent_dn, m->m_searchbase );
+#endif /* CLDAP */
+               else
+                       rc = encode_dn( ber, e->ent_dn, NULLDN );
+
+               if ( rc == -1 ) {
+                       send_ldap_msgresult( sb, SEARCHRESTAG, m,
+                           LDAP_OPERATIONS_ERROR, NULL, "encode_dn" );
+                       return;
+               }
+
+               if ( encode_attrs( ber, e->ent_attr ) == -1 ) {
+                       send_ldap_msgresult( sb, SEARCHRESTAG, m,
+                           LDAP_OPERATIONS_ERROR, NULL, "encode_attrs" );
+                       return;
+               }
+
+#ifdef COMPAT20
+               if ( version == 1 ) {
+                       if ( ber_printf( ber, "}}" ) == -1 ) {
+                               send_ldap_msgresult( sb, SEARCHRESTAG, m,
+                                   LDAP_OPERATIONS_ERROR, NULL,
+                                   "ber_printf 2" );
+                               return;
+                       }
+               } else
+#endif
+#ifdef COMPAT30
+               if ( ldap_compat == 30 ) {
+                       if ( ber_printf( ber, "}}}" ) == -1 ) {
+                               send_ldap_msgresult( sb, SEARCHRESTAG, m,
+                                   LDAP_OPERATIONS_ERROR, NULL,
+                                   "ber_printf 2" );
+                               return;
+                       }
+               } else
+#endif
+#ifdef CLDAP
+               if ( m->m_cldap )
+                       rc = ber_printf( ber, "}" );
+               else
+#endif /* CLDAP */
+                       rc = ber_printf( ber, "}}" );
+
+               if ( rc == -1 ) {
+                       send_ldap_msgresult( sb, SEARCHRESTAG, m,
+                           LDAP_OPERATIONS_ERROR, NULL, "ber_printf 2" );
+                       return;
+               }
+
+#ifdef LDAP_DEBUG
+               if ( ldap_debug & LDAP_DEBUG_BER )
+                       trace_ber( 0, ber->ber_ptr - ber->ber_buf,
+                           ber->ber_buf, stderr, 0, 0 );
+#endif
+
+#ifdef CLDAP
+               if ( !m->m_cldap )
+#endif
+                       (void) ber_flush( sb, ber, 1 );
+       }
+
+       switch ( sr->CSR_limitproblem ) {
+       case LSR_NOLIMITPROBLEM:
+               rc = LDAP_SUCCESS;
+               break;
+       case LSR_TIMELIMITEXCEEDED:
+               rc = LDAP_TIMELIMIT_EXCEEDED;
+               break;
+       case LSR_SIZELIMITEXCEEDED:
+       case LSR_ADMINSIZEEXCEEDED:
+               rc = LDAP_SIZELIMIT_EXCEEDED;
+               break;
+       }
+
+       Debug( LDAP_DEBUG_ARGS, "\tresult:\n", 0, 0, 0 );
+
+#ifdef CLDAP
+       if ( m->m_cldap ) {
+               if ( ber_printf( ber, "t{ess}}}", SEARCHRESTAG, rc, "", "" )
+                   == -1 ) {
+                       send_ldap_msgresult( sb, SEARCHRESTAG, m,
+                           LDAP_OPERATIONS_ERROR, NULL, "ber_printf" );
+                       return;
+               }
+               SAFEMEMCPY( (char *)sb->sb_useaddr, &m->m_clientaddr,
+                   sizeof( struct sockaddr ));
+               if ( ber_flush( sb, ber, 1 ) != 0 ) {
+                   send_ldap_msgresult( sb, SEARCHRESTAG, m, 
+                       LDAP_RESULTS_TOO_LARGE, NULL, "ber_flush" );
+               }
+       } else
+#endif
+       send_ldap_msgresult( sb, SEARCHRESTAG, m, rc, NULL, "" );
+
+       return;
+}
diff --git a/servers/ldapd/setproctitle.c b/servers/ldapd/setproctitle.c
new file mode 100644 (file)
index 0000000..e1022ee
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef NOSETPROCTITLE
+/*
+ * Copyright (c) 1990,1991 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+char   **Argv;         /* pointer to original (main's) argv */
+int    Argc;           /* original argc */
+
+/*
+ * takes a printf-style format string (fmt) and up to three parameters (a,b,c)
+ * this clobbers the original argv...
+ */
+
+/* VARARGS */
+setproctitle( fmt, a, b, c )
+char *fmt;
+{
+       static char *endargv = (char *)0;
+       char    *s;
+       int             i;
+       char    buf[ 1024 ];
+
+       if ( endargv == (char *)0 ) {
+               /* set pointer to end of original argv */
+               endargv = Argv[ Argc-1 ] + strlen( Argv[ Argc-1 ] );
+       }
+       sprintf( buf, fmt, a, b, c );
+       /* make ps print "([prog name])" */
+       s = Argv[0];
+       *s++ = '-';
+       i = strlen( buf );
+       if ( i > endargv - s - 2 ) {
+               i = endargv - s - 2;
+               buf[ i ] = '\0';
+       }
+       strcpy( s, buf );
+       s += i;
+       while ( s < endargv ) *s++ = ' ';
+}
+#endif /* NOSETPROCTITLE */
diff --git a/servers/ldapd/syntax.c b/servers/ldapd/syntax.c
new file mode 100644 (file)
index 0000000..8569478
--- /dev/null
@@ -0,0 +1,1029 @@
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <quipu/commonarg.h>
+#include <quipu/attrvalue.h>
+#include <quipu/ds_error.h>
+#include <quipu/ds_search.h>
+#include <quipu/dap2.h>
+#include <quipu/dua.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "lber.h"
+#include "ldap.h"
+#include "common.h"
+
+short  ldap_photo_syntax;
+short  ldap_jpeg_syntax;
+short  ldap_jpeg_nonfile_syntax;
+short  ldap_audio_syntax;
+short  ldap_dn_syntax;
+short  ldap_postaladdress_syntax;
+short  ldap_acl_syntax;
+short  ldap_mtai_syntax;
+short  ldap_rts_cred_syntax;
+short  ldap_rtl_syntax;
+short  ldap_mailbox_syntax;
+short  ldap_caseignorelist_syntax;
+short  ldap_caseexactstring_syntax;
+short  ldap_certif_syntax;
+short  ldap_iattr_syntax;
+short  ldap_telex_syntax;
+short  ldap_octetstring_syntax;
+short  ldap_deliverymethod_syntax;
+short  ldap_facsimileTelephoneNumber_syntax;
+short  ldap_presentationAddress_syntax;
+short  ldap_teletexTerminalIdentifier_syntax;
+short  ldap_searchGuide_syntax;
+short  ldap_dLSubmitPermission_syntax;
+
+static void    de_t61( char *s, int t61mark );
+static int     syntax_is_string( short syntax );
+
+static get_one_syntax( char *attrib, int required )
+{
+       oid_table_attr  *p, *name2attr();
+
+       if ( (p = name2attr( attrib )) != (oid_table_attr *) 0 )
+           return( p->oa_syntax );
+
+       if ( !required )
+           return( -1 );
+
+       Debug( LDAP_DEBUG_ANY, "name2attr (%s) failed - exiting\n", attrib,
+           0, 0 );
+
+       log_and_exit( 1 );
+}
+
+void
+get_syntaxes()
+{
+       oid_table_attr  *name2attr();
+
+       Debug( LDAP_DEBUG_TRACE, "get_syntaxes\n", 0, 0, 0 );
+
+       ldap_photo_syntax = get_one_syntax( "photo", 0 );
+       ldap_jpeg_syntax = get_one_syntax( "jpegPhoto", 0 );
+       ldap_jpeg_nonfile_syntax = str2syntax( "jpeg" );
+       ldap_audio_syntax = get_one_syntax( "audio", 0 );
+       ldap_postaladdress_syntax = get_one_syntax( "postaladdress", 0 );
+       ldap_dn_syntax = get_one_syntax( "aliasedObjectName", 1 );
+       ldap_acl_syntax = get_one_syntax( "acl", 0 );
+       ldap_mtai_syntax = get_one_syntax( "mTAInfo", 0 );
+       ldap_rts_cred_syntax= get_one_syntax( "initiatingRTSCredentials", 0 );
+       ldap_rtl_syntax= get_one_syntax( "routingTreeList", 0 );
+       ldap_mailbox_syntax = get_one_syntax( "otherMailbox", 0 );
+       ldap_caseignorelist_syntax = str2syntax( "CaseIgnoreList" );
+       ldap_caseexactstring_syntax = str2syntax( "caseexactstring" );
+       ldap_octetstring_syntax = str2syntax( "OctetString" );
+       ldap_deliverymethod_syntax = str2syntax( "DeliveryMethod" );
+       ldap_iattr_syntax = get_one_syntax( "inheritedAttribute", 0 );
+       ldap_certif_syntax = get_one_syntax( "userCertificate", 0 );
+       ldap_telex_syntax = get_one_syntax( "telexNumber", 0 );
+        ldap_facsimileTelephoneNumber_syntax =
+            get_one_syntax( "facsimileTelephoneNumber", 0 );
+        ldap_presentationAddress_syntax =
+            get_one_syntax( "presentationAddress", 0 );
+        ldap_teletexTerminalIdentifier_syntax =
+            get_one_syntax( "teletexTerminalIdentifier", 0 );
+        ldap_searchGuide_syntax = get_one_syntax( "searchGuide", 0 );
+        ldap_dLSubmitPermission_syntax =
+            get_one_syntax( "mhsDLSubmitPermissions", 0 );
+
+       certif_init();  /* initialize certificate syntax handler */
+}
+
+/*
+ *  From RFC 1779 "A String Representation of Distinguished Names"
+ *
+ *                       Key     Attribute (X.520 keys)
+ *                       ------------------------------
+ *                       CN      CommonName
+ *                       L       LocalityName
+ *                       ST      StateOrProvinceName
+ *                       O       OrganizationName
+ *                       OU      OrganizationalUnitName
+ *                       C       CountryName
+ *                       STREET  StreetAddress
+ *
+ *
+ *                      Table 1:  Standardised Keywords
+ *
+ *   There is an escape mechanism from the normal user oriented form, so
+ *   that this syntax may be used to print any valid distinguished name.
+ *
+ *   1.  Attributes types are represented in a (big-endian) dotted
+ *       notation.  (e.g., OID.2.6.53).
+ *
+ */
+static void attr_key_rfc1779 (
+    AttributeType   at,
+    char            *key    /* return key, caller allocated */
+)
+{
+    char    *x;
+
+    x = attr2name_aux ( at );
+
+    if ( x == NULL ) {
+        x = "?";
+    } else if ( isdigit ( *x ) ) {
+        sprintf ( key, "OID.%s", x );
+        return;
+    } else if (strcasecmp(x,"commonName")==0) {
+        x = "CN";
+    } else if (strcasecmp(x,"localityName")==0) {
+        x = "l";
+    } else if (strcasecmp(x,"stateOrProvinceName")==0) {
+        x = "st";
+    } else if (strcasecmp(x,"organizationName")==0) {
+        x = "o";
+    } else if (strcasecmp(x,"organizationalUnitName")==0) {
+        x = "ou";
+    } else if (strcasecmp(x,"countryName")==0) {
+        x = "c";
+    } else if (strcasecmp(x,"streetAddress")==0) {
+        x = "street";
+    }
+
+    strcpy ( key, x );
+}
+
+#define SEPARATOR(c)   (c == ',' || c == ';')
+#define SPACE(c)       (c == ' ' || c == '\n')
+
+int
+dn_print_real(
+    PS ps,
+    DN dn,
+    int        format
+)
+{
+       RDN     rdn;
+       int     firstrdn;
+       char    *value;
+       PS      rps;
+       void    ldap_dn_print();
+        char    key[512];
+
+       if ( dn == NULLDN )
+               return( 0 );
+
+       if ( dn->dn_parent != NULLDN ) {
+               dn_print_real( ps, dn->dn_parent, format );
+               ps_print( ps, ", " );
+       }
+
+       if ( (rps = ps_alloc( str_open )) == NULLPS )
+               return( -1 );
+       if ( str_setup( rps, NULLCP, 0, 0 ) == NOTOK )
+               return( -1 );
+
+       firstrdn = 1;
+       for ( rdn = dn->dn_rdn; rdn != NULLRDN; rdn = rdn->rdn_next ) {
+               if ( firstrdn )
+                       firstrdn = 0;
+               else
+                       ps_print( ps, " + " );
+
+                attr_key_rfc1779 ( rdn->rdn_at, key );
+
+                ps_print ( ps, key );
+               ps_print( ps, "=" );
+
+               if ( rdn->rdn_at->oa_syntax == ldap_dn_syntax ) {
+                       dn_print_real( rps, (DN) rdn->rdn_av.av_struct,
+                           format );
+                       *rps->ps_ptr = '\0';
+                       value = rps->ps_base;
+               } else {
+                       AttrV_print( rps, &rdn->rdn_av, EDBOUT );
+                       *rps->ps_ptr = '\0';
+                       if ( rps->ps_ptr - rps->ps_base >= 5 &&
+                           strncmp( rps->ps_base, "{ASN}", 5 ) == 0 ) {
+                               *rps->ps_base = '#';
+                               SAFEMEMCPY( rps->ps_base + 1, rps->ps_base + 5,
+                                       rps->ps_ptr - rps->ps_base - 4 );
+                       }
+                       value = rps->ps_base;
+                       de_t61( value, 0 );
+               }
+
+               /*
+                * ,+="\\\n all go in quotes.  " and \\ need to
+                * be preceeded by \\.
+                */
+
+               if ( strpbrk( value, ",+=\"\\\n" ) != NULL || SPACE( value[0] )
+                   || SPACE( value[max( strlen(value) - 1, (size_t) 0 )] ) ) {
+                       char    *p, *t, *tmp;
+                       int     specialcount;
+
+                       ps_print( ps, "\"" );
+
+                       specialcount = 0;
+                       for ( p = value; *p != '\0'; p++ ) {
+                               if ( *p == '"' || *p == '\\' ) {
+                                       specialcount++;
+                               }
+                       }
+                       if ( specialcount > 0 ) {
+                               tmp = smalloc( strlen( value ) + specialcount
+                                   + 1 );
+                               for ( p = value, t = tmp; *p != '\0'; p++ ) {
+                                       switch ( *p ) {
+                                       case '"':
+                                       case '\\':
+                                               *t++ = '\\';
+                                               /* FALL THROUGH */
+                                       default:
+                                               *t++ = *p;
+                                       }
+                               }
+                               *t = '\0';
+                               ps_print( ps, tmp );
+                               free( tmp );
+                       } else {
+                               ps_print( ps, value );
+                       }
+
+                       ps_print( ps, "\"" );
+               } else {
+                       ps_print( ps, value );
+               }
+
+               rps->ps_ptr = rps->ps_base;
+       }
+
+       ps_free( rps );
+
+       return( 0 );
+}
+
+void
+ldap_dn_print(
+    PS ps,
+    DN dn,
+    DN base,   /* if non-NULL, subsitute '*' for base (for CLDAP) */
+    int        format
+)
+{
+       DN      tmpdn;
+       int     addstar;
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_dn_print\n", 0, 0, 0 );
+
+       addstar = 0;
+       if ( base != NULLDN && dn != NULL ) {
+               for ( tmpdn = dn; base != NULLDN && tmpdn != NULLDN;
+                   base = base->dn_parent, tmpdn = tmpdn->dn_parent ) {
+                       if ( dn_comp_cmp( base, tmpdn ) == NOTOK ) {
+                               break;
+                       }
+               }
+               if (( addstar = ( base == NULLDN && tmpdn != NULL ))) {
+                       dn = tmpdn;
+               }
+       }
+
+       dn_print_real( ps, dn, format );
+       if ( addstar ) {
+           ps_print( ps, ", *" );
+       }
+}
+
+int
+encode_dn(
+    BerElement *ber,
+    DN         dn,
+    DN         base    /* if non-NULL, subsitute '*' for base (for CLDAP) */
+)
+{
+       PS      ps;
+       int     rc;
+
+       Debug( LDAP_DEBUG_TRACE, "encode_dn\n", 0, 0, 0 );
+
+       if ( (ps = ps_alloc( str_open )) == NULLPS )
+               return( -1 );
+       if ( str_setup( ps, NULLCP, 0, 0 ) == NOTOK )
+               return( -1 );
+
+       ldap_dn_print( ps, dn, base, EDBOUT );
+       *ps->ps_ptr = '\0';
+
+       rc = ber_printf( ber, "s", ps->ps_base );
+
+       ps_free( ps );
+
+       return( rc );
+}
+
+static put_jpeg_value( BerElement *ber, AttributeValue av )
+{
+       PE      pe;
+       int     len;
+
+       Debug( LDAP_DEBUG_TRACE, "put_jpeg_value\n", 0, 0, 0 );
+
+       if (av->av_syntax == AV_FILE)
+               pe = (PE) (((struct file_syntax *) av->av_struct)->
+                   fs_attr->av_struct);
+       else
+               pe = (PE) av->av_struct;
+
+       Debug( LDAP_DEBUG_ARGS,
+           "put_jpeg_value: pe_class %x, pe_form %x, pe_id %x\n",
+           pe->pe_class, pe->pe_form, pe->pe_id );
+
+       if ( (pe->pe_class != PE_CLASS_UNIV && pe->pe_class != PE_CLASS_CONT)
+           || pe->pe_form != PE_FORM_PRIM || pe->pe_id != PE_PRIM_OCTS ) {
+               Debug( LDAP_DEBUG_ANY, "put_jpeg_value: unknown type\n", 0,
+                   0, 0 );
+               return( -1 );
+       }
+
+       if ( pe_pullup( pe ) == NOTOK ) {
+               Debug( LDAP_DEBUG_ANY, "put_jpeg_value: cannot pullup\n", 0,
+                   0, 0 );
+               return( -1 );
+       }
+
+       len = ps_get_abs( pe );
+
+       Debug( LDAP_DEBUG_ARGS, "put_jeg_value: ber_printf %d bytes\n",
+           len, 0, 0 );
+       if ( ber_printf( ber, "o", (char *) pe->pe_prim, len ) == -1 ) {
+               Debug( LDAP_DEBUG_ANY, "put_jpeg_value: ber_printf failed\n",
+                   0, 0, 0 );
+               return( -1 );
+       }
+
+       return( 0 );
+}
+
+static put_audio_value( BerElement *ber, AttributeValue av )
+{
+       struct qbuf     *qb, *p;
+       int             rc, len;
+       char            *buf;
+
+       Debug( LDAP_DEBUG_TRACE, "put_audio_value\n", 0, 0, 0 );
+
+       qb = (struct qbuf *) (((struct file_syntax *)
+           av->av_struct)->fs_attr->av_struct);
+
+       len = 0;
+       for ( p = qb->qb_forw; p != qb; p = p->qb_forw ) {
+               len += p->qb_len;
+       }
+
+       if ( (buf = (char *) malloc( len )) == NULL )
+               return( -1 );
+
+       len = 0;
+       for ( p = qb->qb_forw; p != qb; p = p->qb_forw ) {
+               SAFEMEMCPY( buf + len, p->qb_data, p->qb_len );
+               len += p->qb_len;
+       }
+
+       Debug( LDAP_DEBUG_ARGS, "put_audio_value: ber_printf %d bytes\n",
+           len, 0, 0 );
+
+       if ( (rc = ber_printf( ber, "o", buf, len )) == -1 )
+               Debug( LDAP_DEBUG_ANY, "put_audio_value: ber_printf failed\n",
+                   0, 0, 0 );
+
+       free( buf );
+
+       return( rc );
+}
+
+static put_photo_value( BerElement *ber, AttributeValue av )
+{
+       PE              pe;
+       PS              ps;
+       int             len;
+       char            *faxparamset = "\000\300\000\000";
+       BerElement      *phber;
+
+       Debug( LDAP_DEBUG_TRACE, "put_photo_value\n", 0, 0, 0 );
+
+       pe = (PE) (((struct file_syntax *) av->av_struct)->fs_attr->av_struct);
+
+       /* old bit string-like format - only handle this for now */
+       if ( pe->pe_class == PE_CLASS_UNIV && pe->pe_form == PE_FORM_PRIM
+           && pe->pe_id == PE_PRIM_BITS ) {
+               len = ps_get_abs( pe );
+               Debug( LDAP_DEBUG_ARGS, "put_photo_val: ber_printf %d bytes\n",
+                   len, 0, 0 );
+               if (( phber = der_alloc()) == NULLBER ) {
+                       Debug( LDAP_DEBUG_ANY, "der_alloc failed\n", 0, 0, 0 );
+                       return( -1 );
+               }
+               if ( ber_printf( phber, "t{[tB]{B}}", 0xA3, 0x81, faxparamset,
+                   31, (char *)pe->pe_prim, len * 8 ) == -1 ) {
+                       Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
+                       ber_free( phber, 1 );
+                       return( -1 );
+               }
+               if ( ber_printf( ber, "o", phber->ber_buf, phber->ber_ptr
+                   - phber->ber_buf ) == -1 ) {
+                       Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
+                       ber_free( phber, 1 );
+                       return( -1 );
+               }
+               ber_free( phber, 1 );
+       } else {
+               /*
+                * try just writing this into a PS and sending it along
+                */
+               ps_len_strategy = PS_LEN_LONG;
+               if ( (ps = ps_alloc( str_open )) == NULLPS )
+                       return( -1 );
+               if ( str_setup( ps, NULLCP, 0, 0 ) == NOTOK ||
+                   pe2ps( ps, pe ) == NOTOK ) {
+                       ps_free( ps );
+                       return( -1 );
+               }
+
+               len = ps->ps_ptr - ps->ps_base;
+               Debug( LDAP_DEBUG_ARGS, "put_photo_val: ber_printf %d bytes\n",
+                   len, 0, 0 );
+               if ( ber_printf( ber, "o", (char *) ps->ps_base, len ) == -1 ) {
+                       Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
+                       ps_free( ps );
+                       return( -1 );
+               }
+               ps_free( ps );
+       }
+
+       return( 0 );
+}
+
+static put_values(
+    BerElement *ber,
+    PS         ps,
+    short      syntax,
+    AV_Sequence        vals
+)
+{
+       AV_Sequence     av;
+       char            *strvalue;
+
+       Debug( LDAP_DEBUG_TRACE, "put_values\n", 0, 0, 0 );
+
+       for ( av = vals; av != NULLAV; av = av->avseq_next ) {
+               if ( syntax == ldap_jpeg_syntax ||
+                   syntax == ldap_jpeg_nonfile_syntax ) {
+                       if ( put_jpeg_value( ber, &av->avseq_av ) == -1 )
+                               return( -1 );
+               } else if ( syntax == ldap_photo_syntax ) {
+                       if ( put_photo_value( ber, &av->avseq_av ) == -1 )
+                               return( -1 );
+               } else if ( syntax == ldap_audio_syntax ) {
+                       if ( put_audio_value( ber, &av->avseq_av ) == -1 )
+                               return( -1 );
+               } else if ( syntax == ldap_dn_syntax ) {
+                       if ( encode_dn( ber, (DN) av->avseq_av.av_struct,
+                           NULLDN ) == -1 )
+                               return( -1 );
+               } else if ( syntax > AV_WRITE_FILE ) {
+                       struct file_syntax      *fsyntax;
+
+                       fsyntax = (struct file_syntax *) av->avseq_av.av_struct;
+
+                       ps->ps_ptr = ps->ps_base;
+                       AttrV_print( ps, fsyntax->fs_attr, EDBOUT );
+                       *ps->ps_ptr = '\0';
+
+                       if ( ber_printf( ber, "o", ps->ps_base,
+                           ps->ps_ptr - ps->ps_base ) == -1 )
+                               return( -1 );
+               } else {
+                       ps->ps_ptr = ps->ps_base;
+                       AttrV_print( ps, &av->avseq_av, EDBOUT );
+                       *ps->ps_ptr = '\0';
+                       de_t61( ps->ps_base, 0 );
+
+                       if ( syntax_is_string( av->avseq_av.av_syntax ) &&
+                               *ps->ps_base == '\0' ) {
+                           /*
+                            * If this is a zero-length string, make it
+                            * a single blank (this is gross, but it works
+                            * around a dsap library bug).
+                            */
+                           Debug( LDAP_DEBUG_ANY,
+                                   "put_values: replaced zero-length string with single blank\n", 0, 0, 0 );
+                           strvalue = " ";
+                       } else {
+                           strvalue = ps->ps_base;
+                       }
+                       if ( ber_printf( ber, "s", strvalue ) == -1 )
+                               return( -1 );
+               }
+       }
+
+       return( 0 );
+}
+
+int
+encode_attrs( BerElement *ber, Attr_Sequence as )
+{
+       PS              ps;
+#ifdef COMPAT20
+       extern int      ldap_compat;
+#endif
+
+       Debug( LDAP_DEBUG_TRACE, "encode_attrs\n", 0, 0, 0 );
+
+       if ( (ps = ps_alloc( str_open )) == NULLPS )
+               return( -1 );
+       if ( str_setup( ps, NULLCP, 0, 0 ) == NOTOK )
+               return( -1 );
+
+#ifdef COMPAT20
+       if ( ber_printf( ber, "t{", ldap_compat == 20 ? OLD_LBER_SEQUENCE :
+           LBER_SEQUENCE ) == -1 ) {
+#else
+       if ( ber_printf( ber, "{" ) == -1 ) {
+#endif
+               ps_free( ps );
+               return( -1 );
+       }
+
+       while ( as != NULLATTR ) {
+               ps->ps_ptr = ps->ps_base;
+               AttrT_print( ps, as->attr_type, EDBOUT );
+               *ps->ps_ptr = '\0';
+
+#ifdef COMPAT20
+               if ( ber_printf( ber, "t{st[", ldap_compat == 20 ?
+                   OLD_LBER_SEQUENCE : LBER_SEQUENCE, ps->ps_base,
+                   ldap_compat == 20 ? OLD_LBER_SET : LBER_SET ) == -1 ) {
+#else
+               if ( ber_printf( ber, "{s[", ps->ps_base ) == -1 ) {
+#endif
+                       ps_free( ps );
+                       return( -1 );
+               }
+
+               put_values( ber, ps, as->attr_type->oa_syntax, as->attr_value );
+
+               if ( ber_printf( ber, "]}" ) == -1 ) {
+                       ps_free( ps );
+                       return( -1 );
+               }
+
+               as = as->attr_link;
+       }
+       ps_free( ps );
+
+       if ( ber_printf( ber, "}" ) == -1 )
+               return( -1 );
+
+       return( 0 );
+}
+
+static void
+trim_trailing_spaces( char *s )
+{
+       char    *t;
+
+       t = s + strlen( s );
+       while ( --t > s ) {
+               if ( SPACE( *t ) ) {
+                       *t = '\0';
+               } else {
+                       break;
+               }
+       }
+}
+
+DN ldap_str2dn( char *str )
+{
+       DN              dn, save;
+       RDN             rdn, newrdn, tmprdn;
+       AttributeType   at;
+       AttributeValue  av;
+       char            *type, *value, *savestr;
+       int             morerdncomps;
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_str2dn\n", 0, 0, 0 );
+
+       savestr = str = strdup( str );
+       dn = NULLDN;
+       do {
+               char    *r;
+               int     state;
+
+               rdn = NULLRDN;
+               morerdncomps = 1;
+               do {
+                       /* get the type */
+                       while ( *str == ' ' || *str == '\n' )
+                               str++;
+                       type = str;
+                       while ( *str != '\0' && *str != '=' )
+                               str++;
+                       if ( *str == '\0' ) {
+                               free( savestr );
+                               Debug( LDAP_DEBUG_ARGS, "no =\n", 0, 0, 0 );
+                               return( NULLDN );
+                       }
+                       *str++ = '\0';
+                       if ( strncmp( type, "OID.", 4 ) == 0 )
+                               type += 4;
+
+#define BEGINVALUE     1
+#define INVALUE                2
+#define INQUOTE        3
+#define ENDVALUE       4
+                       if ( *str == '#' ) {
+                               ++str;
+                       }
+                       r = value = str;
+                       state = BEGINVALUE;
+                       /* break or return out */
+                       while ( state != ENDVALUE ) {
+                               switch ( *str ) {
+                               case '"':
+                                       if ( state == BEGINVALUE ) {
+                                               state = INQUOTE;
+                                               str++;
+                                       } else if ( state == INQUOTE ) {
+                                               state = ENDVALUE;
+                                               str++;
+                                       } else {
+                                               free( savestr );
+                                               Debug( LDAP_DEBUG_ARGS,
+                                                   "quote state %d\n", state,
+                                                   0, 0 );
+                                               return( NULLDN );
+                                       }
+                                       break;
+
+                               case ',':
+                               case ';':
+                               case '+':
+                                       if ( state == INVALUE ) {
+                                               state = ENDVALUE;
+                                       } else if ( state == INQUOTE ) {
+                                               *r++ = *str++;
+                                       } else {
+                                               free( savestr );
+                                               Debug( LDAP_DEBUG_ARGS,
+                                                   "comma state %d\n", state,
+                                                   0, 0 );
+                                               return( NULLDN );
+                                       }
+                                       break;
+
+                               case ' ':
+                               case '\n':
+                                       if ( state == BEGINVALUE ) {
+                                               str++;
+                                       } else {
+                                               *r++ = *str++;
+                                       }
+                                       break;
+
+                               case '\\':
+                                       str++;
+                                       *r++ = *str++;
+                                       break;
+
+                               case '\0':
+                                       state = ENDVALUE;
+                                       break;
+
+                               default:
+                                       if ( state == BEGINVALUE )
+                                               state = INVALUE;
+                                       *r++ = *str++;
+                                       break;
+                               }
+                       }
+
+                       while ( SPACE( *str ) )
+                               str++;
+                       if ( *str == '+' ) {
+                               morerdncomps = 1;
+                               str++;
+                       } else {
+                               morerdncomps = 0;
+                               if ( SEPARATOR( *str ) )
+                                       str++;
+                       }
+                       *r = '\0';
+
+                       /* type */
+                       trim_trailing_spaces( type );
+                       if ( (at = str2AttrT( type )) == NULLAttrT ) {
+                               dn_free( dn );
+                               free( savestr );
+                               Debug( LDAP_DEBUG_ARGS, "bad type (%s)\n",
+                                   type, 0, 0 );
+                               return( NULLDN ); /* LDAP_UNDEFINED_TYPE */
+                       }
+                       /* value */
+                       if ( (av = ldap_str2AttrV( value, at->oa_syntax ))
+                           == NULLAttrV ) {
+                               dn_free( dn );
+                               free( savestr );
+                               Debug( LDAP_DEBUG_ARGS, "bad val\n", 0, 0, 0 );
+                               return( NULLDN ); /* LDAP_INVALID_SYNTAX */
+                       }
+                       /* make the rdn */
+                       newrdn = rdn_comp_new( at, av );
+
+                       /* add it to the list */
+                       for ( tmprdn = rdn; tmprdn != NULLRDN &&
+                           tmprdn->rdn_next != NULLRDN;
+                           tmprdn = tmprdn->rdn_next )
+                               ;       /* NULL */
+                       if ( tmprdn != NULLRDN )
+                               tmprdn->rdn_next = newrdn;
+                       else
+                               rdn = newrdn;
+
+                       AttrV_free( av );
+               } while ( morerdncomps );
+
+               save = dn;
+               dn = dn_comp_new( rdn );
+               dn->dn_parent = save;
+       } while ( str != NULL && *str != '\0' );
+
+       free( savestr );
+       Debug( LDAP_DEBUG_TRACE, "ldap_str2dn OK\n", 0, 0, 0 );
+       return( dn );
+}
+
+#define T61    "{T.61}"
+#define T61LEN 6
+
+static void de_t61( char *s, int t61mark )
+{
+       char    *next = s;
+       int     c, hex;
+
+       while ( *s ) {
+               switch ( *s ) {
+               case '{' :
+                       if ( strncasecmp( s, T61, T61LEN) == 0 ) {
+                               s += T61LEN;
+                               if ( t61mark )
+                                       *next++ = '@';
+                       } else {
+                               *next++ = *s++;
+                       }
+                       break;
+
+               case '\\':
+                       c = *(s + 1);
+                       if ( c == '\n' ) {
+                               s += 2;
+                               if ( *s == '\t' )
+                                       s++;
+                               break;
+                       }
+                        if ( c == '\\' ) {
+                            /* reverse solidus character itself */
+                            s += 2;
+                            *next++ = c;
+                            break;
+                        }
+                       if ( isdigit( c ) )
+                               hex = c - '0';
+                       else if ( c >= 'A' && c <= 'F' )
+                               hex = c - 'A' + 10;
+                       else if ( c >= 'a' && c <= 'f' )
+                               hex = c - 'a' + 10;
+                       else {
+                               *next++ = *s++;
+                               break;
+                       }
+                       hex <<= 4;
+                       c = *(s + 2);
+                       if ( isdigit( c ) )
+                               hex += c - '0';
+                       else if ( c >= 'A' && c <= 'F' )
+                               hex += c - 'A' + 10;
+                       else if ( c >= 'a' && c <= 'f' )
+                               hex += c - 'a' + 10;
+                       else {
+                               *next++ = *s++;
+                               *next++ = *s++;
+                               break;
+                       }
+
+                       *next++ = hex;
+                       s += 3;
+                       break;
+
+               default:
+                       *next++ = *s++;
+                       break;
+               }
+       }
+       *next = '\0';
+}
+
+
+static PE
+bv_asn2pe( struct berval *bv )
+{
+       PS      ps;
+       PE      pe;
+
+       if (( ps = ps_alloc(str_open)) == NULLPS || str_setup( ps, bv->bv_val,
+           bv->bv_len, 0 ) == NOTOK ) {
+               Debug( LDAP_DEBUG_TRACE, "bv_asn2pe: ps_alloc failed\n",
+                   0, 0, 0 );
+               return( NULLPE );
+       }
+
+       pe = ps2pe( ps );
+       if ( ps->ps_errno != PS_ERR_NONE ) {
+               Debug( LDAP_DEBUG_TRACE, "bv_asn2pe: ps2pe failed %s\n",
+                   ps_error(ps->ps_errno), 0, 0 );
+               if ( pe != NULLPE ) {
+                       pe_free( pe );
+               }
+               return( NULLPE );
+       }
+
+       return( pe );
+}
+
+
+AttributeValue
+bv_octet2AttrV( struct berval *bv )
+{
+       AttributeValue  av;
+
+       av = AttrV_alloc();
+       if ( av == NULLAttrV ) {
+               return( NULLAttrV );
+       }
+
+       if (( av->av_struct = (caddr_t) str2prim( bv->bv_val, bv->bv_len,
+           PE_CLASS_UNIV, PE_PRIM_OCTS )) == NULL ) {
+               free((char *)av );
+               return( NULLAttrV );
+       }
+
+       av->av_syntax = 0;
+       return( av );
+}
+
+
+AttributeValue
+bv_asn2AttrV( struct berval *bv )
+{
+       AttributeValue  av;
+
+       av = AttrV_alloc();
+       if ( av == NULLAttrV ) {
+               return( NULLAttrV );
+       }
+
+       if (( av->av_struct = (caddr_t) bv_asn2pe( bv )) == NULL ) {
+               free((char *)av );
+               return( NULLAttrV );
+       }
+
+       av->av_syntax = 0;
+       return( av );
+}
+
+
+AttributeValue
+ldap_strdn2AttrV( char *dnstr )
+{
+       DN              dn;
+       AttributeValue  av;
+
+       if (( dn = ldap_str2dn( dnstr )) == NULL ) {
+               return( NULLAttrV );
+       }
+
+       av = AttrV_alloc();
+       if ( av == NULLAttrV ) {
+               dn_free( dn );
+               return( NULLAttrV );
+       }
+
+       av->av_struct = (caddr_t)dn; 
+       av->av_syntax = ldap_dn_syntax;
+       return( av );
+}
+
+RDN
+ldap_str2rdn( char *rdnstr )
+{
+       DN      dn;
+       RDN     rdn;
+
+       if ( (dn = ldap_str2dn( rdnstr )) == NULL ) {
+               return( NULL );
+       }
+
+       if ( (rdn = rdn_cpy( dn->dn_rdn )) == NULL ) {
+               return( NULL );
+       }
+
+       dn_free( dn );
+
+       return( rdn );
+}
+
+AttributeValue
+ldap_str_at2AttrV( char *str, AttributeType type )
+{
+       char            *s, *res, *r;
+       AttributeValue  str_at2AttrV();
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_str_at2AttrV str (%s) type (%s)\n", str,
+           type->oa_ot.ot_name, 0 );
+
+       if ( type->oa_syntax == ldap_rts_cred_syntax ||
+           type->oa_syntax == ldap_mtai_syntax ||
+           type->oa_syntax == ldap_acl_syntax ||
+           type->oa_syntax == ldap_mailbox_syntax ||
+           type->oa_syntax == ldap_caseignorelist_syntax ||
+           type->oa_syntax == ldap_certif_syntax ||
+           type->oa_syntax == ldap_iattr_syntax ||
+           type->oa_syntax == ldap_telex_syntax ||
+           type->oa_syntax == ldap_deliverymethod_syntax ||
+           type->oa_syntax == ldap_facsimileTelephoneNumber_syntax ||
+           type->oa_syntax == ldap_presentationAddress_syntax ||
+           type->oa_syntax == ldap_teletexTerminalIdentifier_syntax ||
+           type->oa_syntax == ldap_searchGuide_syntax ||
+            type->oa_syntax == ldap_dLSubmitPermission_syntax ||
+           type->oa_syntax == ldap_rtl_syntax ) {
+               res = str;
+       } else {
+               res = (char *) malloc( max( 2 * strlen( str ), (size_t) 10 ) );
+
+               r = res;
+               for ( s = str; *s; s++ ) {
+                       switch ( *s ) {
+                       case '&':
+                       case '#':
+                       case '$':
+                       case '%':
+                       case '@':
+                       case '\\':
+                               sprintf( r, "\\%02x", *s & 0xff );
+                               r += 3;
+                               break;
+
+                       default:
+                               *r++ = *s;
+                       }
+               }
+               *r = '\0';
+       }
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_str_at2AttrV returning (%s)\n", res,
+           0, 0 );
+
+       return( str_at2AttrV( res, type ) );
+}
+
+AttributeValue
+ldap_str2AttrV( char *value, short syntax )
+{
+       if ( syntax == ldap_dn_syntax ) {
+               return( ldap_strdn2AttrV( value ) );
+       } else {
+               return( str2AttrV( value, syntax ) );
+       }
+}
+
+
+static int
+syntax_is_string( short syntax )
+{
+/*
+ * this code depends on the order and nunber of strings that are in
+ * the ISODE file lib/syntax/x500/string.c 
+ */
+    return ( syntax >= ldap_caseexactstring_syntax &&
+           syntax <= ldap_caseexactstring_syntax + 8 );
+}
diff --git a/servers/ldapd/util.c b/servers/ldapd/util.c
new file mode 100644 (file)
index 0000000..27ecea9
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <quipu/commonarg.h>
+#include <quipu/ds_error.h>
+#include "lber.h"
+#include "ldap.h"
+#include "common.h"
+
+/*
+ * Print arbitrary stuff, for debugging.
+ */
+
+
+#define BPLEN  48
+
+void
+bprint( char *data, int len )
+{
+    static char        hexdig[] = "0123456789abcdef";
+    char       out[ BPLEN ];
+    int                i = 0;
+
+    (void) memset( out, 0, BPLEN );
+    for ( ;; ) {
+       if ( len < 1 ) {
+           printf( "\t%s\n", ( i == 0 ) ? "(end)" : out );
+           break;
+       }
+
+       if ( isgraph( (unsigned char)*data )) {
+           out[ i ] = ' ';
+           out[ i+1 ] = *data;
+       } else {
+           out[ i ] = hexdig[ ( *data & 0xf0 ) >> 4 ];
+           out[ i+1 ] = hexdig[ *data & 0x0f ];
+       }
+       i += 2;
+       len--;
+       data++;
+
+       if ( i > BPLEN - 2 ) {
+           printf( "\t%s\n", out );
+           (void) memset( out, 0, BPLEN );
+           i = 0;
+           continue;
+       }
+       out[ i++ ] = ' ';
+    }
+}
+
+void charlist_free( char **cl )
+{
+       int     i;
+
+       if ( cl == NULL )
+               return;
+
+       for ( i = 0; cl[i] != NULL; i++ )
+               free( cl[i] );
+       free( (char *) cl );
+}
+
+int
+get_ava( BerElement *ber, AVA *tava )
+{
+       char                    *type, *value;
+       extern short            ldap_dn_syntax;
+
+       Debug( LDAP_DEBUG_TRACE, "get_ava\n", 0, 0, 0 );
+
+       /*
+        * An AVA looks like this:
+        *      AttributeValueAsertion ::= SEQUENCE {
+        *              attributeType   AttributeType,
+        *              attributeValue  AttributeValue
+        *      }
+        */
+
+       if ( ber_scanf( ber, "{aa}", &type, &value ) == LBER_ERROR )
+               return( LDAP_PROTOCOL_ERROR );
+
+       if ( (tava->ava_type = str2AttrT( type )) == NULLAttrT ) {
+               free( type );
+               free( value );
+               return( LDAP_UNDEFINED_TYPE );
+       }
+
+       if ( (tava->ava_value = ldap_str2AttrV( value,
+           tava->ava_type->oa_syntax )) == NULLAttrV ) {
+               free( type );
+               free( value );
+               return( LDAP_INVALID_SYNTAX );
+       }
+
+       free( type );
+       free( value );
+
+       return( 0 );
+}
+
+int
+chase_referral(
+    Sockbuf            *clientsb,
+    struct msg         *m,
+    struct DSError     *err,
+    char               **matched
+)
+{
+       ContinuationRef         cr;
+       struct access_point     *ap;
+       int                     rc, bound;
+       struct conn             *save, *dup, *found;
+       struct PSAPaddr         *psap_cpy();
+
+       Debug( LDAP_DEBUG_TRACE, "chase_referral\n", 0, 0, 0 );
+
+       save = m->m_conn;
+       dup = conn_dup( m->m_conn );
+       m->m_conn = dup;
+       m->m_conn->c_ad = -1;
+
+       /* for each dsa candidate */
+       rc = LDAP_OTHER;
+       for ( cr = err->ERR_REFERRAL.DSE_ref_candidates;
+           cr != NULLCONTINUATIONREF; cr = cr->cr_next ) {
+
+               /* for each access point listed for the dsa */
+               for ( ap = cr->cr_accesspoints; ap != NULLACCESSPOINT;
+                   ap = ap->ap_next ) {
+#ifdef LDAP_DEBUG
+                       if ( ldap_debug & LDAP_DEBUG_ARGS ) {
+                               char    *str;
+
+                               str = paddr2str( ap->ap_address, NULLNA );
+                               fprintf( stderr, "Referring to (%s)...\n",
+                                   str );
+                       }
+#endif
+
+                       if ( m->m_conn->c_paddr )
+                               free( (char *) m->m_conn->c_paddr );
+                       m->m_conn->c_paddr = psap_cpy( ap->ap_address );
+
+                       if ( (found = conn_find( m->m_conn )) != NULL ) {
+                               conn_free( m->m_conn );
+                               m->m_conn = found;
+                               m->m_conn->c_refcnt++;
+                               conn_free( save );
+                               return( LDAP_SUCCESS );
+                       }
+
+                       rc = do_bind_real( m->m_conn, &bound, matched );
+
+                       if ( rc == LDAP_SUCCESS ) {
+                               conn_free( save );
+                               conn_add( m->m_conn );
+                               return( LDAP_SUCCESS );
+                       }
+               }
+
+       }
+
+       /* so the conn can be found and freed later */
+       conn_free( m->m_conn );
+       m->m_conn = save;
+
+       return( rc );
+}
diff --git a/servers/slapd/Make-template b/servers/slapd/Make-template
new file mode 100644 (file)
index 0000000..d3a5f49
--- /dev/null
@@ -0,0 +1,266 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1995 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       Stand alone LDAP server daemon makefile
+#
+#-----------------------------------------------------------------------------
+LDAPSRC        = ../..
+HDIR   = $(LDAPSRC)/include
+LDIR   = $(LDAPSRC)/libraries
+VERSIONFILE = $(LDAPSRC)/build/version
+
+SRCS   = main.c daemon.c connection.c search.c filter.c add.c charray.c \
+               attr.c entry.c config.c backend.c result.c operation.c \
+               dn.c compare.c modify.c delete.c modrdn.c ch_malloc.c \
+               value.c ava.c bind.c unbind.c abandon.c filterentry.c \
+               phonetic.c regex.c acl.c str2filter.c aclparse.c init.c \
+               detach.c strdup.c tempnam.c repl.c lock.c \
+               schema.c schemaparse.c monitor.c configinfo.c
+OBJS   = main.o daemon.o connection.o search.o filter.o add.o charray.o \
+               attr.o entry.o config.o backend.o result.o operation.o \
+               dn.o compare.o modify.o delete.o modrdn.o ch_malloc.o \
+               value.o ava.o bind.o unbind.o abandon.o filterentry.o \
+               phonetic.o regex.o acl.o str2filter.o aclparse.o init.o \
+               detach.o strdup.o tempnam.o repl.o lock.o \
+               schema.o schemaparse.o monitor.o configinfo.o
+
+INCLUDES= -I. -I$(HDIR) $(KRBINCLUDEFLAG)
+DEFINES = $(DEFS) $(SERVERDEFS)
+CFLAGS = $(INCLUDES) $(THREADSINCLUDE) $(DEFINES) $(ACFLAGS) $(THREADS)
+LDFLAGS        = -L$(LDIR) $(KRBLIBFLAG)
+LIBS   = $(KRBLIBS) -llber -lldbm -lavl -llthread -lldif $(THREADSLIB) \
+               $(LDBMLIB) $(ALIBS)
+
+all: FORCE
+       @if [ -z "$(MAKESLAPD)" ]; then \
+               echo "uncomment the MAKESLAPD line in Make-common to make slapd"; \
+               exit 0; \
+       else \
+               echo; \
+               $(MAKE) $(MFLAGS) backendslib; \
+               $(MAKE) $(MFLAGS) slapd; \
+               (cd tools; $(MAKE) $(MFLAGS) all); \
+       fi
+
+backendslib:   FORCE
+       @for i in back-*; do \
+               if [ -d $$i ]; then \
+                       echo; echo "  cd $$i; $(MAKE) $(MFLAGS) all"; \
+                       ( cd $$i; $(MAKE) $(MFLAGS) all ); \
+               fi; \
+       done; \
+       echo; \
+       $(MAKE) $(MFLAGS) libbackends.a
+
+libbackends.a: .backend
+       @$(RM) -r tmp
+       @$(MKDIR) tmp
+       @-for i in back-*/*.a; do \
+               ( \
+                 cd tmp; \
+                 $(AR) x ../$$i; \
+                 pre=`echo $$i | sed -e 's/\/.*$$//' -e 's/back-//'`; \
+                 for j in *.o; do \
+                       mv $$j $${pre}$$j; \
+                 done; \
+                 $(AR) ruv libbackends.a *.o 2>&1 | grep -v truncated; \
+                 $(RM) *.o __.SYMDEF; \
+                 echo "added backend library $$i"; \
+               ); \
+       done
+       @mv -f tmp/libbackends.a ./libbackends.a
+       @$(RM) -r tmp
+       @if [ ! -z "$(RANLIB)" ]; then \
+               $(RANLIB) libbackends.a; \
+       fi
+       @ls -l libbackends.a
+
+slapd: version.o
+       $(CC) $(ALDFLAGS) -o slapd $(OBJS) version.o libbackends.a \
+               $(LDFLAGS) $(LIBS)
+slapd.pure: version.o
+       purify $(CC) $(ALDFLAGS) -o slapd.pure $(OBJS) version.o libbackends.a \
+               $(LDFLAGS) $(LIBS)
+
+version.c: libbackends.a $(OBJS) $(LDIR)/liblber/liblber.a \
+               $(LDIR)/libldbm/libldbm.a $(LDIR)/liblthread/liblthread.a \
+               $(LDIR)/libavl/libavl.a $(LDIR)/libldif/libldif.a
+       $(RM) $@
+       (u=$${USER-root} v=`$(CAT) $(VERSIONFILE)` d=`$(PWD)` h=`$(HOSTNAME)` \
+       t=`$(DATE)`; $(SED) -e "s|%WHEN%|$${t}|" \
+       -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+       -e "s|%VERSION%|$${v}|" \
+       < Version.c > $@)
+
+install: all $(ETCDIR) $(ETCDIR)/slapd $(ETCDIR)/slapd.conf \
+               $(ETCDIR)/slapd.at.conf $(ETCDIR)/slapd.oc.conf \
+               install-tools
+
+$(ETCDIR)/slapd:       slapd
+       $(INSTALL) $(INSTALLFLAGS) -m 755 slapd $(ETCDIR)
+
+$(ETCDIR)/slapd.conf:  slapd.conf
+       $(SED) -e 's;%ETCDIR%;$(RUNTIMEETCDIR);' slapd.conf > /tmp/slapd.$$
+       -$(MV) $(ETCDIR)/slapd.conf $(ETCDIR)/slapd.conf-
+       $(INSTALL) $(INSTALLFLAGS) -m 644 /tmp/slapd.$$ $(ETCDIR)/slapd.conf
+       $(RM) -f /tmp/slapd.$$
+
+$(ETCDIR)/slapd.at.conf:       slapd.at.conf
+       -$(MV) $(ETCDIR)/slapd.at.conf $(ETCDIR)/slapd.at.conf-
+       $(INSTALL) $(INSTALLFLAGS) -m 644 slapd.at.conf $(ETCDIR)
+
+$(ETCDIR)/slapd.oc.conf:       slapd.oc.conf
+       -$(MV) $(ETCDIR)/slapd.oc.conf $(ETCDIR)/slapd.oc.conf-
+       $(INSTALL) $(INSTALLFLAGS) -m 644 slapd.oc.conf $(ETCDIR)
+
+install-tools: FORCE
+       (cd tools; $(MAKE) $(MFLAGS) install)
+
+lint:  FORCE
+       $(LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+5lint: FORCE
+       $(5LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+clean: FORCE
+       @echo "making clean in `$(PWD)`"
+       $(RM) slapd slapd.pure *.o core a.out version.c libbackends.a .backend
+       @for i in back-* tools; do \
+               if [ -d $$i -a $$i != "RCS" ]; then \
+               echo; echo "  cd $$i; $(MAKE) $(MFLAGS) clean"; \
+               ( cd $$i; $(MAKE) $(MFLAGS) clean ); \
+               fi; \
+       done
+
+depend:        FORCE
+       $(MKDEP) $(INCLUDES) $(DEFINES) $(SRCS)
+       @for i in back-* tools; do \
+               if [ -d $$i -a $$i != "RCS" ]; then \
+               echo; echo "  cd $$i; $(MAKE) $(MFLAGS) depend"; \
+               ( cd $$i; $(MAKE) $(MFLAGS) depend ); \
+               fi; \
+       done
+
+
+links:
+       @echo "making links in `$(PWD)`"
+       @$(LN) .src/*.[ch] .src/*.conf .
+       @touch .backend
+       @for i in .src/back-* .src/tools; do \
+           if [ -d $$i -a $$i != ".src/RCS" ]; then \
+               d=`basename $$i`; \
+               ( $(MKDIR) $$d; cd $$d; $(LN) ../.src/$$d .src; \
+                 $(LN) ../.src/$$d/Make-template . ; \
+                 $(MAKE) $(MFLAGS) MKDIR="$(MKDIR)" LN="$(LN)" \
+                   -f Make-template links ) ; \
+           fi; \
+       done; 
+
+
+# DO NOT DELETE THIS LINE -- mkdep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+main.o: main.c ../../include/portable.h slap.h ../../include/avl.h
+main.o: ../../include/lber.h ../../include/ldap.h ../../include/lthread.h
+main.o: ../../include/ldif.h ../../include/ldapconfig.h
+daemon.o: daemon.c slap.h ../../include/avl.h ../../include/lber.h
+daemon.o: ../../include/ldap.h ../../include/lthread.h ../../include/ldif.h
+daemon.o: ../../include/portable.h ../../include/ldapconfig.h
+connection.o: connection.c ../../include/portable.h slap.h ../../include/avl.h
+connection.o: ../../include/lber.h ../../include/ldap.h ../../include/lthread.h
+connection.o: ../../include/ldif.h
+search.o: search.c slap.h ../../include/avl.h ../../include/lber.h
+search.o: ../../include/ldap.h ../../include/lthread.h ../../include/ldif.h
+search.o: ../../include/ldapconfig.h
+filter.o: filter.c slap.h ../../include/avl.h ../../include/lber.h
+filter.o: ../../include/ldap.h ../../include/lthread.h ../../include/ldif.h
+add.o: add.c slap.h ../../include/avl.h ../../include/lber.h
+add.o: ../../include/ldap.h ../../include/lthread.h ../../include/ldif.h
+charray.o: charray.c slap.h ../../include/avl.h ../../include/lber.h
+charray.o: ../../include/ldap.h ../../include/lthread.h ../../include/ldif.h
+attr.o: attr.c ../../include/portable.h slap.h ../../include/avl.h
+attr.o: ../../include/lber.h ../../include/ldap.h ../../include/lthread.h
+attr.o: ../../include/ldif.h
+entry.o: entry.c slap.h ../../include/avl.h ../../include/lber.h
+entry.o: ../../include/ldap.h ../../include/lthread.h ../../include/ldif.h
+config.o: config.c slap.h ../../include/avl.h ../../include/lber.h
+config.o: ../../include/ldap.h ../../include/lthread.h ../../include/ldif.h
+config.o: ../../include/ldapconfig.h
+backend.o: backend.c slap.h ../../include/avl.h ../../include/lber.h
+backend.o: ../../include/ldap.h ../../include/lthread.h ../../include/ldif.h
+result.o: result.c ../../include/portable.h slap.h ../../include/avl.h
+result.o: ../../include/lber.h ../../include/ldap.h ../../include/lthread.h
+result.o: ../../include/ldif.h
+operation.o: operation.c slap.h ../../include/avl.h ../../include/lber.h
+operation.o: ../../include/ldap.h ../../include/lthread.h ../../include/ldif.h
+dn.o: dn.c ../../include/portable.h slap.h ../../include/avl.h
+dn.o: ../../include/lber.h ../../include/ldap.h ../../include/lthread.h
+dn.o: ../../include/ldif.h
+compare.o: compare.c slap.h ../../include/avl.h ../../include/lber.h
+compare.o: ../../include/ldap.h ../../include/lthread.h ../../include/ldif.h
+modify.o: modify.c slap.h ../../include/avl.h ../../include/lber.h
+modify.o: ../../include/ldap.h ../../include/lthread.h ../../include/ldif.h
+delete.o: delete.c slap.h ../../include/avl.h ../../include/lber.h
+delete.o: ../../include/ldap.h ../../include/lthread.h ../../include/ldif.h
+modrdn.o: modrdn.c slap.h ../../include/avl.h ../../include/lber.h
+modrdn.o: ../../include/ldap.h ../../include/lthread.h ../../include/ldif.h
+ch_malloc.o: ch_malloc.c slap.h ../../include/avl.h ../../include/lber.h
+ch_malloc.o: ../../include/ldap.h ../../include/lthread.h ../../include/ldif.h
+value.o: value.c ../../include/portable.h slap.h ../../include/avl.h
+value.o: ../../include/lber.h ../../include/ldap.h ../../include/lthread.h
+value.o: ../../include/ldif.h
+ava.o: ava.c slap.h ../../include/avl.h ../../include/lber.h
+ava.o: ../../include/ldap.h ../../include/lthread.h ../../include/ldif.h
+bind.o: bind.c slap.h ../../include/avl.h ../../include/lber.h
+bind.o: ../../include/ldap.h ../../include/lthread.h ../../include/ldif.h
+unbind.o: unbind.c slap.h ../../include/avl.h ../../include/lber.h
+unbind.o: ../../include/ldap.h ../../include/lthread.h ../../include/ldif.h
+abandon.o: abandon.c slap.h ../../include/avl.h ../../include/lber.h
+abandon.o: ../../include/ldap.h ../../include/lthread.h ../../include/ldif.h
+filterentry.o: filterentry.c ../../include/regex.h slap.h ../../include/avl.h
+filterentry.o: ../../include/lber.h ../../include/ldap.h
+filterentry.o: ../../include/lthread.h ../../include/ldif.h
+phonetic.o: phonetic.c ../../include/portable.h slap.h ../../include/avl.h
+phonetic.o: ../../include/lber.h ../../include/ldap.h ../../include/lthread.h
+phonetic.o: ../../include/ldif.h
+regex.o: regex.c ../../include/portable.h
+acl.o: acl.c ../../include/regex.h slap.h ../../include/avl.h
+acl.o: ../../include/lber.h ../../include/ldap.h ../../include/lthread.h
+acl.o: ../../include/ldif.h
+str2filter.o: str2filter.c slap.h ../../include/avl.h ../../include/lber.h
+str2filter.o: ../../include/ldap.h ../../include/lthread.h ../../include/ldif.h
+aclparse.o: aclparse.c ../../include/regex.h slap.h ../../include/avl.h
+aclparse.o: ../../include/lber.h ../../include/ldap.h ../../include/lthread.h
+aclparse.o: ../../include/ldif.h ../../include/portable.h
+init.o: init.c ../../include/portable.h slap.h ../../include/avl.h
+init.o: ../../include/lber.h ../../include/ldap.h ../../include/lthread.h
+init.o: ../../include/ldif.h
+detach.o: detach.c ../../include/portable.h
+strdup.o: strdup.c
+tempnam.o: tempnam.c
+repl.o: repl.c slap.h ../../include/avl.h ../../include/lber.h
+repl.o: ../../include/ldap.h ../../include/lthread.h ../../include/ldif.h
+lock.o: lock.c ../../include/portable.h slap.h ../../include/avl.h
+lock.o: ../../include/lber.h ../../include/ldap.h ../../include/lthread.h
+lock.o: ../../include/ldif.h
+schema.o: schema.c slap.h ../../include/avl.h ../../include/lber.h
+schema.o: ../../include/ldap.h ../../include/lthread.h ../../include/ldif.h
+schemaparse.o: schemaparse.c slap.h ../../include/avl.h ../../include/lber.h
+schemaparse.o: ../../include/ldap.h ../../include/lthread.h
+schemaparse.o: ../../include/ldif.h
+monitor.o: monitor.c slap.h ../../include/avl.h ../../include/lber.h
+monitor.o: ../../include/ldap.h ../../include/lthread.h ../../include/ldif.h
+monitor.o: ../../include/ldapconfig.h
+configinfo.o: configinfo.c slap.h ../../include/avl.h ../../include/lber.h
+configinfo.o: ../../include/ldap.h ../../include/lthread.h ../../include/ldif.h
+configinfo.o: ../../include/ldapconfig.h
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/servers/slapd/Version.c b/servers/slapd/Version.c
new file mode 100644 (file)
index 0000000..176ddef
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 1991 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+char Versionstr[] = "slapd %VERSION% (%WHEN%)\n\t%WHOANDWHERE%\n";
diff --git a/servers/slapd/abandon.c b/servers/slapd/abandon.c
new file mode 100644 (file)
index 0000000..d6f7291
--- /dev/null
@@ -0,0 +1,70 @@
+/* abandon.c - decode and handle an ldap abandon operation */
+
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+
+extern Backend *select_backend();
+
+extern char    *default_referral;
+
+void
+do_abandon(
+    Connection *conn,
+    Operation  *op
+)
+{
+       int             id;
+       Backend         *be;
+       Operation       *o;
+
+       Debug( LDAP_DEBUG_TRACE, "do_abandon\n", 0, 0, 0 );
+
+       /*
+        * Parse the abandon request.  It looks like this:
+        *
+        *      AbandonRequest := MessageID
+        */
+
+       if ( ber_scanf( op->o_ber, "i", &id ) == LBER_ERROR ) {
+               Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0 ,0 );
+               return;
+       }
+
+       Debug( LDAP_DEBUG_ARGS, "do_abandon: id %d\n", id, 0 ,0 );
+
+       /*
+        * find the operation being abandoned and set the o_abandon
+        * flag.  It's up to the backend to periodically check this
+        * flag and abort the operation at a convenient time.
+        */
+
+       pthread_mutex_lock( &conn->c_opsmutex );
+       for ( o = conn->c_ops; o != NULL; o = o->o_next ) {
+               if ( o->o_msgid == id )
+                       break;
+       }
+
+       if ( o != NULL ) {
+               pthread_mutex_lock( &o->o_abandonmutex );
+               o->o_abandon = 1;
+               pthread_mutex_unlock( &o->o_abandonmutex );
+       } else {
+               Debug( LDAP_DEBUG_TRACE, "do_abandon: op not found\n", 0, 0,
+                   0 );
+       }
+       pthread_mutex_unlock( &conn->c_opsmutex );
+}
diff --git a/servers/slapd/acl.c b/servers/slapd/acl.c
new file mode 100644 (file)
index 0000000..6c3b22e
--- /dev/null
@@ -0,0 +1,404 @@
+/* acl.c - routines to parse and check acl's */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#ifdef sunos5
+#include "regexpr.h"
+#else
+#include "regex.h"
+#endif
+#include "slap.h"
+
+extern Attribute       *attr_find();
+extern char            *re_comp();
+extern struct acl      *global_acl;
+extern int             global_default_access;
+extern char            *access2str();
+extern char            *dn_normalize_case();
+
+int            acl_access_allowed();
+int            access_allowed();
+struct acl     *acl_get_applicable();
+
+static int     regex_matches();
+
+extern pthread_mutex_t regex_mutex;
+
+/*
+ * access_allowed - check whether dn is allowed the requested access
+ * to entry e, attribute attr, value val.  if val is null, access to
+ * the whole attribute is assumed (all values).  this routine finds
+ * the applicable acl and calls acl_access_allowed() to make the
+ * decision.
+ *
+ * returns     0       access NOT allowed
+ *             1       access allowed
+ */
+
+int
+access_allowed(
+    Backend            *be,
+    Connection         *conn,
+    Operation          *op,
+    Entry              *e,
+    char               *attr,
+    struct berval      *val,
+    char               *dn,
+    int                        access
+)
+{
+       int             rc;
+       struct acl      *a;
+
+       if ( be == NULL ) {
+               return( 0 );
+       }
+
+       a = acl_get_applicable( be, op, e, attr );
+       rc = acl_access_allowed( a, be, conn, e, val, op, access );
+
+       return( rc );
+}
+
+/*
+ * acl_get_applicable - return the acl applicable to entry e, attribute
+ * attr.  the acl returned is suitable for use in subsequent calls to
+ * acl_access_allowed().
+ */
+
+struct acl *
+acl_get_applicable(
+    Backend            *be,
+    Operation          *op,
+    Entry              *e,
+    char               *attr
+)
+{
+       int             i;
+       struct acl      *a;
+       char            *edn;
+
+       Debug( LDAP_DEBUG_ACL, "=> acl_get: entry (%s) attr (%s)\n", e->e_dn,
+           attr, 0 );
+
+       if ( be_isroot( be, op->o_dn ) ) {
+               Debug( LDAP_DEBUG_ACL,
+                   "<= acl_get: no acl applicable to database root\n", 0, 0,
+                   0 );
+               return( NULL );
+       }
+
+       /* check for a backend-specific acl that matches the entry */
+       for ( i = 1, a = be->be_acl; a != NULL; a = a->acl_next, i++ ) {
+               if ( a->acl_dnpat != NULL ) {
+                       edn = dn_normalize_case( strdup( e->e_dn ) );
+                       if ( ! regex_matches( a->acl_dnpat, edn ) ) {
+                               free( edn );
+                               continue;
+                       }
+                       free( edn );
+               }
+               if ( a->acl_filter != NULL ) {
+                       if ( test_filter( NULL, NULL, NULL, e, a->acl_filter )
+                           != 0 ) {
+                               continue;
+                       }
+               }
+               if ( attr == NULL || a->acl_attrs == NULL ||
+                   charray_inlist( a->acl_attrs, attr ) ) {
+                       Debug( LDAP_DEBUG_ACL, "<= acl_get: backend acl #%d\n",
+                           i, e->e_dn, attr );
+                       return( a );
+               }
+       }
+
+       /* check for a global acl that matches the entry */
+       for ( i = 1, a = global_acl; a != NULL; a = a->acl_next, i++ ) {
+               if ( a->acl_dnpat != NULL ) {
+                       edn = dn_normalize_case( strdup( e->e_dn ) );
+                       if ( ! regex_matches( a->acl_dnpat, edn ) ) {
+                               free( edn );
+                               continue;
+                       }
+                       free( edn );
+               }
+               if ( a->acl_filter != NULL ) {
+                       if ( test_filter( NULL, NULL, NULL, e, a->acl_filter )
+                           != 0 ) {
+                               continue;
+                       }
+               }
+               if ( attr == NULL || a->acl_attrs == NULL || charray_inlist(
+                   a->acl_attrs, attr ) ) {
+                       Debug( LDAP_DEBUG_ACL, "<= acl_get: global acl #%d\n",
+                           i, e->e_dn, attr );
+                       return( a );
+               }
+       }
+       Debug( LDAP_DEBUG_ACL, "<= acl_get: no match\n", 0, 0, 0 );
+
+       return( NULL );
+}
+
+/*
+ * acl_access_allowed - check whether the given acl allows dn the
+ * requested access to entry e, attribute attr, value val.  if val
+ * is null, access to the whole attribute is assumed (all values).
+ *
+ * returns     0       access NOT allowed
+ *             1       access allowed
+ */
+
+int
+acl_access_allowed(
+    struct acl         *a,
+    Backend            *be,
+    Connection         *conn,
+    Entry              *e,
+    struct berval      *val,
+    Operation          *op,
+    int                        access
+)
+{
+       int             i;
+       char            *edn, *odn;
+       struct access   *b;
+       Attribute       *at;
+       struct berval   bv;
+       int             default_access;
+
+       Debug( LDAP_DEBUG_ACL, "=> acl: %s access to value \"%s\" by \"%s\"\n",
+           access2str( access ), val ? val->bv_val : "any", op->o_dn ?
+           op->o_dn : "" );
+
+       if ( be_isroot( be, op->o_dn ) ) {
+               Debug( LDAP_DEBUG_ACL, "<= acl: granted to database root\n",
+                   0, 0, 0 );
+               return( 1 );
+       }
+
+       default_access = be->be_dfltaccess ? be->be_dfltaccess :
+           global_default_access;
+       if ( a == NULL ) {
+               Debug( LDAP_DEBUG_ACL,
+                   "<= acl: %s by default (no matching to)\n",
+                   default_access >= access ? "granted" : "denied", 0, 0 );
+               return( default_access >= access );
+       }
+
+       odn = NULL;
+       if ( op->o_dn != NULL ) {
+               odn = dn_normalize_case( strdup( op->o_dn ) );
+               bv.bv_val = odn;
+               bv.bv_len = strlen( odn );
+       }
+       for ( i = 1, b = a->acl_access; b != NULL; b = b->a_next, i++ ) {
+               if ( b->a_dnpat != NULL ) {
+                       /*
+                        * if access applies to the entry itself, and the
+                        * user is bound as somebody in the same namespace as
+                        * the entry, OR the given dn matches the dn pattern
+                        */
+                       if ( strcasecmp( b->a_dnpat, "self" ) == 0 && op->o_dn
+                           != NULL && *(op->o_dn) && e->e_dn != NULL ) {
+                               edn = dn_normalize_case( strdup( e->e_dn ) );
+                               if ( strcasecmp( edn, op->o_dn ) == 0 ) {
+                                       free( edn );
+                                       if ( odn ) free( odn );
+                                       Debug( LDAP_DEBUG_ACL,
+                                   "<= acl: matched by clause #%d access %s\n",
+                                           i, (b->a_access & ~ACL_SELF) >=
+                                           access ? "granted" : "denied", 0 );
+
+                                       return( (b->a_access & ~ACL_SELF)
+                                           >= access );
+                               }
+                               free( edn );
+                       } else {
+                               if ( regex_matches( b->a_dnpat, odn ) ) {
+                                       if ( odn ) free( odn );
+                                       Debug( LDAP_DEBUG_ACL,
+                                   "<= acl: matched by clause #%d access %s\n",
+                                   i, (b->a_access & ~ACL_SELF) >= access ?
+                                           "granted" : "denied", 0 );
+
+                                       return( (b->a_access & ~ACL_SELF)
+                                           >= access );
+                               }
+                       }
+               }
+               if ( b->a_addrpat != NULL ) {
+                       if ( regex_matches( b->a_addrpat, conn->c_addr ) ) {
+                               if ( odn ) free( odn );
+                               Debug( LDAP_DEBUG_ACL,
+                                   "<= acl: matched by clause #%d access %s\n",
+                                   i, (b->a_access & ~ACL_SELF) >= access ?
+                                   "granted" : "denied", 0 );
+
+                               return( (b->a_access & ~ACL_SELF) >= access );
+                       }
+               }
+               if ( b->a_domainpat != NULL ) {
+                       if ( regex_matches( b->a_domainpat, conn->c_domain ) ) {
+                               if ( odn ) free( odn );
+                               Debug( LDAP_DEBUG_ACL,
+                                   "<= acl: matched by clause #%d access %s\n",
+                                   i, (b->a_access & ~ACL_SELF) >= access ?
+                                   "granted" : "denied", 0 );
+
+                               return( (b->a_access & ~ACL_SELF) >= access );
+                       }
+               }
+               if ( b->a_dnattr != NULL && op->o_dn != NULL ) {
+                       /* see if asker is listed in dnattr */
+                       if ( (at = attr_find( e->e_attrs, b->a_dnattr ))
+                           != NULL && value_find( at->a_vals, &bv,
+                           at->a_syntax, 3 ) == 0 )
+                       {
+                               if ( (b->a_access & ACL_SELF) && (val == NULL
+                                   || value_cmp( &bv, val, at->a_syntax,
+                                   2 )) ) {
+                                       continue;
+                               }
+
+                               if ( odn ) free( odn );
+                               Debug( LDAP_DEBUG_ACL,
+                                   "<= acl: matched by clause #%d access %s\n",
+                                   i, (b->a_access & ~ACL_SELF) >= access ?
+                                   "granted" : "denied", 0 );
+
+                               return( (b->a_access & ~ACL_SELF) >= access );
+                       }
+
+                       /* asker not listed in dnattr - check for self access */
+                       if ( ! (b->a_access & ACL_SELF) || val == NULL ||
+                           value_cmp( &bv, val, at->a_syntax, 2 ) != 0 ) {
+                               continue;
+                       }
+
+                       if ( odn ) free( odn );
+                       Debug( LDAP_DEBUG_ACL,
+                           "<= acl: matched by clause #%d (self) access %s\n",
+                           i, (b->a_access & ~ACL_SELF) >= access ? "granted"
+                           : "denied", 0 );
+
+                       return( (b->a_access & ~ACL_SELF) >= access );
+               }
+       }
+
+       if ( odn ) free( odn );
+       Debug( LDAP_DEBUG_ACL, "<= acl: %s by default (no matching by)\n",
+           default_access >= access ? "granted" : "denied", 0, 0 );
+
+       return( default_access >= access );
+}
+
+/*
+ * acl_check_mods - check access control on the given entry to see if
+ * it allows the given modifications by the user associated with op.
+ * returns     LDAP_SUCCESS    mods allowed ok
+ *             anything else   mods not allowed - return is an error
+ *                             code indicating the problem
+ */
+
+int
+acl_check_mods(
+    Backend    *be,
+    Connection *conn,
+    Operation  *op,
+    Entry      *e,
+    LDAPMod    *mods
+)
+{
+       int             i;
+       struct acl      *a;
+
+       for ( ; mods != NULL; mods = mods->mod_next ) {
+               if ( strcasecmp( mods->mod_type, "modifiersname" ) == 0 ||
+                   strcasecmp( mods->mod_type, "modifytimestamp" ) == 0 ) {
+                       continue;
+               }
+
+               a = acl_get_applicable( be, op, e, mods->mod_type );
+
+               switch ( mods->mod_op & ~LDAP_MOD_BVALUES ) {
+               case LDAP_MOD_REPLACE:
+               case LDAP_MOD_ADD:
+                       if ( mods->mod_bvalues == NULL ) {
+                               break;
+                       }
+                       for ( i = 0; mods->mod_bvalues[i] != NULL; i++ ) {
+                               if ( ! acl_access_allowed( a, be, conn, e,
+                                   mods->mod_bvalues[i], op, ACL_WRITE ) ) {
+                                       return( LDAP_INSUFFICIENT_ACCESS );
+                               }
+                       }
+                       break;
+
+               case LDAP_MOD_DELETE:
+                       if ( mods->mod_bvalues == NULL ) {
+                               if ( ! acl_access_allowed( a, be, conn, e,
+                                   NULL, op, ACL_WRITE ) ) {
+                                       return( LDAP_INSUFFICIENT_ACCESS );
+                               }
+                               break;
+                       }
+                       for ( i = 0; mods->mod_bvalues[i] != NULL; i++ ) {
+                               if ( ! acl_access_allowed( a, be, conn, e,
+                                   mods->mod_bvalues[i], op, ACL_WRITE ) ) {
+                                       return( LDAP_INSUFFICIENT_ACCESS );
+                               }
+                       }
+                       break;
+               }
+       }
+
+       return( LDAP_SUCCESS );
+}
+
+#ifdef sunos5
+
+static int
+regex_matches( char *pat, char *str )
+{
+       char    *e;
+       int     rc;
+
+       if ( (e = compile( pat, NULL, NULL )) == NULL ) {
+               Debug( LDAP_DEBUG_ANY,
+                   "compile( \"%s\", \"%s\") failed\n", pat, str, 0 );
+               return( 0 );
+       }
+       rc = step( str ? str : "", e );
+       free( e );
+
+       return( rc );
+}
+
+#else /* sunos5 */
+
+static int
+regex_matches( char *pat, char *str )
+{
+       char    *e;
+       int     rc;
+
+       pthread_mutex_lock( &regex_mutex );
+       if ( (e = re_comp( pat )) != NULL ) {
+               Debug( LDAP_DEBUG_ANY,
+                   "re_comp( \"%s\", \"%s\") failed because (%s)\n", pat, str,
+                   e );
+               pthread_mutex_unlock( &regex_mutex );
+               return( 0 );
+       }
+       rc = re_exec( str ? str : "" );
+       pthread_mutex_unlock( &regex_mutex );
+
+       return( rc == 1 );
+}
+
+#endif /* sunos5 */
diff --git a/servers/slapd/aclparse.c b/servers/slapd/aclparse.c
new file mode 100644 (file)
index 0000000..10fa6a0
--- /dev/null
@@ -0,0 +1,376 @@
+/* acl.c - routines to parse and check acl's */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include "regex.h"
+#include "slap.h"
+#include "portable.h"
+
+extern Filter          *str2filter();
+extern char            *re_comp();
+extern struct acl      *global_acl;
+extern char            **str2charray();
+extern char            *dn_upcase();
+
+static void            split();
+static void            acl_append();
+static void            access_append();
+static void            acl_usage();
+#ifdef LDAP_DEBUG
+static void            print_acl();
+static void            print_access();
+#endif
+
+void
+parse_acl(
+    Backend    *be,
+    char       *fname,
+    int                lineno,
+    int                argc,
+    char       **argv
+)
+{
+       int             i;
+       char            *e, *left, *right;
+       struct acl      *a;
+       struct access   *b;
+
+       a = NULL;
+       for ( i = 1; i < argc; i++ ) {
+               /* to clause - select which entries are protected */
+               if ( strcasecmp( argv[i], "to" ) == 0 ) {
+                       if ( a != NULL ) {
+                               fprintf( stderr,
+               "%s: line %d: only one to clause allowed in access line\n",
+                                   fname, lineno );
+                               acl_usage();
+                       }
+                       a = (struct acl *) ch_calloc( 1, sizeof(struct acl) );
+                       for ( ++i; i < argc; i++ ) {
+                               if ( strcasecmp( argv[i], "by" ) == 0 ) {
+                                       i--;
+                                       break;
+                               }
+
+                               if ( strcasecmp( argv[i], "*" ) == 0 ) {
+                                       a->acl_dnpat = strdup( ".*" );
+                                       continue;
+                               }
+
+                               split( argv[i], '=', &left, &right );
+                               if ( right == NULL || *right == '\0' ) {
+                                       fprintf( stderr,
+       "%s: line %d: missing \"=\" in (or value after) \"%s\" in to clause\n",
+                                           fname, lineno, left );
+                                       acl_usage();
+                               }
+
+                               if ( strcasecmp( left, "filter" ) == 0 ) {
+                                       if ( (a->acl_filter = str2filter(
+                                           right )) == NULL ) {
+                                               fprintf( stderr,
+                               "%s: line %d: bad filter \"%s\" in to clause\n",
+                                                   fname, lineno, right );
+                                               acl_usage();
+                                       }
+                               } else if ( strcasecmp( left, "dn" ) == 0 ) {
+                                       if ( (e = re_comp( right )) != NULL ) {
+                                               fprintf( stderr,
+               "%s: line %d: regular expression \"%s\" bad because of %s\n",
+                                                   fname, lineno, right, e );
+                                               acl_usage();
+                                       }
+                                       a->acl_dnpat = dn_upcase( strdup(
+                                           right ) );
+                               } else if ( strncasecmp( left, "attr", 4 )
+                                   == 0 ) {
+                                       char    **alist;
+
+                                       alist = str2charray( right, "," );
+                                       charray_merge( &a->acl_attrs, alist );
+                                       free( alist );
+                               } else {
+                                       fprintf( stderr,
+                               "%s: line %d: expecting <what> got \"%s\"\n",
+                                           fname, lineno, left );
+                                       acl_usage();
+                               }
+                       }
+
+               /* by clause - select who has what access to entries */
+               } else if ( strcasecmp( argv[i], "by" ) == 0 ) {
+                       if ( a == NULL ) {
+                               fprintf( stderr,
+       "%s: line %d: to clause required before by clause in access line\n",
+                                   fname, lineno );
+                               acl_usage();
+                       }
+                       /*
+                        * by clause consists of <who> and <access>
+                        */
+
+                       b = (struct access *) ch_calloc( 1,
+                           sizeof(struct access) );
+
+                       if ( ++i == argc ) {
+                               fprintf( stderr,
+                           "%s: line %d: premature eol: expecting <who>\n",
+                                   fname, lineno );
+                               acl_usage();
+                       }
+
+                       /* get <who> */
+                       split( argv[i], '=', &left, &right );
+                       if ( strcasecmp( argv[i], "*" ) == 0 ) {
+                               b->a_dnpat = strdup( ".*" );
+                       } else if ( strcasecmp( argv[i], "self" ) == 0 ) {
+                               b->a_dnpat = strdup( "self" );
+                       } else if ( strcasecmp( left, "dn" ) == 0 ) {
+                               if ( (e = re_comp( right )) != NULL ) {
+                                       fprintf( stderr,
+                       "%s: line %d: regular expression \"%s\" bad: %s\n",
+                                           fname, lineno, right, e );
+                                       acl_usage();
+                               }
+                               b->a_dnpat = dn_upcase( strdup( right ) );
+                       } else if ( strcasecmp( left, "dnattr" )
+                           == 0 ) {
+                               b->a_dnattr = strdup( right );
+                       } else if ( strcasecmp( left, "domain" )
+                           == 0 ) {
+                               char    *s;
+
+                               if ( (e = re_comp( right )) != NULL ) {
+                                       fprintf( stderr,
+                       "%s: line %d: regular expression \"%s\" bad: %s\n",
+                                           fname, lineno, right, e );
+                                       acl_usage();
+                               }
+                               b->a_domainpat = strdup( right );
+                               /* normalize the domain */
+                               for ( s = b->a_domainpat; *s; s++ ) {
+                                       *s = TOLOWER( *s );
+                               }
+                       } else if ( strcasecmp( left, "addr" ) == 0 ) {
+                               if ( (e = re_comp( right )) != NULL ) {
+                                       fprintf( stderr,
+                       "%s: line %d: regular expression \"%s\" bad: %s\n",
+                                           fname, lineno, right, e );
+                                       acl_usage();
+                               }
+                               b->a_addrpat = strdup( right );
+                       } else {
+                               fprintf( stderr,
+                                   "%s: line %d: expecting <who> got \"%s\"\n",
+                                   fname, lineno, left );
+                               acl_usage();
+                       }
+
+                       if ( ++i == argc ) {
+                               fprintf( stderr,
+                           "%s: line %d: premature eol: expecting <access>\n",
+                                   fname, lineno );
+                               acl_usage();
+                       }
+
+                       /* get <access> */
+                       split( argv[i], '=', &left, &right );
+                       if ( (b->a_access = str2access( left )) == -1 ) {
+                               fprintf( stderr,
+                           "%s: line %d: expecting <access> got \"%s\"\n",
+                                   fname, lineno, left );
+                               acl_usage();
+                       }
+                       access_append( &a->acl_access, b );
+
+               } else {
+                       fprintf( stderr,
+                   "%s: line %d: expecting \"to\" or \"by\" got \"%s\"\n",
+                           fname, lineno, argv[i] );
+                       acl_usage();
+               }
+       }
+
+       /* if we have no real access clause, complain and do nothing */
+       if ( a == NULL ) {
+       
+                       fprintf( stderr,
+                   "%s: line %d: warning: no access clause(s) specified in access line\n",
+                           fname, lineno );
+
+       } else {
+       
+               if ( a->acl_access == NULL ) {
+                       fprintf( stderr,
+                   "%s: line %d: warning: no by clause(s) specified in access line\n",
+                           fname, lineno );
+               }
+
+               if ( be != NULL ) {
+                       acl_append( &be->be_acl, a );
+               } else {
+                       acl_append( &global_acl, a );
+               }
+       }
+}
+
+char *
+access2str( int access )
+{
+       static char     buf[12];
+
+       if ( access & ACL_SELF ) {
+               strcpy( buf, "self" );
+       } else {
+               buf[0] = '\0';
+       }
+
+       if ( access & ACL_NONE ) {
+               strcat( buf, "none" );
+       } else if ( access & ACL_COMPARE ) {
+               strcat( buf, "compare" );
+       } else if ( access & ACL_SEARCH ) {
+               strcat( buf, "search" );
+       } else if ( access & ACL_READ ) {
+               strcat( buf, "read" );
+       } else if ( access & ACL_WRITE ) {
+               strcat( buf, "write" );
+       } else {
+               strcat( buf, "unknown" );
+       }
+
+       return( buf );
+}
+
+int
+str2access( char *str )
+{
+       int     access;
+
+       access = 0;
+       if ( strncasecmp( str, "self", 4 ) == 0 ) {
+               access |= ACL_SELF;
+               str += 4;
+       }
+
+       if ( strcasecmp( str, "none" ) == 0 ) {
+               access |= ACL_NONE;
+       } else if ( strcasecmp( str, "compare" ) == 0 ) {
+               access |= ACL_COMPARE;
+       } else if ( strcasecmp( str, "search" ) == 0 ) {
+               access |= ACL_SEARCH;
+       } else if ( strcasecmp( str, "read" ) == 0 ) {
+               access |= ACL_READ;
+       } else if ( strcasecmp( str, "write" ) == 0 ) {
+               access |= ACL_WRITE;
+       } else {
+               access = -1;
+       }
+
+       return( access );
+}
+
+static void
+acl_usage()
+{
+       fprintf( stderr, "\n<access clause> ::= access to <what> [ by <who> <access> ]+ \n" );
+       fprintf( stderr, "<what> ::= * | [dn=<regex>] [filter=<ldapfilter>] [attrs=<attrlist>]\n" );
+       fprintf( stderr, "<attrlist> ::= <attr> | <attr> , <attrlist>\n" );
+       fprintf( stderr, "<attr> ::= <attrname> | entry | children\n" );
+       fprintf( stderr, "<who> ::= * | self | dn=<regex> | addr=<regex> |\n\tdomain=<regex> | dnattr=<dnattrname>\n" );
+       fprintf( stderr, "<access> ::= [self]{none | compare | search | read | write }\n" );
+       exit( 1 );
+}
+
+static void
+split(
+    char       *line,
+    int                splitchar,
+    char       **left,
+    char       **right
+)
+{
+       *left = line;
+       if ( (*right = strchr( line, splitchar )) != NULL ) {
+               *((*right)++) = '\0';
+       }
+}
+
+static void
+access_append( struct access **l, struct access *a )
+{
+       for ( ; *l != NULL; l = &(*l)->a_next )
+               ;       /* NULL */
+
+       *l = a;
+}
+
+static void
+acl_append( struct acl **l, struct acl *a )
+{
+       for ( ; *l != NULL; l = &(*l)->acl_next )
+               ;       /* NULL */
+
+       *l = a;
+}
+
+#ifdef LDAP_DEBUG
+
+static void
+print_access( struct access *b )
+{
+       printf( "\tby" );
+       if ( b->a_dnpat != NULL ) {
+               printf( " dn=%s", b->a_dnpat );
+       } else if ( b->a_addrpat != NULL ) {
+               printf( " addr=%s", b->a_addrpat );
+       } else if ( b->a_domainpat != NULL ) {
+               printf( " domain=%s", b->a_domainpat );
+       } else if ( b->a_dnattr != NULL ) {
+               printf( " dnattr=%s", b->a_dnattr );
+       }
+       printf( " %s\n", access2str( b->a_access ) );
+}
+
+static void
+print_acl( struct acl *a )
+{
+       int             i;
+       struct access   *b;
+
+       if ( a == NULL ) {
+               printf( "NULL\n" );
+       }
+       printf( "access to" );
+       if ( a->acl_filter != NULL ) {
+               printf( " filter=" );
+               filter_print( a->acl_filter );
+       }
+       if ( a->acl_dnpat != NULL ) {
+               printf( " dn=" );
+               printf( a->acl_dnpat );
+       }
+       if ( a->acl_attrs != NULL ) {
+               int     first = 1;
+
+               printf( " attrs=" );
+               for ( i = 0; a->acl_attrs[i] != NULL; i++ ) {
+                       if ( ! first ) {
+                               printf( "," );
+                       }
+                       printf( a->acl_attrs[i] );
+                       first = 0;
+               }
+       }
+       printf( "\n" );
+       for ( b = a->acl_access; b != NULL; b = b->a_next ) {
+               print_access( b );
+       }
+}
+
+#endif
diff --git a/servers/slapd/add.c b/servers/slapd/add.c
new file mode 100644 (file)
index 0000000..027e40a
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+
+extern Backend *select_backend();
+extern char    *dn_normalize();
+
+extern char            *default_referral;
+extern time_t          currenttime;
+extern pthread_mutex_t currenttime_mutex;
+extern int             global_lastmod;
+
+static void    add_created_attrs();
+
+void
+do_add( conn, op )
+    Connection *conn;
+    Operation  *op;
+{
+       BerElement      *ber = op->o_ber;
+       char            *dn, *last;
+       unsigned long   len, tag;
+       Entry           *e;
+       Backend         *be;
+
+       Debug( LDAP_DEBUG_TRACE, "do_add\n", 0, 0, 0 );
+
+       /*
+        * Parse the add request.  It looks like this:
+        *
+        *      AddRequest := [APPLICATION 14] SEQUENCE {
+        *              name    DistinguishedName,
+        *              attrs   SEQUENCE OF SEQUENCE {
+        *                      type    AttributeType,
+        *                      values  SET OF AttributeValue
+        *              }
+        *      }
+        */
+
+       e = (Entry *) ch_calloc( 1, sizeof(Entry) );
+
+       /* get the name */
+       if ( ber_scanf( ber, "{a", &dn ) == LBER_ERROR ) {
+               Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
+               send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
+                   "decoding error" );
+               return;
+       }
+       e->e_dn = dn;
+       dn = dn_normalize( strdup( dn ) );
+       Debug( LDAP_DEBUG_ARGS, "    do_add: dn (%s)\n", dn, 0, 0 );
+
+       /* get the attrs */
+       e->e_attrs = NULL;
+       for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
+           tag = ber_next_element( ber, &len, last ) ) {
+               char            *type;
+               struct berval   **vals;
+
+               if ( ber_scanf( ber, "{a{V}}", &type, &vals ) == LBER_ERROR ) {
+                       send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR,
+                           NULL, "decoding error" );
+                       entry_free( e );
+                       return;
+               }
+
+               if ( vals == NULL ) {
+                       Debug( LDAP_DEBUG_ANY, "no values for type %s\n", type,
+                           0, 0 );
+                       send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
+                           NULL );
+                       entry_free( e );
+                       return;
+               }
+
+               attr_merge( e, type, vals );
+
+               free( type );
+               ber_bvecfree( vals );
+       }
+
+       Statslog( LDAP_DEBUG_STATS, "conn=%d op=%d ADD dn=\"%s\"\n",
+           conn->c_connid, op->o_opid, dn, 0, 0 );
+
+       /*
+        * We could be serving multiple database backends.  Select the
+        * appropriate one, or send a referral to our "referral server"
+        * if we don't hold it.
+        */
+       if ( (be = select_backend( dn )) == NULL ) {
+               entry_free( e );
+               send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
+                   default_referral );
+               return;
+       }
+
+       /*
+        * do the add if 1 && (2 || 3)
+        * 1) there is an add function implemented in this backend;
+        * 2) this backend is master for what it holds;
+        * 3) it's a replica and the dn supplied is the updatedn.
+        */
+       if ( be->be_add != NULL ) {
+               /* do the update here */
+               if ( be->be_updatedn == NULL || strcasecmp( be->be_updatedn,
+                   op->o_dn ) == 0 ) {
+                       if ( (be->be_lastmod == ON || be->be_lastmod == 0 &&
+                           global_lastmod == ON) && be->be_updatedn == NULL ) {
+                               add_created_attrs( op, e );
+                       }
+                       if ( (*be->be_add)( be, conn, op, e ) == 0 ) {
+                               replog( be, LDAP_REQ_ADD, e->e_dn, e, 0 );
+                       }
+               } else {
+                       entry_free( e );
+                       send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
+                           default_referral );
+               }
+       } else {
+               entry_free( e );
+               send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
+                   "Function not implemented" );
+       }
+}
+
+static void
+add_created_attrs( Operation *op, Entry *e )
+{
+       char            buf[20];
+       struct berval   bv;
+       struct berval   *bvals[2];
+       Attribute       **a, **next;
+       Attribute       *tmp;
+       struct tm       *ltm;
+
+       Debug( LDAP_DEBUG_TRACE, "add_created_attrs\n", 0, 0, 0 );
+
+       bvals[0] = &bv;
+       bvals[1] = NULL;
+
+       /* remove any attempts by the user to add these attrs */
+       for ( a = &e->e_attrs; *a != NULL; a = next ) {
+               if ( strcasecmp( (*a)->a_type, "createtimestamp" ) == 0
+                   || strcasecmp( (*a)->a_type, "creatorsname" ) == 0 ) {
+                       tmp = *a;
+                       *a = (*a)->a_next;
+                       attr_free( tmp );
+                       next = a;
+               } else {
+                       next = &(*a)->a_next;
+               }
+       }
+
+       if ( op->o_dn == NULL || op->o_dn[0] == '\0' ) {
+               bv.bv_val = "NULLDN";
+               bv.bv_len = strlen( bv.bv_val );
+       } else {
+               bv.bv_val = op->o_dn;
+               bv.bv_len = strlen( bv.bv_val );
+       }
+       attr_merge( e, "creatorsname", bvals );
+
+       pthread_mutex_lock( &currenttime_mutex );
+        ltm = localtime( &currenttime );
+        strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm );
+       pthread_mutex_unlock( &currenttime_mutex );
+
+       bv.bv_val = buf;
+       bv.bv_len = strlen( bv.bv_val );
+       attr_merge( e, "createtimestamp", bvals );
+}
diff --git a/servers/slapd/attr.c b/servers/slapd/attr.c
new file mode 100644 (file)
index 0000000..7686d94
--- /dev/null
@@ -0,0 +1,339 @@
+/* attr.c - routines for dealing with attributes */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include "portable.h"
+#include "slap.h"
+
+extern char    **charray_dup();
+extern char    *ch_malloc();
+extern int     errno;
+
+void
+attr_free( Attribute *a )
+{
+       free( a->a_type );
+       ber_bvecfree( a->a_vals );
+       free( a );
+}
+
+/*
+ * attr_normalize - normalize an attribute name (make it all lowercase)
+ */
+
+char *
+attr_normalize( char *s )
+{
+       char    *save;
+
+       for ( save = s; *s; s++ ) {
+               *s = TOLOWER( *s );
+       }
+
+       return( save );
+}
+
+/*
+ * attr_merge_fast - merge the given type and value with the list of
+ * attributes in attrs. called from str2entry(), where we can make some
+ * assumptions to make things faster.
+ * returns     0       everything went ok
+ *             -1      trouble
+ */
+
+int
+attr_merge_fast(
+    Entry              *e,
+    char               *type,
+    struct berval      **vals,
+    int                        nvals,
+    int                        naddvals,
+    int                        *maxvals,
+    Attribute          ***a
+)
+{
+       int             i;
+
+       if ( *a == NULL ) {
+               for ( *a = &e->e_attrs; **a != NULL; *a = &(**a)->a_next ) {
+                       if ( strcasecmp( (**a)->a_type, type ) == 0 ) {
+                               break;
+                       }
+               }
+       }
+
+       if ( **a == NULL ) {
+               **a = (Attribute *) ch_malloc( sizeof(Attribute) );
+               (**a)->a_type = attr_normalize( strdup( type ) );
+               (**a)->a_vals = NULL;
+               (**a)->a_syntax = attr_syntax( type );
+               (**a)->a_next = NULL;
+       }
+
+       return( value_add_fast( &(**a)->a_vals, vals, nvals, naddvals,
+           maxvals ) );
+}
+
+/*
+ * attr_merge - merge the given type and value with the list of
+ * attributes in attrs.
+ * returns     0       everything went ok
+ *             -1      trouble
+ */
+
+int
+attr_merge(
+    Entry              *e,
+    char               *type,
+    struct berval      **vals
+)
+{
+       int             i;
+       Attribute       **a;
+
+       for ( a = &e->e_attrs; *a != NULL; a = &(*a)->a_next ) {
+               if ( strcasecmp( (*a)->a_type, type ) == 0 ) {
+                       break;
+               }
+       }
+
+       if ( *a == NULL ) {
+               *a = (Attribute *) ch_malloc( sizeof(Attribute) );
+               (*a)->a_type = attr_normalize( strdup( type ) );
+               (*a)->a_vals = NULL;
+               (*a)->a_syntax = attr_syntax( type );
+               (*a)->a_next = NULL;
+       }
+
+       return( value_add( &(*a)->a_vals, vals ) );
+}
+
+/*
+ * attr_find - find and return attribute type in list a
+ */
+
+Attribute *
+attr_find(
+    Attribute  *a,
+    char       *type
+)
+{
+       for ( ; a != NULL; a = a->a_next ) {
+               if ( strcasecmp( a->a_type, type ) == 0 ) {
+                       return( a );
+               }
+       }
+
+       return( NULL );
+}
+
+/*
+ * attr_delete - delete the attribute type in list pointed to by attrs
+ * return      0       deleted ok
+ *             1       not found in list a
+ *             -1      something bad happened
+ */
+
+int
+attr_delete(
+    Attribute  **attrs,
+    char       *type
+)
+{
+       Attribute       **a;
+       Attribute       *save;
+
+       for ( a = attrs; *a != NULL; a = &(*a)->a_next ) {
+               if ( strcasecmp( (*a)->a_type, type ) == 0 ) {
+                       break;
+               }
+       }
+
+       if ( *a == NULL ) {
+               return( 1 );
+       }
+
+       save = *a;
+       *a = (*a)->a_next;
+       attr_free( save );
+
+       return( 0 );
+}
+
+#define DEFAULT_SYNTAX SYNTAX_CIS
+
+struct asyntaxinfo {
+       char    **asi_names;
+       int     asi_syntax;
+};
+
+static Avlnode *attr_syntaxes = NULL;
+
+static int
+attr_syntax_cmp(
+    struct asyntaxinfo        *a1,
+    struct asyntaxinfo        *a2
+)
+{
+      return( strcasecmp( a1->asi_names[0], a2->asi_names[0] ) );
+}
+
+static int
+attr_syntax_name_cmp(
+    char               *type,
+    struct asyntaxinfo *a
+)
+{
+       return( strcasecmp( type, a->asi_names[0] ) );
+}
+
+static int
+attr_syntax_names_cmp(
+    char               *type,
+    struct asyntaxinfo *a
+)
+{
+       int     i;
+
+       for ( i = 0; a->asi_names[i] != NULL; i++ ) {
+               if ( strcasecmp( type, a->asi_names[i] ) == 0 ) {
+                       return( 0 );
+               }
+       }
+       return( 1 );
+}
+
+static int
+attr_syntax_dup(
+    struct asyntaxinfo        *a1,
+    struct asyntaxinfo        *a2
+)
+{
+       if ( a1->asi_syntax != a2->asi_syntax ) {
+               return( -1 );
+       }
+
+       return( 1 );
+}
+
+/*
+ * attr_syntax - return the syntax of attribute type
+ */
+
+int
+attr_syntax( char *type )
+{
+       struct asyntaxinfo      *asi = NULL;
+
+       if ( (asi = (struct asyntaxinfo *) avl_find( attr_syntaxes, type,
+            attr_syntax_name_cmp )) != NULL || (asi = (struct asyntaxinfo *)
+           avl_find_lin( attr_syntaxes, type, attr_syntax_names_cmp ))
+           != NULL )
+       {
+               return( asi->asi_syntax );
+       }
+
+       return( DEFAULT_SYNTAX );
+}
+
+/*
+ * attr_syntax_config - process an attribute syntax config line
+ */
+
+void
+attr_syntax_config(
+    char       *fname,
+    int                lineno,
+    int                argc,
+    char       **argv
+)
+{
+       char                    *save;
+       struct asyntaxinfo      *a;
+       int                     i, lasti;
+
+       if ( argc < 2 ) {
+               Debug( LDAP_DEBUG_ANY,
+"%s: line %d: missing name in \"attribute <name>+ <syntax>\" (ignored)\n",
+                   fname, lineno, 0 );
+               return;
+       }
+
+       a = (struct asyntaxinfo *) ch_calloc( 1, sizeof(struct asyntaxinfo) );
+
+       lasti = argc - 1;
+       if ( strcasecmp( argv[lasti], "caseignorestring" ) == 0 ||
+           strcasecmp( argv[lasti], "cis" ) == 0 ) {
+               a->asi_syntax = SYNTAX_CIS;
+       } else if ( strcasecmp( argv[lasti], "telephone" ) == 0 ||
+           strcasecmp( argv[lasti], "tel" ) == 0 ) {
+               a->asi_syntax = (SYNTAX_CIS | SYNTAX_TEL);
+       } else if ( strcasecmp( argv[lasti], "dn" ) == 0 ) {
+               a->asi_syntax = (SYNTAX_CIS | SYNTAX_DN);
+       } else if ( strcasecmp( argv[lasti], "caseexactstring" ) == 0 ||
+           strcasecmp( argv[lasti], "ces" ) == 0 ) {
+               a->asi_syntax = SYNTAX_CES;
+       } else if ( strcasecmp( argv[lasti], "binary" ) == 0 ||
+           strcasecmp( argv[lasti], "bin" ) == 0 ) {
+               a->asi_syntax = SYNTAX_BIN;
+       } else {
+               Debug( LDAP_DEBUG_ANY,
+           "%s: line %d: unknown syntax \"%s\" in attribute line (ignored)\n",
+                   fname, lineno, 0 );
+               Debug( LDAP_DEBUG_ANY,
+    "possible syntaxes are \"cis\", \"ces\", \"tel\", \"dn\", or \"bin\"\n",
+                   0, 0, 0 );
+               free( (char *) a );
+               return;
+       }
+       save = argv[lasti];
+       argv[lasti] = NULL;
+       a->asi_names = charray_dup( argv );
+       argv[lasti] = save;
+
+       switch ( avl_insert( &attr_syntaxes, a, attr_syntax_cmp,
+           attr_syntax_dup ) ) {
+       case -1:        /* duplicate - different syntaxes */
+               Debug( LDAP_DEBUG_ARGS, "%s: line %d: duplicate attribute\n",
+                   fname, lineno, 0 );
+               /* FALL */
+
+       case 1:         /* duplicate - same syntaxes */
+               charray_free( a->asi_names );
+               free( (char *) a );
+               break;
+
+       default:        /* inserted */
+               break;
+       }
+}
+
+#ifdef LDAP_DEBUG
+
+static
+attr_syntax_printnode( struct asyntaxinfo *a )
+{
+       int     i;
+
+       printf( "syntax: 0x%x\n", a->asi_syntax );
+       for ( i = 0; a->asi_names[i] != NULL; i++ ) {
+               printf( " name: %s\n", a->asi_names[i] );
+       }
+       return( 0 );
+}
+
+static
+attr_syntax_print()
+{
+       (void) avl_apply( attr_syntaxes, attr_syntax_printnode, 0, -1,
+           AVL_INORDER );
+}
+
+#endif
diff --git a/servers/slapd/ava.c b/servers/slapd/ava.c
new file mode 100644 (file)
index 0000000..ef0487c
--- /dev/null
@@ -0,0 +1,38 @@
+/* ava.c - routines for dealing with attribute value assertions */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+
+int
+get_ava(
+    BerElement *ber,
+    Ava                *ava
+)
+{
+       if ( ber_scanf( ber, "{ao}", &ava->ava_type, &ava->ava_value )
+           == LBER_ERROR ) {
+               Debug( LDAP_DEBUG_ANY, "  get_ava ber_scanf\n", 0, 0, 0 );
+               return( LDAP_PROTOCOL_ERROR );
+       }
+       attr_normalize( ava->ava_type );
+       value_normalize( ava->ava_value.bv_val, attr_syntax( ava->ava_type ) );
+
+       return( 0 );
+}
+
+void
+ava_free(
+    Ava        *ava,
+    int        freeit
+)
+{
+       free( (char *) ava->ava_type );
+       free( (char *) ava->ava_value.bv_val );
+       if ( freeit ) {
+               free( (char *) ava );
+       }
+}
+
diff --git a/servers/slapd/back-ldbm/Make-template b/servers/slapd/back-ldbm/Make-template
new file mode 100644 (file)
index 0000000..51ef7a8
--- /dev/null
@@ -0,0 +1,148 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1995 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       ldbm backend to stand-alone LDAP server makefile
+#
+#-----------------------------------------------------------------------------
+LDAPSRC        = ../../..
+HDIR   = $(LDAPSRC)/include
+LDIR   = $(LDAPSRC)/libraries
+VERSIONFILE = $(LDAPSRC)/build/version
+
+SRCS   = idl.c add.c search.c cache.c dbcache.c dn2id.c id2entry.c \
+               index.c id2children.c nextid.c abandon.c compare.c \
+               modify.c modrdn.c delete.c init.c config.c bind.c attr.c \
+               filterindex.c unbind.c kerberos.c close.c
+OBJS   = idl.o add.o search.o cache.o dbcache.o dn2id.o id2entry.o \
+               index.o id2children.o nextid.o abandon.o compare.o \
+               modify.o modrdn.o delete.o init.o config.o bind.o attr.o \
+               filterindex.o unbind.o kerberos.o close.o
+
+INCLUDES= -I. -I.. -I$(HDIR) $(KRBINCLUDEFLAG)
+DEFINES = $(DEFS) $(THREADS)
+CFLAGS = $(INCLUDES) $(THREADSINCLUDE) $(DEFINES) $(ACFLAGS)
+LDFLAGS        = -L$(LDIR) $(KRBLIBFLAG)
+
+all:   FORCE
+       -@echo "$(SLAPD_BACKENDS)" | grep LDAP_LDBM 2>&1 > /dev/null; \
+       if [ $$? = 0 ]; then \
+            $(MAKE) $(MFLAGS) CC=$(CC) libback-ldbm.a; \
+       else \
+           echo "Include -DLDAP_LDBM in SLAPD_BACKENDS in the"; \
+           echo "Make-common file to build the ldbm backend"; \
+        fi
+
+libback-ldbm.a:        version.o
+       $(AR) ruv $@ $(OBJS) version.o
+       @if [ ! -z "$(RANLIB)" ]; then \
+               $(RANLIB) $@; \
+       fi
+       @touch ../.backend
+
+version.c: $(OBJS)
+       $(RM) $@
+       (u=$${USER-root} v=`$(CAT) $(VERSIONFILE)` d=`$(PWD)` h=`$(HOSTNAME)` \
+       t=`$(DATE)`; $(SED) -e "s|%WHEN%|$${t}|" \
+       -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+       -e "s|%VERSION%|$${v}|" \
+       < Version.c > $@)
+
+lint:  FORCE
+       $(LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+5lint: FORCE
+       $(5LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+clean: FORCE
+       $(RM) libback-ldbm.a *.o core a.out version.c
+
+depend:        FORCE
+       $(MKDEP) $(INCLUDES) $(DEFINES) $(SRCS)
+
+links:
+       @$(LN) .src/*.[ch] .
+# DO NOT DELETE THIS LINE -- mkdep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+idl.o: idl.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+idl.o: ../../../include/ldap.h ../../../include/lthread.h
+idl.o: ../../../include/ldif.h ../../../include/ldapconfig.h back-ldbm.h
+idl.o: ../../../include/ldbm.h
+add.o: add.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+add.o: ../../../include/ldap.h ../../../include/lthread.h
+add.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h
+search.o: search.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+search.o: ../../../include/ldap.h ../../../include/lthread.h
+search.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h
+cache.o: cache.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+cache.o: ../../../include/ldap.h ../../../include/lthread.h
+cache.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h
+dbcache.o: dbcache.c ../../../include/portable.h ../slap.h
+dbcache.o: ../../../include/avl.h ../../../include/lber.h
+dbcache.o: ../../../include/ldap.h ../../../include/lthread.h
+dbcache.o: ../../../include/ldif.h ../../../include/ldapconfig.h back-ldbm.h
+dbcache.o: ../../../include/ldbm.h
+dn2id.o: dn2id.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+dn2id.o: ../../../include/ldap.h ../../../include/lthread.h
+dn2id.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h
+id2entry.o: id2entry.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+id2entry.o: ../../../include/ldap.h ../../../include/lthread.h
+id2entry.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h
+index.o: index.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+index.o: ../../../include/ldap.h ../../../include/lthread.h
+index.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h
+id2children.o: id2children.c ../slap.h ../../../include/avl.h
+id2children.o: ../../../include/lber.h ../../../include/ldap.h
+id2children.o: ../../../include/lthread.h ../../../include/ldif.h back-ldbm.h
+id2children.o: ../../../include/ldbm.h
+nextid.o: nextid.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+nextid.o: ../../../include/ldap.h ../../../include/lthread.h
+nextid.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h
+abandon.o: abandon.c
+compare.o: compare.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+compare.o: ../../../include/ldap.h ../../../include/lthread.h
+compare.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h
+modify.o: modify.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+modify.o: ../../../include/ldap.h ../../../include/lthread.h
+modify.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h
+modrdn.o: modrdn.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+modrdn.o: ../../../include/ldap.h ../../../include/lthread.h
+modrdn.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h
+delete.o: delete.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+delete.o: ../../../include/ldap.h ../../../include/lthread.h
+delete.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h
+init.o: init.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+init.o: ../../../include/ldap.h ../../../include/lthread.h
+init.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h
+config.o: config.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+config.o: ../../../include/ldap.h ../../../include/lthread.h
+config.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h
+bind.o: bind.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+bind.o: ../../../include/ldap.h ../../../include/lthread.h
+bind.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h
+attr.o: attr.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+attr.o: ../../../include/ldap.h ../../../include/lthread.h
+attr.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h
+filterindex.o: filterindex.c ../slap.h ../../../include/avl.h
+filterindex.o: ../../../include/lber.h ../../../include/ldap.h
+filterindex.o: ../../../include/lthread.h ../../../include/ldif.h back-ldbm.h
+filterindex.o: ../../../include/ldbm.h
+unbind.o: unbind.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+unbind.o: ../../../include/ldap.h ../../../include/lthread.h
+unbind.o: ../../../include/ldif.h
+kerberos.o: kerberos.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+kerberos.o: ../../../include/ldap.h ../../../include/lthread.h
+kerberos.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h
+close.o: close.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+close.o: ../../../include/ldap.h ../../../include/lthread.h
+close.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/servers/slapd/back-ldbm/Version.c b/servers/slapd/back-ldbm/Version.c
new file mode 100644 (file)
index 0000000..caca46b
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+static char Versionstr[] = "  ldbm backend %VERSION% (%WHEN%)\n\t%WHOANDWHERE%\n";
diff --git a/servers/slapd/back-ldbm/abandon.c b/servers/slapd/back-ldbm/abandon.c
new file mode 100644 (file)
index 0000000..8ed2dfd
--- /dev/null
@@ -0,0 +1,5 @@
+/* abandon.c - ldbm backend abandon routine */
+
+ldbm_back_abandon()
+{
+}
diff --git a/servers/slapd/back-ldbm/add.c b/servers/slapd/back-ldbm/add.c
new file mode 100644 (file)
index 0000000..3dacd6d
--- /dev/null
@@ -0,0 +1,173 @@
+/* add.c - ldap ldbm back-end add routine */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "back-ldbm.h"
+
+extern int     global_schemacheck;
+extern char    *dn_parent();
+extern char    *dn_normalize();
+extern Entry   *dn2entry();
+
+int
+ldbm_back_add(
+    Backend    *be,
+    Connection *conn,
+    Operation  *op,
+    Entry      *e
+)
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+       char            *matched;
+       char            *dn = NULL, *pdn = NULL;
+       Entry           *p;
+
+       dn = dn_normalize( strdup( e->e_dn ) );
+       matched = NULL;
+       if ( (p = dn2entry( be, dn, &matched )) != NULL ) {
+               cache_return_entry( &li->li_cache, p );
+               entry_free( e );
+               free( dn );
+               send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, "", "" );
+               return( -1 );
+       }
+       if ( matched != NULL ) {
+               free( matched );
+       }
+       /* XXX race condition here til we cache_add_entry_lock below XXX */
+
+       if ( global_schemacheck && oc_schema_check( e ) != 0 ) {
+               Debug( LDAP_DEBUG_TRACE, "entry failed schema check\n", 0, 0,
+                   0 );
+               entry_free( e );
+               free( dn );
+               send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION, "",
+                   "" );
+               return( -1 );
+       }
+
+       /*
+        * Try to add the entry to the cache, assign it a new dnid
+        * and mark it locked.  This should only fail if the entry
+        * already exists.
+        */
+
+       e->e_id = next_id( be );
+       if ( cache_add_entry_lock( &li->li_cache, e, ENTRY_STATE_CREATING )
+           != 0 ) {
+               Debug( LDAP_DEBUG_ANY, "cache_add_entry_lock failed\n", 0, 0,
+                   0 );
+               next_id_return( be, e->e_id );
+               entry_free( e );
+               free( dn );
+               send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, "", "" );
+               return( -1 );
+       }
+
+       /*
+        * Get the parent dn and see if the corresponding entry exists.
+        * If the parent does not exist, only allow the "root" user to
+        * add the entry.
+        */
+
+       if ( (pdn = dn_parent( be, dn )) != NULL ) {
+               /* no parent */
+               matched = NULL;
+               if ( (p = dn2entry( be, pdn, &matched )) == NULL ) {
+                       send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT,
+                           matched, "" );
+                       if ( matched != NULL ) {
+                               free( matched );
+                       }
+                       Debug( LDAP_DEBUG_TRACE, "parent does not exist\n", 0,
+                           0, 0 );
+                       goto error_return;
+               }
+               if ( matched != NULL ) {
+                       free( matched );
+               }
+
+               if ( ! access_allowed( be, conn, op, p, "children", NULL,
+                   op->o_dn, ACL_WRITE ) ) {
+                       Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
+                           0, 0 );
+                       send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
+                           "", "" );
+                       goto error_return;
+               }
+       } else {
+               if ( ! be_isroot( be, op->o_dn ) ) {
+                       Debug( LDAP_DEBUG_TRACE, "no parent & not root\n", 0,
+                           0, 0 );
+                       send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
+                           "", "" );
+                       goto error_return;
+               }
+               p = NULL;
+       }
+
+       /*
+        * add it to the id2children index for the parent
+        */
+
+       if ( id2children_add( be, p, e ) != 0 ) {
+               Debug( LDAP_DEBUG_TRACE, "id2children_add failed\n", 0,
+                   0, 0 );
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "",
+                   "" );
+               goto error_return;
+       }
+
+       /*
+        * Add the entry to the attribute indexes, then add it to
+        * the id2children index, dn2id index, and the id2entry index.
+        */
+
+       /* attribute indexes */
+       if ( index_add_entry( be, e ) != 0 ) {
+               Debug( LDAP_DEBUG_TRACE, "index_add_entry failed\n", 0,
+                   0, 0 );
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
+               goto error_return;
+       }
+
+       /* dn2id index */
+       if ( dn2id_add( be, dn, e->e_id ) != 0 ) {
+               Debug( LDAP_DEBUG_TRACE, "dn2id_add failed\n", 0,
+                   0, 0 );
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
+               goto error_return;
+       }
+
+       /* id2entry index */
+       if ( id2entry_add( be, e ) != 0 ) {
+               Debug( LDAP_DEBUG_TRACE, "id2entry_add failed\n", 0,
+                   0, 0 );
+               (void) dn2id_delete( be, dn );
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
+               goto error_return;
+       }
+
+       send_ldap_result( conn, op, LDAP_SUCCESS, "", "" );
+       if ( dn != NULL )
+               free( dn );
+       if ( pdn != NULL )
+               free( pdn );
+       cache_set_state( &li->li_cache, e, 0 );
+       cache_return_entry( &li->li_cache, e );
+       return( 0 );
+
+error_return:;
+       if ( dn != NULL )
+               free( dn );
+       if ( pdn != NULL )
+               free( pdn );
+       next_id_return( be, e->e_id );
+       cache_delete_entry( &li->li_cache, e );
+       cache_return_entry( &li->li_cache, e );
+
+       return( -1 );
+}
diff --git a/servers/slapd/back-ldbm/attr.c b/servers/slapd/back-ldbm/attr.c
new file mode 100644 (file)
index 0000000..d0bb831
--- /dev/null
@@ -0,0 +1,165 @@
+/* attr.c - backend routines for dealing with attributes */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "back-ldbm.h"
+
+extern char    **str2charray();
+
+static int
+ainfo_type_cmp(
+    char               *type,
+    struct attrinfo    *a
+)
+{
+       return( strcasecmp( type, a->ai_type ) );
+}
+
+static int
+ainfo_cmp(
+    struct attrinfo    *a,
+    struct attrinfo    *b
+)
+{
+       return( strcasecmp( a->ai_type, b->ai_type ) );
+}
+
+/*
+ * Called when a duplicate "index" line is encountered.
+ *
+ * returns 1 => original from init code, indexmask updated
+ *        2 => original not from init code, warn the user
+ */
+
+static int
+ainfo_dup(
+    struct attrinfo    *a,
+    struct attrinfo    *b
+)
+{
+       /*
+        * if the duplicate definition is because we initialized the attr,
+        * just add what came from the config file. otherwise, complain.
+        */
+       if ( a->ai_indexmask & INDEX_FROMINIT ) {
+               a->ai_indexmask |= b->ai_indexmask;
+
+               return( 1 );
+       }
+
+       return( 2 );
+}
+
+void
+attr_masks(
+    struct ldbminfo    *li,
+    char               *type,
+    int                        *indexmask,
+    int                        *syntaxmask
+)
+{
+       struct attrinfo *a;
+
+       *indexmask = 0;
+       *syntaxmask = 0;
+       if ( (a = (struct attrinfo *) avl_find( li->li_attrs, type,
+           ainfo_type_cmp )) == NULL ) {
+               if ( (a = (struct attrinfo *) avl_find( li->li_attrs, "default",
+                   ainfo_type_cmp )) == NULL ) {
+                       return;
+               }
+       }
+       *indexmask = a->ai_indexmask;
+       if ( strcasecmp( a->ai_type, "default" ) == 0 ) {
+               *syntaxmask = attr_syntax( type );
+       } else {
+               *syntaxmask = a->ai_syntaxmask;
+       }
+}
+
+void
+attr_index_config(
+    struct ldbminfo    *li,
+    char               *fname,
+    int                        lineno,
+    int                        argc,
+    char               **argv,
+    int                        init
+)
+{
+       int             i, j;
+       char            **attrs, **indexes;
+       struct attrinfo *a;
+
+       attrs = str2charray( argv[0], "," );
+       if ( argc > 1 ) {
+               indexes = str2charray( argv[1], "," );
+       }
+       for ( i = 0; attrs[i] != NULL; i++ ) {
+               a = (struct attrinfo *) ch_malloc( sizeof(struct attrinfo) );
+               a->ai_type = strdup( attrs[i] );
+               a->ai_syntaxmask = attr_syntax( a->ai_type );
+               if ( argc == 1 ) {
+                       a->ai_indexmask = (INDEX_PRESENCE | INDEX_EQUALITY |
+                           INDEX_APPROX | INDEX_SUB);
+               } else {
+                       a->ai_indexmask = 0;
+                       for ( j = 0; indexes[j] != NULL; j++ ) {
+                               if ( strncasecmp( indexes[j], "pres", 4 )
+                                   == 0 ) {
+                                       a->ai_indexmask |= INDEX_PRESENCE;
+                               } else if ( strncasecmp( indexes[j], "eq", 2 )
+                                   == 0 ) {
+                                       a->ai_indexmask |= INDEX_EQUALITY;
+                               } else if ( strncasecmp( indexes[j], "approx",
+                                   6 ) == 0 ) {
+                                       a->ai_indexmask |= INDEX_APPROX;
+                               } else if ( strncasecmp( indexes[j], "sub", 3 )
+                                   == 0 ) {
+                                       a->ai_indexmask |= INDEX_SUB;
+                               } else if ( strncasecmp( indexes[j], "none", 4 )
+                                   == 0 ) {
+                                       if ( a->ai_indexmask != 0 ) {
+                                               fprintf( stderr,
+"%s: line %d: index type \"none\" cannot be combined with other types\n",
+                                                   fname, lineno );
+                                       }
+                                       a->ai_indexmask = 0;
+                               } else {
+                                       fprintf( stderr,
+                       "%s: line %d: unknown index type \"%s\" (ignored)\n",
+                                           fname, lineno, indexes[j] );
+                                       fprintf( stderr,
+       "valid index types are \"pres\", \"eq\", \"approx\", or \"sub\"\n" );
+                               }
+                       }
+               }
+               if ( init ) {
+                       a->ai_indexmask |= INDEX_FROMINIT;
+               }
+
+               switch (avl_insert( &li->li_attrs, a, ainfo_cmp, ainfo_dup )) {
+               case 1:         /* duplicate - updating init version */
+                       free( a->ai_type );
+                       free( (char *) a );
+                       break;
+
+               case 2:         /* user duplicate - ignore and warn */
+                       fprintf( stderr,
+    "%s: line %d: duplicate index definition for attr \"%s\" (ignored)\n",
+                           fname, lineno, a->ai_type );
+                       free( a->ai_type );
+                       free( (char *) a );
+                       break;
+
+               default:;       /* inserted ok */
+                       /* FALL */
+               }
+       }
+       charray_free( attrs );
+       if ( argc > 1 )
+               charray_free( indexes );
+}
diff --git a/servers/slapd/back-ldbm/back-ldbm.h b/servers/slapd/back-ldbm/back-ldbm.h
new file mode 100644 (file)
index 0000000..2824330
--- /dev/null
@@ -0,0 +1,114 @@
+/* back-ldbm.h - ldap ldbm back-end header file */
+
+#ifndef _BACK_LDBM_H_
+#define _BACK_LDBM_H_
+
+#include "ldbm.h"
+
+#define DEFAULT_CACHE_SIZE     1000
+#define DEFAULT_DBCACHE_SIZE   100000
+#define DEFAULT_DB_DIRECTORY   "/usr/tmp"
+#define DEFAULT_MODE           0600
+
+#define SUBLEN                 3
+
+/*
+ * there is a single index for each attribute.  these prefixes insure
+ * that there is no collision among keys.
+ */
+#define EQ_PREFIX      '='     /* prefix for equality keys     */
+#define APPROX_PREFIX  '~'     /* prefix for approx keys       */
+#define SUB_PREFIX     '*'     /* prefix for substring keys    */
+#define CONT_PREFIX    '\\'    /* prefix for continuation keys */
+
+#define DEFAULT_BLOCKSIZE      8192
+
+/*
+ * This structure represents an id block on disk and an id list
+ * in core.
+ *
+ * The fields have the following meanings:
+ *
+ *     b_nmax  maximum number of ids in this block. if this is == ALLIDSBLOCK,
+ *             then this block represents all ids.
+ *     b_nids  current number of ids in use in this block.  if this
+ *             is == INDBLOCK, then this block is an indirect block
+ *             containing a list of other blocks containing actual ids.
+ *             the list is terminated by an id of NOID.
+ *     b_ids   a list of the actual ids themselves
+ */
+typedef struct block {
+       ID              b_nmax;         /* max number of ids in this list  */
+#define ALLIDSBLOCK    0               /* == 0 => this is an allid block  */
+       ID              b_nids;         /* current number of ids used      */
+#define INDBLOCK       0               /* == 0 => this is an indirect blk */
+       ID              b_ids[1];       /* the ids - actually bigger       */
+} Block, IDList;
+
+#define ALLIDS( idl )          ((idl)->b_nmax == ALLIDSBLOCK)
+#define INDIRECT_BLOCK( idl )  ((idl)->b_nids == INDBLOCK)
+
+/* for the in-core cache of entries */
+struct cache {
+       int             c_maxsize;
+       int             c_cursize;
+       Avlnode         *c_dntree;
+       Avlnode         *c_idtree;
+       Entry           *c_lruhead;     /* lru - add accessed entries here */
+       Entry           *c_lrutail;     /* lru - rem lru entries from here */
+       pthread_mutex_t c_mutex;
+};
+
+/* for the cache of open index files */
+struct dbcache {
+       char            *dbc_name;
+       int             dbc_refcnt;
+       time_t          dbc_lastref;
+       pthread_mutex_t dbc_mutex;
+       pthread_cond_t  dbc_cv;
+       int             dbc_readers;
+       long            dbc_blksize;
+       int             dbc_maxids;
+       int             dbc_maxindirect;
+       LDBM            dbc_db;
+};
+
+/* for the cache of attribute information (which are indexed, etc.) */
+struct attrinfo {
+       char    *ai_type;       /* type name (cn, sn, ...)      */
+       int     ai_indexmask;   /* how the attr is indexed      */
+#define INDEX_PRESENCE 0x01
+#define INDEX_EQUALITY 0x02
+#define INDEX_APPROX   0x04
+#define INDEX_SUB      0x08
+#define INDEX_UNKNOWN  0x10
+#define INDEX_FROMINIT 0x20
+       int     ai_syntaxmask;  /* what kind of syntax          */
+/* ...from slap.h...
+#define SYNTAX_CIS      0x01
+#define SYNTAX_CES      0x02
+#define SYNTAX_BIN      0x04
+   ... etc. ...
+*/
+};
+
+#define MAXDBCACHE     10
+
+struct ldbminfo {
+       ID                      li_nextid;
+       pthread_mutex_t         li_nextid_mutex;
+       int                     li_mode;
+       char                    *li_directory;
+       struct cache            li_cache;
+       Avlnode                 *li_attrs;
+       int                     li_dbcachesize;
+       struct dbcache          li_dbcache[MAXDBCACHE];
+       pthread_mutex_t         li_dbcache_mutex;
+       pthread_cond_t          li_dbcache_cv;
+};
+
+#ifdef NEEDPROTOS
+#include "proto-back-ldbm.h"
+#endif
+
+#endif /* _back_ldbm_h_ */
diff --git a/servers/slapd/back-ldbm/bind.c b/servers/slapd/back-ldbm/bind.c
new file mode 100644 (file)
index 0000000..88fd403
--- /dev/null
@@ -0,0 +1,150 @@
+/* bind.c - ldbm backend bind and unbind routines */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "back-ldbm.h"
+#ifdef KERBEROS
+#include "krb.h"
+#endif
+
+extern Entry           *dn2entry();
+extern Attribute       *attr_find();
+
+#ifdef KERBEROS
+extern int     krbv4_ldap_auth();
+#endif
+
+int
+ldbm_back_bind(
+    Backend            *be,
+    Connection         *conn,
+    Operation          *op,
+    char               *dn,
+    int                        method,
+    struct berval      *cred
+)
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+       Entry           *e;
+       Attribute       *a;
+       int             rc;
+       char            *matched = NULL;
+#ifdef KERBEROS
+       char            krbname[MAX_K_NAME_SZ + 1];
+       AUTH_DAT        ad;
+#endif
+
+       if ( (e = dn2entry( be, dn, &matched )) == NULL ) {
+               /* allow noauth binds */
+               if ( method == LDAP_AUTH_SIMPLE && cred->bv_len == 0 ) {
+                       /*
+                        * bind successful, but return 1 so we don't
+                        * authorize based on noauth credentials
+                        */
+                       send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
+                       rc = 1;
+               } else if ( be_isroot_pw( be, dn, cred ) ) {
+                       /* front end will send result */
+                       rc = 0;
+               } else {
+                       send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT,
+                           matched, NULL );
+                       rc = 1;
+               }
+               if ( matched != NULL ) {
+                       free( matched );
+               }
+               return( rc );
+       }
+
+       switch ( method ) {
+       case LDAP_AUTH_SIMPLE:
+               if ( cred->bv_len == 0 ) {
+                       send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
+                       return( 1 );
+               } else if ( be_isroot_pw( be, dn, cred ) ) {
+                       /* front end will send result */
+                       return( 0 );
+               }
+
+               if ( (a = attr_find( e->e_attrs, "userpassword" )) == NULL ) {
+                       if ( be_isroot_pw( be, dn, cred ) ) {
+                               /* front end will send result */
+                               return( 0 );
+                       }
+                       send_ldap_result( conn, op, LDAP_INAPPROPRIATE_AUTH,
+                           NULL, NULL );
+                       cache_return_entry( &li->li_cache, e );
+                       return( 1 );
+               }
+
+               if ( value_find( a->a_vals, cred, a->a_syntax, 0 ) != 0 ) {
+                       if ( be_isroot_pw( be, dn, cred ) ) {
+                               /* front end will send result */
+                               return( 0 );
+                       }
+                       send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS,
+                           NULL, NULL );
+                       cache_return_entry( &li->li_cache, e );
+                       return( 1 );
+               }
+               break;
+
+#ifdef KERBEROS
+       case LDAP_AUTH_KRBV41:
+               if ( krbv4_ldap_auth( be, cred, &ad ) != LDAP_SUCCESS ) {
+                       send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS,
+                           NULL, NULL );
+                       cache_return_entry( &li->li_cache, e );
+                       return( 1 );
+               }
+               sprintf( krbname, "%s%s%s@%s", ad.pname, *ad.pinst ? "."
+                   : "", ad.pinst, ad.prealm );
+               if ( (a = attr_find( e->e_attrs, "krbname" )) == NULL ) {
+                       /*
+                        * no krbName values present:  check against DN
+                        */
+                       if ( strcasecmp( dn, krbname ) == 0 ) {
+                               break;
+                       }
+                       send_ldap_result( conn, op, LDAP_INAPPROPRIATE_AUTH,
+                           NULL, NULL );
+                       cache_return_entry( &li->li_cache, e );
+                       return( 1 );
+               } else {        /* look for krbName match */
+                       struct berval   krbval;
+
+                       krbval.bv_val = krbname;
+                       krbval.bv_len = strlen( krbname );
+
+                       if ( value_find( a->a_vals, &krbval, a->a_syntax, 3 )
+                           != 0 ) {
+                               send_ldap_result( conn, op,
+                                   LDAP_INVALID_CREDENTIALS, NULL, NULL );
+                               cache_return_entry( &li->li_cache, e );
+                               return( 1 );
+                       }
+               }
+               break;
+
+       case LDAP_AUTH_KRBV42:
+               send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
+               cache_return_entry( &li->li_cache, e );
+               return( 1 );
+#endif
+
+       default:
+               send_ldap_result( conn, op, LDAP_STRONG_AUTH_NOT_SUPPORTED,
+                   NULL, "auth method not supported" );
+               cache_return_entry( &li->li_cache, e );
+               return( 1 );
+       }
+
+       cache_return_entry( &li->li_cache, e );
+
+       /* success:  front end will send result */
+       return( 0 );
+}
diff --git a/servers/slapd/back-ldbm/cache.c b/servers/slapd/back-ldbm/cache.c
new file mode 100644 (file)
index 0000000..49fafb6
--- /dev/null
@@ -0,0 +1,342 @@
+/* cache.c - routines to maintain an in-core cache of entries */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "back-ldbm.h"
+
+static int     cache_delete_entry_internal();
+#ifdef LDAP_DEBUG
+static void    lru_print();
+#endif
+
+/*
+ * the cache has three entry points (ways to find things):
+ *
+ *     by entry        e.g., if you already have an entry from the cache
+ *                     and want to delete it. (really by entry ptr)
+ *     by dn           e.g., when looking for the base object of a search
+ *     by id           e.g., for search candidates
+ *
+ * these correspond to three different avl trees that are maintained.
+ */
+
+static int
+cache_entry_cmp( Entry *e1, Entry *e2 )
+{
+       return( e1 < e2 ? -1 : (e1 > e2 ? 1 : 0) );
+}
+
+static int
+cache_entrydn_cmp( Entry *e1, Entry *e2 )
+{
+       return( strcasecmp( e1->e_dn, e2->e_dn ) );
+}
+
+static int
+cache_entryid_cmp( Entry *e1, Entry *e2 )
+{
+       return( e1->e_id < e2->e_id ? -1 : (e1->e_id > e2->e_id ? 1 : 0) );
+}
+
+void
+cache_set_state( struct cache *cache, Entry *e, int state )
+{
+       /* set cache mutex */
+       pthread_mutex_lock( &cache->c_mutex );
+
+       e->e_state = state;
+
+       /* free cache mutex */
+       pthread_mutex_unlock( &cache->c_mutex );
+}
+
+void
+cache_return_entry( struct cache *cache, Entry *e )
+{
+       /* set cache mutex */
+       pthread_mutex_lock( &cache->c_mutex );
+
+       if ( --e->e_refcnt == 0 && e->e_state == ENTRY_STATE_DELETED ) {
+               entry_free( e );
+       }
+
+       /* free cache mutex */
+       pthread_mutex_unlock( &cache->c_mutex );
+}
+
+#define LRU_DELETE( cache, e ) { \
+       if ( e->e_lruprev != NULL ) { \
+               e->e_lruprev->e_lrunext = e->e_lrunext; \
+       } else { \
+               cache->c_lruhead = e->e_lrunext; \
+       } \
+       if ( e->e_lrunext != NULL ) { \
+               e->e_lrunext->e_lruprev = e->e_lruprev; \
+       } else { \
+               cache->c_lrutail = e->e_lruprev; \
+       } \
+}
+
+#define LRU_ADD( cache, e ) { \
+       e->e_lrunext = cache->c_lruhead; \
+       if ( e->e_lrunext != NULL ) { \
+               e->e_lrunext->e_lruprev = e; \
+       } \
+       cache->c_lruhead = e; \
+       e->e_lruprev = NULL; \
+       if ( cache->c_lrutail == NULL ) { \
+               cache->c_lrutail = e; \
+       } \
+}
+
+/*
+ * cache_create_entry_lock - create an entry in the cache, and lock it.
+ * returns:    0       entry has been created and locked
+ *             1       entry already existed
+ *             -1      something bad happened
+ */
+int
+cache_add_entry_lock(
+    struct cache       *cache,
+    Entry              *e,
+    int                        state
+)
+{
+       int     i, rc;
+       Entry   *ee;
+
+       /* set cache mutex */
+       pthread_mutex_lock( &cache->c_mutex );
+
+       if ( avl_insert( &cache->c_dntree, e, cache_entrydn_cmp, avl_dup_error )
+           != 0 ) {
+               Debug( LDAP_DEBUG_TRACE,
+                   "entry %20s id %d already in dn cache\n", e->e_dn,
+                   e->e_id, 0 );
+
+               /* free cache mutex */
+               pthread_mutex_unlock( &cache->c_mutex );
+               return( 1 );
+       }
+
+       /* id tree */
+       if ( avl_insert( &cache->c_idtree, e, cache_entryid_cmp, avl_dup_error )
+           != 0 ) {
+               Debug( LDAP_DEBUG_ANY, "entry %20s id %d already in id cache\n",
+                   e->e_dn, e->e_id, 0 );
+
+               /* delete from dn tree inserted above */
+               if ( avl_delete( &cache->c_dntree, e, cache_entrydn_cmp )
+                   == NULL ) {
+                       Debug( LDAP_DEBUG_ANY, "can't delete from dn cache\n",
+                           0, 0, 0 );
+               }
+
+               /* free cache mutex */
+               pthread_mutex_unlock( &cache->c_mutex );
+               return( -1 );
+       }
+
+       e->e_state = state;
+       e->e_refcnt = 1;
+
+       /* lru */
+       LRU_ADD( cache, e );
+       if ( ++cache->c_cursize > cache->c_maxsize ) {
+               /*
+                * find the lru entry not currently in use and delete it.
+                * in case a lot of entries are in use, only look at the
+                * first 10 on the tail of the list.
+                */
+               i = 0;
+               while ( cache->c_lrutail != NULL && cache->c_lrutail->e_refcnt
+                   != 0 && i < 10 ) {
+                       /* move this in-use entry to the front of the q */
+                       ee = cache->c_lrutail;
+                       LRU_DELETE( cache, ee );
+                       LRU_ADD( cache, ee );
+                       i++;
+               }
+
+               /*
+                * found at least one to delete - try to get back under
+                * the max cache size.
+                */
+               while ( cache->c_lrutail != NULL && cache->c_lrutail->e_refcnt
+                    == 0 && cache->c_cursize > cache->c_maxsize ) {
+                       e = cache->c_lrutail;
+
+                       /* delete from cache and lru q */
+                       rc = cache_delete_entry_internal( cache, e );
+
+                       entry_free( e );
+               }
+       }
+
+       /* free cache mutex */
+       pthread_mutex_unlock( &cache->c_mutex );
+       return( 0 );
+}
+
+/*
+ * cache_find_entry_dn - find an entry in the cache, given dn
+ */
+
+Entry *
+cache_find_entry_dn(
+    struct cache       *cache,
+    char               *dn
+)
+{
+       Entry           e, *ep;
+
+       /* set cache mutex */
+       pthread_mutex_lock( &cache->c_mutex );
+
+       e.e_dn = dn;
+       if ( (ep = (Entry *) avl_find( cache->c_dntree, &e, cache_entrydn_cmp ))
+           != NULL ) {
+               /*
+                * entry is deleted or not fully created yet
+                */
+               if ( ep->e_state == ENTRY_STATE_DELETED ||
+                   ep->e_state == ENTRY_STATE_CREATING )
+               {
+                       /* free cache mutex */
+                       pthread_mutex_unlock( &cache->c_mutex );
+                       return( NULL );
+               }
+               ep->e_refcnt++;
+
+               /* lru */
+               LRU_DELETE( cache, ep );
+               LRU_ADD( cache, ep );
+       }
+
+       /* free cache mutex */
+       pthread_mutex_unlock( &cache->c_mutex );
+
+       return( ep );
+}
+
+/*
+ * cache_find_entry_id - find an entry in the cache, given id
+ */
+
+Entry *
+cache_find_entry_id(
+    struct cache       *cache,
+    ID                 id
+)
+{
+       Entry   e;
+       Entry   *ep;
+
+       /* set cache mutex */
+       pthread_mutex_lock( &cache->c_mutex );
+
+       e.e_id = id;
+       if ( (ep = (Entry *) avl_find( cache->c_idtree, &e, cache_entryid_cmp ))
+           != NULL ) {
+               /*
+                * entry is deleted or not fully created yet
+                */
+               if ( ep->e_state == ENTRY_STATE_DELETED ||
+                   ep->e_state == ENTRY_STATE_CREATING )
+               {
+                       /* free cache mutex */
+                       pthread_mutex_unlock( &cache->c_mutex );
+                       return( NULL );
+               }
+               ep->e_refcnt++;
+
+               /* lru */
+               LRU_DELETE( cache, ep );
+               LRU_ADD( cache, ep );
+       }
+
+       /* free cache mutex */
+       pthread_mutex_unlock( &cache->c_mutex );
+
+       return( ep );
+}
+
+/*
+ * cache_delete_entry - delete the entry e from the cache.  the caller
+ * should have obtained e (increasing its ref count) via a call to one
+ * of the cache_find_* routines.  the caller should *not* call the
+ * cache_return_entry() routine prior to calling cache_delete_entry().
+ * it performs this function.
+ *
+ * returns:    0       e was deleted ok
+ *             1       e was not in the cache
+ *             -1      something bad happened
+ */
+int
+cache_delete_entry(
+    struct cache       *cache,
+    Entry              *e
+)
+{
+       int     rc;
+
+       /* set cache mutex */
+       pthread_mutex_lock( &cache->c_mutex );
+
+       rc = cache_delete_entry_internal( cache, e );
+
+       /* free cache mutex */
+       pthread_mutex_unlock( &cache->c_mutex );
+       return( rc );
+}
+
+static int
+cache_delete_entry_internal(
+    struct cache       *cache,
+    Entry              *e
+)
+{
+       /* dn tree */
+       if ( avl_delete( &cache->c_dntree, e, cache_entrydn_cmp ) == NULL ) {
+               return( -1 );
+       }
+
+       /* id tree */
+       if ( avl_delete( &cache->c_idtree, e, cache_entryid_cmp ) == NULL ) {
+               return( -1 );
+       }
+
+       /* lru */
+       LRU_DELETE( cache, e );
+       cache->c_cursize--;
+
+       /*
+        * flag entry to be freed later by a call to cache_return_entry()
+        */
+       e->e_state = ENTRY_STATE_DELETED;
+
+       return( 0 );
+}
+
+#ifdef LDAP_DEBUG
+
+static void
+lru_print( struct cache *cache )
+{
+       Entry   *e;
+
+       fprintf( stderr, "LRU queue (head to tail):\n" );
+       for ( e = cache->c_lruhead; e != NULL; e = e->e_lrunext ) {
+               fprintf( stderr, "\tdn %20s id %d refcnt %d\n", e->e_dn,
+                   e->e_id, e->e_refcnt );
+       }
+       fprintf( stderr, "LRU queue (tail to head):\n" );
+       for ( e = cache->c_lrutail; e != NULL; e = e->e_lruprev ) {
+               fprintf( stderr, "\tdn %20s id %d refcnt %d\n", e->e_dn,
+                   e->e_id, e->e_refcnt );
+       }
+}
+
+#endif
diff --git a/servers/slapd/back-ldbm/close.c b/servers/slapd/back-ldbm/close.c
new file mode 100644 (file)
index 0000000..d6758e1
--- /dev/null
@@ -0,0 +1,14 @@
+/* close.c - close ldbm backend */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "back-ldbm.h"
+
+ldbm_back_close( Backend *be )
+{
+       Debug( LDAP_DEBUG_TRACE, "ldbm backend syncing\n", 0, 0, 0 );
+       ldbm_cache_flush_all( be );
+       Debug( LDAP_DEBUG_TRACE, "ldbm backend done syncing\n", 0, 0, 0 );
+}
diff --git a/servers/slapd/back-ldbm/compare.c b/servers/slapd/back-ldbm/compare.c
new file mode 100644 (file)
index 0000000..4757a29
--- /dev/null
@@ -0,0 +1,55 @@
+/* compare.c - ldbm backend compare routine */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "back-ldbm.h"
+
+extern Entry           *dn2entry();
+extern Attribute       *attr_find();
+
+int
+ldbm_back_compare(
+    Backend    *be,
+    Connection *conn,
+    Operation  *op,
+    char       *dn,
+    Ava                *ava
+)
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+       char            *matched;
+       Entry           *e;
+       Attribute       *a;
+       int             i;
+
+       if ( (e = dn2entry( be, dn, &matched )) == NULL ) {
+               send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, "" );
+               return( 1 );
+       }
+
+       if ( ! access_allowed( be, conn, op, e, ava->ava_type, &ava->ava_value,
+           op->o_dn, ACL_COMPARE ) ) {
+               send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, "", "" );
+               cache_return_entry( &li->li_cache, e );
+               return( 1 );
+       }
+
+       if ( (a = attr_find( e->e_attrs, ava->ava_type )) == NULL ) {
+               send_ldap_result( conn, op, LDAP_NO_SUCH_ATTRIBUTE, "", "" );
+               cache_return_entry( &li->li_cache, e );
+               return( 1 );
+       }
+
+       if ( value_find( a->a_vals, &ava->ava_value, a->a_syntax, 1 ) == 0 ) {
+               send_ldap_result( conn, op, LDAP_COMPARE_TRUE, "", "" );
+               cache_return_entry( &li->li_cache, e );
+               return( 0 );
+       }
+
+       send_ldap_result( conn, op, LDAP_COMPARE_FALSE, "", "" );
+       cache_return_entry( &li->li_cache, e );
+       return( 0 );
+}
diff --git a/servers/slapd/back-ldbm/config.c b/servers/slapd/back-ldbm/config.c
new file mode 100644 (file)
index 0000000..d6aca2c
--- /dev/null
@@ -0,0 +1,86 @@
+/* config.c - ldbm backend configuration file routine */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "back-ldbm.h"
+
+ldbm_back_config(
+    Backend    *be,
+    char       *fname,
+    int                lineno,
+    int                argc,
+    char       **argv
+)
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+
+       if ( li == NULL ) {
+               fprintf( stderr, "%s: line %d: ldbm backend info is null!\n",
+                   fname, lineno );
+               exit( 1 );
+       }
+
+       /* directory where database files live */
+       if ( strcasecmp( argv[0], "directory" ) == 0 ) {
+               if ( argc < 2 ) {
+                       fprintf( stderr,
+               "%s: line %d: missing dir in \"directory <dir>\" line\n",
+                           fname, lineno );
+                       exit( 1 );
+               }
+               li->li_directory = strdup( argv[1] );
+
+       /* mode with which to create new database files */
+       } else if ( strcasecmp( argv[0], "mode" ) == 0 ) {
+               if ( argc < 2 ) {
+                       fprintf( stderr,
+                       "%s: line %d: missing mode in \"mode <mode>\" line\n",
+                           fname, lineno );
+                       exit( 1 );
+               }
+               li->li_mode = strtol( argv[1], NULL, 0 );
+
+       /* attribute to index */
+       } else if ( strcasecmp( argv[0], "index" ) == 0 ) {
+               if ( argc < 2 ) {
+                       fprintf( stderr,
+"%s: line %d: missing attr in \"index <attr> [pres,eq,approx,sub]\" line\n",
+                           fname, lineno );
+                       exit( 1 );
+               } else if ( argc > 3 ) {
+                       fprintf( stderr,
+"%s: line %d: extra junk after \"index <attr> [pres,eq,approx,sub]\" line (ignored)\n",
+                           fname, lineno );
+               }
+               attr_index_config( li, fname, lineno, argc - 1, &argv[1], 0 );
+
+       /* size of the cache in entries */
+       } else if ( strcasecmp( argv[0], "cachesize" ) == 0 ) {
+               if ( argc < 2 ) {
+                       fprintf( stderr,
+               "%s: line %d: missing size in \"cachesize <size>\" line\n",
+                           fname, lineno );
+                       exit( 1 );
+               }
+               li->li_cache.c_maxsize = atoi( argv[1] );
+
+       /* size of each dbcache in bytes */
+       } else if ( strcasecmp( argv[0], "dbcachesize" ) == 0 ) {
+               if ( argc < 2 ) {
+                       fprintf( stderr,
+               "%s: line %d: missing size in \"dbcachesize <size>\" line\n",
+                           fname, lineno );
+                       exit( 1 );
+               }
+               li->li_dbcachesize = atoi( argv[1] );
+
+       /* anything else */
+       } else {
+               fprintf( stderr,
+"%s: line %d: unknown directive \"%s\" in ldbm database definition (ignored)\n",
+                   fname, lineno, argv[0] );
+       }
+}
diff --git a/servers/slapd/back-ldbm/dbcache.c b/servers/slapd/back-ldbm/dbcache.c
new file mode 100644 (file)
index 0000000..c16c8b1
--- /dev/null
@@ -0,0 +1,247 @@
+/* ldbmcache.c - maintain a cache of open ldbm files */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include "portable.h"
+#include "slap.h"
+#include "ldapconfig.h"
+#include "back-ldbm.h"
+
+#ifndef SYSERRLIST_IN_STDIO
+extern int             sys_nerr;
+extern char            *sys_errlist[];
+#endif
+extern time_t          currenttime;
+extern pthread_mutex_t currenttime_mutex;
+
+struct dbcache *
+ldbm_cache_open(
+    Backend    *be,
+    char       *name,
+    char       *suffix,
+    int                flags
+)
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+       int             i, lru;
+       time_t          oldtime, curtime;
+       char            buf[MAXPATHLEN];
+       LDBM            db;
+       struct stat     st;
+
+       sprintf( buf, "%s/%s%s", li->li_directory, name, suffix );
+
+       Debug( LDAP_DEBUG_TRACE, "=> ldbm_cache_open( \"%s\", %d, %o )\n", buf,
+           flags, li->li_mode );
+
+       lru = 0;
+       pthread_mutex_lock( &currenttime_mutex );
+       curtime = currenttime;
+       pthread_mutex_unlock( &currenttime_mutex );
+       oldtime = curtime;
+
+       pthread_mutex_lock( &li->li_dbcache_mutex );
+       for ( i = 0; i < MAXDBCACHE && li->li_dbcache[i].dbc_name != NULL;
+           i++ ) {
+               /* already open - return it */
+               if ( strcmp( li->li_dbcache[i].dbc_name, buf ) == 0 ) {
+                       li->li_dbcache[i].dbc_refcnt++;
+                       Debug( LDAP_DEBUG_TRACE,
+                           "<= ldbm_cache_open (cache %d)\n", i, 0, 0 );
+                       pthread_mutex_unlock( &li->li_dbcache_mutex );
+                       return( &li->li_dbcache[i] );
+               }
+
+               /* keep track of lru db */
+               if ( li->li_dbcache[i].dbc_lastref < oldtime &&
+                   li->li_dbcache[i].dbc_refcnt == 0 ) {
+                       lru = i;
+                       oldtime = li->li_dbcache[i].dbc_lastref;
+               }
+       }
+
+       /* no empty slots, not already open - close lru and use that slot */
+       if ( i == MAXDBCACHE ) {
+               i = lru;
+               if ( li->li_dbcache[i].dbc_refcnt != 0 ) {
+                       Debug( LDAP_DEBUG_ANY,
+                           "ldbm_cache_open no unused db to close - waiting\n",
+                           0, 0, 0 );
+                       lru = -1;
+                       while ( lru == -1 ) {
+                               pthread_cond_wait( &li->li_dbcache_cv,
+                                   &li->li_dbcache_mutex );
+                               for ( i = 0; i < MAXDBCACHE; i++ ) {
+                                       if ( li->li_dbcache[i].dbc_refcnt
+                                           == 0 ) {
+                                               lru = i;
+                                               break;
+                                       }
+                               }
+                       }
+                       i = lru;
+               }
+               ldbm_close( li->li_dbcache[i].dbc_db );
+               free( li->li_dbcache[i].dbc_name );
+               li->li_dbcache[i].dbc_name = NULL;
+       }
+
+       if ( (li->li_dbcache[i].dbc_db = ldbm_open( buf, flags, li->li_mode,
+           li->li_dbcachesize )) == NULL ) {
+               Debug( LDAP_DEBUG_TRACE,
+                   "<= ldbm_cache_open NULL \"%s\" errno %d reason \"%s\")\n",
+                   buf, errno, errno > -1 && errno < sys_nerr ?
+                   sys_errlist[errno] : "unknown" );
+               pthread_mutex_unlock( &li->li_dbcache_mutex );
+               return( NULL );
+       }
+       li->li_dbcache[i].dbc_name = strdup( buf );
+       li->li_dbcache[i].dbc_refcnt = 1;
+       li->li_dbcache[i].dbc_lastref = curtime;
+       if ( stat( buf, &st ) == 0 ) {
+               li->li_dbcache[i].dbc_blksize = st.st_blksize;
+       } else {
+               li->li_dbcache[i].dbc_blksize = DEFAULT_BLOCKSIZE;
+       }
+       li->li_dbcache[i].dbc_maxids = (li->li_dbcache[i].dbc_blksize /
+           sizeof(ID)) - 2;
+       li->li_dbcache[i].dbc_maxindirect = (SLAPD_LDBM_MIN_MAXIDS /
+           li->li_dbcache[i].dbc_maxids) + 1;
+
+       Debug( LDAP_DEBUG_ARGS,
+           "ldbm_cache_open (blksize %d) (maxids %d) (maxindirect %d)\n",
+           li->li_dbcache[i].dbc_blksize, li->li_dbcache[i].dbc_maxids,
+           li->li_dbcache[i].dbc_maxindirect );
+       Debug( LDAP_DEBUG_TRACE, "<= ldbm_cache_open (opened %d)\n", i, 0, 0 );
+       pthread_mutex_unlock( &li->li_dbcache_mutex );
+       return( &li->li_dbcache[i] );
+}
+
+void
+ldbm_cache_close( Backend *be, struct dbcache *db )
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+
+       pthread_mutex_lock( &li->li_dbcache_mutex );
+       if ( --db->dbc_refcnt == 0 ) {
+               pthread_cond_signal( &li->li_dbcache_cv );
+       }
+       pthread_mutex_unlock( &li->li_dbcache_mutex );
+}
+
+void
+ldbm_cache_really_close( Backend *be, struct dbcache *db )
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+
+       pthread_mutex_lock( &li->li_dbcache_mutex );
+       if ( --db->dbc_refcnt == 0 ) {
+               pthread_cond_signal( &li->li_dbcache_cv );
+               ldbm_close( db->dbc_db );
+               free( db->dbc_name );
+               db->dbc_name = NULL;
+       }
+       pthread_mutex_unlock( &li->li_dbcache_mutex );
+}
+
+void
+ldbm_cache_flush_all( Backend *be )
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+       int             i;
+
+       pthread_mutex_lock( &li->li_dbcache_mutex );
+       for ( i = 0; i < MAXDBCACHE; i++ ) {
+               if ( li->li_dbcache[i].dbc_name != NULL ) {
+                       Debug( LDAP_DEBUG_TRACE, "ldbm flushing db (%s)\n",
+                           li->li_dbcache[i].dbc_name, 0, 0 );
+                       pthread_mutex_lock( &li->li_dbcache[i].dbc_mutex );
+                       ldbm_sync( li->li_dbcache[i].dbc_db );
+                       pthread_mutex_unlock( &li->li_dbcache[i].dbc_mutex );
+               }
+       }
+       pthread_mutex_unlock( &li->li_dbcache_mutex );
+}
+
+Datum
+ldbm_cache_fetch(
+    struct dbcache     *db,
+    Datum              key
+)
+{
+       Datum   data;
+
+       pthread_mutex_lock( &db->dbc_mutex );
+#ifdef reentrant_database
+       /* increment reader count */
+       db->dbc_readers++
+       pthread_mutex_unlock( &db->dbc_mutex );
+#endif
+
+       data = ldbm_fetch( db->dbc_db, key );
+
+#ifdef reentrant_database
+       pthread_mutex_lock( &db->dbc_mutex );
+       /* decrement reader count & signal any waiting writers */
+       if ( --db->dbc_readers == 0 ) {
+               pthread_cond_signal( &db->dbc_cv );
+       }
+#endif
+       pthread_mutex_unlock( &db->dbc_mutex );
+
+       return( data );
+}
+
+int
+ldbm_cache_store(
+    struct dbcache     *db,
+    Datum              key,
+    Datum              data,
+    int                        flags
+)
+{
+       int     rc;
+
+       pthread_mutex_lock( &db->dbc_mutex );
+#ifdef reentrant_database
+       /* wait for reader count to drop to zero */
+       while ( db->dbc_readers > 0 ) {
+               pthread_cond_wait( &db->dbc_cv, &db->dbc_mutex );
+       }
+#endif
+
+       rc = ldbm_store( db->dbc_db, key, data, flags );
+
+       pthread_mutex_unlock( &db->dbc_mutex );
+
+       return( rc );
+}
+
+int
+ldbm_cache_delete(
+    struct dbcache     *db,
+    Datum              key
+)
+{
+       int     rc;
+
+       pthread_mutex_lock( &db->dbc_mutex );
+#ifdef reentrant_database
+       /* wait for reader count to drop to zero - then write */
+       while ( db->dbc_readers > 0 ) {
+               pthread_cond_wait( &db->dbc_cv, &db->dbc_mutex );
+       }
+#endif
+
+       rc = ldbm_delete( db->dbc_db, key );
+
+       pthread_mutex_unlock( &db->dbc_mutex );
+
+       return( rc );
+}
diff --git a/servers/slapd/back-ldbm/delete.c b/servers/slapd/back-ldbm/delete.c
new file mode 100644 (file)
index 0000000..c773929
--- /dev/null
@@ -0,0 +1,67 @@
+/* delete.c - ldbm backend delete routine */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "back-ldbm.h"
+
+extern Entry           *dn2entry();
+extern Attribute       *attr_find();
+
+int
+ldbm_back_delete(
+    Backend    *be,
+    Connection *conn,
+    Operation  *op,
+    char       *dn
+)
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+       char            *matched = NULL;
+       Entry           *e;
+
+       if ( (e = dn2entry( be, dn, &matched )) == NULL ) {
+               send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, "" );
+               if ( matched != NULL ) {
+                       free( matched );
+               }
+               return( -1 );
+       }
+
+       if ( has_children( be, e ) ) {
+               send_ldap_result( conn, op, LDAP_NOT_ALLOWED_ON_NONLEAF, "",
+                   "" );
+               cache_return_entry( &li->li_cache, e );
+               return( -1 );
+       }
+
+       if ( ! access_allowed( be, conn, op, e, "entry", NULL, op->o_dn,
+           ACL_WRITE ) ) {
+               send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, "", "" );
+               cache_return_entry( &li->li_cache, e );
+               return( -1 );
+       }
+
+       /* XXX delete from parent's id2children entry XXX */
+
+       /* delete from dn2id mapping */
+       if ( dn2id_delete( be, e->e_dn ) != 0 ) {
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
+               cache_return_entry( &li->li_cache, e );
+               return( -1 );
+       }
+
+       /* delete from disk and cache */
+       if ( id2entry_delete( be, e ) != 0 ) {
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
+               cache_return_entry( &li->li_cache, e );
+               return( -1 );
+       }
+       cache_return_entry( &li->li_cache, e );
+
+       send_ldap_result( conn, op, LDAP_SUCCESS, "", "" );
+
+       return( 0 );
+}
diff --git a/servers/slapd/back-ldbm/dn2id.c b/servers/slapd/back-ldbm/dn2id.c
new file mode 100644 (file)
index 0000000..c411608
--- /dev/null
@@ -0,0 +1,182 @@
+/* dn2id.c - routines to deal with the dn2id index */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "back-ldbm.h"
+
+extern struct dbcache  *ldbm_cache_open();
+extern Entry           *cache_find_entry_dn();
+extern Entry           *id2entry();
+extern char            *dn_parent();
+extern Datum           ldbm_cache_fetch();
+
+int
+dn2id_add(
+    Backend    *be,
+    char       *dn,
+    ID         id
+)
+{
+       int             rc;
+       struct dbcache  *db;
+       Datum           key, data;
+
+       Debug( LDAP_DEBUG_TRACE, "=> dn2id_add( \"%s\", %ld )\n", dn, id, 0 );
+
+       if ( (db = ldbm_cache_open( be, "dn2id", LDBM_SUFFIX, LDBM_WRCREAT ))
+           == NULL ) {
+               Debug( LDAP_DEBUG_ANY, "Could not open/create dn2id%s\n",
+                   LDBM_SUFFIX, 0, 0 );
+               return( -1 );
+       }
+
+       dn = strdup( dn );
+       dn_normalize_case( dn );
+
+       key.dptr = dn;
+       key.dsize = strlen( dn ) + 1;
+       data.dptr = (char *) &id;
+       data.dsize = sizeof(ID);
+
+       rc = ldbm_cache_store( db, key, data, LDBM_INSERT );
+
+       free( dn );
+       ldbm_cache_close( be, db );
+
+       Debug( LDAP_DEBUG_TRACE, "<= dn2id_add %d\n", rc, 0, 0 );
+       return( rc );
+}
+
+ID
+dn2id(
+    Backend    *be,
+    char       *dn
+)
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+       struct dbcache  *db;
+       Entry           *e;
+       ID              id;
+       Datum           key, data;
+
+       Debug( LDAP_DEBUG_TRACE, "=> dn2id( \"%s\" )\n", dn, 0, 0 );
+
+       dn = strdup( dn );
+       dn_normalize_case( dn );
+
+       /* first check the cache */
+       if ( (e = cache_find_entry_dn( &li->li_cache, dn )) != NULL ) {
+               id = e->e_id;
+               free( dn );
+               Debug( LDAP_DEBUG_TRACE, "<= dn2id %d (in cache)\n", e->e_id,
+                   0, 0 );
+               cache_return_entry( &li->li_cache, e );
+
+               return( id );
+       }
+
+       if ( (db = ldbm_cache_open( be, "dn2id", LDBM_SUFFIX, LDBM_WRCREAT ))
+           == NULL ) {
+               free( dn );
+               Debug( LDAP_DEBUG_ANY, "<= dn2id could not open dn2id%s\n",
+                   LDBM_SUFFIX, 0, 0 );
+               return( NOID );
+       }
+
+       key.dptr = dn;
+       key.dsize = strlen( dn ) + 1;
+
+       data = ldbm_cache_fetch( db, key );
+
+       ldbm_cache_close( be, db );
+       free( dn );
+
+       if ( data.dptr == NULL ) {
+               Debug( LDAP_DEBUG_TRACE, "<= dn2id NOID\n", 0, 0, 0 );
+               return( NOID );
+       }
+
+       (void) memcpy( (char *) &id, data.dptr, sizeof(ID) );
+
+       ldbm_datum_free( db->dbc_db, data );
+
+       Debug( LDAP_DEBUG_TRACE, "<= dn2id %d\n", id, 0, 0 );
+       return( id );
+}
+
+int
+dn2id_delete(
+    Backend    *be,
+    char       *dn
+)
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+       struct dbcache  *db;
+       Datum           key;
+       int             rc;
+
+       Debug( LDAP_DEBUG_TRACE, "=> dn2id_delete( \"%s\" )\n", dn, 0, 0 );
+
+       if ( (db = ldbm_cache_open( be, "dn2id", LDBM_SUFFIX, LDBM_WRCREAT ))
+           == NULL ) {
+               Debug( LDAP_DEBUG_ANY,
+                   "<= dn2id_delete could not open dn2id%s\n", LDBM_SUFFIX,
+                   0, 0 );
+               return( -1 );
+       }
+
+       dn_normalize_case( dn );
+       key.dptr = dn;
+       key.dsize = strlen( dn ) + 1;
+
+       rc = ldbm_cache_delete( db, key );
+
+       ldbm_cache_close( be, db );
+
+       Debug( LDAP_DEBUG_TRACE, "<= dn2id_delete %d\n", rc, 0, 0 );
+       return( rc );
+}
+
+/*
+ * dn2entry - look up dn in the cache/indexes and return the corresponding
+ * entry.
+ */
+
+Entry *
+dn2entry(
+    Backend    *be,
+    char       *dn,
+    char       **matched
+)
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+       ID              id;
+       Entry           *e;
+       char            *pdn;
+
+       if ( (id = dn2id( be, dn )) != NOID && (e = id2entry( be, id ))
+           != NULL ) {
+               return( e );
+       }
+       *matched = NULL;
+
+       /* stop when we get to the suffix */
+       if ( be_issuffix( be, dn ) ) {
+               return( NULL );
+       }
+
+       /* entry does not exist - see how much of the dn does exist */
+       if ( (pdn = dn_parent( be, dn )) != NULL ) {
+               if ( (e = dn2entry( be, pdn, matched )) != NULL ) {
+                       *matched = pdn;
+                       cache_return_entry( &li->li_cache, e );
+               } else {
+                       free( pdn );
+               }
+       }
+
+       return( NULL );
+}
diff --git a/servers/slapd/back-ldbm/filterindex.c b/servers/slapd/back-ldbm/filterindex.c
new file mode 100644 (file)
index 0000000..55aada5
--- /dev/null
@@ -0,0 +1,356 @@
+/* filterindex.c - generate the list of candidate entries from a filter */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "back-ldbm.h"
+
+extern char    *first_word();
+extern char    *next_word();
+extern char    *phonetic();
+extern IDList  *index_read();
+extern IDList  *idl_intersection();
+extern IDList  *idl_union();
+extern IDList  *idl_notin();
+extern IDList  *idl_allids();
+
+static IDList  *ava_candidates();
+static IDList  *presence_candidates();
+static IDList  *approx_candidates();
+static IDList  *list_candidates();
+static IDList  *substring_candidates();
+static IDList  *substring_comp_candidates();
+
+/*
+ * test_filter - test a filter against a single entry.
+ * returns     0       filter matched
+ *             -1      filter did not match
+ *             >0      an ldap error code
+ */
+
+IDList *
+filter_candidates(
+    Backend    *be,
+    Filter     *f
+)
+{
+       IDList  *result;
+
+       Debug( LDAP_DEBUG_TRACE, "=> filter_candidates\n", 0, 0, 0 );
+
+       result = NULL;
+       switch ( f->f_choice ) {
+       case LDAP_FILTER_EQUALITY:
+               Debug( LDAP_DEBUG_FILTER, "\tEQUALITY\n", 0, 0, 0 );
+               result = ava_candidates( be, &f->f_ava, LDAP_FILTER_EQUALITY );
+               break;
+
+       case LDAP_FILTER_SUBSTRINGS:
+               Debug( LDAP_DEBUG_FILTER, "\tSUBSTRINGS\n", 0, 0, 0 );
+               result = substring_candidates( be, f );
+               break;
+
+       case LDAP_FILTER_GE:
+               Debug( LDAP_DEBUG_FILTER, "\tGE\n", 0, 0, 0 );
+               result = ava_candidates( be, &f->f_ava, LDAP_FILTER_GE );
+               break;
+
+       case LDAP_FILTER_LE:
+               Debug( LDAP_DEBUG_FILTER, "\tLE\n", 0, 0, 0 );
+               result = ava_candidates( be, &f->f_ava, LDAP_FILTER_LE );
+               break;
+
+       case LDAP_FILTER_PRESENT:
+               Debug( LDAP_DEBUG_FILTER, "\tPRESENT\n", 0, 0, 0 );
+               result = presence_candidates( be, f->f_type );
+               break;
+
+       case LDAP_FILTER_APPROX:
+               Debug( LDAP_DEBUG_FILTER, "\tAPPROX\n", 0, 0, 0 );
+               result = approx_candidates( be, &f->f_ava );
+               break;
+
+       case LDAP_FILTER_AND:
+               Debug( LDAP_DEBUG_FILTER, "\tAND\n", 0, 0, 0 );
+               result = list_candidates( be, f->f_and, LDAP_FILTER_AND );
+               break;
+
+       case LDAP_FILTER_OR:
+               Debug( LDAP_DEBUG_FILTER, "\tOR\n", 0, 0, 0 );
+               result = list_candidates( be, f->f_or, LDAP_FILTER_OR );
+               break;
+
+       case LDAP_FILTER_NOT:
+               Debug( LDAP_DEBUG_FILTER, "\tNOT\n", 0, 0, 0 );
+               result = idl_notin( be, idl_allids( be ), filter_candidates( be,
+                   f->f_not ) );
+               break;
+       }
+
+       Debug( LDAP_DEBUG_TRACE, "<= filter_candidates %d\n",
+           result ? result->b_nids : 0, 0, 0 );
+       return( result );
+}
+
+static IDList *
+ava_candidates(
+    Backend    *be,
+    Ava                *ava,
+    int                type
+)
+{
+       IDList  *idl;
+
+       Debug( LDAP_DEBUG_TRACE, "=> ava_candidates 0x%x\n", type, 0, 0 );
+
+       switch ( type ) {
+       case LDAP_FILTER_EQUALITY:
+               idl = index_read( be, ava->ava_type, INDEX_EQUALITY,
+                   ava->ava_value.bv_val );
+               break;
+
+       case LDAP_FILTER_GE:
+               idl = idl_allids( be );
+               break;
+
+       case LDAP_FILTER_LE:
+               idl = idl_allids( be );
+               break;
+       }
+
+       Debug( LDAP_DEBUG_TRACE, "<= ava_candidates %d\n",
+           idl ? idl->b_nids : 0, 0, 0 );
+       return( idl );
+}
+
+static IDList *
+presence_candidates(
+    Backend    *be,
+    char       *type
+)
+{
+       IDList  *idl;
+
+       Debug( LDAP_DEBUG_TRACE, "=> presence_candidates\n", 0, 0, 0 );
+
+       idl = index_read( be, type, 0, "*" );
+
+       Debug( LDAP_DEBUG_TRACE, "<= presence_candidates %d\n",
+           idl ? idl->b_nids : 0, 0, 0 );
+       return( idl );
+}
+
+static IDList *
+approx_candidates(
+    Backend    *be,
+    Ava                *ava
+)
+{
+       char    *w, *c;
+       IDList  *idl, *tmp;
+
+       Debug( LDAP_DEBUG_TRACE, "=> approx_candidates\n", 0, 0, 0 );
+
+       idl = NULL;
+       for ( w = first_word( ava->ava_value.bv_val ); w != NULL;
+           w = next_word( w ) ) {
+               c = phonetic( w );
+               if ( (tmp = index_read( be, ava->ava_type, INDEX_APPROX, c ))
+                   == NULL ) {
+                       free( c );
+                       idl_free( idl );
+                       Debug( LDAP_DEBUG_TRACE, "<= approx_candidates NULL\n",
+                           0, 0, 0 );
+                       return( NULL );
+               }
+               free( c );
+
+               if ( idl == NULL ) {
+                       idl = tmp;
+               } else {
+                       idl = idl_intersection( be, idl, tmp );
+               }
+       }
+
+       Debug( LDAP_DEBUG_TRACE, "<= approx_candidates %d\n",
+           idl ? idl->b_nids : 0, 0, 0 );
+       return( idl );
+}
+
+static IDList *
+list_candidates(
+    Backend    *be,
+    Filter     *flist,
+    int                ftype
+)
+{
+       IDList  *idl, *tmp, *tmp2;
+       Filter  *f;
+
+       Debug( LDAP_DEBUG_TRACE, "=> list_candidates 0x%x\n", ftype, 0, 0 );
+
+       idl = NULL;
+       for ( f = flist; f != NULL; f = f->f_next ) {
+               if ( (tmp = filter_candidates( be, f )) == NULL &&
+                   ftype == LDAP_FILTER_AND ) {
+                               Debug( LDAP_DEBUG_TRACE,
+                                   "<= list_candidates NULL\n", 0, 0, 0 );
+                               idl_free( idl );
+                               return( NULL );
+               }
+
+               tmp2 = idl;
+               if ( idl == NULL ) {
+                       idl = tmp;
+               } else if ( ftype == LDAP_FILTER_AND ) {
+                       idl = idl_intersection( be, idl, tmp );
+                       idl_free( tmp );
+                       idl_free( tmp2 );
+               } else {
+                       idl = idl_union( be, idl, tmp );
+                       idl_free( tmp );
+                       idl_free( tmp2 );
+               }
+       }
+
+       Debug( LDAP_DEBUG_TRACE, "<= list_candidates %d\n",
+           idl ? idl->b_nids : 0, 0, 0 );
+       return( idl );
+}
+
+static IDList *
+substring_candidates(
+    Backend    *be,
+    Filter     *f
+)
+{
+       int     i;
+       IDList  *idl, *tmp, *tmp2;
+
+       Debug( LDAP_DEBUG_TRACE, "=> substring_candidates\n", 0, 0, 0 );
+
+       idl = NULL;
+
+       /* initial */
+       if ( f->f_sub_initial != NULL ) {
+               if ( (int) strlen( f->f_sub_initial ) < SUBLEN - 1 ) {
+                       idl = idl_allids( be );
+               } else if ( (idl = substring_comp_candidates( be, f->f_sub_type,
+                   f->f_sub_initial, '^' )) == NULL ) {
+                       return( NULL );
+               }
+       }
+
+       /* final */
+       if ( f->f_sub_final != NULL ) {
+               if ( (int) strlen( f->f_sub_final ) < SUBLEN - 1 ) {
+                       tmp = idl_allids( be );
+               } else if ( (tmp = substring_comp_candidates( be, f->f_sub_type,
+                   f->f_sub_final, '$' )) == NULL ) {
+                       idl_free( idl );
+                       return( NULL );
+               }
+
+               if ( idl == NULL ) {
+                       idl = tmp;
+               } else {
+                       tmp2 = idl;
+                       idl = idl_intersection( be, idl, tmp );
+                       idl_free( tmp );
+                       idl_free( tmp2 );
+               }
+       }
+
+       for ( i = 0; f->f_sub_any != NULL && f->f_sub_any[i] != NULL; i++ ) {
+               if ( (int) strlen( f->f_sub_any[i] ) < SUBLEN ) {
+                       tmp = idl_allids( be );
+               } else if ( (tmp = substring_comp_candidates( be, f->f_sub_type,
+                   f->f_sub_any[i], 0 )) == NULL ) {
+                       idl_free( idl );
+                       return( NULL );
+               }
+
+               if ( idl == NULL ) {
+                       idl = tmp;
+               } else {
+                       tmp2 = idl;
+                       idl = idl_intersection( be, idl, tmp );
+                       idl_free( tmp );
+                       idl_free( tmp2 );
+               }
+       }
+
+       Debug( LDAP_DEBUG_TRACE, "<= substring_candidates %d\n",
+           idl ? idl->b_nids : 0, 0, 0 );
+       return( idl );
+}
+
+static IDList *
+substring_comp_candidates(
+    Backend    *be,
+    char       *type,
+    char       *val,
+    int                prepost
+)
+{
+       int     i, len;
+       IDList  *idl, *tmp, *tmp2;
+       char    *p;
+       char    buf[SUBLEN + 1];
+
+       Debug( LDAP_DEBUG_TRACE, "=> substring_comp_candidates\n", 0, 0, 0 );
+
+       len = strlen( val );
+       idl = NULL;
+
+       /* prepend ^ for initial substring */
+       if ( prepost == '^' ) {
+               buf[0] = '^';
+               for ( i = 0; i < SUBLEN - 1; i++ ) {
+                       buf[i + 1] = val[i];
+               }
+               buf[SUBLEN] = '\0';
+
+               if ( (idl = index_read( be, type, INDEX_SUB, buf )) == NULL ) {
+                       return( NULL );
+               }
+       } else if ( prepost == '$' ) {
+               p = val + len - SUBLEN + 1;
+               for ( i = 0; i < SUBLEN - 1; i++ ) {
+                       buf[i] = p[i];
+               }
+               buf[SUBLEN - 1] = '$';
+               buf[SUBLEN] = '\0';
+
+               if ( (idl = index_read( be, type, INDEX_SUB, buf )) == NULL ) {
+                       return( NULL );
+               }
+       }
+
+       for ( p = val; p < (val + len - SUBLEN + 1); p++ ) {
+               for ( i = 0; i < SUBLEN; i++ ) {
+                       buf[i] = p[i];
+               }
+               buf[SUBLEN] = '\0';
+
+               if ( (tmp = index_read( be, type, INDEX_SUB, buf )) == NULL ) {
+                       idl_free( idl );
+                       return( NULL );
+               }
+
+               if ( idl == NULL ) {
+                       idl = tmp;
+               } else {
+                       tmp2 = idl;
+                       idl = idl_intersection( be, idl, tmp );
+                       idl_free( tmp );
+                       idl_free( tmp2 );
+               }
+       }
+
+       Debug( LDAP_DEBUG_TRACE, "<= substring_comp_candidates %d\n",
+           idl ? idl->b_nids : 0, 0, 0 );
+       return( idl );
+}
diff --git a/servers/slapd/back-ldbm/id2children.c b/servers/slapd/back-ldbm/id2children.c
new file mode 100644 (file)
index 0000000..3b2c55d
--- /dev/null
@@ -0,0 +1,88 @@
+/* id2children.c - routines to deal with the id2children index */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "back-ldbm.h"
+
+struct dbcache *ldbm_cache_open();
+extern Datum   ldbm_cache_fetch();
+IDList         *idl_fetch();
+
+int
+id2children_add(
+    Backend    *be,
+    Entry      *p,
+    Entry      *e
+)
+{
+       struct dbcache  *db;
+       Datum           key, data;
+       int             len, rc;
+       IDList          *idl;
+       char            buf[20];
+
+       Debug( LDAP_DEBUG_TRACE, "=> id2children_add( %d, %d )\n", p ? p->e_id
+           : 0, e->e_id, 0 );
+
+       if ( (db = ldbm_cache_open( be, "id2children", LDBM_SUFFIX,
+           LDBM_WRCREAT )) == NULL ) {
+               Debug( LDAP_DEBUG_ANY,
+                   "<= id2children_add -1 could not open \"id2children%s\"\n",
+                   LDBM_SUFFIX, 0, 0 );
+               return( -1 );
+       }
+
+       sprintf( buf, "%c%d", EQ_PREFIX, p ? p->e_id : 0 );
+       key.dptr = buf;
+       key.dsize = strlen( buf ) + 1;
+
+       if ( idl_insert_key( be, db, key, e->e_id ) != 0 ) {
+               Debug( LDAP_DEBUG_TRACE, "<= id2children_add -1 (idl_insert)\n",
+                   0, 0, 0 );
+               ldbm_cache_close( be, db );
+               return( -1 );
+       }
+
+       ldbm_cache_close( be, db );
+
+       Debug( LDAP_DEBUG_TRACE, "<= id2children_add 0\n", 0, 0, 0 );
+       return( 0 );
+}
+
+int
+has_children(
+    Backend    *be,
+    Entry      *p
+)
+{
+       struct dbcache  *db;
+       Datum           key;
+       int             rc;
+       IDList          *idl;
+       char            buf[20];
+
+       Debug( LDAP_DEBUG_TRACE, "=> has_children( %d )\n", p->e_id , 0, 0 );
+
+       if ( (db = ldbm_cache_open( be, "id2children", LDBM_SUFFIX,
+           LDBM_WRCREAT )) == NULL ) {
+               Debug( LDAP_DEBUG_ANY,
+                   "<= has_children -1 could not open \"id2children%s\"\n",
+                   LDBM_SUFFIX, 0, 0 );
+               return( 0 );
+       }
+
+       sprintf( buf, "%c%d", EQ_PREFIX, p->e_id );
+       key.dptr = buf;
+       key.dsize = strlen( buf ) + 1;
+
+       idl = idl_fetch( be, db, key );
+
+       ldbm_cache_close( be, db );
+       rc = idl ? 1 : 0;
+       idl_free( idl );
+
+       Debug( LDAP_DEBUG_TRACE, "<= has_children %d\n", rc, 0, 0 );
+       return( rc );
+}
diff --git a/servers/slapd/back-ldbm/id2entry.c b/servers/slapd/back-ldbm/id2entry.c
new file mode 100644 (file)
index 0000000..fbda3c9
--- /dev/null
@@ -0,0 +1,133 @@
+/* id2entry.c - routines to deal with the id2entry index */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "back-ldbm.h"
+
+extern struct dbcache  *ldbm_cache_open();
+extern Datum           ldbm_cache_fetch();
+extern char            *dn_parent();
+extern Entry           *str2entry();
+extern Entry           *cache_find_entry_id();
+extern char            *entry2str();
+extern pthread_mutex_t entry2str_mutex;
+
+int
+id2entry_add( Backend *be, Entry *e )
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+       struct dbcache  *db;
+       Datum           key, data;
+       int             len, rc;
+
+       Debug( LDAP_DEBUG_TRACE, "=> id2entry_add( %d, \"%s\" )\n", e->e_id,
+           e->e_dn, 0 );
+
+       if ( (db = ldbm_cache_open( be, "id2entry", LDBM_SUFFIX, LDBM_WRCREAT ))
+           == NULL ) {
+               Debug( LDAP_DEBUG_ANY, "Could not open/create id2entry%s\n",
+                   LDBM_SUFFIX, 0, 0 );
+               return( -1 );
+       }
+
+       key.dptr = (char *) &e->e_id;
+       key.dsize = sizeof(ID);
+
+       pthread_mutex_lock( &entry2str_mutex );
+       data.dptr = entry2str( e, &len, 1 );
+       data.dsize = len + 1;
+
+       /* store it - LDBM_SYNC ensures id2entry is always consistent */
+       rc = ldbm_cache_store( db, key, data, LDBM_REPLACE|LDBM_SYNC );
+
+       pthread_mutex_unlock( &entry2str_mutex );
+
+       ldbm_cache_close( be, db );
+       (void) cache_add_entry_lock( &li->li_cache, e, 0 );
+
+       Debug( LDAP_DEBUG_TRACE, "<= id2entry_add %d\n", rc, 0, 0 );
+       return( rc );
+}
+
+int
+id2entry_delete( Backend *be, Entry *e )
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+       struct dbcache  *db;
+       Datum           key;
+       int             rc;
+
+       Debug( LDAP_DEBUG_TRACE, "=> id2entry_delete( %d, \"%s\" )\n", e->e_id,
+           e->e_dn, 0 );
+
+       if ( (db = ldbm_cache_open( be, "id2entry", LDBM_SUFFIX, LDBM_WRCREAT ))
+           == NULL ) {
+               Debug( LDAP_DEBUG_ANY, "Could not open/create id2entry%s\n",
+                   LDBM_SUFFIX, 0, 0 );
+               return( -1 );
+       }
+
+       if ( cache_delete_entry( &li->li_cache, e ) != 0 ) {
+               Debug( LDAP_DEBUG_ANY, "could not delete %d (%s) from cache\n",
+                   e->e_id, e->e_dn, 0 );
+       }
+
+       key.dptr = (char *) &e->e_id;
+       key.dsize = sizeof(ID);
+
+       rc = ldbm_cache_delete( db, key );
+
+       ldbm_cache_close( be, db );
+
+       Debug( LDAP_DEBUG_TRACE, "<= id2entry_delete %d\n", rc, 0, 0 );
+       return( rc );
+}
+
+Entry *
+id2entry( Backend *be, ID id )
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+       struct dbcache  *db;
+       Datum           key, data;
+       Entry           *e;
+
+       Debug( LDAP_DEBUG_TRACE, "=> id2entry( %ld )\n", id, 0, 0 );
+
+       if ( (e = cache_find_entry_id( &li->li_cache, id )) != NULL ) {
+               Debug( LDAP_DEBUG_TRACE, "<= id2entry 0x%x (cache)\n", e, 0,
+                   0 );
+               return( e );
+       }
+
+       if ( (db = ldbm_cache_open( be, "id2entry", LDBM_SUFFIX, LDBM_WRCREAT ))
+           == NULL ) {
+               Debug( LDAP_DEBUG_ANY, "Could not open id2entry%s\n",
+                   LDBM_SUFFIX, 0, 0 );
+               return( NULL );
+       }
+
+       key.dptr = (char *) &id;
+       key.dsize = sizeof(ID);
+
+       data = ldbm_cache_fetch( db, key );
+
+       if ( data.dptr == NULL ) {
+               Debug( LDAP_DEBUG_TRACE, "<= id2entry( %ld ) not found\n", id,
+                   0, 0 );
+               ldbm_cache_close( be, db );
+               return( NULL );
+       }
+
+       if ( (e = str2entry( data.dptr )) != NULL ) {
+               e->e_id = id;
+               (void) cache_add_entry_lock( &li->li_cache, e, 0 );
+       }
+
+       ldbm_datum_free( db->dbc_db, data );
+       ldbm_cache_close( be, db );
+
+       Debug( LDAP_DEBUG_TRACE, "<= id2entry( %ld ) 0x%x (disk)\n", id, e, 0 );
+       return( e );
+}
diff --git a/servers/slapd/back-ldbm/idl.c b/servers/slapd/back-ldbm/idl.c
new file mode 100644 (file)
index 0000000..60828a2
--- /dev/null
@@ -0,0 +1,821 @@
+/* idl.c - ldap id list handling routines */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "ldapconfig.h"
+#include "back-ldbm.h"
+
+extern Datum   ldbm_cache_fetch();
+
+IDList *
+idl_alloc( int nids )
+{
+       IDList  *new;
+
+       /* nmax + nids + space for the ids */
+       new = (IDList *) ch_calloc( (2 + nids), sizeof(ID) );
+       new->b_nmax = nids;
+       new->b_nids = 0;
+
+       return( new );
+}
+
+IDList *
+idl_allids( Backend *be )
+{
+       IDList  *idl;
+
+       idl = idl_alloc( 0 );
+       idl->b_nmax = ALLIDSBLOCK;
+       idl->b_nids = next_id_get( be );
+
+       return( idl );
+}
+
+void
+idl_free( IDList *idl )
+{
+       if ( idl == NULL ) {
+               return;
+       }
+
+       free( (char *) idl );
+}
+
+static IDList *
+idl_fetch_one(
+    Backend            *be,
+    struct dbcache     *db,
+    Datum              key
+)
+{
+       Datum   data, k2;
+       IDList  *idl;
+       IDList  **tmp;
+       char    *kstr;
+       int     i, nids;
+
+       /* Debug( LDAP_DEBUG_TRACE, "=> idl_fetch_one\n", 0, 0, 0 ); */
+
+       data = ldbm_cache_fetch( db, key );
+
+       idl = (IDList *) data.dptr;
+
+       return( idl );
+}
+
+IDList *
+idl_fetch(
+    Backend            *be,
+    struct dbcache     *db,
+    Datum              key
+)
+{
+       Datum   data, k2;
+       IDList  *idl;
+       IDList  **tmp;
+       char    *kstr;
+       int     i, nids;
+
+       /* Debug( LDAP_DEBUG_TRACE, "=> idl_fetch\n", 0, 0, 0 ); */
+
+       data = ldbm_cache_fetch( db, key );
+
+       if ( (idl = (IDList *) data.dptr) == NULL ) {
+               return( NULL );
+       }
+
+       /* regular block */
+       if ( ! INDIRECT_BLOCK( idl ) ) {
+               /*
+               Debug( LDAP_DEBUG_TRACE, "<= idl_fetch %d ids (%d max)\n",
+                   idl->b_nids, idl->b_nmax, 0 );
+               */
+
+               /* make sure we have the current value of highest id */
+               if ( idl->b_nmax == ALLIDSBLOCK ) {
+                       idl_free( idl );
+                       idl = idl_allids( be );
+               }
+               return( idl );
+       }
+
+       /*
+        * this is an indirect block which points to other blocks.
+        * we need to read in all the blocks it points to and construct
+        * a big id list containing all the ids, which we will return.
+        */
+
+       /* count the number of blocks & allocate space for pointers to them */
+       for ( i = 0; idl->b_ids[i] != NOID; i++ )
+               ;       /* NULL */
+       tmp = (IDList **) ch_malloc( (i + 1) * sizeof(IDList *) );
+
+       /* read in all the blocks */
+       kstr = (char *) ch_malloc( key.dsize + 20 );
+       nids = 0;
+       for ( i = 0; idl->b_ids[i] != NOID; i++ ) {
+               sprintf( kstr, "%c%s%d", CONT_PREFIX, key.dptr, idl->b_ids[i] );
+               k2.dptr = kstr;
+               k2.dsize = strlen( kstr ) + 1;
+
+               if ( (tmp[i] = idl_fetch_one( be, db, k2 )) == NULL ) {
+                       Debug( LDAP_DEBUG_ANY,
+                           "idl_fetch of (%s) returns NULL\n", k2.dptr, 0, 0 );
+                       continue;
+               }
+
+               nids += tmp[i]->b_nids;
+       }
+       tmp[i] = NULL;
+       idl_free( idl );
+
+       /* allocate space for the big block */
+       idl = idl_alloc( nids );
+       idl->b_nids = nids;
+       nids = 0;
+
+       /* copy in all the ids from the component blocks */
+       for ( i = 0; tmp[i] != NULL; i++ ) {
+               if ( tmp[i] == NULL ) {
+                       continue;
+               }
+
+               SAFEMEMCPY( (char *) &idl->b_ids[nids], (char *) tmp[i]->b_ids,
+                   tmp[i]->b_nids * sizeof(ID) );
+               nids += tmp[i]->b_nids;
+
+               idl_free( tmp[i] );
+       }
+       free( (char *) tmp );
+
+       Debug( LDAP_DEBUG_TRACE, "<= idl_fetch %d ids (%d max)\n", idl->b_nids,
+           idl->b_nmax, 0 );
+       return( idl );
+}
+
+static int
+idl_store(
+    Backend            *be,
+    struct dbcache     *db,
+    Datum              key, 
+    IDList             *idl
+)
+{
+       int     rc;
+       Datum   data;
+
+       /* Debug( LDAP_DEBUG_TRACE, "=> idl_store\n", 0, 0, 0 ); */
+
+       data.dptr = (char *) idl;
+       data.dsize = (2 + idl->b_nmax) * sizeof(ID);
+
+       rc = ldbm_cache_store( db, key, data, LDBM_REPLACE );
+
+       /* Debug( LDAP_DEBUG_TRACE, "<= idl_store %d\n", rc, 0, 0 ); */
+       return( rc );
+}
+
+static void
+idl_split_block(
+    IDList     *b,
+    ID         id,
+    IDList     **n1,
+    IDList     **n2
+)
+{
+       int     i;
+
+       /* find where to split the block */
+       for ( i = 0; i < b->b_nids && id > b->b_ids[i]; i++ )
+               ;       /* NULL */
+
+       *n1 = idl_alloc( i == 0 ? 1 : i );
+       *n2 = idl_alloc( b->b_nids - i + (i == 0 ? 0 : 1));
+
+       /*
+        * everything before the id being inserted in the first block
+        * unless there is nothing, in which case the id being inserted
+        * goes there.
+        */
+       SAFEMEMCPY( (char *) &(*n1)->b_ids[0], (char *) &b->b_ids[0],
+           i * sizeof(ID) );
+       (*n1)->b_nids = (i == 0 ? 1 : i);
+
+       if ( i == 0 ) {
+               (*n1)->b_ids[0] = id;
+       } else {
+               (*n2)->b_ids[0] = id;
+       }
+
+       /* the id being inserted & everything after in the second block */
+       SAFEMEMCPY( (char *) &(*n2)->b_ids[i == 0 ? 0 : 1],
+           (char *) &b->b_ids[i], (b->b_nids - i) * sizeof(ID) );
+       (*n2)->b_nids = b->b_nids - i + (i == 0 ? 0 : 1);
+}
+
+/*
+ * idl_change_first - called when an indirect block's first key has
+ * changed, meaning it needs to be stored under a new key, and the
+ * header block pointing to it needs updating.
+ */
+
+static int
+idl_change_first(
+    Backend            *be,
+    struct dbcache     *db,
+    Datum              hkey,           /* header block key     */
+    IDList             *h,             /* header block         */
+    int                        pos,            /* pos in h to update   */
+    Datum              bkey,           /* data block key       */
+    IDList             *b              /* data block           */
+)
+{
+       int     rc;
+
+       /* Debug( LDAP_DEBUG_TRACE, "=> idl_change_first\n", 0, 0, 0 ); */
+
+       /* delete old key block */
+       if ( (rc = ldbm_cache_delete( db, bkey )) != 0 ) {
+               Debug( LDAP_DEBUG_ANY,
+                   "ldbm_delete of (%s) returns %d\n", bkey.dptr, rc,
+                   0 );
+               return( rc );
+       }
+
+       /* write block with new key */
+       sprintf( bkey.dptr, "%c%s%d", CONT_PREFIX, hkey.dptr, b->b_ids[0] );
+       bkey.dsize = strlen( bkey.dptr ) + 1;
+       if ( (rc = idl_store( be, db, bkey, b )) != 0 ) {
+               Debug( LDAP_DEBUG_ANY,
+                   "idl_store of (%s) returns %d\n", bkey.dptr, rc, 0 );
+               return( rc );
+       }
+
+       /* update + write indirect header block */
+       h->b_ids[pos] = b->b_ids[0];
+       if ( (rc = idl_store( be, db, hkey, h )) != 0 ) {
+               Debug( LDAP_DEBUG_ANY,
+                   "idl_store of (%s) returns %d\n", hkey.dptr, rc, 0 );
+               return( rc );
+       }
+
+       return( 0 );
+}
+
+int
+idl_insert_key(
+    Backend            *be,
+    struct dbcache     *db,
+    Datum              key,
+    ID                 id
+)
+{
+       int     i, j, first, rc;
+       IDList  *idl, *tmp, *tmp2, *tmp3;
+       char    *kstr;
+       Datum   k2;
+
+       if ( (idl = idl_fetch_one( be, db, key )) == NULL ) {
+               idl = idl_alloc( 1 );
+               idl->b_ids[idl->b_nids++] = id;
+               rc = idl_store( be, db, key, idl );
+
+               idl_free( idl );
+               return( rc );
+       }
+
+       /* regular block */
+       if ( ! INDIRECT_BLOCK( idl ) ) {
+               switch ( idl_insert( &idl, id, db->dbc_maxids ) ) {
+               case 0:         /* id inserted - store the updated block */
+               case 1:
+                       rc = idl_store( be, db, key, idl );
+                       break;
+
+               case 2:         /* id already there - nothing to do */
+                       rc = 0;
+                       break;
+
+               case 3:         /* id not inserted - block must be split */
+                       /* check threshold for marking this an all-id block */
+                       if ( db->dbc_maxindirect < 2 ) {
+                               idl_free( idl );
+                               idl = idl_allids( be );
+                               rc = idl_store( be, db, key, idl );
+                               idl_free( idl );
+
+                               return( rc );
+                       }
+
+                       idl_split_block( idl, id, &tmp, &tmp2 );
+                       idl_free( idl );
+
+                       /* create the header indirect block */
+                       idl = idl_alloc( 3 );
+                       idl->b_nmax = 3;
+                       idl->b_nids = INDBLOCK;
+                       idl->b_ids[0] = tmp->b_ids[0];
+                       idl->b_ids[1] = tmp2->b_ids[0];
+                       idl->b_ids[2] = NOID;
+
+                       /* store it */
+                       rc = idl_store( be, db, key, idl );
+
+                       /* store the first id block */
+                       kstr = (char *) ch_malloc( key.dsize + 20 );
+                       sprintf( kstr, "%c%s%d", CONT_PREFIX, key.dptr,
+                           tmp->b_ids[0] );
+                       k2.dptr = kstr;
+                       k2.dsize = strlen( kstr ) + 1;
+                       rc = idl_store( be, db, k2, tmp );
+
+                       /* store the second id block */
+                       sprintf( kstr, "%c%s%d", CONT_PREFIX, key.dptr,
+                           tmp2->b_ids[0] );
+                       k2.dptr = kstr;
+                       k2.dsize = strlen( kstr ) + 1;
+                       rc = idl_store( be, db, k2, tmp2 );
+
+                       free( kstr );
+                       idl_free( tmp );
+                       idl_free( tmp2 );
+                       break;
+               }
+
+               idl_free( idl );
+               return( rc );
+       }
+
+       /*
+        * this is an indirect block which points to other blocks.
+        * we need to read in the block into which the id should be
+        * inserted, then insert the id and store the block.  we might
+        * have to split the block if it is full, which means we also
+        * need to write a new "header" block.
+        */
+
+       /* select the block to try inserting into */
+       for ( i = 0; idl->b_ids[i] != NOID && id > idl->b_ids[i]; i++ )
+               ;       /* NULL */
+       if ( i != 0 ) {
+               i--;
+               first = 0;
+       } else {
+               first = 1;
+       }
+
+       /* get the block */
+       kstr = (char *) ch_malloc( key.dsize + 20 );
+       sprintf( kstr, "%c%s%d", CONT_PREFIX, key.dptr, idl->b_ids[i] );
+       k2.dptr = kstr;
+       k2.dsize = strlen( kstr ) + 1;
+       if ( (tmp = idl_fetch_one( be, db, k2 )) == NULL ) {
+               Debug( LDAP_DEBUG_ANY, "nonexistent continuation block (%s)\n",
+                   k2.dptr, 0, 0 );
+               return( -1 );
+       }
+
+       /* insert the id */
+       switch ( idl_insert( &tmp, id, db->dbc_maxids ) ) {
+       case 0:         /* id inserted ok */
+               if ( (rc = idl_store( be, db, k2, tmp )) != 0 ) {
+                       Debug( LDAP_DEBUG_ANY,
+                           "idl_store of (%s) returns %d\n", k2.dptr, rc, 0 );
+               }
+               break;
+
+       case 1:         /* id inserted - first id in block has changed */
+               /*
+                * key for this block has changed, so we have to
+                * write the block under the new key, delete the
+                * old key block + update and write the indirect
+                * header block.
+                */
+
+               rc = idl_change_first( be, db, key, idl, i, k2, tmp );
+               break;
+
+       case 2:         /* id not inserted - already there */
+               break;
+
+       case 3:         /* id not inserted - block is full */
+               /*
+                * first, see if it will fit in the next block,
+                * without splitting, unless we're trying to insert
+                * into the beginning of the first block.
+                */
+
+               /* is there a next block? */
+               if ( !first && idl->b_ids[i + 1] != NOID ) {
+                       /* read it in */
+                       sprintf( kstr, "%c%s%d", CONT_PREFIX, key.dptr,
+                           idl->b_ids[i + 1] );
+                       k2.dptr = kstr;
+                       k2.dsize = strlen( kstr ) + 1;
+                       if ( (tmp2 = idl_fetch_one( be, db, k2 )) == NULL ) {
+                               Debug( LDAP_DEBUG_ANY,
+                                   "idl_fetch_one (%s) returns NULL\n",
+                                   k2.dptr, 0, 0 );
+                               break;
+                       }
+
+                       switch ( (rc = idl_insert( &tmp2, id,
+                           db->dbc_maxids )) ) {
+                       case 1:         /* id inserted first in block */
+                               rc = idl_change_first( be, db, key, idl,
+                                   i + 1, k2, tmp2 );
+                               /* FALL */
+
+                       case 2:         /* id already there - how? */
+                       case 0:         /* id inserted */
+                               if ( rc == 2 ) {
+                                       Debug( LDAP_DEBUG_ANY,
+                                           "id %d already in next block\n",
+                                           id, 0, 0 );
+                               }
+                               free( kstr );
+                               idl_free( tmp );
+                               idl_free( tmp2 );
+                               idl_free( idl );
+                               return( 0 );
+
+                       case 3:         /* split the original block */
+                               idl_free( tmp2 );
+                               break;
+                       }
+
+               }
+
+               /*
+                * must split the block, write both new blocks + update
+                * and write the indirect header block.
+                */
+
+               /* count how many indirect blocks */
+               for ( j = 0; idl->b_ids[j] != NOID; j++ )
+                       ;       /* NULL */
+
+               /* check it against all-id thresholed */
+               if ( j + 1 > db->dbc_maxindirect ) {
+                       /*
+                        * we've passed the all-id threshold, meaning
+                        * that this set of blocks should be replaced
+                        * by a single "all-id" block.  our job: delete
+                        * all the indirect blocks, and replace the header
+                        * block by an all-id block.
+                        */
+
+                       /* delete all indirect blocks */
+                       for ( j = 0; idl->b_ids[j] != NOID; j++ ) {
+                               sprintf( kstr, "%c%s%d", CONT_PREFIX, key.dptr,
+                                   idl->b_ids[j] );
+                               k2.dptr = kstr;
+                               k2.dsize = strlen( kstr ) + 1;
+
+                               rc = ldbm_cache_delete( db, k2 );
+                       }
+
+                       /* store allid block in place of header block */
+                       idl_free( idl );
+                       idl = idl_allids( be );
+                       rc = idl_store( be, db, key, idl );
+
+                       free( kstr );
+                       idl_free( idl );
+                       idl_free( tmp );
+                       return( rc );
+               }
+
+               idl_split_block( tmp, id, &tmp2, &tmp3 );
+               idl_free( tmp );
+
+               /* create a new updated indirect header block */
+               tmp = idl_alloc( idl->b_nmax + 1 );
+               tmp->b_nids = INDBLOCK;
+               /* everything up to the split block */
+               SAFEMEMCPY( (char *) tmp->b_ids, (char *) idl->b_ids,
+                   i * sizeof(ID) );
+               /* the two new blocks */
+               tmp->b_ids[i] = tmp2->b_ids[0];
+               tmp->b_ids[i + 1] = tmp3->b_ids[0];
+               /* everything after the split block */
+               SAFEMEMCPY( (char *) &tmp->b_ids[i + 2], (char *)
+                   &idl->b_ids[i + 1], (idl->b_nmax - i - 1) * sizeof(ID) );
+
+               /* store the header block */
+               rc = idl_store( be, db, key, tmp );
+
+               /* store the first id block */
+               sprintf( kstr, "%c%s%d", CONT_PREFIX, key.dptr,
+                   tmp2->b_ids[0] );
+               k2.dptr = kstr;
+               k2.dsize = strlen( kstr ) + 1;
+               rc = idl_store( be, db, k2, tmp2 );
+
+               /* store the second id block */
+               sprintf( kstr, "%c%s%d", CONT_PREFIX, key.dptr,
+                   tmp3->b_ids[0] );
+               k2.dptr = kstr;
+               k2.dsize = strlen( kstr ) + 1;
+               rc = idl_store( be, db, k2, tmp3 );
+
+               idl_free( tmp2 );
+               idl_free( tmp3 );
+               break;
+       }
+
+       free( kstr );
+       idl_free( tmp );
+       idl_free( idl );
+       return( rc );
+}
+
+/*
+ * idl_insert - insert an id into an id list.
+ * returns     0       id inserted
+ *             1       id inserted, first id in block has changed
+ *             2       id not inserted, already there
+ *             3       id not inserted, block must be split
+ */
+
+int
+idl_insert( IDList **idl, ID id, int maxids )
+{
+       int     i, j;
+
+       if ( ALLIDS( *idl ) ) {
+               return( 2 );    /* already there */
+       }
+
+       /* is it already there? XXX bin search XXX */
+       for ( i = 0; i < (*idl)->b_nids && id > (*idl)->b_ids[i]; i++ ) {
+               ;       /* NULL */
+       }
+       if ( i < (*idl)->b_nids && (*idl)->b_ids[i] == id ) {
+               return( 2 );    /* already there */
+       }
+
+       /* do we need to make room for it? */
+       if ( (*idl)->b_nids == (*idl)->b_nmax ) {
+               /* make room or indicate block needs splitting */
+               if ( (*idl)->b_nmax == maxids ) {
+                       return( 3 );    /* block needs splitting */
+               }
+
+               (*idl)->b_nmax *= 2;
+               if ( (*idl)->b_nmax > maxids ) {
+                       (*idl)->b_nmax = maxids;
+               }
+               *idl = (IDList *) ch_realloc( (char *) *idl,
+                   ((*idl)->b_nmax + 2) * sizeof(ID) );
+       }
+
+       /* make a slot for the new id */
+       for ( j = (*idl)->b_nids; j != i; j-- ) {
+               (*idl)->b_ids[j] = (*idl)->b_ids[j-1];
+       }
+       (*idl)->b_ids[i] = id;
+       (*idl)->b_nids++;
+       (void) memset( (char *) &(*idl)->b_ids[(*idl)->b_nids], '\0',
+           ((*idl)->b_nmax - (*idl)->b_nids) * sizeof(ID) );
+
+       return( i == 0 ? 1 : 0 );       /* inserted - first id changed or not */
+}
+
+static IDList *
+idl_dup( IDList *idl )
+{
+       IDList  *new;
+
+       if ( idl == NULL ) {
+               return( NULL );
+       }
+
+       new = idl_alloc( idl->b_nmax );
+       SAFEMEMCPY( (char *) new, (char *) idl, (idl->b_nmax + 2)
+           * sizeof(ID) );
+
+       return( new );
+}
+
+static IDList *
+idl_min( IDList *a, IDList *b )
+{
+       return( a->b_nids > b->b_nids ? b : a );
+}
+
+/*
+ * idl_intersection - return a intersection b
+ */
+
+IDList *
+idl_intersection(
+    Backend    *be,
+    IDList     *a,
+    IDList     *b
+)
+{
+       int     ai, bi, ni;
+       IDList  *n;
+
+       if ( a == NULL || b == NULL ) {
+               return( NULL );
+       }
+       if ( ALLIDS( a ) ) {
+               return( idl_dup( b ) );
+       }
+       if ( ALLIDS( b ) ) {
+               return( idl_dup( a ) );
+       }
+
+       n = idl_dup( idl_min( a, b ) );
+
+       for ( ni = 0, ai = 0, bi = 0; ai < a->b_nids; ai++ ) {
+               for ( ; bi < b->b_nids && b->b_ids[bi] < a->b_ids[ai]; bi++ )
+                       ;       /* NULL */
+
+               if ( bi == b->b_nids ) {
+                       break;
+               }
+
+               if ( b->b_ids[bi] == a->b_ids[ai] ) {
+                       n->b_ids[ni++] = a->b_ids[ai];
+               }
+       }
+
+       if ( ni == 0 ) {
+               idl_free( n );
+               return( NULL );
+       }
+       n->b_nids = ni;
+
+       return( n );
+}
+
+/*
+ * idl_union - return a union b
+ */
+
+IDList *
+idl_union(
+    Backend    *be,
+    IDList     *a,
+    IDList     *b
+)
+{
+       int     ai, bi, ni;
+       IDList  *n;
+
+       if ( a == NULL ) {
+               return( idl_dup( b ) );
+       }
+       if ( b == NULL ) {
+               return( idl_dup( a ) );
+       }
+       if ( ALLIDS( a ) || ALLIDS( b ) ) {
+               return( idl_allids( be ) );
+       }
+
+       if ( b->b_nids < a->b_nids ) {
+               n = a;
+               a = b;
+               b = n;
+       }
+
+       n = idl_alloc( a->b_nids + b->b_nids );
+
+       for ( ni = 0, ai = 0, bi = 0; ai < a->b_nids && bi < b->b_nids; ) {
+               if ( a->b_ids[ai] < b->b_ids[bi] ) {
+                       n->b_ids[ni++] = a->b_ids[ai++];
+               } else if ( b->b_ids[bi] < a->b_ids[ai] ) {
+                       n->b_ids[ni++] = b->b_ids[bi++];
+               } else {
+                       n->b_ids[ni++] = a->b_ids[ai];
+                       ai++, bi++;
+               }
+       }
+
+       for ( ; ai < a->b_nids; ai++ ) {
+               n->b_ids[ni++] = a->b_ids[ai];
+       }
+       for ( ; bi < b->b_nids; bi++ ) {
+               n->b_ids[ni++] = b->b_ids[bi];
+       }
+       n->b_nids = ni;
+
+       return( n );
+}
+
+/*
+ * idl_notin - return a intersection ~b (or a minus b)
+ */
+
+IDList *
+idl_notin(
+    Backend    *be,
+    IDList     *a,
+    IDList     *b
+)
+{
+       int     ni, ai, bi;
+       IDList  *n;
+
+       if ( a == NULL ) {
+               return( NULL );
+       }
+       if ( b == NULL ) {
+               return( idl_dup( a ) );
+       }
+       if ( ALLIDS( b ) ) {
+               return( NULL );
+       }
+
+       if ( ALLIDS( a ) ) {
+               n = idl_alloc( SLAPD_LDBM_MIN_MAXIDS );
+               ni = 0;
+
+               for ( ai = 1, bi = 0; ai < a->b_nids && ni < n->b_nmax &&
+                   bi < b->b_nmax; ai++ ) {
+                       if ( b->b_ids[bi] == ai ) {
+                               bi++;
+                       } else {
+                               n->b_ids[ni++] = ai;
+                       }
+               }
+
+               for ( ; ai < a->b_nids && ni < n->b_nmax; ai++ ) {
+                       n->b_ids[ni++] = ai;
+               }
+
+               if ( ni == n->b_nmax ) {
+                       idl_free( n );
+                       return( idl_allids( be ) );
+               } else {
+                       n->b_nids = ni;
+                       return( n );
+               }
+       }
+
+       n = idl_dup( a );
+
+       ni = 0;
+       for ( ai = 0, bi = 0; ai < a->b_nids; ai++ ) {
+               for ( ; bi < b->b_nids && b->b_ids[bi] < a->b_ids[ai];
+                   bi++ ) {
+                       ;       /* NULL */
+               }
+
+               if ( bi == b->b_nids ) {
+                       break;
+               }
+
+               if ( b->b_ids[bi] != a->b_ids[ai] ) {
+                       n->b_ids[ni++] = a->b_ids[ai];
+               }
+       }
+
+       for ( ; ai < a->b_nids; ai++ ) {
+               n->b_ids[ni++] = a->b_ids[ai];
+       }
+       n->b_nids = ni;
+
+       return( n );
+}
+
+ID
+idl_firstid( IDList *idl )
+{
+       if ( idl == NULL || idl->b_nids == 0 ) {
+               return( NOID );
+       }
+
+       if ( ALLIDS( idl ) ) {
+               return( idl->b_nids == 1 ? NOID : 1 );
+       }
+
+       return( idl->b_ids[0] );
+}
+
+ID
+idl_nextid( IDList *idl, ID id )
+{
+       int     i;
+
+       if ( ALLIDS( idl ) ) {
+               return( ++id < idl->b_nids ? id : NOID );
+       }
+
+       for ( i = 0; i < idl->b_nids && idl->b_ids[i] < id; i++ ) {
+               ;       /* NULL */
+       }
+       i++;
+
+       if ( i >= idl->b_nids ) {
+               return( NOID );
+       } else {
+               return( idl->b_ids[i] );
+       }
+}
diff --git a/servers/slapd/back-ldbm/index.c b/servers/slapd/back-ldbm/index.c
new file mode 100644 (file)
index 0000000..3d75a09
--- /dev/null
@@ -0,0 +1,364 @@
+/* index.c - routines for dealing with attribute indexes */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "back-ldbm.h"
+
+extern char            *first_word();
+extern char            *next_word();
+extern char            *phonetic();
+extern IDList          *idl_fetch();
+extern IDList          *idl_allids();
+extern struct dbcache  *ldbm_cache_open();
+
+int    index_add_values();
+
+static int     add_value();
+static int     index2prefix();
+
+int
+index_add_entry(
+    Backend    *be,
+    Entry      *e
+)
+{
+       Attribute       *ap;
+       char            *dnval;
+       struct berval   bv;
+       struct berval   *bvals[2];
+
+       Debug( LDAP_DEBUG_TRACE, "=> index_add( %ld, \"%s\" )\n", e->e_id,
+           e->e_dn, 0 );
+
+       /*
+        * dn index entry - make it look like an attribute so it works
+        * with index_add_values() call
+        */
+
+       bv.bv_val = strdup( e->e_dn );
+       bv.bv_len = strlen( bv.bv_val );
+       (void) dn_normalize_case( bv.bv_val );
+       bvals[0] = &bv;
+       bvals[1] = NULL;
+
+       /* add the dn to the indexes */
+       index_add_values( be, "dn", bvals, e->e_id );
+
+       free( bv.bv_val );
+
+       /* add each attribute to the indexes */
+       for ( ap = e->e_attrs; ap != NULL; ap = ap->a_next ) {
+               index_add_values( be, ap->a_type, ap->a_vals, e->e_id );
+       }
+
+       Debug( LDAP_DEBUG_TRACE, "<= index_add( %ld, \"%s\" ) 0\n", e->e_id,
+           e->e_dn, 0 );
+       return( 0 );
+}
+
+int
+index_add_mods(
+    Backend    *be,
+    LDAPMod    *mods,
+    ID         id
+)
+{
+       int     rc;
+
+       for ( ; mods != NULL; mods = mods->mod_next ) {
+               switch ( mods->mod_op & ~LDAP_MOD_BVALUES ) {
+               case LDAP_MOD_ADD:
+               case LDAP_MOD_REPLACE:
+                       rc = index_add_values( be, mods->mod_type,
+                           mods->mod_bvalues, id );
+                       break;
+
+               case LDAP_MOD_DELETE:
+                       rc = 0;
+                       break;
+               }
+
+               if ( rc != 0 ) {
+                       return( rc );
+               }
+       }
+
+       return( 0 );
+}
+
+IDList *
+index_read(
+    Backend    *be,
+    char       *type,
+    int                indextype,
+    char       *val
+)
+{
+       struct dbcache  *db;
+       Datum           key;
+       IDList          *idl;
+       int             indexmask, syntax;
+       char            prefix;
+       char            *realval, *tmpval;
+       char            buf[BUFSIZ];
+
+       prefix = index2prefix( indextype );
+       Debug( LDAP_DEBUG_TRACE, "=> index_read( \"%s\" \"%c\" \"%s\" )\n",
+           type, prefix, val );
+
+       attr_masks( be->be_private, type, &indexmask, &syntax );
+       if ( ! (indextype & indexmask) ) {
+               idl =  idl_allids( be );
+               Debug( LDAP_DEBUG_TRACE,
+                   "<= index_read %d candidates (allids - not indexed)\n",
+                   idl ? idl->b_nids : 0, 0, 0 );
+               return( idl );
+       }
+
+       attr_normalize( type );
+       if ( (db = ldbm_cache_open( be, type, LDBM_SUFFIX, LDBM_WRCREAT ))
+           == NULL ) {
+               Debug( LDAP_DEBUG_ANY,
+                   "<= index_read NULL (could not open %s%s)\n", type,
+                   LDBM_SUFFIX, 0 );
+               return( NULL );
+       }
+
+       realval = val;
+       tmpval = NULL;
+       if ( prefix != '\0' ) {
+               int     len;
+
+               if ( (len = strlen( val )) < sizeof(buf) ) {
+                       buf[0] = prefix;
+                       strcpy( &buf[1], val );
+                       realval = buf;
+               } else {
+                       /* value + prefix + null */
+                       tmpval = (char *) ch_malloc( len + 2 );
+                       tmpval[0] = prefix;
+                       strcat( &tmpval[1], val );
+                       realval = tmpval;
+               }
+       }
+
+       key.dptr = realval;
+       key.dsize = strlen( realval ) + 1;
+
+       idl = idl_fetch( be, db, key );
+
+       ldbm_cache_close( be, db );
+
+       Debug( LDAP_DEBUG_TRACE, "<= index_read %d candidates\n",
+           idl ? idl->b_nids : 0, 0, 0 );
+       return( idl );
+}
+
+static int
+add_value(
+    Backend            *be,
+    struct dbcache     *db,
+    char               *type,
+    int                        indextype,
+    char               *val,
+    ID                 id
+)
+{
+       int     rc;
+       Datum   key;
+       IDList  *idl;
+       char    prefix;
+       char    *realval, *tmpval, *s;
+       char    buf[BUFSIZ];
+
+       prefix = index2prefix( indextype );
+       Debug( LDAP_DEBUG_TRACE, "=> add_value( \"%c%s\" )\n", prefix, val, 0 );
+
+       realval = val;
+       tmpval = NULL;
+       idl = NULL;
+       if ( prefix != '\0' ) {
+               int     len;
+
+               if ( (len = strlen( val )) < sizeof(buf) ) {
+                       buf[0] = prefix;
+                       strcpy( &buf[1], val );
+                       realval = buf;
+               } else {
+                       /* value + prefix + null */
+                       tmpval = (char *) ch_malloc( len + 2 );
+                       tmpval[0] = prefix;
+                       strcat( &tmpval[1], val );
+                       realval = tmpval;
+               }
+       }
+
+       key.dptr = realval;
+       key.dsize = strlen( realval ) + 1;
+
+       rc = idl_insert_key( be, db, key, id );
+
+       if ( tmpval != NULL ) {
+               free( tmpval );
+       }
+       idl_free( idl );
+
+       pthread_yield();
+
+       /* Debug( LDAP_DEBUG_TRACE, "<= add_value %d\n", rc, 0, 0 ); */
+       return( rc );
+}
+
+int
+index_add_values(
+    Backend            *be,
+    char               *type,
+    struct berval      **vals,
+    ID                 id
+)
+{
+       char            *val, *p, *code, *w;
+       int             i, j, len;
+       int             indexmask, syntax;
+       char            buf[SUBLEN + 1];
+       char            vbuf[BUFSIZ];
+       char            *bigbuf;
+       struct dbcache  *db;
+
+       Debug( LDAP_DEBUG_TRACE, "=> index_add_values( \"%s\", %ld )\n", type,
+           id, 0 );
+
+       attr_masks( be->be_private, type, &indexmask, &syntax );
+       if ( indexmask == 0 ) {
+               return( 0 );
+       }
+
+       if ( (db = ldbm_cache_open( be, type, LDBM_SUFFIX, LDBM_WRCREAT ))
+           == NULL ) {
+               Debug( LDAP_DEBUG_ANY,
+                   "<= index_add_values -1 (could not open/create %s%s)\n",
+                   type, LDBM_SUFFIX, 0 );
+               return( -1 );
+       }
+
+
+       for ( i = 0; vals[i] != NULL; i++ ) {
+               /*
+                * presence index entry
+                */
+               if ( indexmask & INDEX_PRESENCE ) {
+                       add_value( be, db, type, INDEX_PRESENCE, "*", id );
+               }
+
+               Debug( LDAP_DEBUG_TRACE, "*** index_add_values syntax 0x%x syntax bin 0x%x\n",
+                   syntax, SYNTAX_BIN, 0 );
+               if ( syntax & SYNTAX_BIN ) {
+                       ldbm_cache_close( be, db );
+                       return( 0 );
+               }
+
+               bigbuf = NULL;
+               len = vals[i]->bv_len;
+
+               /* value + null */
+               if ( len + 2 > sizeof(vbuf) ) {
+                       bigbuf = (char *) ch_malloc( len + 1 );
+                       val = bigbuf;
+               } else {
+                       val = vbuf;
+               }
+               (void) memcpy( val, vals[i]->bv_val, len );
+               val[len] = '\0';
+
+               value_normalize( val, syntax );
+
+               /*
+                * equality index entry
+                */
+               if ( indexmask & INDEX_EQUALITY ) {
+                       add_value( be, db, type, INDEX_EQUALITY, val, id );
+               }
+
+               /*
+                * approximate index entry
+                */
+               if ( indexmask & INDEX_APPROX ) {
+                       for ( w = first_word( val ); w != NULL;
+                           w = next_word( w ) ) {
+                               if ( (code = phonetic( w )) != NULL ) {
+                                       add_value( be, db, type, INDEX_APPROX,
+                                           code, id );
+                                       free( code );
+                               }
+                       }
+               }
+
+               /*
+                * substrings index entry
+                */
+               if ( indexmask & INDEX_SUB ) {
+                       /* leading and trailing */
+                       if ( len > SUBLEN - 2 ) {
+                               buf[0] = '^';
+                               for ( j = 0; j < SUBLEN - 1; j++ ) {
+                                       buf[j + 1] = val[j];
+                               }
+                               buf[SUBLEN] = '\0';
+
+                               add_value( be, db, type, INDEX_SUB, buf, id );
+
+                               p = val + len - SUBLEN + 1;
+                               for ( j = 0; j < SUBLEN - 1; j++ ) {
+                                       buf[j] = p[j];
+                               }
+                               buf[SUBLEN - 1] = '$';
+                               buf[SUBLEN] = '\0';
+
+                               add_value( be, db, type, INDEX_SUB, buf, id );
+                       }
+
+                       /* any */
+                       for ( p = val; p < (val + len - SUBLEN + 1); p++ ) {
+                               for ( j = 0; j < SUBLEN; j++ ) {
+                                       buf[j] = p[j];
+                               }
+                               buf[SUBLEN] = '\0';
+
+                               add_value( be, db, type, INDEX_SUB, buf, id );
+                       }
+               }
+
+               if ( bigbuf != NULL ) {
+                       free( bigbuf );
+               }
+       }
+       ldbm_cache_close( be, db );
+
+       return( 0 );
+}
+
+static int
+index2prefix( int indextype )
+{
+       int     prefix;
+
+       switch ( indextype ) {
+       case INDEX_EQUALITY:
+               prefix = EQ_PREFIX;
+               break;
+       case INDEX_APPROX:
+               prefix = APPROX_PREFIX;
+               break;
+       case INDEX_SUB:
+               prefix = SUB_PREFIX;
+               break;
+       default:
+               prefix = '\0';
+               break;
+       }
+
+       return( prefix );
+}
diff --git a/servers/slapd/back-ldbm/init.c b/servers/slapd/back-ldbm/init.c
new file mode 100644 (file)
index 0000000..b9c5c2f
--- /dev/null
@@ -0,0 +1,71 @@
+/* init.c - initialize ldbm backend */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "back-ldbm.h"
+
+ldbm_back_init(
+    Backend    *be
+)
+{
+       struct ldbminfo *li;
+       char            *argv[ 4 ];
+       int             i;
+
+       /* allocate backend-specific stuff */
+       li = (struct ldbminfo *) ch_calloc( 1, sizeof(struct ldbminfo) );
+
+       /* arrange to read nextid later (on first request for it) */
+       li->li_nextid = -1;
+
+       /* default cache size */
+       li->li_cache.c_maxsize = DEFAULT_CACHE_SIZE;
+
+       /* default database cache size */
+       li->li_dbcachesize = DEFAULT_DBCACHE_SIZE;
+
+       /* default file creation mode */
+       li->li_mode = DEFAULT_MODE;
+
+       /* default database directory */
+       li->li_directory = DEFAULT_DB_DIRECTORY;
+
+       /* always index dn, id2children, objectclass (used in some searches) */
+       argv[ 0 ] = "dn";
+       argv[ 1 ] = "dn";
+       argv[ 2 ] = NULL;
+       attr_syntax_config( "ldbm dn initialization", 0, 2, argv );
+       argv[ 0 ] = "dn";
+       argv[ 1 ] = "sub";
+       argv[ 2 ] = "eq";
+       argv[ 3 ] = NULL;
+       attr_index_config( li, "ldbm dn initialization", 0, 3, argv, 1 );
+       argv[ 0 ] = "id2children";
+       argv[ 1 ] = "eq";
+       argv[ 2 ] = NULL;
+       attr_index_config( li, "ldbm id2children initialization", 0, 2, argv,
+           1 );
+       argv[ 0 ] = "objectclass";
+       argv[ 1 ] = strdup( "pres,eq" );
+       argv[ 2 ] = NULL;
+       attr_index_config( li, "ldbm objectclass initialization", 0, 2, argv,
+           1 );
+       free( argv[ 1 ] );
+
+       /* initialize various mutex locks & condition variables */
+       pthread_mutex_init( &li->li_cache.c_mutex, pthread_mutexattr_default );
+       pthread_mutex_init( &li->li_nextid_mutex, pthread_mutexattr_default );
+       pthread_mutex_init( &li->li_dbcache_mutex, pthread_mutexattr_default );
+       pthread_cond_init( &li->li_dbcache_cv, pthread_condattr_default );
+       for ( i = 0; i < MAXDBCACHE; i++ ) {
+               pthread_mutex_init( &li->li_dbcache[i].dbc_mutex,
+                   pthread_mutexattr_default );
+               pthread_cond_init( &li->li_dbcache[i].dbc_cv,
+                   pthread_condattr_default );
+       }
+
+       be->be_private = li;
+}
diff --git a/servers/slapd/back-ldbm/kerberos.c b/servers/slapd/back-ldbm/kerberos.c
new file mode 100644 (file)
index 0000000..d22553c
--- /dev/null
@@ -0,0 +1,46 @@
+/* kerberos.c - ldbm backend kerberos bind routines */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "back-ldbm.h"
+
+#ifdef KERBEROS
+#include "krb.h"
+
+#define LDAP_KRB_PRINCIPAL     "ldapserver"
+
+extern char            *ldap_srvtab;
+extern Entry           *dn2entry();
+extern Attribute       *attr_find();
+
+krbv4_ldap_auth(
+    Backend            *be,
+    struct berval      *cred,
+    AUTH_DAT           *ad
+)
+{
+       KTEXT_ST        k;
+       KTEXT           ktxt = &k;
+       char            instance[INST_SZ];
+       int             err;
+
+       Debug( LDAP_DEBUG_TRACE, "=> kerberosv4_ldap_auth\n", 0, 0, 0 );
+
+       SAFEMEMCPY( ktxt->dat, cred->bv_val, cred->bv_len );
+       ktxt->length = cred->bv_len;
+
+       strcpy( instance, "*" );
+       if ( (err = krb_rd_req( ktxt, LDAP_KRB_PRINCIPAL, instance, 0L, ad,
+           ldap_srvtab )) != KSUCCESS ) {
+               Debug( LDAP_DEBUG_ANY, "krb_rd_req failed (%s)\n",
+                   krb_err_txt[err], 0, 0 );
+               return( LDAP_INVALID_CREDENTIALS );
+       }
+
+       return( LDAP_SUCCESS );
+}
+
+#endif /* kerberos */
diff --git a/servers/slapd/back-ldbm/modify.c b/servers/slapd/back-ldbm/modify.c
new file mode 100644 (file)
index 0000000..3fa6c61
--- /dev/null
@@ -0,0 +1,216 @@
+/* modify.c - ldbm backend modify routine */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "back-ldbm.h"
+
+extern int             global_schemacheck;
+extern Entry           *dn2entry();
+extern Attribute       *attr_find();
+
+static int     add_values();
+static int     delete_values();
+static int     replace_values();
+
+int
+ldbm_back_modify(
+    Backend    *be,
+    Connection *conn,
+    Operation  *op,
+    char       *dn,
+    LDAPMod    *mods
+)
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+       char            *matched = NULL;
+       Entry           *e;
+       int             i, err, modtype;
+       LDAPMod         *mod;
+
+       if ( (e = dn2entry( be, dn, &matched )) == NULL ) {
+               send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched,
+                   NULL );
+               if ( matched != NULL ) {
+                       free( matched );
+               }
+               return( -1 );
+       }
+       /* lock entry */
+
+       if ( (err = acl_check_mods( be, conn, op, e, mods )) != LDAP_SUCCESS ) {
+               send_ldap_result( conn, op, err, NULL, NULL );
+               cache_return_entry( &li->li_cache, e );
+               return( -1 );
+       }
+
+       for ( mod = mods; mod != NULL; mod = mod->mod_next ) {
+               switch ( mod->mod_op & ~LDAP_MOD_BVALUES ) {
+               case LDAP_MOD_ADD:
+                       err = add_values( e, mod, op->o_dn );
+                       break;
+
+               case LDAP_MOD_DELETE:
+                       err = delete_values( e, mod, op->o_dn );
+                       break;
+
+               case LDAP_MOD_REPLACE:
+                       err = replace_values( e, mod, op->o_dn );
+                       break;
+               }
+
+               if ( err != LDAP_SUCCESS ) {
+                       /* unlock entry, delete from cache */
+                       send_ldap_result( conn, op, err, NULL, NULL );
+                       cache_return_entry( &li->li_cache, e );
+                       return( -1 );
+               }
+       }
+
+       /* check for abandon */
+       pthread_mutex_lock( &op->o_abandonmutex );
+       if ( op->o_abandon ) {
+               pthread_mutex_unlock( &op->o_abandonmutex );
+               cache_return_entry( &li->li_cache, e );
+               return( -1 );
+       }
+       pthread_mutex_unlock( &op->o_abandonmutex );
+
+       /* check that the entry still obeys the schema */
+       if ( global_schemacheck && oc_schema_check( e ) != 0 ) {
+               send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION, NULL,
+                   NULL );
+               cache_return_entry( &li->li_cache, e );
+               return( -1 );
+       }
+
+       /* modify indexes */
+       if ( index_add_mods( be, mods, e->e_id ) != 0 ) {
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
+               cache_return_entry( &li->li_cache, e );
+               return( -1 );
+       }
+
+       /* check for abandon */
+       pthread_mutex_lock( &op->o_abandonmutex );
+       if ( op->o_abandon ) {
+               pthread_mutex_unlock( &op->o_abandonmutex );
+               cache_return_entry( &li->li_cache, e );
+               return( -1 );
+       }
+       pthread_mutex_unlock( &op->o_abandonmutex );
+
+       /* change the entry itself */
+       if ( id2entry_add( be, e ) != 0 ) {
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
+               cache_return_entry( &li->li_cache, e );
+               return( -1 );
+       }
+
+       send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
+       cache_return_entry( &li->li_cache, e );
+
+       return( 0 );
+}
+
+static int
+add_values(
+    Entry      *e,
+    LDAPMod    *mod,
+    char       *dn
+)
+{
+       int             i;
+       Attribute       *a;
+
+       /* check if the values we're adding already exist */
+       if ( (a = attr_find( e->e_attrs, mod->mod_type )) != NULL ) {
+               for ( i = 0; mod->mod_bvalues[i] != NULL; i++ ) {
+                       if ( value_find( a->a_vals, mod->mod_bvalues[i],
+                           a->a_syntax, 3 ) == 0 ) {
+                               return( LDAP_TYPE_OR_VALUE_EXISTS );
+                       }
+               }
+       }
+
+       /* no - add them */
+       if( attr_merge( e, mod->mod_type, mod->mod_bvalues ) != 0 ) {
+               return( LDAP_CONSTRAINT_VIOLATION );
+       }
+
+       return( LDAP_SUCCESS );
+}
+
+static int
+delete_values(
+    Entry      *e,
+    LDAPMod    *mod,
+    char       *dn
+)
+{
+       int             i, j, k, found;
+       Attribute       *a;
+
+       /* delete the entire attribute */
+       if ( mod->mod_bvalues == NULL ) {
+               Debug( LDAP_DEBUG_ARGS, "removing entire attribute %s\n",
+                   mod->mod_type, 0, 0 );
+               return( attr_delete( &e->e_attrs, mod->mod_type ) ?
+                   LDAP_NO_SUCH_ATTRIBUTE : LDAP_SUCCESS );
+       }
+
+       /* delete specific values - find the attribute first */
+       if ( (a = attr_find( e->e_attrs, mod->mod_type )) == NULL ) {
+               Debug( LDAP_DEBUG_ARGS, "could not find attribute %s\n",
+                   mod->mod_type, 0, 0 );
+               return( LDAP_NO_SUCH_ATTRIBUTE );
+       }
+
+       /* find each value to delete */
+       for ( i = 0; mod->mod_bvalues[i] != NULL; i++ ) {
+               found = 0;
+               for ( j = 0; a->a_vals[j] != NULL; j++ ) {
+                       if ( value_cmp( mod->mod_bvalues[i], a->a_vals[j],
+                           a->a_syntax, 3 ) != 0 ) {
+                               continue;
+                       }
+                       found = 1;
+
+                       /* found a matching value - delete it */
+                       ber_bvfree( a->a_vals[j] );
+                       for ( k = j + 1; a->a_vals[k] != NULL; k++ ) {
+                               a->a_vals[k - 1] = a->a_vals[k];
+                       }
+                       a->a_vals[k - 1] = NULL;
+                       break;
+               }
+
+               /* looked through them all w/o finding it */
+               if ( ! found ) {
+                       Debug( LDAP_DEBUG_ARGS,
+                           "could not find value for attr %s\n",
+                           mod->mod_type, 0, 0 );
+                       return( LDAP_NO_SUCH_ATTRIBUTE );
+               }
+       }
+
+       return( LDAP_SUCCESS );
+}
+
+static int
+replace_values(
+    Entry      *e,
+    LDAPMod    *mod,
+    char       *dn
+)
+{
+       (void) attr_delete( &e->e_attrs, mod->mod_type );
+
+       if ( attr_merge( e, mod->mod_type, mod->mod_bvalues ) != 0 ) {
+               return( LDAP_CONSTRAINT_VIOLATION );
+       }
+
+       return( LDAP_SUCCESS );
+}
diff --git a/servers/slapd/back-ldbm/modrdn.c b/servers/slapd/back-ldbm/modrdn.c
new file mode 100644 (file)
index 0000000..fcd9fcc
--- /dev/null
@@ -0,0 +1,132 @@
+/* modrdn.c - ldbm backend modrdn routine */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "back-ldbm.h"
+
+extern Entry   *dn2entry();
+extern char    *dn_parent();
+
+int
+ldbm_back_modrdn(
+    Backend    *be,
+    Connection *conn,
+    Operation  *op,
+    char       *dn,
+    char       *newrdn,
+    int                deleteoldrdn
+)
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+       char            *matched;
+       char            *pdn, *newdn, *p;
+       char            sep[2];
+       Entry           *e, *e2;
+
+       matched = NULL;
+       if ( (e = dn2entry( be, dn, &matched )) == NULL ) {
+               send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, "" );
+               if ( matched != NULL ) {
+                       free( matched );
+               }
+               return( -1 );
+       }
+
+       if ( (pdn = dn_parent( be, dn )) != NULL ) {
+               /* parent + rdn + separator(s) + null */
+               newdn = (char *) ch_malloc( strlen( pdn ) + strlen( newrdn )
+                   + 3 );
+               if ( dn_type( dn ) == DN_X500 ) {
+                       strcpy( newdn, newrdn );
+                       strcat( newdn, ", " );
+                       strcat( newdn, pdn );
+               } else {
+                       strcpy( newdn, newrdn );
+                       p = strchr( newrdn, '\0' );
+                       p--;
+                       if ( *p != '.' && *p != '@' ) {
+                               if ( (p = strpbrk( dn, ".@" )) != NULL ) {
+                                       sep[0] = *p;
+                                       sep[1] = '\0';
+                                       strcat( newdn, sep );
+                               }
+                       }
+                       strcat( newdn, pdn );
+               }
+       } else {
+               newdn = strdup( newrdn );
+       }
+       (void) dn_normalize( newdn );
+
+       matched = NULL;
+       if ( (e2 = dn2entry( be, newdn, &matched )) != NULL ) {
+               free( newdn );
+               free( pdn );
+               send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, NULL, NULL );
+               cache_return_entry( &li->li_cache, e2 );
+               cache_return_entry( &li->li_cache, e );
+               return( -1 );
+       }
+       if ( matched != NULL ) {
+               free( matched );
+       }
+
+       /* check for abandon */
+       pthread_mutex_lock( &op->o_abandonmutex );
+       if ( op->o_abandon ) {
+               pthread_mutex_unlock( &op->o_abandonmutex );
+               free( newdn );
+               free( pdn );
+               cache_return_entry( &li->li_cache, e2 );
+               cache_return_entry( &li->li_cache, e );
+               return( -1 );
+       }
+       pthread_mutex_unlock( &op->o_abandonmutex );
+
+       /* add new one */
+       if ( dn2id_add( be, newdn, e->e_id ) != 0 ) {
+               free( newdn );
+               free( pdn );
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
+               cache_return_entry( &li->li_cache, e );
+               return( -1 );
+       }
+
+       /* delete old one */
+       if ( dn2id_delete( be, dn ) != 0 ) {
+               free( newdn );
+               free( pdn );
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
+               cache_return_entry( &li->li_cache, e );
+               return( -1 );
+       }
+
+       (void) cache_delete_entry( &li->li_cache, e );
+       free( e->e_dn );
+       e->e_dn = newdn;
+
+       /* XXX
+        * At some point here we need to update the attribute values in
+        * the entry itself that were effected by this RDN change
+        * (respecting the value of the deleteoldrdn parameter).
+        *
+        * Since the code to do this has not yet been written, treat this
+        * omission as a (documented) bug.
+        */
+
+       /* id2entry index */
+       if ( id2entry_add( be, e ) != 0 ) {
+               entry_free( e );
+
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
+               return( -1 );
+       }
+       free( pdn );
+       cache_return_entry( &li->li_cache, e );
+       send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
+
+       return( 0 );
+}
diff --git a/servers/slapd/back-ldbm/nextid.c b/servers/slapd/back-ldbm/nextid.c
new file mode 100644 (file)
index 0000000..e51f4d8
--- /dev/null
@@ -0,0 +1,132 @@
+/* id.c - keep track of the next id to be given out */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include "slap.h"
+#include "back-ldbm.h"
+
+ID
+next_id( Backend *be )
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+       char            buf[MAXPATHLEN];
+       char            buf2[20];
+       FILE            *fp;
+       ID              id;
+
+       sprintf( buf, "%s/NEXTID", li->li_directory );
+
+       pthread_mutex_lock( &li->li_nextid_mutex );
+       /* first time in here since startup - try to read the nexid */
+       if ( li->li_nextid == -1 ) {
+               if ( (fp = fopen( buf, "r" )) == NULL ) {
+                       Debug( LDAP_DEBUG_ANY,
+                           "next_id %d: could not open \"%s\"\n",
+                           li->li_nextid, buf, 0 );
+                       li->li_nextid = 1;
+               } else {
+                       if ( fgets( buf2, sizeof(buf2), fp ) != NULL ) {
+                               li->li_nextid = atol( buf2 );
+                       } else {
+                               Debug( LDAP_DEBUG_ANY,
+                           "next_id %d: could not fgets nextid from \"%s\"\n",
+                                   li->li_nextid, buf2, 0 );
+                               li->li_nextid = 1;
+                       }
+                       fclose( fp );
+               }
+       }
+
+       li->li_nextid++;
+       if ( (fp = fopen( buf, "w" )) == NULL ) {
+               Debug( LDAP_DEBUG_ANY, "next_id %d: could not open \"%s\"\n",
+                   li->li_nextid, buf, 0 );
+       } else {
+               if ( fprintf( fp, "%ld\n", li->li_nextid ) == EOF ) {
+                       Debug( LDAP_DEBUG_ANY, "next_id %d: cannot fprintf\n",
+                           li->li_nextid, 0, 0 );
+               }
+               if( fclose( fp ) != 0 ) {
+                       Debug( LDAP_DEBUG_ANY, "next_id %d: cannot fclose\n",
+                           li->li_nextid, 0, 0 );
+               }
+       }
+       id = li->li_nextid - 1;
+       pthread_mutex_unlock( &li->li_nextid_mutex );
+
+       return( id );
+}
+
+void
+next_id_return( Backend *be, ID id )
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+       char            buf[MAXPATHLEN];
+       FILE            *fp;
+
+       pthread_mutex_lock( &li->li_nextid_mutex );
+       if ( id != li->li_nextid - 1 ) {
+               pthread_mutex_unlock( &li->li_nextid_mutex );
+               return;
+       }
+
+       sprintf( buf, "%s/NEXTID", li->li_directory );
+
+       li->li_nextid--;
+       if ( (fp = fopen( buf, "w" )) == NULL ) {
+               Debug( LDAP_DEBUG_ANY,
+                   "next_id_return of %d: could not open \"%s\" next id %d\n",
+                   id, buf, li->li_nextid );
+       } else {
+               if ( fprintf( fp, "%ld\n", li->li_nextid ) == EOF ) {
+                       Debug( LDAP_DEBUG_ANY,
+                   "next_id_return of %d: cannot fprintf \"%s\" next id %d\n",
+                           id, buf, li->li_nextid );
+               }
+               if( fclose( fp ) != 0 ) {
+                       Debug( LDAP_DEBUG_ANY,
+                   "next_id_return of %d: cannot fclose \"%s\" next id %d\n",
+                           id, buf, li->li_nextid );
+               }
+       }
+       pthread_mutex_unlock( &li->li_nextid_mutex );
+}
+
+ID
+next_id_get( Backend *be )
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+       char            buf[MAXPATHLEN];
+       char            buf2[20];
+       FILE            *fp;
+       ID              id;
+
+       sprintf( buf, "%s/NEXTID", li->li_directory );
+
+       pthread_mutex_lock( &li->li_nextid_mutex );
+       /* first time in here since startup - try to read the nexid */
+       if ( li->li_nextid == -1 ) {
+               if ( (fp = fopen( buf, "r" )) == NULL ) {
+                       Debug( LDAP_DEBUG_ANY,
+                           "next_id %d: could not open \"%s\"\n",
+                           li->li_nextid, buf, 0 );
+                       li->li_nextid = 1;
+               } else {
+                       if ( fgets( buf2, sizeof(buf2), fp ) != NULL ) {
+                               li->li_nextid = atol( buf2 );
+                       } else {
+                               Debug( LDAP_DEBUG_ANY,
+                           "next_id %d: cannot fgets nextid from \"%s\"\n",
+                                   li->li_nextid, buf2, 0 );
+                               li->li_nextid = 1;
+                       }
+                       fclose( fp );
+               }
+       }
+       id = li->li_nextid;
+       pthread_mutex_unlock( &li->li_nextid_mutex );
+
+       return( id );
+}
diff --git a/servers/slapd/back-ldbm/proto-back-ldbm.h b/servers/slapd/back-ldbm/proto-back-ldbm.h
new file mode 100644 (file)
index 0000000..acc69ca
--- /dev/null
@@ -0,0 +1,107 @@
+#ifndef _PROTO_BACK_LDBM
+#define _PROTO_BACK_LDBM
+
+/*
+ * attr.c
+ */
+
+void attr_masks( struct ldbminfo *li, char *type, int *indexmask,
+ int *syntaxmask );
+void attr_index_config( struct ldbminfo *li, char *fname, int lineno,
+ int argc, char **argv, int init );
+
+/*
+ * cache.c
+ */
+
+void cache_set_state( struct cache *cache, Entry *e, int state );
+void cache_return_entry( struct cache *cache, Entry *e );
+int cache_add_entry_lock( struct cache *cache, Entry *e, int state );
+Entry * cache_find_entry_dn( struct cache *cache, char *dn );
+Entry * cache_find_entry_id( struct cache *cache, ID id );
+int cache_delete_entry( struct cache *cache, Entry *e );
+
+/*
+ * dbcache.c
+ */
+
+struct dbcache * ldbm_cache_open( Backend *be, char *name, char *suffix,
+ int flags );
+void ldbm_cache_close( Backend *be, struct dbcache *db );
+void ldbm_cache_flush_all( Backend *be );
+Datum ldbm_cache_fetch( struct dbcache *db, Datum key );
+int ldbm_cache_store( struct dbcache *db, Datum key, Datum data, int flags );
+int ldbm_cache_delete( struct dbcache *db, Datum key );
+
+/*
+ * dn2id.c
+ */
+
+int dn2id_add( Backend *be, char *dn, ID id );
+ID dn2id( Backend *be, char *dn );
+int dn2id_delete( Backend *be, char *dn );
+Entry * dn2entry( Backend *be, char *dn, char **matched );
+
+/*
+ * filterindex.c
+ */
+
+IDList * filter_candidates( Backend *be, Filter *f );
+
+/*
+ * id2children.c
+ */
+
+int id2children_add( Backend *be, Entry *p, Entry *e );
+int has_children( Backend *be, Entry *p );
+
+/*
+ * id2entry.c
+ */
+
+int id2entry_add( Backend *be, Entry *e );
+int id2entry_delete( Backend *be, Entry *e );
+Entry * id2entry( Backend *be, ID id );
+
+/*
+ * idl.c
+ */
+
+IDList * idl_alloc( int nids );
+IDList * idl_allids( Backend *be );
+void idl_free( IDList *idl );
+IDList * idl_fetch( Backend *be, struct dbcache *db, Datum key );
+int idl_insert_key( Backend *be, struct dbcache *db, Datum key, ID id );
+int idl_insert( IDList **idl, ID id, int maxids );
+IDList * idl_intersection( Backend *be, IDList *a, IDList *b );
+IDList * idl_union( Backend *be, IDList *a, IDList *b );
+IDList * idl_notin( Backend *be, IDList *a, IDList *b );
+ID idl_firstid( IDList *idl );
+ID idl_nextid( IDList *idl, ID id );
+
+/*
+ * index.c
+ */
+
+int index_add_entry( Backend *be, Entry *e );
+int index_add_mods( Backend *be, LDAPMod *mods, ID id );
+IDList * index_read( Backend *be, char *type, int indextype, char *val );
+int index_add_values( Backend *be, char *type, struct berval **vals, ID  id );
+
+/*
+ * kerberos.c
+ */
+
+#ifdef KERBEROS
+/* krbv4_ldap_auth( Backend *be, struct berval *cred, AUTH_DAT *ad ); */
+#endif
+
+/*
+ * nextid.c
+ */
+
+ID next_id( Backend *be );
+void next_id_return( Backend *be, ID id );
+ID next_id_get( Backend *be );
+
+#endif
diff --git a/servers/slapd/back-ldbm/search.c b/servers/slapd/back-ldbm/search.c
new file mode 100644 (file)
index 0000000..6a53be4
--- /dev/null
@@ -0,0 +1,414 @@
+/* search.c - ldbm backend search function */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "back-ldbm.h"
+
+extern time_t          currenttime;
+extern pthread_mutex_t currenttime_mutex;
+
+extern ID              dn2id();
+extern IDList          *idl_alloc();
+extern Entry           *id2entry();
+extern Entry           *dn2entry();
+extern Attribute       *attr_find();
+extern IDList          *filter_candidates();
+extern char            *ch_realloc();
+extern char            *dn_parent();
+
+static IDList  *base_candidates();
+static IDList  *onelevel_candidates();
+static IDList  *subtree_candidates();
+
+#define GRABSIZE       BUFSIZ
+
+#define MAKE_SPACE( n ) { \
+       if ( rcur + n > rbuf + rmaxsize ) { \
+               int     offset = rcur - rbuf; \
+               rbuf =  ch_realloc( rbuf, rmaxsize + GRABSIZE ); \
+               rmaxsize += GRABSIZE; \
+               rcur = rbuf + offset; \
+       } \
+}
+
+int
+ldbm_back_search(
+    Backend    *be,
+    Connection *conn,
+    Operation  *op,
+    char       *base,
+    int                scope,
+    int                deref,
+    int                slimit,
+    int                tlimit,
+    Filter     *filter,
+    char       *filterstr,
+    char       **attrs,
+    int                attrsonly
+)
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+       int             err;
+       time_t          stoptime;
+       IDList          *candidates;
+       ID              id;
+       Entry           *e;
+       Attribute       *ref;
+       char            *matched = NULL;
+       int             rmaxsize, nrefs;
+       char            *rbuf, *rcur, *r;
+       int             nentries = 0;
+
+       if ( tlimit == 0 && be_isroot( be, op->o_dn ) ) {
+               tlimit = -1;    /* allow root to set no limit */
+       } else {
+               tlimit = (tlimit > be->be_timelimit || tlimit < 1) ?
+                   be->be_timelimit : tlimit;
+               stoptime = op->o_time + tlimit;
+       }
+       if ( slimit == 0 && be_isroot( be, op->o_dn ) ) {
+               slimit = -1;    /* allow root to set no limit */
+       } else {
+               slimit = (slimit > be->be_sizelimit || slimit < 1) ?
+                   be->be_sizelimit : slimit;
+       }
+
+       switch ( scope ) {
+       case LDAP_SCOPE_BASE:
+               candidates = base_candidates( be, conn, op, base, filter,
+                   attrs, attrsonly, &matched, &err );
+               break;
+
+       case LDAP_SCOPE_ONELEVEL:
+               candidates = onelevel_candidates( be, conn, op, base, filter,
+                   attrs, attrsonly, &matched, &err );
+               break;
+
+       case LDAP_SCOPE_SUBTREE:
+               candidates = subtree_candidates( be, conn, op, base, filter,
+                   attrs, attrsonly, &matched, NULL, &err, 1 );
+               break;
+
+       default:
+               send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, "",
+                   "Bad scope" );
+               return( -1 );
+       }
+
+       /* null candidates means we could not find the base object */
+       if ( candidates == NULL ) {
+               send_ldap_result( conn, op, err, matched, "" );
+               if ( matched != NULL ) {
+                       free( matched );
+               }
+               return( -1 );
+       }
+
+       rmaxsize = 0;
+       nrefs = 0;
+       rbuf = rcur = NULL;
+       MAKE_SPACE( sizeof("Referral:") + 1 );
+       strcpy( rbuf, "Referral:" );
+       rcur = strchr( rbuf, '\0' );
+       for ( id = idl_firstid( candidates ); id != NOID;
+           id = idl_nextid( candidates, id ) ) {
+               /* check for abandon */
+               pthread_mutex_lock( &op->o_abandonmutex );
+               if ( op->o_abandon ) {
+                       pthread_mutex_unlock( &op->o_abandonmutex );
+                       idl_free( candidates );
+                       free( rbuf );
+                       return( 0 );
+               }
+               pthread_mutex_unlock( &op->o_abandonmutex );
+
+               /* check time limit */
+               pthread_mutex_lock( &currenttime_mutex );
+               time( &currenttime );
+               if ( tlimit != -1 && currenttime > stoptime ) {
+                       pthread_mutex_unlock( &currenttime_mutex );
+                       send_ldap_search_result( conn, op,
+                           LDAP_TIMELIMIT_EXCEEDED, NULL, nrefs > 0 ? rbuf :
+                           NULL, nentries );
+                       idl_free( candidates );
+                       free( rbuf );
+                       return( 0 );
+               }
+               pthread_mutex_unlock( &currenttime_mutex );
+
+               /* get the entry */
+               if ( (e = id2entry( be, id )) == NULL ) {
+                       Debug( LDAP_DEBUG_ARGS, "candidate %d not found\n", id,
+                           0, 0 );
+                       continue;
+               }
+
+               /*
+                * if it's a referral, add it to the list of referrals. only do
+                * this for subtree searches, and don't check the filter explicitly
+                * here since it's only a candidate anyway.
+                */
+               if ( e->e_dn != NULL && strncasecmp( e->e_dn, "ref=", 4 )
+                   == 0 && (ref = attr_find( e->e_attrs, "ref" )) != NULL &&
+                   scope == LDAP_SCOPE_SUBTREE )
+               {
+                       int     i, len;
+
+                       if ( ref->a_vals == NULL ) {
+                               Debug( LDAP_DEBUG_ANY, "null ref in (%s)\n", 0,
+                                   0, 0 );
+                       } else {
+                               for ( i = 0; ref->a_vals[i] != NULL; i++ ) {
+                                       /* referral + newline + null */
+                                       MAKE_SPACE( ref->a_vals[i]->bv_len + 2 );
+                                       *rcur++ = '\n';
+                                       strncpy( rcur, ref->a_vals[i]->bv_val,
+                                         ref->a_vals[i]->bv_len );
+                                       rcur = rcur + ref->a_vals[i]->bv_len;
+                                       *rcur = '\0';
+                                       nrefs++;
+                               }
+                       }
+
+               /* otherwise it's an entry - see if it matches the filter */
+               } else {
+                       /* if it matches the filter and scope, send it */
+                       if ( test_filter( be, conn, op, e, filter ) == 0 ) {
+                               int             scopeok;
+                               char    *dn;
+
+                               /* check scope */
+                               scopeok = 1;
+                               if ( scope == LDAP_SCOPE_ONELEVEL ) {
+                                       if ( (dn = dn_parent( be, e->e_dn )) != NULL ) {
+                                               (void) dn_normalize( dn );
+                                               scopeok = (dn == base) ? 1 : (! strcasecmp( dn, base ));
+                                       } else {
+                                               scopeok = (base == NULL || *base == '\0');
+                                       }
+                                       free( dn );
+                               } else if ( scope == LDAP_SCOPE_SUBTREE ) {
+                                       dn = strdup( e->e_dn );
+                                       (void) dn_normalize( dn );
+                                       scopeok = dn_issuffix( dn, base );
+                                       free( dn );
+                               }
+
+                               if ( scopeok ) {
+                                       /* check size limit */
+                                       if ( --slimit == -1 ) {
+                                               cache_return_entry( &li->li_cache, e );
+                                               send_ldap_search_result( conn, op,
+                                                       LDAP_SIZELIMIT_EXCEEDED, NULL,
+                                                       nrefs > 0 ? rbuf : NULL, nentries );
+                                               idl_free( candidates );
+                                               free( rbuf );
+                                               return( 0 );
+                                       }
+
+                                       switch ( send_search_entry( be, conn, op, e,
+                                               attrs, attrsonly ) ) {
+                                       case 0:         /* entry sent ok */
+                                               nentries++;
+                                               break;
+                                       case 1:         /* entry not sent */
+                                               break;
+                                       case -1:        /* connection closed */
+                                               cache_return_entry( &li->li_cache, e );
+                                               idl_free( candidates );
+                                               free( rbuf );
+                                               return( 0 );
+                                       }
+                               }
+                       }
+               }
+
+               cache_return_entry( &li->li_cache, e );
+
+               pthread_yield();
+       }
+       idl_free( candidates );
+       if ( nrefs > 0 ) {
+               send_ldap_search_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
+                   rbuf, nentries );
+       } else {
+               send_ldap_search_result( conn, op, LDAP_SUCCESS, NULL, NULL,
+                   nentries );
+       }
+       free( rbuf );
+
+       return( 0 );
+}
+
+static IDList *
+base_candidates(
+    Backend    *be,
+    Connection *conn,
+    Operation  *op,
+    char       *base,
+    Filter     *filter,
+    char       **attrs,
+    int                attrsonly,
+    char       **matched,
+    int                *err
+)
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+       int             rc;
+       ID              id;
+       IDList          *idl;
+       Entry           *e;
+
+       *err = LDAP_SUCCESS;
+       if ( (e = dn2entry( be, base, matched )) == NULL ) {
+               *err = LDAP_NO_SUCH_OBJECT;
+               return( NULL );
+       }
+
+       idl = idl_alloc( 1 );
+       idl_insert( &idl, e->e_id, 1 );
+
+       cache_return_entry( &li->li_cache, e );
+
+       return( idl );
+}
+
+static IDList *
+onelevel_candidates(
+    Backend    *be,
+    Connection *conn,
+    Operation  *op,
+    char       *base,
+    Filter     *filter,
+    char       **attrs,
+    int                attrsonly,
+    char       **matched,
+    int                *err
+)
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+       Entry           *e;
+       Filter          *f;
+       char            buf[20];
+       IDList          *candidates;
+
+       *err = LDAP_SUCCESS;
+       e = NULL;
+       /* get the base object */
+       if ( base != NULL && *base != '\0' && (e = dn2entry( be, base,
+           matched )) == NULL ) {
+               *err = LDAP_NO_SUCH_OBJECT;
+               return( NULL );
+       }
+
+       /*
+        * modify the filter to be something like this:
+        *
+        *      parent=baseobject & originalfilter
+        */
+
+       f = (Filter *) ch_malloc( sizeof(Filter) );
+       f->f_next = NULL;
+       f->f_choice = LDAP_FILTER_AND;
+       f->f_and = (Filter *) ch_malloc( sizeof(Filter) );
+       f->f_and->f_choice = LDAP_FILTER_EQUALITY;
+       f->f_and->f_ava.ava_type = strdup( "id2children" );
+       sprintf( buf, "%d", e != NULL ? e->e_id : 0 );
+       f->f_and->f_ava.ava_value.bv_val = strdup( buf );
+       f->f_and->f_ava.ava_value.bv_len = strlen( buf );
+       f->f_and->f_next = filter;
+
+       /* from here, it's just like subtree_candidates */
+       candidates = subtree_candidates( be, conn, op, base, f, attrs,
+           attrsonly, matched, e, err, 0 );
+
+       /* free up just the filter stuff we allocated above */
+       f->f_and->f_next = NULL;
+       filter_free( f );
+
+       return( candidates );
+}
+
+static IDList *
+subtree_candidates(
+    Backend    *be,
+    Connection *conn,
+    Operation  *op,
+    char       *base,
+    Filter     *filter,
+    char       **attrs,
+    int                attrsonly,
+    char       **matched,
+    Entry      *e,
+    int                *err,
+    int                lookupbase
+)
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+       Filter          *f;
+       IDList          *candidates;
+
+       /*
+        * get the base object - unless we already have it (from one-level).
+        * also, unless this is a one-level search or a subtree search
+        * starting at the very top of our subtree, we need to modify the
+        * filter to be something like this:
+        *
+        *      dn=*baseobjectdn & (originalfilter | ref=*)
+        *
+        * the "objectclass=referral" part is used to select referrals to return
+        */
+
+       *err = LDAP_SUCCESS;
+       f = NULL;
+       if ( lookupbase ) {
+               if ( base != NULL && *base != '\0' && (e = dn2entry( be, base,
+                   matched )) == NULL ) {
+                       *err = LDAP_NO_SUCH_OBJECT;
+                       return( NULL );
+               }
+
+               f = (Filter *) ch_malloc( sizeof(Filter) );
+               f->f_next = NULL;
+               f->f_choice = LDAP_FILTER_OR;
+               f->f_or = (Filter *) ch_malloc( sizeof(Filter) );
+               f->f_or->f_choice = LDAP_FILTER_EQUALITY;
+               f->f_or->f_avtype = strdup( "objectclass" );
+               f->f_or->f_avvalue.bv_val = strdup( "referral" );
+               f->f_or->f_avvalue.bv_len = strlen( "referral" );
+               f->f_or->f_next = filter;
+               filter = f;
+
+               if ( ! be_issuffix( be, base ) ) {
+                       f = (Filter *) ch_malloc( sizeof(Filter) );
+                       f->f_next = NULL;
+                       f->f_choice = LDAP_FILTER_AND;
+                       f->f_and = (Filter *) ch_malloc( sizeof(Filter) );
+                       f->f_and->f_choice = LDAP_FILTER_SUBSTRINGS;
+                       f->f_and->f_sub_type = strdup( "dn" );
+                       f->f_and->f_sub_initial = NULL;
+                       f->f_and->f_sub_any = NULL;
+                       f->f_and->f_sub_final = strdup( base );
+                       value_normalize( f->f_and->f_sub_final, SYNTAX_CIS );
+                       f->f_and->f_next = filter;
+                       filter = f;
+               }
+       }
+
+       candidates = filter_candidates( be, filter );
+
+       /* free up just the parts we allocated above */
+       if ( f != NULL ) {
+               f->f_and->f_next = NULL;
+               filter_free( f );
+       }
+
+       if ( e != NULL ) {
+               cache_return_entry( &li->li_cache, e );
+       }
+
+       return( candidates );
+}
diff --git a/servers/slapd/back-ldbm/unbind.c b/servers/slapd/back-ldbm/unbind.c
new file mode 100644 (file)
index 0000000..9f3421d
--- /dev/null
@@ -0,0 +1,16 @@
+/* unbind.c - handle an ldap unbind operation */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+
+int
+ldbm_back_unbind(
+       Backend     *be,
+       Connection  *conn,
+       Operation   *op
+)
+{
+       return( 0 );
+}
diff --git a/servers/slapd/back-passwd/Make-template b/servers/slapd/back-passwd/Make-template
new file mode 100644 (file)
index 0000000..39ea8c2
--- /dev/null
@@ -0,0 +1,78 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1995 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       /etc/passwd file backend to stand-alone LDAP server makefile
+#
+#-----------------------------------------------------------------------------
+LDAPSRC        = ../../..
+HDIR   = $(LDAPSRC)/include
+LDIR   = $(LDAPSRC)/libraries
+VERSIONFILE = $(LDAPSRC)/build/version
+
+SRCS   = search.c config.c
+OBJS   = search.o config.o
+
+INCLUDES= -I. -I.. -I$(HDIR)
+DEFINES = $(DEFS) $(THREADS)
+CFLAGS = $(INCLUDES) $(THREADSINCLUDE) $(DEFINES) $(ACFLAGS)
+
+all:   FORCE
+       -@echo "$(SLAPD_BACKENDS)" | grep LDAP_PASSWD 2>&1 > /dev/null; \
+       if [ $$? = 0 ]; then \
+            $(MAKE) $(MFLAGS) CC=$(CC) libback-passwd.a; \
+       else \
+           echo "Include -DLDAP_PASSWD in SLAPD_BACKENDS in the"; \
+           echo "Make-common file to build the passwd backend"; \
+        fi
+
+
+libback-passwd.a:      version.o
+       $(AR) ruv $@ $(OBJS) version.o
+       @if [ ! -z "$(RANLIB)" ]; then \
+               $(RANLIB) $@; \
+       fi
+       @touch ../.backend
+
+version.c: $(OBJS)
+       $(RM) $@
+       (u=$${USER-root} v=`$(CAT) $(VERSIONFILE)` d=`$(PWD)` h=`$(HOSTNAME)` \
+        t=`$(DATE)`; $(SED) -e "s|%WHEN%|$${t}|" \
+       -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+       -e "s|%VERSION%|$${v}|" \
+       < Version.c > $@)
+
+install:       FORCE
+
+lint:  FORCE
+       $(LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+5lint: FORCE
+       $(5LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+clean: FORCE
+       $(RM) libback-passwd.a *.o core a.out version.c
+
+depend:        FORCE
+       $(MKDEP) $(INCLUDES) $(DEFINES) $(SRCS)
+
+links:
+       @$(LN) .src/*.[ch] .
+# DO NOT DELETE THIS LINE -- mkdep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+search.o: search.c ../../../include/portable.h ../slap.h ../../../include/avl.h
+search.o: ../../../include/lber.h ../../../include/ldap.h
+search.o: ../../../include/lthread.h ../../../include/ldif.h
+config.o: config.c ../../../include/portable.h ../slap.h ../../../include/avl.h
+config.o: ../../../include/lber.h ../../../include/ldap.h
+config.o: ../../../include/lthread.h ../../../include/ldif.h
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/servers/slapd/back-passwd/Version.c b/servers/slapd/back-passwd/Version.c
new file mode 100644 (file)
index 0000000..99b0fc2
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+static char Versionstr[] = "  passwd backend %VERSION% (%WHEN%)\n\t%WHOANDWHERE%\n";
diff --git a/servers/slapd/back-passwd/config.c b/servers/slapd/back-passwd/config.c
new file mode 100644 (file)
index 0000000..5a26ff0
--- /dev/null
@@ -0,0 +1,41 @@
+/* config.c - passwd backend configuration file routine */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "portable.h"
+#include "slap.h"
+
+passwd_back_config(
+    Backend    *be,
+    char       *fname,
+    int                lineno,
+    int                argc,
+    char       **argv
+)
+{
+       /* alternate passwd file */
+       if ( strcasecmp( argv[0], "file" ) == 0 ) {
+#ifdef HAVE_SETPWFILE
+               if ( argc < 2 ) {
+                       fprintf( stderr,
+               "%s: line %d: missing filename in \"file <filename>\" line\n",
+                           fname, lineno );
+                       exit( 1 );
+               }
+               be->be_private = strdup( argv[1] );
+#else /* HAVE_SETPWFILE */
+               fprintf( stderr,
+    "%s: line %d: ignoring \"file\" option (not supported on this platform)\n",
+                           fname, lineno );
+#endif /* HAVE_SETPWFILE */
+
+       /* anything else */
+       } else {
+               fprintf( stderr,
+"%s: line %d: unknown directive \"%s\" in passwd database definition (ignored)\n",
+                   fname, lineno, argv[0] );
+       }
+}
diff --git a/servers/slapd/back-passwd/search.c b/servers/slapd/back-passwd/search.c
new file mode 100644 (file)
index 0000000..11c1d8e
--- /dev/null
@@ -0,0 +1,153 @@
+/* search.c - /etc/passwd backend search function */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <pwd.h>
+#include "portable.h"
+#include "slap.h"
+
+extern time_t          currenttime;
+extern pthread_mutex_t currenttime_mutex;
+
+static Entry   *pw2entry();
+
+int
+passwd_back_search(
+    Backend    *be,
+    Connection *conn,
+    Operation  *op,
+    char       *base,
+    int                scope,
+    int                deref,
+    int                slimit,
+    int                tlimit,
+    Filter     *filter,
+    char       *filterstr,
+    char       **attrs,
+    int                attrsonly
+)
+{
+       struct passwd   *pw;
+       Entry           *e;
+       char            *s;
+       time_t          stoptime;
+
+       tlimit = (tlimit > be->be_timelimit || tlimit < 1) ? be->be_timelimit
+           : tlimit;
+       stoptime = op->o_time + tlimit;
+       slimit = (slimit > be->be_sizelimit || slimit < 1) ? be->be_sizelimit
+           : slimit;
+
+#ifdef HAVE_SETPWFILE
+       if ( be->be_private != NULL ) {
+               endpwent();
+               (void) setpwfile( (char *) be->be_private );
+       }
+#endif /* HAVE_SETPWFILE */
+
+       if ( scope == LDAP_SCOPE_BASE ) {
+               if ( (s = strchr( base, '@' )) != NULL ) {
+                       *s = '\0';
+               }
+
+               if ( (pw = getpwnam( base )) == NULL ) {
+                       send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT,
+                           s != NULL ? s + 1 : NULL, NULL );
+                       return( -1 );
+               }
+
+               e = pw2entry( be, pw );
+               if ( test_filter( be, conn, op, e, filter ) == 0 ) {
+                       send_search_entry( be, conn, op, e, attrs, attrsonly );
+               }
+               entry_free( e );
+
+               send_ldap_result( conn, op, LDAP_SUCCESS, "", "" );
+
+               return( 0 );
+       }
+
+       for ( pw = getpwent(); pw != NULL; pw = getpwent() ) {
+               /* check for abandon */
+               pthread_mutex_lock( &op->o_abandonmutex );
+               if ( op->o_abandon ) {
+                       pthread_mutex_unlock( &op->o_abandonmutex );
+                       endpwent();
+                       return( -1 );
+               }
+               pthread_mutex_unlock( &op->o_abandonmutex );
+
+               /* check size limit */
+               if ( --slimit == -1 ) {
+                       send_ldap_result( conn, op, LDAP_SIZELIMIT_EXCEEDED,
+                           NULL, NULL );
+                       endpwent();
+                       return( 0 );
+               }
+
+               /* check time limit */
+               pthread_mutex_lock( &currenttime_mutex );
+               time( &currenttime );
+               if ( currenttime > stoptime ) {
+                       pthread_mutex_unlock( &currenttime_mutex );
+                       send_ldap_result( conn, op, LDAP_TIMELIMIT_EXCEEDED,
+                           NULL, NULL );
+                       endpwent();
+                       return( 0 );
+               }
+               pthread_mutex_unlock( &currenttime_mutex );
+
+               e = pw2entry( be, pw );
+
+               if ( test_filter( be, conn, op, e, filter ) == 0 ) {
+                       send_search_entry( be, conn, op, e, attrs, attrsonly );
+               }
+
+               entry_free( e );
+       }
+       endpwent();
+       send_ldap_result( conn, op, LDAP_SUCCESS, "", "" );
+
+       return( 0 );
+}
+
+static Entry *
+pw2entry( Backend *be, struct passwd *pw )
+{
+       Entry           *e;
+       char            buf[256];
+       struct berval   val;
+       struct berval   *vals[2];
+
+       vals[0] = &val;
+       vals[1] = NULL;
+
+       /*
+        * from pw we get pw_name and make it uid and cn and sn and
+        * we get pw_gecos and make it cn and we give it an objectclass
+        * of person.
+        */
+
+       e = (Entry *) ch_calloc( 1, sizeof(Entry) );
+       e->e_attrs = NULL;
+
+       sprintf( buf, "%s@%s", pw->pw_name, be->be_suffix[0] );
+       e->e_dn = strdup( buf );
+
+       val.bv_val = pw->pw_name;
+       val.bv_len = strlen( pw->pw_name );
+       attr_merge( e, "cn", vals );
+       attr_merge( e, "sn", vals );
+       attr_merge( e, "uid", vals );
+       val.bv_val = pw->pw_gecos;
+       val.bv_len = strlen( pw->pw_gecos );
+       attr_merge( e, "cn", vals );
+       val.bv_val = "person";
+       val.bv_len = strlen( val.bv_val );
+       attr_merge( e, "objectclass", vals );
+
+       return( e );
+}
diff --git a/servers/slapd/back-shell/Make-template b/servers/slapd/back-shell/Make-template
new file mode 100644 (file)
index 0000000..1eb631b
--- /dev/null
@@ -0,0 +1,113 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1995 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       shell backend to stand-alone LDAP server makefile
+#
+#-----------------------------------------------------------------------------
+LDAPSRC        = ../../..
+HDIR   = $(LDAPSRC)/include
+LDIR   = $(LDAPSRC)/libraries
+VERSIONFILE = $(LDAPSRC)/build/version
+
+SRCS   = init.c config.c fork.c search.c bind.c unbind.c add.c delete.c \
+               modify.c modrdn.c compare.c abandon.c result.c
+OBJS   = init.o config.o fork.o search.o bind.o unbind.o add.o delete.o \
+               modify.o modrdn.o compare.o abandon.o result.o
+
+INCLUDES= -I. -I.. -I$(HDIR)
+DEFINES = $(DEFS) $(THREADS)
+CFLAGS = $(INCLUDES) $(THREADSINCLUDE) $(DEFINES) $(ACFLAGS)
+
+all:   FORCE
+       -@echo "$(SLAPD_BACKENDS)" | grep LDAP_SHELL 2>&1 > /dev/null; \
+       if [ $$? = 0 ]; then \
+            $(MAKE) $(MFLAGS) CC=$(CC) libback-shell.a; \
+       else \
+           echo "Include -DLDAP_SHELL in SLAPD_BACKENDS in the"; \
+           echo "Make-common file to build the shell backend"; \
+        fi
+
+
+libback-shell.a:       version.o
+       $(AR) ruv $@ $(OBJS) version.o
+       @if [ ! -z "$(RANLIB)" ]; then \
+               $(RANLIB) $@; \
+       fi
+       @touch ../.backend
+
+version.c: $(OBJS)
+       $(RM) $@
+       (u=$${USER-root} v=`$(CAT) $(VERSIONFILE)` d=`$(PWD)` h=`$(HOSTNAME)` \
+       t=`$(DATE)`; $(SED) -e "s|%WHEN%|$${t}|" \
+       -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+       -e "s|%VERSION%|$${v}|" \
+       < Version.c > $@)
+
+install:       FORCE
+
+lint:  FORCE
+       $(LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+5lint: FORCE
+       $(5LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+clean: FORCE
+       $(RM) libback-shell.a *.o core a.out version.c
+
+depend:        FORCE
+       $(MKDEP) $(INCLUDES) $(DEFINES) $(SRCS)
+
+links:
+       @$(LN) .src/*.[ch] .
+# DO NOT DELETE THIS LINE -- mkdep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+init.o: init.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+init.o: ../../../include/ldap.h ../../../include/lthread.h
+init.o: ../../../include/ldif.h shell.h
+config.o: config.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+config.o: ../../../include/ldap.h ../../../include/lthread.h
+config.o: ../../../include/ldif.h shell.h
+fork.o: fork.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+fork.o: ../../../include/ldap.h ../../../include/lthread.h
+fork.o: ../../../include/ldif.h
+search.o: search.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+search.o: ../../../include/ldap.h ../../../include/lthread.h
+search.o: ../../../include/ldif.h shell.h
+bind.o: bind.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+bind.o: ../../../include/ldap.h ../../../include/lthread.h
+bind.o: ../../../include/ldif.h shell.h
+unbind.o: unbind.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+unbind.o: ../../../include/ldap.h ../../../include/lthread.h
+unbind.o: ../../../include/ldif.h shell.h
+add.o: add.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+add.o: ../../../include/ldap.h ../../../include/lthread.h
+add.o: ../../../include/ldif.h shell.h
+delete.o: delete.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+delete.o: ../../../include/ldap.h ../../../include/lthread.h
+delete.o: ../../../include/ldif.h shell.h
+modify.o: modify.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+modify.o: ../../../include/ldap.h ../../../include/lthread.h
+modify.o: ../../../include/ldif.h shell.h
+modrdn.o: modrdn.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+modrdn.o: ../../../include/ldap.h ../../../include/lthread.h
+modrdn.o: ../../../include/ldif.h shell.h
+compare.o: compare.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+compare.o: ../../../include/ldap.h ../../../include/lthread.h
+compare.o: ../../../include/ldif.h shell.h
+abandon.o: abandon.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+abandon.o: ../../../include/ldap.h ../../../include/lthread.h
+abandon.o: ../../../include/ldif.h shell.h
+result.o: result.c ../slap.h ../../../include/avl.h ../../../include/lber.h
+result.o: ../../../include/ldap.h ../../../include/lthread.h
+result.o: ../../../include/ldif.h shell.h
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/servers/slapd/back-shell/Version.c b/servers/slapd/back-shell/Version.c
new file mode 100644 (file)
index 0000000..f29d1ee
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+static char Versionstr[] = "  shell backend %VERSION% (%WHEN%)\n\t%WHOANDWHERE%\n";
diff --git a/servers/slapd/back-shell/abandon.c b/servers/slapd/back-shell/abandon.c
new file mode 100644 (file)
index 0000000..fc9d6a4
--- /dev/null
@@ -0,0 +1,59 @@
+/* abandon.c - shell backend abandon function */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <signal.h>
+#include "slap.h"
+#include "shell.h"
+
+void
+shell_back_abandon(
+    Backend    *be,
+    Connection *conn,
+    Operation  *op,
+    int                msgid
+)
+{
+       struct shellinfo        *si = (struct shellinfo *) be->be_private;
+       FILE                    *rfp, *wfp;
+       int                     pid;
+       Operation               *o;
+
+       /* no abandon command defined - just kill the process handling it */
+       if ( si->si_abandon == NULL ) {
+               pthread_mutex_lock( &conn->c_opsmutex );
+               pid = -1;
+               for ( o = conn->c_ops; o != NULL; o = o->o_next ) {
+                       if ( o->o_msgid == msgid ) {
+                               pid = o->o_private;
+                               break;
+                       }
+               }
+               pthread_mutex_unlock( &conn->c_opsmutex );
+
+               if ( pid != -1 ) {
+                       Debug( LDAP_DEBUG_ARGS, "shell killing pid %d\n", pid,
+                           0, 0 );
+                       kill( pid, SIGTERM );
+               } else {
+                       Debug( LDAP_DEBUG_ARGS, "shell could not find op %d\n",
+                           msgid, 0, 0 );
+               }
+               return;
+       }
+
+       if ( forkandexec( si->si_abandon, &rfp, &wfp ) == -1 ) {
+               return;
+       }
+
+       /* write out the request to the abandon process */
+       fprintf( wfp, "ABANDON\n" );
+       fprintf( wfp, "msgid: %d\n", msgid );
+       print_suffixes( wfp, be );
+       fclose( wfp );
+
+       /* no result from abandon */
+       fclose( rfp );
+}
diff --git a/servers/slapd/back-shell/add.c b/servers/slapd/back-shell/add.c
new file mode 100644 (file)
index 0000000..89f054c
--- /dev/null
@@ -0,0 +1,50 @@
+/* add.c - shell backend add function */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "shell.h"
+
+extern pthread_mutex_t entry2str_mutex;
+extern char            *entry2str();
+
+void
+shell_back_add(
+    Backend    *be,
+    Connection *conn,
+    Operation  *op,
+    Entry      *e
+)
+{
+       struct shellinfo        *si = (struct shellinfo *) be->be_private;
+       FILE                    *rfp, *wfp;
+       int                     len;
+
+       if ( si->si_add == NULL ) {
+               send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
+                   "add not implemented" );
+               return;
+       }
+
+       if ( (op->o_private = forkandexec( si->si_add, &rfp, &wfp )) == -1 ) {
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL,
+                   "could not fork/exec" );
+               return;
+       }
+
+       /* write out the request to the add process */
+       fprintf( wfp, "ADD\n" );
+       fprintf( wfp, "msgid: %d\n", op->o_msgid );
+       print_suffixes( wfp, be );
+       pthread_mutex_lock( &entry2str_mutex );
+       fprintf( wfp, "%s", entry2str( e, &len, 0 ) );
+       pthread_mutex_unlock( &entry2str_mutex );
+       fclose( wfp );
+
+       /* read in the result and send it along */
+       read_and_send_results( be, conn, op, rfp, NULL, 0 );
+
+       fclose( rfp );
+}
diff --git a/servers/slapd/back-shell/bind.c b/servers/slapd/back-shell/bind.c
new file mode 100644 (file)
index 0000000..dea149e
--- /dev/null
@@ -0,0 +1,52 @@
+/* bind.c - shell backend bind function */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "shell.h"
+
+int
+shell_back_bind(
+    Backend            *be,
+    Connection         *conn,
+    Operation          *op,
+    char               *dn,
+    int                        method,
+    struct berval      *cred
+)
+{
+       struct shellinfo        *si = (struct shellinfo *) be->be_private;
+       FILE                    *rfp, *wfp;
+       int                     rc;
+
+       if ( si->si_bind == NULL ) {
+               send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
+                   "bind not implemented" );
+               return;
+       }
+
+       if ( (op->o_private = forkandexec( si->si_bind, &rfp, &wfp ))
+           == -1 ) {
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL,
+                   "could not fork/exec" );
+               return;
+       }
+
+       /* write out the request to the bind process */
+       fprintf( wfp, "BIND\n" );
+       fprintf( wfp, "msgid: %d\n", op->o_msgid );
+       print_suffixes( wfp, be );
+       fprintf( wfp, "dn: %s\n", dn );
+       fprintf( wfp, "method: %d\n", method );
+       fprintf( wfp, "credlen: %d\n", cred->bv_len );
+       fprintf( wfp, "cred: %s\n", cred->bv_val ); /* XXX */
+       fclose( wfp );
+
+       /* read in the results and send them along */
+       rc = read_and_send_results( be, conn, op, rfp, NULL, 0 );
+       fclose( rfp );
+
+       return( rc );
+}
diff --git a/servers/slapd/back-shell/compare.c b/servers/slapd/back-shell/compare.c
new file mode 100644 (file)
index 0000000..48dfbb5
--- /dev/null
@@ -0,0 +1,47 @@
+/* compare.c - shell backend compare function */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "shell.h"
+
+void
+shell_back_compare(
+    Backend    *be,
+    Connection *conn,
+    Operation  *op,
+    char       *dn,
+    Ava                *ava
+)
+{
+       struct shellinfo        *si = (struct shellinfo *) be->be_private;
+       FILE                    *rfp, *wfp;
+
+       if ( si->si_compare == NULL ) {
+               send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
+                   "compare not implemented" );
+               return;
+       }
+
+       if ( (op->o_private = forkandexec( si->si_compare, &rfp, &wfp ))
+           == -1 ) {
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL,
+                   "could not fork/exec" );
+               return;
+       }
+
+       /* write out the request to the compare process */
+       fprintf( wfp, "COMPARE\n" );
+       fprintf( wfp, "msgid: %d\n", op->o_msgid );
+       print_suffixes( wfp, be );
+       fprintf( wfp, "dn: %s\n", dn );
+       fprintf( wfp, "%s: %s\n", ava->ava_type, ava->ava_value.bv_val );
+       fclose( wfp );
+
+       /* read in the result and send it along */
+       read_and_send_results( be, conn, op, rfp, NULL, 0 );
+
+       fclose( rfp );
+}
diff --git a/servers/slapd/back-shell/config.c b/servers/slapd/back-shell/config.c
new file mode 100644 (file)
index 0000000..5d2fa1c
--- /dev/null
@@ -0,0 +1,124 @@
+/* config.c - shell backend configuration file routine */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "shell.h"
+
+extern char    **charray_dup();
+
+shell_back_config(
+    Backend    *be,
+    char       *fname,
+    int                lineno,
+    int                argc,
+    char       **argv
+)
+{
+       struct shellinfo        *si = (struct shellinfo *) be->be_private;
+
+       if ( si == NULL ) {
+               fprintf( stderr, "%s: line %d: shell backend info is null!\n",
+                   fname, lineno );
+               exit( 1 );
+       }
+
+       /* command + args to exec for binds */
+       if ( strcasecmp( argv[0], "bind" ) == 0 ) {
+               if ( argc < 2 ) {
+                       fprintf( stderr,
+       "%s: line %d: missing executable in \"bind <executable>\" line\n",
+                           fname, lineno );
+                       exit( 1 );
+               }
+               si->si_bind = charray_dup( &argv[1] );
+
+       /* command + args to exec for unbinds */
+       } else if ( strcasecmp( argv[0], "unbind" ) == 0 ) {
+               if ( argc < 2 ) {
+                       fprintf( stderr,
+       "%s: line %d: missing executable in \"unbind <executable>\" line\n",
+                           fname, lineno );
+                       exit( 1 );
+               }
+               si->si_unbind = charray_dup( &argv[1] );
+
+       /* command + args to exec for searches */
+       } else if ( strcasecmp( argv[0], "search" ) == 0 ) {
+               if ( argc < 2 ) {
+                       fprintf( stderr,
+       "%s: line %d: missing executable in \"search <executable>\" line\n",
+                           fname, lineno );
+                       exit( 1 );
+               }
+               si->si_search = charray_dup( &argv[1] );
+
+       /* command + args to exec for compares */
+       } else if ( strcasecmp( argv[0], "compare" ) == 0 ) {
+               if ( argc < 2 ) {
+                       fprintf( stderr,
+       "%s: line %d: missing executable in \"compare <executable>\" line\n",
+                           fname, lineno );
+                       exit( 1 );
+               }
+               si->si_compare = charray_dup( &argv[1] );
+
+       /* command + args to exec for modifies */
+       } else if ( strcasecmp( argv[0], "modify" ) == 0 ) {
+               if ( argc < 2 ) {
+                       fprintf( stderr,
+       "%s: line %d: missing executable in \"modify <executable>\" line\n",
+                           fname, lineno );
+                       exit( 1 );
+               }
+               si->si_modify = charray_dup( &argv[1] );
+
+       /* command + args to exec for modrdn */
+       } else if ( strcasecmp( argv[0], "modrdn" ) == 0 ) {
+               if ( argc < 2 ) {
+                       fprintf( stderr,
+       "%s: line %d: missing executable in \"modrdn <executable>\" line\n",
+                           fname, lineno );
+                       exit( 1 );
+               }
+               si->si_modrdn = charray_dup( &argv[1] );
+
+       /* command + args to exec for add */
+       } else if ( strcasecmp( argv[0], "add" ) == 0 ) {
+               if ( argc < 2 ) {
+                       fprintf( stderr,
+       "%s: line %d: missing executable in \"add <executable>\" line\n",
+                           fname, lineno );
+                       exit( 1 );
+               }
+               si->si_add = charray_dup( &argv[1] );
+
+       /* command + args to exec for delete */
+       } else if ( strcasecmp( argv[0], "delete" ) == 0 ) {
+               if ( argc < 2 ) {
+                       fprintf( stderr,
+       "%s: line %d: missing executable in \"delete <executable>\" line\n",
+                           fname, lineno );
+                       exit( 1 );
+               }
+               si->si_delete = charray_dup( &argv[1] );
+
+       /* command + args to exec for abandon */
+       } else if ( strcasecmp( argv[0], "abandon" ) == 0 ) {
+               if ( argc < 2 ) {
+                       fprintf( stderr,
+       "%s: line %d: missing executable in \"abandon <executable>\" line\n",
+                           fname, lineno );
+                       exit( 1 );
+               }
+               si->si_abandon = charray_dup( &argv[1] );
+
+       /* anything else */
+       } else {
+               fprintf( stderr,
+"%s: line %d: unknown directive \"%s\" in shell database definition (ignored)\n",
+                   fname, lineno, argv[0] );
+       }
+}
diff --git a/servers/slapd/back-shell/delete.c b/servers/slapd/back-shell/delete.c
new file mode 100644 (file)
index 0000000..0dc3439
--- /dev/null
@@ -0,0 +1,44 @@
+/* delete.c - shell backend delete function */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "shell.h"
+
+void
+shell_back_delete(
+    Backend    *be,
+    Connection *conn,
+    Operation  *op,
+    char       *dn
+)
+{
+       struct shellinfo        *si = (struct shellinfo *) be->be_private;
+       FILE                    *rfp, *wfp;
+
+       if ( si->si_delete == NULL ) {
+               send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
+                   "delete not implemented" );
+               return;
+       }
+
+       if ( (op->o_private = forkandexec( si->si_delete, &rfp, &wfp ))
+           == -1 ) {
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL,
+                   "could not fork/exec" );
+               return;
+       }
+
+       /* write out the request to the delete process */
+       fprintf( wfp, "DELETE\n" );
+       fprintf( wfp, "msgid: %d\n", op->o_msgid );
+       print_suffixes( wfp, be );
+       fprintf( wfp, "dn: %s\n", dn );
+       fclose( wfp );
+
+       /* read in the results and send them along */
+       read_and_send_results( be, conn, op, rfp, NULL, 0 );
+       fclose( rfp );
+}
diff --git a/servers/slapd/back-shell/fork.c b/servers/slapd/back-shell/fork.c
new file mode 100644 (file)
index 0000000..aff0e5b
--- /dev/null
@@ -0,0 +1,63 @@
+/* fork.c - fork and exec a process, connecting stdin/out w/pipes */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+
+forkandexec(
+    char       **args,
+    FILE       **rfp,
+    FILE       **wfp
+)
+{
+       int     p2c[2], c2p[2];
+       int     pid;
+
+       if ( pipe( p2c ) != 0 || pipe( c2p ) != 0 ) {
+               Debug( LDAP_DEBUG_ANY, "pipe failed\n", 0, 0, 0 );
+               return( -1 );
+       }
+
+       /*
+        * what we're trying to set up looks like this:
+        *      parent *wfp -> p2c[1] | p2c[0] -> stdin child
+        *      parent *rfp <- c2p[0] | c2p[1] <- stdout child
+        */
+
+       switch ( (pid = fork()) ) {
+       case 0:         /* child */
+               close( p2c[1] );
+               close( c2p[0] );
+               if ( dup2( p2c[0], 0 ) == -1 || dup2( c2p[1], 1 ) == -1 ) {
+                       Debug( LDAP_DEBUG_ANY, "dup2 failed\n", 0, 0, 0 );
+                       exit( -1 );
+               }
+
+               execv( args[0], args );
+
+               Debug( LDAP_DEBUG_ANY, "execv failed\n", 0, 0, 0 );
+               exit( -1 );
+
+       case -1:        /* trouble */
+               Debug( LDAP_DEBUG_ANY, "fork failed\n", 0, 0, 0 );
+               return( -1 );
+
+       default:        /* parent */
+               close( p2c[0] );
+               close( c2p[1] );
+               break;
+       }
+
+       if ( (*rfp = fdopen( c2p[0], "r" )) == NULL || (*wfp = fdopen( p2c[1],
+           "w" )) == NULL ) {
+               Debug( LDAP_DEBUG_ANY, "fdopen failed\n", 0, 0, 0 );
+               close( c2p[0] );
+               close( p2c[1] );
+
+               return( -1 );
+       }
+
+       return( pid );
+}
diff --git a/servers/slapd/back-shell/init.c b/servers/slapd/back-shell/init.c
new file mode 100644 (file)
index 0000000..1df9c4b
--- /dev/null
@@ -0,0 +1,18 @@
+/* init.c - initialize shell backend */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "shell.h"
+
+shell_back_init(
+    Backend    *be
+)
+{
+       struct shellinfo        *si;
+
+       si = (struct shellinfo *) ch_calloc( 1, sizeof(struct shellinfo) );
+
+       be->be_private = si;
+}
diff --git a/servers/slapd/back-shell/modify.c b/servers/slapd/back-shell/modify.c
new file mode 100644 (file)
index 0000000..d05b796
--- /dev/null
@@ -0,0 +1,67 @@
+/* modify.c - shell backend modify function */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "shell.h"
+
+void
+shell_back_modify(
+    Backend    *be,
+    Connection *conn,
+    Operation  *op,
+    char       *dn,
+    LDAPMod    *mods
+)
+{
+       struct shellinfo        *si = (struct shellinfo *) be->be_private;
+       FILE                    *rfp, *wfp;
+       int                     i;
+
+       if ( si->si_modify == NULL ) {
+               send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
+                   "modify not implemented" );
+               return;
+       }
+
+       if ( (op->o_private = forkandexec( si->si_modify, &rfp, &wfp ))
+           == -1 ) {
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL,
+                   "could not fork/exec" );
+               return;
+       }
+
+       /* write out the request to the modify process */
+       fprintf( wfp, "MODIFY\n" );
+       fprintf( wfp, "msgid: %d\n", op->o_msgid );
+       print_suffixes( wfp, be );
+       fprintf( wfp, "dn: %s\n", dn );
+       for ( ; mods != NULL; mods = mods->mod_next ) {
+               switch ( mods->mod_op & ~LDAP_MOD_BVALUES ) {
+               case LDAP_MOD_ADD:
+                       fprintf( wfp, "add: %s", mods->mod_type );
+                       break;
+
+               case LDAP_MOD_DELETE:
+                       fprintf( wfp, "delete: %s", mods->mod_type );
+                       break;
+
+               case LDAP_MOD_REPLACE:
+                       fprintf( wfp, "replace: %s", mods->mod_type );
+                       break;
+               }
+
+               for ( i = 0; mods->mod_bvalues != NULL && mods->mod_bvalues[i]
+                   != NULL; i++ ) {
+                       fprintf( wfp, "%s: %s\n", mods->mod_type,
+                           mods->mod_bvalues[i]->bv_val );
+               }
+       }
+       fclose( wfp );
+
+       /* read in the results and send them along */
+       read_and_send_results( be, conn, op, rfp, NULL, 0 );
+       fclose( rfp );
+}
diff --git a/servers/slapd/back-shell/modrdn.c b/servers/slapd/back-shell/modrdn.c
new file mode 100644 (file)
index 0000000..9fd7933
--- /dev/null
@@ -0,0 +1,48 @@
+/* modrdn.c - shell backend modrdn function */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "shell.h"
+
+void
+shell_back_modrdn(
+    Backend    *be,
+    Connection *conn,
+    Operation  *op,
+    char       *dn,
+    char       *newrdn,
+    int                deleteoldrdn
+)
+{
+       struct shellinfo        *si = (struct shellinfo *) be->be_private;
+       FILE                    *rfp, *wfp;
+
+       if ( si->si_modrdn == NULL ) {
+               send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
+                   "modrdn not implemented" );
+               return;
+       }
+
+       if ( (op->o_private = forkandexec( si->si_modrdn, &rfp, &wfp ))
+           == -1 ) {
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL,
+                   "could not fork/exec" );
+               return;
+       }
+
+       /* write out the request to the modrdn process */
+       fprintf( wfp, "MODRDN\n" );
+       fprintf( wfp, "msgid: %d\n", op->o_msgid );
+       print_suffixes( wfp, be );
+       fprintf( wfp, "dn: %s\n", dn );
+       fprintf( wfp, "newrdn: %s\n", newrdn );
+       fprintf( wfp, "deleteoldrdn: %d\n", deleteoldrdn ? 1 : 0 );
+       fclose( wfp );
+
+       /* read in the results and send them along */
+       read_and_send_results( be, conn, op, rfp, NULL, 0 );
+       fclose( rfp );
+}
diff --git a/servers/slapd/back-shell/result.c b/servers/slapd/back-shell/result.c
new file mode 100644 (file)
index 0000000..675aa1f
--- /dev/null
@@ -0,0 +1,90 @@
+/* result.c - shell backend result reading function */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "shell.h"
+
+extern Entry   *str2entry();
+
+int
+read_and_send_results(
+    Backend    *be,
+    Connection *conn,
+    Operation  *op,
+    FILE       *fp,
+    char       **attrs,
+    int                attrsonly
+)
+{
+       int     bsize, len;
+       char    *buf, *bp;
+       char    line[BUFSIZ];
+       Entry   *e;
+       int     err;
+       char    *matched, *info;
+
+       /* read in the result and send it along */
+       buf = (char *) ch_malloc( BUFSIZ );
+       buf[0] = '\0';
+       bsize = BUFSIZ;
+       bp = buf;
+       while ( fgets( line, sizeof(line), fp ) != NULL ) {
+               Debug( LDAP_DEBUG_SHELL, "shell search reading line (%s)\n",
+                   line, 0, 0 );
+               /* ignore lines beginning with DEBUG: */
+               if ( strncasecmp( line, "DEBUG:", 6 ) == 0 ) {
+                       continue;
+               }
+               len = strlen( line );
+               while ( bp + len - buf > bsize ) {
+                       bsize += BUFSIZ;
+                       buf = (char *) ch_realloc( buf, bsize );
+               }
+               strcpy( bp, line );
+               bp += len;
+
+               /* line marked the end of an entry or result */
+               if ( *line == '\n' ) {
+                       if ( strncasecmp( buf, "RESULT", 6 ) == 0 ) {
+                               break;
+                       }
+
+                       if ( (e = str2entry( buf )) == NULL ) {
+                               Debug( LDAP_DEBUG_ANY, "str2entry(%s) failed\n",
+                                   buf, 0, 0 );
+                       } else {
+                               send_search_entry( be, conn, op, e, attrs,
+                                   attrsonly );
+                               entry_free( e );
+                       }
+
+                       bp = buf;
+               }
+       }
+       (void) str2result( buf, &err, &matched, &info );
+
+       /* otherwise, front end will send this result */
+       if ( err != 0 || op->o_tag != LDAP_REQ_BIND ) {
+               send_ldap_result( conn, op, err, matched, info );
+       }
+
+       free( buf );
+
+       return( err );
+}
+
+void
+print_suffixes(
+    FILE       *fp,
+    Backend    *be
+)
+{
+       int     i;
+
+       for ( i = 0; be->be_suffix[i] != NULL; i++ ) {
+               fprintf( fp, "suffix: %s\n", be->be_suffix[i] );
+       }
+}
diff --git a/servers/slapd/back-shell/search.c b/servers/slapd/back-shell/search.c
new file mode 100644 (file)
index 0000000..749b112
--- /dev/null
@@ -0,0 +1,69 @@
+/* search.c - shell backend search function */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "shell.h"
+
+extern Entry   *str2entry();
+
+void
+shell_back_search(
+    Backend    *be,
+    Connection *conn,
+    Operation  *op,
+    char       *base,
+    int                scope,
+    int                deref,
+    int                size,
+    int                time,
+    Filter     *filter,
+    char       *filterstr,
+    char       **attrs,
+    int                attrsonly
+)
+{
+       struct shellinfo        *si = (struct shellinfo *) be->be_private;
+       int                     i, rc, bsize, len;
+       int                     err;
+       char                    *matched, *info;
+       FILE                    *rfp, *wfp;
+
+       if ( si->si_search == NULL ) {
+               send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
+                   "search not implemented" );
+               return;
+       }
+
+       if ( (op->o_private = forkandexec( si->si_search, &rfp, &wfp ))
+           == -1 ) {
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL,
+                   "could not fork/exec" );
+               return;
+       }
+
+       /* write out the request to the search process */
+       fprintf( wfp, "SEARCH\n" );
+       fprintf( wfp, "msgid: %d\n", op->o_msgid );
+       print_suffixes( wfp, be );
+       fprintf( wfp, "base: %s\n", base );
+       fprintf( wfp, "scope: %d\n", scope );
+       fprintf( wfp, "deref: %d\n", deref );
+       fprintf( wfp, "sizelimit: %d\n", size );
+       fprintf( wfp, "timelimit: %d\n", time );
+       fprintf( wfp, "filter: %s\n", filterstr );
+       fprintf( wfp, "attrsonly: %d\n", attrsonly ? 1 : 0 );
+       fprintf( wfp, "attrs:%s", attrs == NULL ? " all" : "" );
+       for ( i = 0; attrs != NULL && attrs[i] != NULL; i++ ) {
+               fprintf( wfp, " %s", attrs[i] );
+       }
+       fprintf( wfp, "\n" );
+       fclose( wfp );
+
+       /* read in the results and send them along */
+       read_and_send_results( be, conn, op, rfp, attrs, attrsonly );
+
+       fclose( rfp );
+}
diff --git a/servers/slapd/back-shell/searchexample.conf b/servers/slapd/back-shell/searchexample.conf
new file mode 100644 (file)
index 0000000..4defa4b
--- /dev/null
@@ -0,0 +1,4 @@
+referral       ldap://ldap.itd.umich.edu
+database       shell
+suffix         "o=university of michigan, c=us"
+search         /usr/local/etc/searchexample.sh
diff --git a/servers/slapd/back-shell/searchexample.sh b/servers/slapd/back-shell/searchexample.sh
new file mode 100644 (file)
index 0000000..26b70fe
--- /dev/null
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+while [ 1 ]; do
+       read TAG VALUE
+       if [ $? -ne 0 ]; then
+               break
+       fi
+       case "$TAG" in
+               base:)
+               BASE=$VALUE
+               ;;
+               filter:)
+               FILTER=$VALUE
+               ;;
+               # include other parameters here
+       esac
+done
+
+LOGIN=`echo $FILTER | sed -e 's/.*=\(.*\))/\1/'`
+
+PWLINE=`grep -i "^$LOGIN" /etc/passwd`
+
+sleep 60
+# if we found an entry that matches
+if [ $? = 0 ]; then
+       echo $PWLINE | awk -F: '{
+               printf("dn: cn=%s,%s\n", $1, base);
+               printf("cn: %s\n", $1);
+               printf("cn: %s\n", $5);
+               printf("sn: %s\n", $1);
+               printf("uid: %s\n", $1);
+       }' base="$BASE"
+       echo ""
+fi
+
+# result
+echo "RESULT"
+echo "code: 0"
+
+exit 0
diff --git a/servers/slapd/back-shell/shell.h b/servers/slapd/back-shell/shell.h
new file mode 100644 (file)
index 0000000..5ef493c
--- /dev/null
@@ -0,0 +1,13 @@
+/* shell.h - shell backend header file */
+
+struct shellinfo {
+       char    **si_bind;      /* cmd + args to exec for bind    */
+       char    **si_unbind;    /* cmd + args to exec for unbind  */
+       char    **si_search;    /* cmd + args to exec for search  */
+       char    **si_compare;   /* cmd + args to exec for compare */
+       char    **si_modify;    /* cmd + args to exec for modify  */
+       char    **si_modrdn;    /* cmd + args to exec for modrdn  */
+       char    **si_add;       /* cmd + args to exec for add     */
+       char    **si_delete;    /* cmd + args to exec for delete  */
+       char    **si_abandon;   /* cmd + args to exec for abandon */
+};
diff --git a/servers/slapd/back-shell/unbind.c b/servers/slapd/back-shell/unbind.c
new file mode 100644 (file)
index 0000000..649fe96
--- /dev/null
@@ -0,0 +1,45 @@
+/* unbind.c - shell backend unbind function */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "shell.h"
+
+void
+shell_back_unbind(
+    Backend            *be,
+    Connection         *conn,
+    Operation          *op,
+    char               *dn,
+    int                        method,
+    struct berval      *cred
+)
+{
+       struct shellinfo        *si = (struct shellinfo *) be->be_private;
+       FILE                    *rfp, *wfp;
+
+       if ( si->si_unbind == NULL ) {
+               send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
+                   "unbind not implemented" );
+               return;
+       }
+
+       if ( (op->o_private = forkandexec( si->si_unbind, &rfp, &wfp ))
+           == -1 ) {
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL,
+                   "could not fork/exec" );
+               return;
+       }
+
+       /* write out the request to the unbind process */
+       fprintf( wfp, "UNBIND\n" );
+       fprintf( wfp, "msgid: %d\n", op->o_msgid );
+       print_suffixes( wfp, be );
+       fprintf( wfp, "dn: %s\n", dn );
+       fclose( wfp );
+
+       /* no response to unbind */
+       fclose( rfp );
+}
diff --git a/servers/slapd/backend.c b/servers/slapd/backend.c
new file mode 100644 (file)
index 0000000..998bfa8
--- /dev/null
@@ -0,0 +1,233 @@
+/* backend.c - routines for dealing with back-end databases */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include "slap.h"
+
+#ifdef LDAP_LDBM
+extern int     ldbm_back_bind();
+extern int     ldbm_back_unbind();
+extern int     ldbm_back_search();
+extern int     ldbm_back_compare();
+extern int     ldbm_back_modify();
+extern int     ldbm_back_modrdn();
+extern int     ldbm_back_add();
+extern int     ldbm_back_delete();
+extern int     ldbm_back_abandon();
+extern int     ldbm_back_config();
+extern int     ldbm_back_init();
+extern int     ldbm_back_close();
+#endif
+
+#ifdef LDAP_PASSWD
+extern int     passwd_back_search();
+extern int     passwd_back_config();
+#endif
+
+#ifdef LDAP_SHELL
+extern int     shell_back_bind();
+extern int     shell_back_unbind();
+extern int     shell_back_search();
+extern int     shell_back_compare();
+extern int     shell_back_modify();
+extern int     shell_back_modrdn();
+extern int     shell_back_add();
+extern int     shell_back_delete();
+extern int     shell_back_abandon();
+extern int     shell_back_config();
+extern int     shell_back_init();
+#endif
+
+extern int     defsize;
+extern int     deftime;
+
+#define BACKEND_GRAB_SIZE      10
+
+int            nbackends;
+Backend                *backends;
+static int     maxbackends;
+
+Backend *
+new_backend(
+    char       *type
+)
+{
+       Backend *be;
+       int     foundit;
+
+       if ( nbackends == maxbackends ) {
+               maxbackends += BACKEND_GRAB_SIZE;
+               backends = (Backend *) ch_realloc( (char *) backends,
+                   maxbackends * sizeof(Backend) );
+               memset( &backends[nbackends], '\0', BACKEND_GRAB_SIZE *
+                   sizeof(Backend) );
+       }
+
+       be = &backends[nbackends++];
+       be->be_sizelimit = defsize;
+       be->be_timelimit = deftime;
+       foundit = 0;
+
+#ifdef LDAP_LDBM
+       if ( strcasecmp( type, "ldbm" ) == 0 ) {
+               be->be_bind = ldbm_back_bind;
+               be->be_unbind = ldbm_back_unbind;
+               be->be_search = ldbm_back_search;
+               be->be_compare = ldbm_back_compare;
+               be->be_modify = ldbm_back_modify;
+               be->be_modrdn = ldbm_back_modrdn;
+               be->be_add = ldbm_back_add;
+               be->be_delete = ldbm_back_delete;
+               be->be_abandon = ldbm_back_abandon;
+               be->be_config = ldbm_back_config;
+               be->be_init = ldbm_back_init;
+               be->be_close = ldbm_back_close;
+               be->be_type = "ldbm";
+               foundit = 1;
+       }
+#endif
+
+#ifdef LDAP_PASSWD
+       if ( strcasecmp( type, "passwd" ) == 0 ) {
+               be->be_bind = NULL;
+               be->be_unbind = NULL;
+               be->be_search = passwd_back_search;
+               be->be_compare = NULL;
+               be->be_modify = NULL;
+               be->be_modrdn = NULL;
+               be->be_add = NULL;
+               be->be_delete = NULL;
+               be->be_abandon = NULL;
+               be->be_config = passwd_back_config;
+               be->be_init = NULL;
+               be->be_close = NULL;
+               be->be_type = "passwd";
+               foundit = 1;
+       }
+#endif
+
+#ifdef LDAP_SHELL
+       if ( strcasecmp( type, "shell" ) == 0 ) {
+               be->be_bind = shell_back_bind;
+               be->be_unbind = shell_back_unbind;
+               be->be_search = shell_back_search;
+               be->be_compare = shell_back_compare;
+               be->be_modify = shell_back_modify;
+               be->be_modrdn = shell_back_modrdn;
+               be->be_add = shell_back_add;
+               be->be_delete = shell_back_delete;
+               be->be_abandon = shell_back_abandon;
+               be->be_config = shell_back_config;
+               be->be_init = shell_back_init;
+               be->be_close = NULL;
+               be->be_type = "shell";
+               foundit = 1;
+       }
+#endif
+
+       if ( be->be_init != NULL ) {
+               (*be->be_init)( be );
+       }
+
+       if ( foundit == 0 ) {
+               fprintf( stderr, "Unrecognized database type (%s)\n", type );
+               exit( 1 );
+       }
+
+       return( be );
+}
+
+Backend *
+select_backend( char * dn )
+{
+       int     i, j, len, dnlen;
+
+       dnlen = strlen( dn );
+       for ( i = 0; i < nbackends; i++ ) {
+               for ( j = 0; backends[i].be_suffix != NULL &&
+                   backends[i].be_suffix[j] != NULL; j++ ) {
+                       len = strlen( backends[i].be_suffix[j] );
+
+                       if ( len > dnlen ) {
+                               continue;
+                       }
+
+                       if ( strcasecmp( backends[i].be_suffix[j],
+                           dn + (dnlen - len) ) == 0 ) {
+                               return( &backends[i] );
+                       }
+               }
+       }
+
+       return( NULL );
+}
+
+int
+be_issuffix(
+    Backend    *be,
+    char       *suffix
+)
+{
+       int     i;
+
+       for ( i = 0; be->be_suffix != NULL && be->be_suffix[i] != NULL; i++ ) {
+               if ( strcasecmp( be->be_suffix[i], suffix ) == 0 ) {
+                       return( 1 );
+               }
+       }
+
+       return( 0 );
+}
+
+int
+be_isroot( Backend *be, char *dn )
+{
+       if ( dn == NULL ) {
+               return( 0 );
+       }
+
+       return( be->be_rootdn ? strcasecmp( be->be_rootdn, dn ) == 0
+           : 0 );
+}
+
+int
+be_isroot_pw( Backend *be, char *dn, struct berval *cred )
+{
+       if ( ! be_isroot( be, dn ) || be->be_rootpw == NULL ) {
+               return( 0 );
+       }
+
+       return( strcmp( be->be_rootpw, cred->bv_val ) == 0 );
+}
+
+void
+be_close()
+{
+       int     i;
+
+       for ( i = 0; i < nbackends; i++ ) {
+               if ( backends[i].be_close != NULL ) {
+                       (*backends[i].be_close)( &backends[i] );
+               }
+       }
+}
+
+
+void
+be_unbind(
+       Connection   *conn,
+       Operation    *op
+)
+{
+       int     i;
+
+       for ( i = 0; i < nbackends; i++ ) {
+               if ( backends[i].be_unbind != NULL ) {
+                       (*backends[i].be_unbind)( &backends[i], conn, op );
+               }
+       }
+}
diff --git a/servers/slapd/bind.c b/servers/slapd/bind.c
new file mode 100644 (file)
index 0000000..562ce5b
--- /dev/null
@@ -0,0 +1,175 @@
+/* bind.c - decode an ldap bind operation and pass it to a backend db */
+
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+
+extern Backend *select_backend();
+
+extern char    *default_referral;
+
+void
+do_bind(
+    Connection *conn,
+    Operation  *op
+)
+{
+       BerElement      *ber = op->o_ber;
+       int             version, method, len, rc;
+       char            *dn;
+       struct berval   cred;
+       Backend         *be;
+
+       Debug( LDAP_DEBUG_TRACE, "do_bind\n", 0, 0, 0 );
+
+       /*
+        * Parse the bind request.  It looks like this:
+        *
+        *      BindRequest ::= SEQUENCE {
+        *              version         INTEGER,                 -- version
+        *              name            DistinguishedName,       -- dn
+        *              authentication  CHOICE {
+        *                      simple          [0] OCTET STRING -- passwd
+        *                      krbv42ldap      [1] OCTET STRING
+        *                      krbv42dsa       [1] OCTET STRING
+        *              }
+        *      }
+        */
+
+#ifdef COMPAT30
+       /*
+        * in version 3.0 there is an extra SEQUENCE tag after the
+        * BindRequest SEQUENCE tag.
+        */
+
+       {
+       BerElement      tber;
+       unsigned long   tlen, ttag;
+
+       tber = *op->o_ber;
+       ttag = ber_skip_tag( &tber, &tlen );
+       if ( ber_peek_tag( &tber, &tlen ) == LBER_SEQUENCE ) {
+               Debug( LDAP_DEBUG_ANY, "version 3.0 detected\n", 0, 0, 0 );
+               conn->c_version = 30;
+               rc = ber_scanf(ber, "{{iato}}", &version, &dn, &method, &cred);
+       } else {
+               rc = ber_scanf( ber, "{iato}", &version, &dn, &method, &cred );
+       }
+       }
+#else
+       rc = ber_scanf( ber, "{iato}", &version, &dn, &method, &cred );
+#endif
+       if ( rc == LBER_ERROR ) {
+               Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
+               send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
+                   "decoding error" );
+               return;
+       }
+#ifdef COMPAT30
+       if ( conn->c_version == 30 ) {
+               switch ( method ) {
+               case LDAP_AUTH_SIMPLE_30:
+                       method = LDAP_AUTH_SIMPLE;
+                       break;
+#ifdef KERBEROS
+               case LDAP_AUTH_KRBV41_30:
+                       method = LDAP_AUTH_KRBV41;
+                       break;
+               case LDAP_AUTH_KRBV42_30:
+                       method = LDAP_AUTH_KRBV42;
+                       break;
+#endif
+               }
+       }
+#endif /* compat30 */
+       dn_normalize( dn );
+
+       Statslog( LDAP_DEBUG_STATS, "conn=%d op=%d BIND dn=\"%s\" method=%d\n",
+           conn->c_connid, op->o_opid, dn, method, 0 );
+
+       if ( version != LDAP_VERSION2 ) {
+               if ( dn != NULL ) {
+                       free( dn );
+               }
+               if ( cred.bv_val != NULL ) {
+                       free( cred.bv_val );
+               }
+
+               Debug( LDAP_DEBUG_ANY, "unknown version %d\n", version, 0, 0 );
+               send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
+                   "version not supported" );
+               return;
+       }
+
+       Debug( LDAP_DEBUG_TRACE, "do_bind: version %d dn (%s) method %d\n",
+           version, dn, method );
+
+       /* accept null binds */
+       if ( dn == NULL || *dn == '\0' ) {
+               if ( dn != NULL ) {
+                       free( dn );
+               }
+               if ( cred.bv_val != NULL ) {
+                       free( cred.bv_val );
+               }
+
+               send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
+               return;
+       }
+
+       /*
+        * We could be serving multiple database backends.  Select the
+        * appropriate one, or send a referral to our "referral server"
+        * if we don't hold it.
+        */
+
+       if ( (be = select_backend( dn )) == NULL ) {
+               free( dn );
+               if ( cred.bv_val != NULL ) {
+                       free( cred.bv_val );
+               }
+               if ( cred.bv_len == 0 ) {
+                       send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
+               } else {
+                       send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
+                           default_referral );
+               }
+               return;
+       }
+
+       if ( be->be_bind != NULL ) {
+               if ( (*be->be_bind)( be, conn, op, dn, method, &cred ) == 0 ) {
+                       pthread_mutex_lock( &conn->c_dnmutex );
+                       if ( conn->c_dn != NULL ) {
+                               free( conn->c_dn );
+                       }
+                       conn->c_dn = strdup( dn );
+                       pthread_mutex_unlock( &conn->c_dnmutex );
+
+                       /* send this here to avoid a race condition */
+                       send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
+               }
+       } else {
+               send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
+                   "Function not implemented" );
+       }
+
+       free( dn );
+       if ( cred.bv_val != NULL ) {
+               free( cred.bv_val );
+       }
+}
diff --git a/servers/slapd/ch_malloc.c b/servers/slapd/ch_malloc.c
new file mode 100644 (file)
index 0000000..43ec4c9
--- /dev/null
@@ -0,0 +1,58 @@
+/* ch_malloc.c - malloc routines that test returns from malloc and friends */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+
+char *
+ch_malloc(
+    unsigned long      size
+)
+{
+       char    *new;
+
+       if ( (new = (char *) malloc( size )) == NULL ) {
+               Debug( LDAP_DEBUG_ANY, "malloc of %d bytes failed\n", size, 0, 0 );
+               exit( 1 );
+       }
+
+       return( new );
+}
+
+char *
+ch_realloc(
+    char               *block,
+    unsigned long      size
+)
+{
+       char    *new;
+
+       if ( block == NULL ) {
+               return( ch_malloc( size ) );
+       }
+
+       if ( (new = (char *) realloc( block, size )) == NULL ) {
+               Debug( LDAP_DEBUG_ANY, "realloc of %d bytes failed\n", size, 0, 0 );
+               exit( 1 );
+       }
+
+       return( new );
+}
+
+char *
+ch_calloc(
+    unsigned long      nelem,
+    unsigned long      size
+)
+{
+       char    *new;
+
+       if ( (new = (char *) calloc( nelem, size )) == NULL ) {
+               Debug( LDAP_DEBUG_ANY, "calloc of %d elems of %d bytes failed\n",
+                 nelem, size, 0 );
+               exit( 1 );
+       }
+
+       return( new );
+}
diff --git a/servers/slapd/charray.c b/servers/slapd/charray.c
new file mode 100644 (file)
index 0000000..b731cf1
--- /dev/null
@@ -0,0 +1,132 @@
+/* charray.c - routines for dealing with char * arrays */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+
+void
+charray_add(
+    char       ***a,
+    char       *s
+)
+{
+       int     n;
+
+       if ( *a == NULL ) {
+               *a = (char **) ch_malloc( 2 * sizeof(char *) );
+               n = 0;
+       } else {
+               for ( n = 0; *a != NULL && (*a)[n] != NULL; n++ ) {
+                       ;       /* NULL */
+               }
+
+               *a = (char **) ch_realloc( (char *) *a,
+                   (n + 2) * sizeof(char *) );
+       }
+
+       (*a)[n++] = s;
+       (*a)[n] = NULL;
+}
+
+void
+charray_merge(
+    char       ***a,
+    char       **s
+)
+{
+       int     i, n, nn;
+
+       for ( n = 0; *a != NULL && (*a)[n] != NULL; n++ ) {
+               ;       /* NULL */
+       }
+       for ( nn = 0; s[nn] != NULL; nn++ ) {
+               ;       /* NULL */
+       }
+
+       *a = (char **) ch_realloc( (char *) *a, (n + nn + 1) * sizeof(char *) );
+
+       for ( i = 0; i < nn; i++ ) {
+               (*a)[n + i] = s[i];
+       }
+       (*a)[n + nn] = NULL;
+}
+
+void
+charray_free( char **array )
+{
+       char    **a;
+
+       if ( array == NULL ) {
+               return;
+       }
+
+       for ( a = array; *a != NULL; a++ ) {
+               if ( *a != NULL ) {
+                       free( *a );
+               }
+       }
+       free( (char *) array );
+}
+
+int
+charray_inlist(
+    char       **a,
+    char       *s
+)
+{
+       int     i;
+
+       for ( i = 0; a[i] != NULL; i++ ) {
+               if ( strcasecmp( s, a[i] ) == 0 ) {
+                       return( 1 );
+               }
+       }
+
+       return( 0 );
+}
+
+char **
+charray_dup( char **a )
+{
+       int     i;
+       char    **new;
+
+       for ( i = 0; a[i] != NULL; i++ )
+               ;       /* NULL */
+
+       new = (char **) ch_malloc( (i + 1) * sizeof(char *) );
+
+       for ( i = 0; a[i] != NULL; i++ ) {
+               new[i] = strdup( a[i] );
+       }
+       new[i] = NULL;
+
+       return( new );
+}
+
+char **
+str2charray( char *str, char *brkstr )
+{
+       char    **res;
+       char    *s;
+       int     i;
+
+       i = 1;
+       for ( s = str; *s; s++ ) {
+               if ( strchr( brkstr, *s ) != NULL ) {
+                       i++;
+               }
+       }
+
+       res = (char **) ch_malloc( (i + 1) * sizeof(char *) );
+       i = 0;
+       for ( s = strtok( str, brkstr ); s != NULL; s = strtok( NULL,
+           brkstr ) ) {
+               res[i++] = strdup( s );
+       }
+       res[i] = NULL;
+
+       return( res );
+}
diff --git a/servers/slapd/compare.c b/servers/slapd/compare.c
new file mode 100644 (file)
index 0000000..248c8b1
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+
+extern Backend *select_backend();
+
+extern char    *default_referral;
+
+void
+do_compare(
+    Connection *conn,
+    Operation  *op
+)
+{
+       char    *dn;
+       Ava     ava;
+       int     rc;
+       Backend *be;
+
+       Debug( LDAP_DEBUG_TRACE, "do_compare\n", 0, 0, 0 );
+
+       /*
+        * Parse the compare request.  It looks like this:
+        *
+        *      CompareRequest := [APPLICATION 14] SEQUENCE {
+        *              entry   DistinguishedName,
+        *              ava     SEQUENCE {
+        *                      type    AttributeType,
+        *                      value   AttributeValue
+        *              }
+        *      }
+        */
+
+       if ( ber_scanf( op->o_ber, "{a{ao}}", &dn, &ava.ava_type,
+           &ava.ava_value ) == LBER_ERROR ) {
+               Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
+               send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL, "" );
+               return;
+       }
+       value_normalize( ava.ava_value.bv_val, attr_syntax( ava.ava_type ) );
+       dn_normalize( dn );
+
+       Debug( LDAP_DEBUG_ARGS, "do_compare: dn (%s) attr (%s) value (%s)\n",
+           dn, ava.ava_type, ava.ava_value.bv_val );
+
+       Statslog( LDAP_DEBUG_STATS, "conn=%d op=%d CMP dn=\"%s\" attr=\"%s\"\n",
+           conn->c_connid, op->o_opid, dn, ava.ava_type, 0 );
+
+       /*
+        * We could be serving multiple database backends.  Select the
+        * appropriate one, or send a referral to our "referral server"
+        * if we don't hold it.
+        */
+       if ( (be = select_backend( dn )) == NULL ) {
+               free( dn );
+               ava_free( &ava, 0 );
+
+               send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
+                   default_referral );
+               return;
+       }
+
+       if ( be->be_compare != NULL ) {
+               (*be->be_compare)( be, conn, op, dn, &ava );
+       } else {
+               send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
+                   "Function not implemented" );
+       }
+
+       free( dn );
+       ava_free( &ava, 0 );
+}
diff --git a/servers/slapd/config.c b/servers/slapd/config.c
new file mode 100644 (file)
index 0000000..6605058
--- /dev/null
@@ -0,0 +1,510 @@
+/* config.c - configuration file handling routines */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "ldapconfig.h"
+
+#define MAXARGS        100
+
+extern Backend *new_backend();
+extern char    *default_referral;
+extern int     ldap_syslog;
+extern int     global_schemacheck;
+
+/*
+ * defaults for various global variables
+ */
+int            defsize = SLAPD_DEFAULT_SIZELIMIT;
+int            deftime = SLAPD_DEFAULT_TIMELIMIT;
+struct acl     *global_acl = NULL;
+int            global_default_access = ACL_READ;
+char           *replogfile;
+int            global_lastmod;
+char           *ldap_srvtab = "";
+
+static char    *fp_getline();
+static void    fp_getline_init();
+static void    fp_parse_line();
+
+static char    *strtok_quote();
+
+void
+read_config( char *fname, Backend **bep, FILE *pfp )
+{
+       FILE    *fp;
+       char    *line, *savefname, *dn;
+       int     cargc, savelineno;
+       char    *cargv[MAXARGS];
+       int     lineno, i;
+       Backend *be;
+
+       if ( (fp = pfp) == NULL && (fp = fopen( fname, "r" )) == NULL ) {
+               ldap_syslog = 1;
+               Debug( LDAP_DEBUG_ANY,
+                   "could not open config file \"%s\" - absolute path?\n",
+                   fname, 0, 0 );
+               perror( fname );
+               exit( 1 );
+       }
+
+       Debug( LDAP_DEBUG_CONFIG, "reading config file %s\n", fname, 0, 0 );
+       be = *bep;
+       fp_getline_init( &lineno );
+       while ( (line = fp_getline( fp, &lineno )) != NULL ) {
+               /* skip comments and blank lines */
+               if ( line[0] == '#' || line[0] == '\0' ) {
+                       continue;
+               }
+
+               Debug( LDAP_DEBUG_CONFIG, "line %d (%s)\n", lineno, line, 0 );
+
+               fp_parse_line( line, &cargc, cargv );
+
+               if ( cargc < 1 ) {
+                       Debug( LDAP_DEBUG_ANY,
+                           "%s: line %d: bad config line (ignored)\n",
+                           fname, lineno, 0 );
+                       continue;
+               }
+
+               /* start of a new database definition */
+               if ( strcasecmp( cargv[0], "database" ) == 0 ) {
+                       if ( cargc < 2 ) {
+                               Debug( LDAP_DEBUG_ANY,
+               "%s: line %d: missing type in \"database <type>\" line\n",
+                                   fname, lineno, 0 );
+                               exit( 1 );
+                       }
+                       *bep = new_backend( cargv[1] );
+                       be = *bep;
+
+               /* set size limit */
+               } else if ( strcasecmp( cargv[0], "sizelimit" ) == 0 ) {
+                       if ( cargc < 2 ) {
+                               Debug( LDAP_DEBUG_ANY,
+           "%s: line %d: missing limit in \"sizelimit <limit>\" line\n",
+                                   fname, lineno, 0 );
+                               exit( 1 );
+                       }
+                       if ( be == NULL ) {
+                               defsize = atoi( cargv[1] );
+                       } else {
+                               be->be_sizelimit = atoi( cargv[1] );
+                       }
+
+               /* set time limit */
+               } else if ( strcasecmp( cargv[0], "timelimit" ) == 0 ) {
+                       if ( cargc < 2 ) {
+                               Debug( LDAP_DEBUG_ANY,
+           "%s: line %d: missing limit in \"timelimit <limit>\" line\n",
+                                   fname, lineno, 0 );
+                               exit( 1 );
+                       }
+                       if ( be == NULL ) {
+                               deftime = atoi( cargv[1] );
+                       } else {
+                               be->be_timelimit = atoi( cargv[1] );
+                       }
+
+               /* set database suffix */
+               } else if ( strcasecmp( cargv[0], "suffix" ) == 0 ) {
+                       if ( cargc < 2 ) {
+                               Debug( LDAP_DEBUG_ANY,
+                   "%s: line %d: missing dn in \"suffix <dn>\" line\n",
+                                   fname, lineno, 0 );
+                               exit( 1 );
+                       } else if ( cargc > 2 ) {
+                               Debug( LDAP_DEBUG_ANY,
+    "%s: line %d: extra cruft after <dn> in \"suffix %s\" line (ignored)\n",
+                                   fname, lineno, cargv[1] );
+                       }
+                       if ( be == NULL ) {
+                               Debug( LDAP_DEBUG_ANY,
+"%s: line %d: suffix line must appear inside a database definition (ignored)\n",
+                                   fname, lineno, 0 );
+                       } else {
+                               dn = strdup( cargv[1] );
+                               (void) dn_normalize( dn );
+                               charray_add( &be->be_suffix, dn );
+                       }
+
+               /* set magic "root" dn for this database */
+               } else if ( strcasecmp( cargv[0], "rootdn" ) == 0 ) {
+                       if ( cargc < 2 ) {
+                               Debug( LDAP_DEBUG_ANY,
+                   "%s: line %d: missing dn in \"rootdn <dn>\" line\n",
+                                   fname, lineno, 0 );
+                               exit( 1 );
+                       }
+                       if ( be == NULL ) {
+                               Debug( LDAP_DEBUG_ANY,
+"%s: line %d: rootdn line must appear inside a database definition (ignored)\n",
+                                   fname, lineno, 0 );
+                       } else {
+                               dn = strdup( cargv[1] );
+                               (void) dn_normalize( dn );
+                               be->be_rootdn = dn;
+                       }
+
+               /* set super-secret magic database password */
+               } else if ( strcasecmp( cargv[0], "rootpw" ) == 0 ) {
+                       if ( cargc < 2 ) {
+                               Debug( LDAP_DEBUG_ANY,
+           "%s: line %d: missing passwd in \"rootpw <passwd>\" line\n",
+                                   fname, lineno, 0 );
+                               exit( 1 );
+                       }
+                       if ( be == NULL ) {
+                               Debug( LDAP_DEBUG_ANY,
+"%s: line %d: rootpw line must appear inside a database definition (ignored)\n",
+                                   fname, lineno, 0 );
+                       } else {
+                               be->be_rootpw = strdup( cargv[1] );
+                       }
+
+               /* make this database read-only */
+               } else if ( strcasecmp( cargv[0], "readonly" ) == 0 ) {
+                       if ( cargc < 2 ) {
+                               Debug( LDAP_DEBUG_ANY,
+           "%s: line %d: missing on|off in \"readonly <on|off>\" line\n",
+                                   fname, lineno, 0 );
+                               exit( 1 );
+                       }
+                       if ( be == NULL ) {
+                               Debug( LDAP_DEBUG_ANY,
+"%s: line %d: readonly line must appear inside a database definition (ignored)\n",
+                                   fname, lineno, 0 );
+                       } else {
+                               if ( strcasecmp( cargv[1], "on" ) == 0 ) {
+                                       be->be_readonly = 1;
+                               } else {
+                                       be->be_readonly = 0;
+                               }
+                       }
+
+               /* where to send clients when we don't hold it */
+               } else if ( strcasecmp( cargv[0], "referral" ) == 0 ) {
+                       if ( cargc < 2 ) {
+                               Debug( LDAP_DEBUG_ANY,
+                   "%s: line %d: missing URL in \"referral <URL>\" line\n",
+                                   fname, lineno, 0 );
+                               exit( 1 );
+                       }
+                       default_referral = (char *) malloc( strlen( cargv[1] )
+                           + sizeof("Referral:\n") + 1 );
+                       strcpy( default_referral, "Referral:\n" );
+                       strcat( default_referral, cargv[1] );
+
+               /* specify an objectclass */
+               } else if ( strcasecmp( cargv[0], "objectclass" ) == 0 ) {
+                       parse_oc( be, fname, lineno, cargc, cargv );
+
+               /* specify an attribute */
+               } else if ( strcasecmp( cargv[0], "attribute" ) == 0 ) {
+                       attr_syntax_config( fname, lineno, cargc - 1,
+                           &cargv[1] );
+
+               /* turn on/off schema checking */
+               } else if ( strcasecmp( cargv[0], "schemacheck" ) == 0 ) {
+                       if ( cargc < 2 ) {
+                               Debug( LDAP_DEBUG_ANY,
+    "%s: line %d: missing on|off in \"schemacheck <on|off>\" line\n",
+                                   fname, lineno, 0 );
+                               exit( 1 );
+                       }
+                       if ( strcasecmp( cargv[1], "on" ) == 0 ) {
+                               global_schemacheck = 1;
+                       } else {
+                               global_schemacheck = 0;
+                       }
+
+               /* specify access control info */
+               } else if ( strcasecmp( cargv[0], "access" ) == 0 ) {
+                       parse_acl( be, fname, lineno, cargc, cargv );
+
+               /* specify default access control info */
+               } else if ( strcasecmp( cargv[0], "defaultaccess" ) == 0 ) {
+                       if ( cargc < 2 ) {
+                               Debug( LDAP_DEBUG_ANY,
+           "%s: line %d: missing limit in \"defaultaccess <access>\" line\n",
+                                   fname, lineno, 0 );
+                               exit( 1 );
+                       }
+                       if ( be == NULL ) {
+                               if ( (global_default_access =
+                                   str2access( cargv[1] )) == -1 ) {
+                                       Debug( LDAP_DEBUG_ANY,
+"%s: line %d: bad access \"%s\" expecting [self]{none|compare|read|write}\n",
+                                           fname, lineno, cargv[1] );
+                                       exit( 1 );
+                               }
+                       } else {
+                               if ( (be->be_dfltaccess =
+                                   str2access( cargv[1] )) == -1 ) {
+                                       Debug( LDAP_DEBUG_ANY,
+"%s: line %d: bad access \"%s\" expecting [self]{none|compare|read|write}\n",
+                                           fname, lineno, cargv[1] );
+                                       exit( 1 );
+                               }
+                       }
+
+               /* debug level to log things to syslog */
+               } else if ( strcasecmp( cargv[0], "loglevel" ) == 0 ) {
+                       if ( cargc < 2 ) {
+                               Debug( LDAP_DEBUG_ANY,
+                   "%s: line %d: missing level in \"loglevel <level>\" line\n",
+                                   fname, lineno, 0 );
+                               exit( 1 );
+                       }
+                       ldap_syslog = atoi( cargv[1] );
+
+               /* list of replicas of the data in this backend (master only) */
+               } else if ( strcasecmp( cargv[0], "replica" ) == 0 ) {
+                       if ( cargc < 2 ) {
+                               Debug( LDAP_DEBUG_ANY,
+           "%s: line %d: missing host in \"replica <host[:port]>\" line\n",
+                                   fname, lineno, 0 );
+                               exit( 1 );
+                       }
+                       if ( be == NULL ) {
+                               Debug( LDAP_DEBUG_ANY,
+"%s: line %d: replica line must appear inside a database definition (ignored)\n",
+                                   fname, lineno, 0 );
+                       } else {
+                               for ( i = 1; i < cargc; i++ ) {
+                                       if ( strncasecmp( cargv[i], "host=", 5 )
+                                           == 0 ) {
+                                               charray_add( &be->be_replica,
+                                                   strdup( cargv[i] + 5 ) );
+                                               break;
+                                       }
+                               }
+                               if ( i == cargc ) {
+                                       Debug( LDAP_DEBUG_ANY,
+                   "%s: line %d: missing host in \"replica\" line (ignored)\n",
+                                           fname, lineno, 0 );
+                               }
+                       }
+
+               /* dn of master entity allowed to write to replica */
+               } else if ( strcasecmp( cargv[0], "updatedn" ) == 0 ) {
+                       if ( cargc < 2 ) {
+                               Debug( LDAP_DEBUG_ANY,
+                   "%s: line %d: missing dn in \"updatedn <dn>\" line\n",
+                                   fname, lineno, 0 );
+                               exit( 1 );
+                       }
+                       if ( be == NULL ) {
+                               Debug( LDAP_DEBUG_ANY,
+"%s: line %d: updatedn line must appear inside a database definition (ignored)\n",
+                                   fname, lineno, 0 );
+                       } else {
+                               be->be_updatedn = strdup( cargv[1] );
+                               (void) dn_normalize( be->be_updatedn );
+                       }
+
+               /* replication log file to which changes are appended */
+               } else if ( strcasecmp( cargv[0], "replogfile" ) == 0 ) {
+                       if ( cargc < 2 ) {
+                               Debug( LDAP_DEBUG_ANY,
+           "%s: line %d: missing dn in \"replogfile <filename>\" line\n",
+                                   fname, lineno, 0 );
+                               exit( 1 );
+                       }
+                       if ( be ) {
+                               be->be_replogfile = strdup( cargv[1] );
+                       } else {
+                               replogfile = strdup( cargv[1] );
+                       }
+
+               /* maintain lastmodified{by,time} attributes */
+               } else if ( strcasecmp( cargv[0], "lastmod" ) == 0 ) {
+                       if ( cargc < 2 ) {
+                               Debug( LDAP_DEBUG_ANY,
+           "%s: line %d: missing on|off in \"lastmod <on|off>\" line\n",
+                                   fname, lineno, 0 );
+                               exit( 1 );
+                       }
+                       if ( strcasecmp( cargv[1], "on" ) == 0 ) {
+                               if ( be )
+                                       be->be_lastmod = ON;
+                               else
+                                       global_lastmod = ON;
+                       } else {
+                               if ( be )
+                                       be->be_lastmod = OFF;
+                               else
+                                       global_lastmod = OFF;
+                       }
+
+               /* include another config file */
+               } else if ( strcasecmp( cargv[0], "include" ) == 0 ) {
+                       if ( cargc < 2 ) {
+                               Debug( LDAP_DEBUG_ANY,
+    "%s: line %d: missing filename in \"include <filename>\" line\n",
+                                   fname, lineno, 0 );
+                               exit( 1 );
+                       }
+                       savefname = strdup( cargv[1] );
+                       savelineno = lineno;
+                       read_config( savefname, bep, NULL );
+                       be = *bep;
+                       free( savefname );
+                       lineno = savelineno - 1;
+
+               /* location of kerberos srvtab file */
+               } else if ( strcasecmp( cargv[0], "srvtab" ) == 0 ) {
+                       if ( cargc < 2 ) {
+                               Debug( LDAP_DEBUG_ANY,
+           "%s: line %d: missing filename in \"srvtab <filename>\" line\n",
+                                   fname, lineno, 0 );
+                               exit( 1 );
+                       }
+                       ldap_srvtab = strdup( cargv[1] );
+
+               /* pass anything else to the current backend config routine */
+               } else {
+                       if ( be == NULL ) {
+                               Debug( LDAP_DEBUG_ANY,
+"%s: line %d: unknown directive \"%s\" outside database definition (ignored)\n",
+                                   fname, lineno, cargv[0] );
+                       } else if ( be->be_config == NULL ) {
+                               Debug( LDAP_DEBUG_ANY,
+"%s: line %d: unknown directive \"%s\" inside database definition (ignored)\n",
+                                   fname, lineno, cargv[0] );
+                       } else {
+                               (*be->be_config)( be, fname, lineno, cargc,
+                                   cargv );
+                       }
+               }
+       }
+       fclose( fp );
+}
+
+static void
+fp_parse_line(
+    char       *line,
+    int                *argcp,
+    char       **argv
+)
+{
+       char *  token;
+
+       *argcp = 0;
+       for ( token = strtok_quote( line, " \t" ); token != NULL;
+           token = strtok_quote( NULL, " \t" ) ) {
+               if ( *argcp == MAXARGS ) {
+                       Debug( LDAP_DEBUG_ANY, "Too many tokens (max %d)\n",
+                           MAXARGS, 0, 0 );
+                       exit( 1 );
+               }
+               argv[(*argcp)++] = token;
+       }
+       argv[*argcp] = NULL;
+}
+
+static char *
+strtok_quote( char *line, char *sep )
+{
+       int             inquote;
+       char            *tmp;
+       static char     *next;
+
+       if ( line != NULL ) {
+               next = line;
+       }
+       while ( *next && strchr( sep, *next ) ) {
+               next++;
+       }
+
+       if ( *next == '\0' ) {
+               next = NULL;
+               return( NULL );
+       }
+       tmp = next;
+
+       for ( inquote = 0; *next; ) {
+               switch ( *next ) {
+               case '"':
+                       if ( inquote ) {
+                               inquote = 0;
+                       } else {
+                               inquote = 1;
+                       }
+                       strcpy( next, next + 1 );
+                       break;
+
+               case '\\':
+                       strcpy( next, next + 1 );
+                       break;
+
+               default:
+                       if ( ! inquote ) {
+                               if ( strchr( sep, *next ) != NULL ) {
+                                       *next++ = '\0';
+                                       return( tmp );
+                               }
+                       }
+                       next++;
+                       break;
+               }
+       }
+
+       return( tmp );
+}
+
+static char    buf[BUFSIZ];
+static char    *line;
+static int     lmax, lcur;
+
+#define CATLINE( buf ) { \
+       int     len; \
+       len = strlen( buf ); \
+       while ( lcur + len + 1 > lmax ) { \
+               lmax += BUFSIZ; \
+               line = (char *) ch_realloc( line, lmax ); \
+       } \
+       strcpy( line + lcur, buf ); \
+       lcur += len; \
+}
+
+static char *
+fp_getline( FILE *fp, int *lineno )
+{
+       char            *p;
+
+       lcur = 0;
+       CATLINE( buf );
+       (*lineno)++;
+
+       /* hack attack - keeps us from having to keep a stack of bufs... */
+       if ( strncasecmp( line, "include", 7 ) == 0 ) {
+               buf[0] = '\0';
+               return( line );
+       }
+
+       while ( fgets( buf, sizeof(buf), fp ) != NULL ) {
+               if ( (p = strchr( buf, '\n' )) != NULL ) {
+                       *p = '\0';
+               }
+               if ( ! isspace( buf[0] ) ) {
+                       return( line );
+               }
+
+               CATLINE( buf );
+               (*lineno)++;
+       }
+       buf[0] = '\0';
+
+       return( line[0] ? line : NULL );
+}
+
+static void
+fp_getline_init( int *lineno )
+{
+       *lineno = -1;
+       buf[0] = '\0';
+}
diff --git a/servers/slapd/configinfo.c b/servers/slapd/configinfo.c
new file mode 100644 (file)
index 0000000..5599193
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "ldapconfig.h"
+
+#if defined( SLAPD_CONFIG_DN )
+
+extern int             nbackends;
+extern Backend         *backends;
+extern char            *default_referral;
+
+/*
+ * no mutex protection in here - take our chances!
+ */
+
+void
+config_info( Connection *conn, Operation *op )
+{
+       Entry           *e;
+       char            buf[BUFSIZ];
+       struct berval   val;
+       struct berval   *vals[2];
+       int             i, j;
+
+       vals[0] = &val;
+       vals[1] = NULL;
+
+       e = (Entry *) ch_calloc( 1, sizeof(Entry) );
+       e->e_attrs = NULL;
+       e->e_dn = strdup( SLAPD_CONFIG_DN );
+
+       for ( i = 0; i < nbackends; i++ ) {
+               strcpy( buf, backends[i].be_type );
+               for ( j = 0; backends[i].be_suffix[j] != NULL; j++ ) {
+                       strcat( buf, " : " );
+                       strcat( buf, backends[i].be_suffix[j] );
+               }
+               val.bv_val = buf;
+               val.bv_len = strlen( buf );
+               attr_merge( e, "database", vals );
+       }
+
+       if ( default_referral != NULL ) {
+               strcpy( buf, default_referral );
+               val.bv_val = buf;
+               val.bv_len = strlen( buf );
+               attr_merge( e, "database", vals );
+       }
+
+       send_search_entry( &backends[0], conn, op, e, NULL, 0 );
+       send_ldap_search_result( conn, op, LDAP_SUCCESS, NULL, NULL, 1 );
+
+       entry_free( e );
+}
+
+#endif /* slapd_config_dn */
diff --git a/servers/slapd/connection.c b/servers/slapd/connection.c
new file mode 100644 (file)
index 0000000..5c3ebdf
--- /dev/null
@@ -0,0 +1,215 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <signal.h>
+#include "portable.h"
+#include "slap.h"
+
+extern Operation       *op_add();
+extern int             active_threads;
+extern pthread_mutex_t active_threads_mutex;
+extern pthread_mutex_t new_conn_mutex;
+extern long            ops_initiated;
+extern long            ops_completed;
+extern pthread_mutex_t ops_mutex;
+extern pthread_t       listener_tid;
+#ifndef SYSERRLIST_IN_STDIO
+extern int             sys_nerr;
+extern char            *sys_errlist[];
+#endif
+
+struct co_arg {
+       Connection      *co_conn;
+       Operation       *co_op;
+};
+
+/*
+ * connection_activity - handle the request operation op on connection
+ * conn.  This routine figures out what kind of operation it is and
+ * calls the appropriate stub to handle it.
+ */
+
+static void
+connection_operation( struct co_arg *arg )
+{
+       unsigned long   len;
+
+       pthread_mutex_lock( &arg->co_conn->c_opsmutex );
+       arg->co_conn->c_opsinitiated++;
+       pthread_mutex_unlock( &arg->co_conn->c_opsmutex );
+
+       pthread_mutex_lock( &ops_mutex );
+       ops_initiated++;
+       pthread_mutex_unlock( &ops_mutex );
+
+       switch ( arg->co_op->o_tag ) {
+       case LDAP_REQ_BIND:
+               do_bind( arg->co_conn, arg->co_op );
+               break;
+
+#ifdef COMPAT30
+       case LDAP_REQ_UNBIND_30:
+#endif
+       case LDAP_REQ_UNBIND:
+               do_unbind( arg->co_conn, arg->co_op );
+               break;
+
+       case LDAP_REQ_ADD:
+               do_add( arg->co_conn, arg->co_op );
+               break;
+
+#ifdef COMPAT30
+       case LDAP_REQ_DELETE_30:
+#endif
+       case LDAP_REQ_DELETE:
+               do_delete( arg->co_conn, arg->co_op );
+               break;
+
+       case LDAP_REQ_MODRDN:
+               do_modrdn( arg->co_conn, arg->co_op );
+               break;
+
+       case LDAP_REQ_MODIFY:
+               do_modify( arg->co_conn, arg->co_op );
+               break;
+
+       case LDAP_REQ_COMPARE:
+               do_compare( arg->co_conn, arg->co_op );
+               break;
+
+       case LDAP_REQ_SEARCH:
+               do_search( arg->co_conn, arg->co_op );
+               break;
+
+#ifdef COMPAT30
+       case LDAP_REQ_ABANDON_30:
+#endif
+       case LDAP_REQ_ABANDON:
+               do_abandon( arg->co_conn, arg->co_op );
+               break;
+
+       default:
+               Debug( LDAP_DEBUG_ANY, "unknown request 0x%x\n",
+                   arg->co_op->o_tag, 0, 0 );
+               break;
+       }
+
+       pthread_mutex_lock( &arg->co_conn->c_opsmutex );
+       arg->co_conn->c_opscompleted++;
+       op_delete( &arg->co_conn->c_ops, arg->co_op );
+       pthread_mutex_unlock( &arg->co_conn->c_opsmutex );
+
+       free( (char *) arg );
+
+       pthread_mutex_lock( &ops_mutex );
+       ops_completed++;
+       pthread_mutex_unlock( &ops_mutex );
+
+       pthread_mutex_lock( &active_threads_mutex );
+       active_threads--;
+       pthread_mutex_unlock( &active_threads_mutex );
+}
+
+void
+connection_activity(
+    Connection *conn
+)
+{
+       pthread_attr_t  attr;
+       struct co_arg   *arg;
+       unsigned long   tag, len;
+       long            msgid;
+       BerElement      *ber;
+       char            *tmpdn;
+
+       if ( conn->c_currentber == NULL && (conn->c_currentber = ber_alloc())
+           == NULL ) {
+               Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
+               return;
+       }
+
+       errno = 0;
+       if ( (tag = ber_get_next( &conn->c_sb, &len, conn->c_currentber ))
+           != LDAP_TAG_MESSAGE ) {
+               Debug( LDAP_DEBUG_TRACE,
+                   "ber_get_next on fd %d failed errno %d (%s)\n",
+                   conn->c_sb.sb_sd, errno, errno > -1 && errno < sys_nerr ?
+                   sys_errlist[errno] : "unknown" );
+               Debug( LDAP_DEBUG_TRACE, "*** got %d of %d so far\n",
+                   conn->c_currentber->ber_rwptr - conn->c_currentber->ber_buf,
+                   conn->c_currentber->ber_len, 0 );
+
+               if ( errno != EWOULDBLOCK && errno != EAGAIN ) {
+                       /* log, close and send error */
+                       ber_free( conn->c_currentber, 1 );
+                       conn->c_currentber = NULL;
+
+                       close_connection( conn, conn->c_connid, -1 );
+               }
+
+               return;
+       }
+       ber = conn->c_currentber;
+       conn->c_currentber = NULL;
+
+       if ( (tag = ber_get_int( ber, &msgid )) != LDAP_TAG_MSGID ) {
+               /* log, close and send error */
+               Debug( LDAP_DEBUG_ANY, "ber_get_int returns 0x%x\n", tag, 0,
+                   0 );
+               ber_free( ber, 1 );
+
+               close_connection( conn, conn->c_connid, -1 );
+               return;
+       }
+
+       if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) {
+               /* log, close and send error */
+               Debug( LDAP_DEBUG_ANY, "ber_peek_tag returns 0x%x\n", tag, 0,
+                   0 );
+               ber_free( ber, 1 );
+
+               close_connection( conn, conn->c_connid, -1 );
+               return;
+       }
+
+#ifdef COMPAT30
+       if ( conn->c_version == 30 ) {
+               (void) ber_skip_tag( ber, &len );
+       }
+#endif
+
+       arg = (struct co_arg *) ch_malloc( sizeof(struct co_arg) );
+       arg->co_conn = conn;
+
+       pthread_mutex_lock( &conn->c_dnmutex );
+       if ( conn->c_dn != NULL ) {
+               tmpdn = strdup( conn->c_dn );
+       } else {
+               tmpdn = NULL;
+       }
+       pthread_mutex_unlock( &conn->c_dnmutex );
+
+       pthread_mutex_lock( &conn->c_opsmutex );
+       arg->co_op = op_add( &conn->c_ops, ber, msgid, tag, tmpdn,
+           conn->c_opsinitiated, conn->c_connid );
+       pthread_mutex_unlock( &conn->c_opsmutex );
+
+       if ( tmpdn != NULL ) {
+               free( tmpdn );
+       }
+
+       pthread_attr_init( &attr );
+       pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED );
+       if ( pthread_create( &arg->co_op->o_tid, attr,
+           (void *) connection_operation, (void *) arg ) != 0 ) {
+               Debug( LDAP_DEBUG_ANY, "pthread_create failed\n", 0, 0, 0 );
+       } else {
+               pthread_mutex_lock( &active_threads_mutex );
+               active_threads++;
+               pthread_mutex_unlock( &active_threads_mutex );
+       }
+       pthread_attr_destroy( &attr );
+}
diff --git a/servers/slapd/daemon.c b/servers/slapd/daemon.c
new file mode 100644 (file)
index 0000000..161fb79
--- /dev/null
@@ -0,0 +1,363 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <signal.h>
+#ifdef _AIX
+#include <sys/select.h>
+#endif
+#include "slap.h"
+#include "portable.h"
+#include "ldapconfig.h"
+#ifdef NEED_FILIO
+#include <sys/filio.h>
+#else /* NEED_FILIO */
+#include <sys/ioctl.h>
+#endif /* NEED_FILIO */
+#ifdef USE_SYSCONF
+#include <unistd.h>
+#endif /* USE_SYSCONF */
+
+extern Operation       *op_add();
+
+#ifndef SYSERRLIST_IN_STDIO
+extern int             sys_nerr;
+extern char            *sys_errlist[];
+#endif
+extern time_t          currenttime;
+extern pthread_mutex_t currenttime_mutex;
+extern int             active_threads;
+extern pthread_mutex_t active_threads_mutex;
+extern pthread_mutex_t new_conn_mutex;
+extern int             slapd_shutdown;
+extern pthread_t       listener_tid;
+extern int             num_conns;
+extern pthread_mutex_t ops_mutex;
+extern int             g_argc;
+extern char            **g_argv;
+
+int            dtblsize;
+Connection     *c;
+
+static void    set_shutdown();
+static void    do_nothing();
+
+void
+daemon(
+    int        port
+)
+{
+       Operation               *o;
+       BerElement              ber;
+       unsigned long           len, tag, msgid;
+       int                     i;
+       int                     tcps, ns;
+       struct sockaddr_in      addr;
+       fd_set                  readfds;
+       fd_set                  writefds;
+       FILE                    *fp;
+       int                     on = 1;
+
+#ifdef USE_SYSCONF
+        dtblsize = sysconf( _SC_OPEN_MAX );
+#else /* USE_SYSCONF */
+        dtblsize = getdtablesize();
+#endif /* USE_SYSCONF */
+
+       c = (Connection *) ch_calloc( 1, dtblsize * sizeof(Connection) );
+
+       for ( i = 0; i < dtblsize; i++ ) {
+               c[i].c_dn = NULL;
+               c[i].c_addr = NULL;
+               c[i].c_domain = NULL;
+               c[i].c_ops = NULL;
+               c[i].c_sb.sb_sd = -1;
+               c[i].c_sb.sb_options = LBER_NO_READ_AHEAD;
+               c[i].c_sb.sb_naddr = 0;
+               c[i].c_sb.sb_ber.ber_buf = NULL;
+               c[i].c_sb.sb_ber.ber_ptr = NULL;
+               c[i].c_sb.sb_ber.ber_end = NULL;
+               c[i].c_writewaiter = 0;
+               c[i].c_connid = 0;
+               pthread_mutex_init( &c[i].c_dnmutex,
+                   pthread_mutexattr_default );
+               pthread_mutex_init( &c[i].c_opsmutex,
+                   pthread_mutexattr_default );
+               pthread_mutex_init( &c[i].c_pdumutex,
+                   pthread_mutexattr_default );
+               pthread_cond_init( &c[i].c_wcv, pthread_condattr_default );
+       }
+
+       if ( (tcps = socket( AF_INET, SOCK_STREAM, 0 )) == -1 ) {
+               Debug( LDAP_DEBUG_ANY, "socket() failed errno %d (%s)", errno,
+                   errno > -1 && errno < sys_nerr ? sys_errlist[errno] :
+                   "unknown", 0 );
+               exit( 1 );
+       }
+
+       i = 1;
+       if ( setsockopt( tcps, SOL_SOCKET, SO_REUSEADDR, (char *) &i,
+           sizeof(i) ) == -1 ) {
+               Debug( LDAP_DEBUG_ANY, "setsockopt() failed errno %d (%s)",
+                   errno, errno > -1 && errno < sys_nerr ? sys_errlist[errno] :
+                   "unknown", 0 );
+       }
+
+       (void) memset( (void *) &addr, '\0', sizeof(addr) );
+       addr.sin_family = AF_INET;
+       addr.sin_addr.s_addr = INADDR_ANY;
+       addr.sin_port = htons( port );
+       if ( bind( tcps, (struct sockaddr *) &addr, sizeof(addr) ) == -1 ) {
+               Debug( LDAP_DEBUG_ANY, "bind() failed errno %d (%s)\n",
+                   errno, errno > -1 && errno < sys_nerr ? sys_errlist[errno] :
+                   "unknown", 0 );
+               exit( 1 );
+       }
+
+       if ( listen( tcps, 5 ) == -1 ) {
+               Debug( LDAP_DEBUG_ANY, "listen() failed errno %d (%s)",
+                   errno, errno > -1 && errno < sys_nerr ? sys_errlist[errno] :
+                   "unknown", 0 );
+               exit( 1 );
+       }
+
+       (void) SIGNAL( SIGPIPE, SIG_IGN );
+       (void) SIGNAL( SIGUSR1, (void *) do_nothing );
+       (void) SIGNAL( SIGUSR2, (void *) set_shutdown );
+       (void) SIGNAL( SIGTERM, (void *) set_shutdown );
+       (void) SIGNAL( SIGHUP, (void *) set_shutdown );
+
+       Debug( LDAP_DEBUG_ANY, "slapd starting\n", 0, 0, 0 );
+#ifdef SLAPD_PIDFILE
+       if ( (fp = fopen( SLAPD_PIDFILE, "w" )) != NULL ) {
+               fprintf( fp, "%d\n", getpid() );
+               fclose( fp );
+       }
+#endif
+#ifdef SLAPD_ARGSFILE
+       if ( (fp = fopen( SLAPD_ARGSFILE, "w" )) != NULL ) {
+               for ( i = 0; i < g_argc; i++ ) {
+                       fprintf( fp, "%s ", g_argv[i] );
+               }
+               fprintf( fp, "\n" );
+               fclose( fp );
+       }
+#endif
+
+       while ( !slapd_shutdown ) {
+               struct sockaddr_in      from;
+               struct hostent          *hp;
+               struct timeval          zero;
+               struct timeval          *tvp;
+               int                     len, pid;
+
+               FD_ZERO( &writefds );
+               FD_ZERO( &readfds );
+               FD_SET( tcps, &readfds );
+
+               pthread_mutex_lock( &active_threads_mutex );
+               Debug( LDAP_DEBUG_CONNS,
+                   "listening for connections on %d, activity on:",
+                   tcps, 0, 0 );
+               for ( i = 0; i < dtblsize; i++ ) {
+                       if ( c[i].c_sb.sb_sd != -1 ) {
+                               FD_SET( c[i].c_sb.sb_sd, &readfds );
+
+                               if ( c[i].c_writewaiter ) {
+                                       FD_SET( c[i].c_sb.sb_sd, &writefds );
+                               }
+                               Debug( LDAP_DEBUG_CONNS, " %dr%s", i,
+                                   c[i].c_writewaiter ? "w" : "", 0 );
+                       }
+               }
+               Debug( LDAP_DEBUG_CONNS, "\n", 0, 0, 0 );
+
+               zero.tv_sec = 0;
+               zero.tv_usec = 0;
+               Debug( LDAP_DEBUG_CONNS, "before select active_threads %d\n",
+                   active_threads, 0, 0 );
+#ifdef PTHREAD_PREEMPTIVE
+               tvp = NULL;
+#else
+               tvp = active_threads ? &zero : NULL;
+#endif
+               pthread_mutex_unlock( &active_threads_mutex );
+
+               switch ( select( dtblsize, &readfds, &writefds, 0, tvp ) ) {
+               case -1:        /* failure - try again */
+                       Debug( LDAP_DEBUG_CONNS,
+                           "select failed errno %d (%s)\n",
+                           errno, errno > -1 && errno < sys_nerr ?
+                           sys_errlist[errno] : "unknown", 0 );
+                       continue;
+
+               case 0:         /* timeout - let threads run */
+                       Debug( LDAP_DEBUG_CONNS, "select timeout - yielding\n",
+                           0, 0, 0 );
+                       pthread_yield();
+                       continue;
+
+               default:        /* something happened - deal with it */
+                       Debug( LDAP_DEBUG_CONNS, "select activity\n", 0, 0, 0 );
+                       ;       /* FALL */
+               }
+               pthread_mutex_lock( &currenttime_mutex );
+               time( &currenttime );
+               pthread_mutex_unlock( &currenttime_mutex );
+
+               /* new connection */
+               pthread_mutex_lock( &new_conn_mutex );
+               if ( FD_ISSET( tcps, &readfds ) ) {
+                       len = sizeof(from);
+                       if ( (ns = accept( tcps, (struct sockaddr *) &from,
+                           &len )) == -1 ) {
+                               Debug( LDAP_DEBUG_ANY,
+                                   "accept() failed errno %d (%s)", errno,
+                                   errno > -1 && errno < sys_nerr ?
+                                   sys_errlist[errno] : "unknown", 0 );
+                               pthread_mutex_unlock( &new_conn_mutex );
+                               continue;
+                       }
+                       if ( ioctl( ns, FIONBIO, (caddr_t) &on ) == -1 ) {
+                               Debug( LDAP_DEBUG_ANY,
+                                   "FIONBIO ioctl on %d faled\n", ns, 0, 0 );
+                       }
+                       c[ns].c_sb.sb_sd = ns;
+                       Debug( LDAP_DEBUG_CONNS, "new connection on %d\n", ns,
+                           0, 0 );
+
+                       pthread_mutex_lock( &ops_mutex );
+                       c[ns].c_connid = num_conns++;
+                       pthread_mutex_unlock( &ops_mutex );
+                       len = sizeof(from);
+                       if ( getpeername( ns, (struct sockaddr *) &from, &len )
+                           == 0 ) {
+                               char    *s;
+#ifdef REVERSE_LOOKUP
+                               hp = gethostbyaddr( (char *)
+                                   &(from.sin_addr.s_addr),
+                                   sizeof(from.sin_addr.s_addr), AF_INET );
+#else
+                               hp = NULL;
+#endif
+
+                               Statslog( LDAP_DEBUG_STATS,
+                                   "conn=%d fd=%d connection from %s (%s)\n",
+                                   c[ns].c_connid, ns, hp == NULL ? "unknown"
+                                   : hp->h_name, inet_ntoa( from.sin_addr ),
+                                   0 );
+
+                               if ( c[ns].c_addr != NULL ) {
+                                       free( c[ns].c_addr );
+                               }
+                               c[ns].c_addr = strdup( inet_ntoa(
+                                   from.sin_addr ) );
+                               if ( c[ns].c_domain != NULL ) {
+                                       free( c[ns].c_domain );
+                               }
+                               c[ns].c_domain = strdup( hp == NULL ? "" :
+                                   hp->h_name );
+                               /* normalize the domain */
+                               for ( s = c[ns].c_domain; *s; s++ ) {
+                                       *s = TOLOWER( *s );
+                               }
+                       } else {
+                               Statslog( LDAP_DEBUG_STATS,
+                                   "conn=%d fd=%d connection from unknown\n",
+                                   c[ns].c_connid, ns, 0, 0, 0 );
+                       }
+                       pthread_mutex_lock( &c[ns].c_dnmutex );
+                       if ( c[ns].c_dn != NULL ) {
+                               free( c[ns].c_dn );
+                               c[ns].c_dn = NULL;
+                       }
+                       pthread_mutex_unlock( &c[ns].c_dnmutex );
+                       c[ns].c_starttime = currenttime;
+                       c[ns].c_opsinitiated = 0;
+                       c[ns].c_opscompleted = 0;
+               }
+               pthread_mutex_unlock( &new_conn_mutex );
+
+               Debug( LDAP_DEBUG_CONNS, "activity on:", 0, 0, 0 );
+               for ( i = 0; i < dtblsize; i++ ) {
+                       int     r, w;
+
+                       r = FD_ISSET( i, &readfds );
+                       w = FD_ISSET( i, &writefds );
+                       if ( i != tcps && (r || w) ) {
+                               Debug( LDAP_DEBUG_CONNS, " %d%s%s", i,
+                                   r ? "r" : "", w ? "w" : "" );
+                       }
+               }
+               Debug( LDAP_DEBUG_CONNS, "\n", 0, 0, 0 );
+
+               for ( i = 0; i < dtblsize; i++ ) {
+                       if ( i == tcps || (! FD_ISSET( i, &readfds ) &&
+                           ! FD_ISSET( i, &writefds )) ) {
+                               continue;
+                       }
+
+                       if ( FD_ISSET( i, &writefds ) ) {
+                               Debug( LDAP_DEBUG_CONNS,
+                                   "signaling write waiter on %d\n", i, 0, 0 );
+
+                               pthread_mutex_lock( &active_threads_mutex );
+                               pthread_cond_signal( &c[i].c_wcv );
+                               c[i].c_writewaiter = 0;
+                               active_threads++;
+                               pthread_mutex_unlock( &active_threads_mutex );
+                       }
+
+                       if ( FD_ISSET( i, &readfds ) ) {
+                               Debug( LDAP_DEBUG_CONNS,
+                                   "read activity on %d\n", i, 0, 0 );
+
+                               connection_activity( &c[i] );
+                       }
+               }
+
+               pthread_yield();
+       }
+
+       close( tcps );
+       pthread_mutex_lock( &active_threads_mutex );
+       Debug( LDAP_DEBUG_ANY,
+           "slapd shutting down - waiting for %d threads to terminate\n",
+           active_threads, 0, 0 );
+       while ( active_threads > 0 ) {
+               pthread_mutex_unlock( &active_threads_mutex );
+               pthread_yield();
+               pthread_mutex_lock( &active_threads_mutex );
+       }
+       pthread_mutex_unlock( &active_threads_mutex );
+
+       /* let backends do whatever cleanup they need to do */
+       Debug( LDAP_DEBUG_TRACE,
+           "slapd shutting down - waiting for backends to close down\n", 0, 0,
+           0 );
+       be_close();
+       Debug( LDAP_DEBUG_ANY, "slapd stopping\n", 0, 0, 0 );
+}
+
+static void
+set_shutdown()
+{
+       Debug( LDAP_DEBUG_ANY, "slapd got shutdown signal\n", 0, 0, 0 );
+       slapd_shutdown = 1;
+       pthread_kill( listener_tid, SIGUSR1 );
+       (void) SIGNAL( SIGUSR2, (void *) set_shutdown );
+       (void) SIGNAL( SIGTERM, (void *) set_shutdown );
+       (void) SIGNAL( SIGHUP, (void *) set_shutdown );
+}
+
+static void
+do_nothing()
+{
+       Debug( LDAP_DEBUG_TRACE, "slapd got SIGUSR1\n", 0, 0, 0 );
+       (void) SIGNAL( SIGUSR1, (void *) do_nothing );
+}
diff --git a/servers/slapd/delete.c b/servers/slapd/delete.c
new file mode 100644 (file)
index 0000000..bbab478
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+
+extern Backend *select_backend();
+
+extern char    *default_referral;
+
+void
+do_delete(
+    Connection *conn,
+    Operation  *op
+)
+{
+       char    *dn, *odn;
+       Backend *be;
+
+       Debug( LDAP_DEBUG_TRACE, "do_delete\n", 0, 0, 0 );
+
+       /*
+        * Parse the delete request.  It looks like this:
+        *
+        *      DelRequest := DistinguishedName
+        */
+
+       if ( ber_scanf( op->o_ber, "a", &dn ) == LBER_ERROR ) {
+               Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
+               send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL, "" );
+               return;
+       }
+       odn = strdup( dn );
+       dn_normalize( dn );
+
+       Debug( LDAP_DEBUG_ARGS, "do_delete: dn (%s)\n", dn, 0, 0 );
+
+       Debug( LDAP_DEBUG_STATS, "DEL dn=\"%s\"\n", dn, 0, 0 );
+
+       /*
+        * We could be serving multiple database backends.  Select the
+        * appropriate one, or send a referral to our "referral server"
+        * if we don't hold it.
+        */
+       if ( (be = select_backend( dn )) == NULL ) {
+               free( dn );
+               free( odn );
+               send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
+                   default_referral );
+               return;
+       }
+
+       /*
+        * do the delete if 1 && (2 || 3)
+        * 1) there is a delete function implemented in this backend;
+        * 2) this backend is master for what it holds;
+        * 3) it's a replica and the dn supplied is the updatedn.
+        */
+       if ( be->be_delete != NULL ) {
+               /* do the update here */
+               if ( be->be_updatedn == NULL || strcasecmp( be->be_updatedn,
+                   op->o_dn ) == 0 ) {
+                       if ( (*be->be_delete)( be, conn, op, dn ) == 0 ) {
+                               replog( be, LDAP_REQ_DELETE, odn, NULL, 0 );
+                       }
+               } else {
+                       send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
+                           default_referral );
+               }
+       } else {
+               send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
+                   "Function not implemented" );
+       }
+
+       free( dn );
+       free( odn );
+}
diff --git a/servers/slapd/detach.c b/servers/slapd/detach.c
new file mode 100644 (file)
index 0000000..7b3fdab
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 1990, 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef SVR4
+#include <sys/stat.h>
+#endif /* svr4 */
+#include <fcntl.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <signal.h>
+#include "portable.h"
+
+#ifdef USE_SYSCONF
+#include <unistd.h>
+#endif /* USE_SYSCONF */
+
+
+detach()
+{
+       int             i, sd, nbits;
+#ifdef LDAP_DEBUG
+       extern int      ldap_debug;
+#endif
+
+#ifdef USE_SYSCONF
+       nbits = sysconf( _SC_OPEN_MAX );
+#else /* USE_SYSCONF */
+       nbits = getdtablesize();
+#endif /* USE_SYSCONF */
+
+#ifdef LDAP_DEBUG
+       if ( ldap_debug == 0 ) {
+#endif
+               for ( i = 0; i < 5; i++ ) {
+#if defined( sunos5 ) && defined( THREAD_SUNOS5_LWP )
+                       switch ( fork1() ) {
+#else
+                       switch ( fork() ) {
+#endif
+                       case -1:
+                               sleep( 5 );
+                               continue;
+
+                       case 0:
+                               break;
+
+                       default:
+                               _exit( 0 );
+                       }
+                       break;
+               }
+
+/*
+               for ( i = 3; i < nbits; i++ )
+                       close( i );
+*/
+
+               (void) chdir( "/" );
+
+               if ( (sd = open( "/dev/null", O_RDWR )) == -1 ) {
+                       perror( "/dev/null" );
+                       exit( 1 );
+               }
+               if ( isatty( 0 ) )
+                       (void) dup2( sd, 0 );
+               if ( isatty( 1 ) )
+                       (void) dup2( sd, 1 );
+               if ( isatty(2) )
+                       (void) dup2( sd, 2 );
+               close( sd );
+
+#ifdef USE_SETSID
+               setsid();
+#else /* USE_SETSID */
+               if ( (sd = open( "/dev/tty", O_RDWR )) != -1 ) {
+                       (void) ioctl( sd, TIOCNOTTY, NULL );
+                       (void) close( sd );
+               }
+#endif /* USE_SETSID */
+#ifdef LDAP_DEBUG
+       } 
+#endif
+
+       (void) SIGNAL( SIGPIPE, SIG_IGN );
+}
diff --git a/servers/slapd/dn.c b/servers/slapd/dn.c
new file mode 100644 (file)
index 0000000..226937e
--- /dev/null
@@ -0,0 +1,262 @@
+/* dn.c - routines for dealing with distinguished names */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "portable.h"
+#include "slap.h"
+
+static char    **dn_explode();
+
+#define DNSEPARATOR(c) (c == ',' || c == ';')
+#define SEPARATOR(c)   (c == ',' || c == ';' || c == '+')
+#define SPACE(c)       (c == ' ' || c == '\n')
+#define NEEDSESCAPE(c) (c == '\\' || c == '"')
+#define B4TYPE         0
+#define INTYPE         1
+#define B4EQUAL                2
+#define B4VALUE                3
+#define INVALUE                4
+#define INQUOTEDVALUE  5
+#define B4SEPARATOR    6
+
+/*
+ * dn_normalize - put dn into a canonical format.  the dn is
+ * normalized in place, as well as returned.
+ */
+
+char *
+dn_normalize( char *dn )
+{
+       char    *d, *s;
+       int     state, gotesc;
+
+       /* Debug( LDAP_DEBUG_TRACE, "=> dn_normalize \"%s\"\n", dn, 0, 0 ); */
+
+       gotesc = 0;
+       state = B4TYPE;
+       for ( d = s = dn; *s; s++ ) {
+               switch ( state ) {
+               case B4TYPE:
+                       if ( ! SPACE( *s ) ) {
+                               state = INTYPE;
+                               *d++ = *s;
+                       }
+                       break;
+               case INTYPE:
+                       if ( *s == '=' ) {
+                               state = B4VALUE;
+                               *d++ = *s;
+                       } else if ( SPACE( *s ) ) {
+                               state = B4EQUAL;
+                       } else {
+                               *d++ = *s;
+                       }
+                       break;
+               case B4EQUAL:
+                       if ( *s == '=' ) {
+                               state = B4VALUE;
+                               *d++ = *s;
+                       } else if ( ! SPACE( *s ) ) {
+                               /* not a valid dn - but what can we do here? */
+                               *d++ = *s;
+                       }
+                       break;
+               case B4VALUE:
+                       if ( *s == '"' ) {
+                               state = INQUOTEDVALUE;
+                               *d++ = *s;
+                       } else if ( ! SPACE( *s ) ) { 
+                               state = INVALUE;
+                               *d++ = *s;
+                       }
+                       break;
+               case INVALUE:
+                       if ( !gotesc && SEPARATOR( *s ) ) {
+                               while ( SPACE( *(d - 1) ) )
+                                       d--;
+                               state = B4TYPE;
+                               if ( *s == '+' ) {
+                                       *d++ = *s;
+                               } else {
+                                       *d++ = ',';
+                               }
+                       } else if ( gotesc && !NEEDSESCAPE( *s ) &&
+                           !SEPARATOR( *s ) ) {
+                               *--d = *s;
+                               d++;
+                       } else {
+                               *d++ = *s;
+                       }
+                       break;
+               case INQUOTEDVALUE:
+                       if ( !gotesc && *s == '"' ) {
+                               state = B4SEPARATOR;
+                               *d++ = *s;
+                       } else if ( gotesc && !NEEDSESCAPE( *s ) ) {
+                               *--d = *s;
+                               d++;
+                       } else {
+                               *d++ = *s;
+                       }
+                       break;
+               case B4SEPARATOR:
+                       if ( SEPARATOR( *s ) ) {
+                               state = B4TYPE;
+                               *d++ = *s;
+                       }
+                       break;
+               default:
+                       Debug( LDAP_DEBUG_ANY,
+                           "dn_normalize - unknown state %d\n", state, 0, 0 );
+                       break;
+               }
+               if ( *s == '\\' ) {
+                       gotesc = 1;
+               } else {
+                       gotesc = 0;
+               }
+       }
+       *d = '\0';
+
+       /* Debug( LDAP_DEBUG_TRACE, "<= dn_normalize \"%s\"\n", dn, 0, 0 ); */
+       return( dn );
+}
+
+/*
+ * dn_normalize_case - put dn into a canonical form suitable for storing
+ * in a hash database.  this involves normalizing the case as well as
+ * the format.  the dn is normalized in place as well as returned.
+ */
+
+char *
+dn_normalize_case( char *dn )
+{
+       char    *s;
+
+       /* normalize format */
+       dn_normalize( dn );
+
+       /* normalize case */
+       for ( s = dn; *s; s++ ) {
+               *s = TOUPPER( *s );
+       }
+
+       return( dn );
+}
+
+/*
+ * dn_parent - return a copy of the dn of dn's parent
+ */
+
+char *
+dn_parent(
+    Backend    *be,
+    char       *dn
+)
+{
+       char    *s;
+       int     inquote, gotesc;
+
+       if ( dn == NULL || *dn == '\0' || be_issuffix( be, dn ) ) {
+               return( NULL );
+       }
+
+       /*
+        * no =, assume it is a dns name, like blah@some.domain.name
+        * if the blah@ part is there, return some.domain.name.  if
+        * it's just some.domain.name, return domain.name.
+        */
+       if ( strchr( dn, '=' ) == NULL ) {
+               if ( (s = strchr( dn, '@' )) == NULL ) {
+                       if ( (s = strchr( dn, '.' )) == NULL ) {
+                               return( NULL );
+                       }
+               }
+               if ( *(s + 1) == '\0' ) {
+                       return( NULL );
+               } else {
+                       return( strdup( s + 1 ) );
+               }
+       }
+
+       /*
+        * else assume it is an X.500-style name, which looks like
+        * foo=bar,sha=baz,...
+        */
+
+       inquote = 0;
+       for ( s = dn; *s; s++ ) {
+               if ( *s == '\\' ) {
+                       if ( *(s + 1) )
+                               s++;
+                       continue;
+               }
+               if ( inquote ) {
+                       if ( *s == '"' )
+                               inquote = 0;
+               } else {
+                       if ( *s == '"' )
+                               inquote = 1;
+                       else if ( DNSEPARATOR( *s ) )
+                               return( strdup( s + 1 ) );
+               }
+       }
+
+       return( NULL );
+}
+
+/*
+ * dn_issuffix - tells whether suffix is a suffix of dn.  both dn
+ * and suffix must be normalized.
+ */
+
+int
+dn_issuffix(
+    char       *dn,
+    char       *suffix
+)
+{
+       int     dnlen, suffixlen;
+
+       if ( dn == NULL ) {
+               return( 0 );
+       }
+
+       suffixlen = strlen( suffix );
+       dnlen = strlen( dn );
+
+       if ( suffixlen > dnlen ) {
+               return( 0 );
+       }
+
+       return( strcasecmp( dn + dnlen - suffixlen, suffix ) == 0 );
+}
+
+/*
+ * dn_type - tells whether the given dn is an X.500 thing or DNS thing
+ * returns (defined in slap.h):        DN_DNS          dns-style thing
+ *                             DN_X500         x500-style thing
+ */
+
+int
+dn_type( char *dn )
+{
+       return( strchr( dn, '=' ) == NULL ? DN_DNS : DN_X500 );
+}
+
+char *
+dn_upcase( char *dn )
+{
+       char    *s;
+
+       /* normalize case */
+       for ( s = dn; *s; s++ ) {
+               *s = TOUPPER( *s );
+       }
+
+       return( dn );
+}
diff --git a/servers/slapd/entry.c b/servers/slapd/entry.c
new file mode 100644 (file)
index 0000000..d5ee966
--- /dev/null
@@ -0,0 +1,198 @@
+/* entry.c - routines for dealing with entries */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+
+void   entry_free();
+char   *entry2str();
+
+static unsigned char   *ebuf;  /* buf returned by entry2str             */
+static unsigned char   *ecur;  /* pointer to end of currently used ebuf */
+static int             emaxsize;/* max size of ebuf                     */
+
+Entry *
+str2entry( char        *s )
+{
+       int             i;
+       Entry           *e;
+       Attribute       **a;
+       char            *type;
+       char            *value;
+       char            *next;
+       int             vlen, nvals, maxvals;
+       struct berval   bval;
+       struct berval   *vals[2];
+       char            ptype[64];
+
+       /*
+        * In string format, an entry looks like this:
+        *
+        *      <id>\n
+        *      dn: <dn>\n
+        *      [<attr>:[:] <value>\n]
+        *      [<tab><continuedvalue>\n]*
+        *      ...
+        *
+        * If a double colon is used after a type, it means the
+        * following value is encoded as a base 64 string.  This
+        * happens if the value contains a non-printing character
+        * or newline.
+        */
+
+       Debug( LDAP_DEBUG_TRACE, "=> str2entry\n", s, 0, 0 );
+
+       e = (Entry *) ch_calloc( 1, sizeof(Entry) );
+
+       /* check to see if there's an id included */
+       next = s;
+       if ( isdigit( *s ) ) {
+               e->e_id = atoi( s );
+               if ( (s = str_getline( &next )) == NULL ) {
+                       Debug( LDAP_DEBUG_TRACE,
+                           "<= str2entry NULL (missing newline after id)\n",
+                           0, 0, 0 );
+                       return( NULL );
+               }
+       }
+
+       /* dn + attributes */
+       e->e_attrs = NULL;
+       vals[0] = &bval;
+       vals[1] = NULL;
+       ptype[0] = '\0';
+       while ( (s = str_getline( &next )) != NULL ) {
+               if ( *s == '\n' || *s == '\0' ) {
+                       break;
+               }
+
+               if ( str_parse_line( s, &type, &value, &vlen ) != 0 ) {
+                       Debug( LDAP_DEBUG_TRACE,
+                           "<= str2entry NULL (parse_line)\n", 0, 0, 0 );
+                       continue;
+               }
+
+               if ( strcasecmp( type, ptype ) != 0 ) {
+                       strncpy( ptype, type, sizeof(ptype) - 1 );
+                       nvals = 0;
+                       maxvals = 0;
+                       a = NULL;
+               }
+               if ( strcasecmp( type, "dn" ) == 0 ) {
+                       if ( e->e_dn != NULL ) {
+                               Debug( LDAP_DEBUG_ANY,
+    "str2entry: entry %d has multiple dns \"%s\" and \"%s\" (second ignored)\n",
+                                   e->e_id, e->e_dn, value );
+                               continue;
+                       }
+                       e->e_dn = strdup( value );
+                       continue;
+               }
+
+               bval.bv_val = value;
+               bval.bv_len = vlen;
+               if ( attr_merge_fast( e, type, vals, nvals, 1, &maxvals, &a )
+                   != 0 ) {
+                       Debug( LDAP_DEBUG_TRACE,
+                           "<= str2entry NULL (attr_merge)\n", 0, 0, 0 );
+                       return( NULL );
+               }
+               nvals++;
+       }
+
+       /* check to make sure there was a dn: line */
+       if ( e->e_dn == NULL ) {
+               Debug( LDAP_DEBUG_ANY, "str2entry: entry %d has no dn\n",
+                   e->e_id, 0, 0 );
+               entry_free( e );
+               return( NULL );
+       }
+
+       Debug( LDAP_DEBUG_TRACE, "<= str2entry 0x%x\n", e, 0, 0 );
+       return( e );
+}
+
+#define GRABSIZE       BUFSIZ
+
+#define MAKE_SPACE( n )        { \
+               while ( ecur + (n) > ebuf + emaxsize ) { \
+                       int     offset; \
+                       offset = (int) (ecur - ebuf); \
+                       ebuf = (unsigned char *) ch_realloc( (char *) ebuf, \
+                           emaxsize + GRABSIZE ); \
+                       emaxsize += GRABSIZE; \
+                       ecur = ebuf + offset; \
+               } \
+}
+
+char *
+entry2str(
+    Entry      *e,
+    int                *len,
+    int                printid
+)
+{
+       Attribute       *a;
+       struct berval   *bv;
+       int             i, tmplen;
+
+       /*
+        * In string format, an entry looks like this:
+        *      <id>\n
+        *      dn: <dn>\n
+        *      [<attr>: <value>\n]*
+        */
+
+       ecur = ebuf;
+
+       if ( printid ) {
+               /* id + newline */
+               MAKE_SPACE( 10 );
+               sprintf( (char *) ecur, "%ld\n", e->e_id );
+               ecur = (unsigned char *) strchr( (char *) ecur, '\0' );
+       }
+
+       /* put the dn */
+       if ( e->e_dn != NULL ) {
+               /* put "dn: <dn>" */
+               tmplen = strlen( e->e_dn );
+               MAKE_SPACE( LDIF_SIZE_NEEDED( 2, tmplen ));
+               put_type_and_value( (char **) &ecur, "dn", e->e_dn, tmplen );
+       }
+
+       /* put the attributes */
+       for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
+               /* put "<type>:[:] <value>" line for each value */
+               for ( i = 0; a->a_vals[i] != NULL; i++ ) {
+                       bv = a->a_vals[i];
+                       tmplen = strlen( a->a_type );
+                       MAKE_SPACE( LDIF_SIZE_NEEDED( tmplen, bv->bv_len ));
+                       put_type_and_value( (char **) &ecur, a->a_type,
+                           bv->bv_val, bv->bv_len );
+               }
+       }
+       MAKE_SPACE( 1 );
+       *ecur = '\0';
+       *len = ecur - ebuf;
+
+       return( (char *) ebuf );
+}
+
+void
+entry_free( Entry *e )
+{
+       int             i;
+       Attribute       *a, *next;
+
+       if ( e->e_dn != NULL ) {
+               free( e->e_dn );
+       }
+       for ( a = e->e_attrs; a != NULL; a = next ) {
+               next = a->a_next;
+               attr_free( a );
+       }
+       free( e );
+}
diff --git a/servers/slapd/filter.c b/servers/slapd/filter.c
new file mode 100644 (file)
index 0000000..8d990b3
--- /dev/null
@@ -0,0 +1,449 @@
+/* filter.c - routines for parsing and dealing with filters */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+
+static int     get_filter_list();
+static int     get_substring_filter();
+
+extern int     get_ava();
+extern char    *ch_malloc();
+extern char    *ch_realloc();
+
+int
+get_filter( Connection *conn, BerElement *ber, Filter **filt, char **fstr )
+{
+       unsigned long   tag, len;
+       int             err;
+       Filter          *f;
+       char            *ftmp;
+
+       Debug( LDAP_DEBUG_FILTER, "begin get_filter\n", 0, 0, 0 );
+
+       /*
+        * A filter looks like this coming in:
+        *      Filter ::= CHOICE {
+        *              and             [0]     SET OF Filter,
+        *              or              [1]     SET OF Filter,
+        *              not             [2]     Filter,
+        *              equalityMatch   [3]     AttributeValueAssertion,
+        *              substrings      [4]     SubstringFilter,
+        *              greaterOrEqual  [5]     AttributeValueAssertion,
+        *              lessOrEqual     [6]     AttributeValueAssertion,
+        *              present         [7]     AttributeType,,
+        *              approxMatch     [8]     AttributeValueAssertion
+        *      }
+        *
+        *      SubstringFilter ::= SEQUENCE {
+        *              type               AttributeType,
+        *              SEQUENCE OF CHOICE {
+        *                      initial          [0] IA5String,
+        *                      any              [1] IA5String,
+        *                      final            [2] IA5String
+        *              }
+        *      }
+        */
+
+       f = (Filter *) ch_malloc( sizeof(Filter) );
+       *filt = f;
+       f->f_next = NULL;
+
+       err = 0;
+       *fstr = NULL;
+       f->f_choice = ber_peek_tag( ber, &len );
+#ifdef COMPAT30
+       if ( conn->c_version == 30 ) {
+               switch ( f->f_choice ) {
+               case LDAP_FILTER_EQUALITY:
+               case LDAP_FILTER_GE:
+               case LDAP_FILTER_LE:
+               case LDAP_FILTER_PRESENT:
+               case LDAP_FILTER_PRESENT_30:
+               case LDAP_FILTER_APPROX:
+                       (void) ber_skip_tag( ber, &len );
+                       if ( f->f_choice == LDAP_FILTER_PRESENT_30 ) {
+                               f->f_choice = LDAP_FILTER_PRESENT;
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }
+#endif
+       switch ( f->f_choice ) {
+       case LDAP_FILTER_EQUALITY:
+               Debug( LDAP_DEBUG_FILTER, "EQUALITY\n", 0, 0, 0 );
+               if ( (err = get_ava( ber, &f->f_ava )) == 0 ) {
+                       *fstr = ch_malloc(4 + strlen( f->f_avtype ) +
+                           f->f_avvalue.bv_len);
+                       sprintf( *fstr, "(%s=%s)", f->f_avtype,
+                           f->f_avvalue.bv_val );
+               }
+               break;
+
+       case LDAP_FILTER_SUBSTRINGS:
+               Debug( LDAP_DEBUG_FILTER, "SUBSTRINGS\n", 0, 0, 0 );
+               err = get_substring_filter( conn, ber, f, fstr );
+               break;
+
+       case LDAP_FILTER_GE:
+               Debug( LDAP_DEBUG_FILTER, "GE\n", 0, 0, 0 );
+               if ( (err = get_ava( ber, &f->f_ava )) == 0 ) {
+                       *fstr = ch_malloc(5 + strlen( f->f_avtype ) +
+                           f->f_avvalue.bv_len);
+                       sprintf( *fstr, "(%s>=%s)", f->f_avtype,
+                           f->f_avvalue.bv_val );
+               }
+               break;
+
+       case LDAP_FILTER_LE:
+               Debug( LDAP_DEBUG_FILTER, "LE\n", 0, 0, 0 );
+               if ( (err = get_ava( ber, &f->f_ava )) == 0 ) {
+                       *fstr = ch_malloc(5 + strlen( f->f_avtype ) +
+                           f->f_avvalue.bv_len);
+                       sprintf( *fstr, "(%s<=%s)", f->f_avtype,
+                           f->f_avvalue.bv_val );
+               }
+               break;
+
+       case LDAP_FILTER_PRESENT:
+               Debug( LDAP_DEBUG_FILTER, "PRESENT\n", 0, 0, 0 );
+               if ( ber_scanf( ber, "a", &f->f_type ) == LBER_ERROR ) {
+                       err = LDAP_PROTOCOL_ERROR;
+               } else {
+                       err = LDAP_SUCCESS;
+                       attr_normalize( f->f_type );
+                       *fstr = ch_malloc( 5 + strlen( f->f_type ) );
+                       sprintf( *fstr, "(%s=*)", f->f_type );
+               }
+               break;
+
+       case LDAP_FILTER_APPROX:
+               Debug( LDAP_DEBUG_FILTER, "APPROX\n", 0, 0, 0 );
+               if ( (err = get_ava( ber, &f->f_ava )) == 0 ) {
+                       *fstr = ch_malloc(5 + strlen( f->f_avtype ) +
+                           f->f_avvalue.bv_len);
+                       sprintf( *fstr, "(%s~=%s)", f->f_avtype,
+                           f->f_avvalue.bv_val );
+               }
+               break;
+
+       case LDAP_FILTER_AND:
+               Debug( LDAP_DEBUG_FILTER, "AND\n", 0, 0, 0 );
+               if ( (err = get_filter_list( conn, ber, &f->f_and, &ftmp ))
+                   == 0 ) {
+                       *fstr = ch_malloc( 4 + strlen( ftmp ) );
+                       sprintf( *fstr, "(&%s)", ftmp );
+                       free( ftmp );
+               }
+               break;
+
+       case LDAP_FILTER_OR:
+               Debug( LDAP_DEBUG_FILTER, "OR\n", 0, 0, 0 );
+               if ( (err = get_filter_list( conn, ber, &f->f_or, &ftmp ))
+                   == 0 ) {
+                       *fstr = ch_malloc( 4 + strlen( ftmp ) );
+                       sprintf( *fstr, "(|%s)", ftmp );
+                       free( ftmp );
+               }
+               break;
+
+       case LDAP_FILTER_NOT:
+               Debug( LDAP_DEBUG_FILTER, "NOT\n", 0, 0, 0 );
+               (void) ber_skip_tag( ber, &len );
+               if ( (err = get_filter( conn, ber, &f->f_not, &ftmp )) == 0 ) {
+                       *fstr = ch_malloc( 4 + strlen( ftmp ) );
+                       sprintf( *fstr, "(!%s)", ftmp );
+                       free( ftmp );
+               }
+               break;
+
+       default:
+               Debug( LDAP_DEBUG_ANY, "unknown filter type %d\n", f->f_choice,
+                   0, 0 );
+               err = LDAP_PROTOCOL_ERROR;
+               break;
+       }
+
+       if ( err != 0 ) {
+               free( (char *) f );
+               if ( *fstr != NULL ) {
+                       free( *fstr );
+               }
+       }
+
+       Debug( LDAP_DEBUG_FILTER, "end get_filter %d\n", err, 0, 0 );
+       return( err );
+}
+
+static int
+get_filter_list( Connection *conn, BerElement *ber, Filter **f, char **fstr )
+{
+       Filter          **new;
+       int             err;
+       unsigned long   tag, len;
+       char            *last, *ftmp;
+
+       Debug( LDAP_DEBUG_FILTER, "begin get_filter_list\n", 0, 0, 0 );
+
+#ifdef COMPAT30
+       if ( conn->c_version == 30 ) {
+               (void) ber_skip_tag( ber, &len );
+       }
+#endif
+       *fstr = NULL;
+       new = f;
+       for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
+           tag = ber_next_element( ber, &len, last ) ) {
+               if ( (err = get_filter( conn, ber, new, &ftmp )) != 0 )
+                       return( err );
+               if ( *fstr == NULL ) {
+                       *fstr = ftmp;
+               } else {
+                       *fstr = ch_realloc( *fstr, strlen( *fstr ) +
+                           strlen( ftmp ) + 1 );
+                       strcat( *fstr, ftmp );
+                       free( ftmp );
+               }
+               new = &(*new)->f_next;
+       }
+       *new = NULL;
+
+       Debug( LDAP_DEBUG_FILTER, "end get_filter_list\n", 0, 0, 0 );
+       return( 0 );
+}
+
+static int
+get_substring_filter(
+    Connection *conn,
+    BerElement *ber,
+    Filter     *f,
+    char       **fstr
+)
+{
+       unsigned long   tag, len, rc;
+       char            *val, *last;
+       int             syntax;
+
+       Debug( LDAP_DEBUG_FILTER, "begin get_substring_filter\n", 0, 0, 0 );
+
+#ifdef COMPAT30
+       if ( conn->c_version == 30 ) {
+               (void) ber_skip_tag( ber, &len );
+       }
+#endif
+       if ( ber_scanf( ber, "{a", &f->f_sub_type ) == LBER_ERROR ) {
+               return( LDAP_PROTOCOL_ERROR );
+       }
+       attr_normalize( f->f_sub_type );
+       syntax = attr_syntax( f->f_sub_type );
+       f->f_sub_initial = NULL;
+       f->f_sub_any = NULL;
+       f->f_sub_final = NULL;
+
+       *fstr = ch_malloc( strlen( f->f_sub_type ) + 3 );
+       sprintf( *fstr, "(%s=", f->f_sub_type );
+       for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
+           tag = ber_next_element( ber, &len, last ) ) {
+#ifdef COMPAT30
+               if ( conn->c_version == 30 ) {
+                       rc = ber_scanf( ber, "{a}", &val );
+               } else
+#endif
+                       rc = ber_scanf( ber, "a", &val );
+               if ( rc == LBER_ERROR ) {
+                       return( LDAP_PROTOCOL_ERROR );
+               }
+               if ( val == NULL || *val == '\0' ) {
+                       if ( val != NULL ) {
+                               free( val );
+                       }
+                       return( LDAP_INVALID_SYNTAX );
+               }
+               value_normalize( val, syntax );
+
+               switch ( tag ) {
+#ifdef COMPAT30
+               case LDAP_SUBSTRING_INITIAL_30:
+#endif
+               case LDAP_SUBSTRING_INITIAL:
+                       Debug( LDAP_DEBUG_FILTER, "  INITIAL\n", 0, 0, 0 );
+                       if ( f->f_sub_initial != NULL ) {
+                               return( LDAP_PROTOCOL_ERROR );
+                       }
+                       f->f_sub_initial = val;
+                       *fstr = ch_realloc( *fstr, strlen( *fstr ) +
+                           strlen( val ) + 1 );
+                       strcat( *fstr, val );
+                       break;
+
+#ifdef COMPAT30
+               case LDAP_SUBSTRING_ANY_30:
+#endif
+               case LDAP_SUBSTRING_ANY:
+                       Debug( LDAP_DEBUG_FILTER, "  ANY\n", 0, 0, 0 );
+                       charray_add( &f->f_sub_any, val );
+                       *fstr = ch_realloc( *fstr, strlen( *fstr ) +
+                           strlen( val ) + 2 );
+                       strcat( *fstr, "*" );
+                       strcat( *fstr, val );
+                       break;
+
+#ifdef COMPAT30
+               case LDAP_SUBSTRING_FINAL_30:
+#endif
+               case LDAP_SUBSTRING_FINAL:
+                       Debug( LDAP_DEBUG_FILTER, "  FINAL\n", 0, 0, 0 );
+                       if ( f->f_sub_final != NULL ) {
+                               return( LDAP_PROTOCOL_ERROR );
+                       }
+                       f->f_sub_final = val;
+                       *fstr = ch_realloc( *fstr, strlen( *fstr ) +
+                           strlen( val ) + 2 );
+                       strcat( *fstr, "*" );
+                       strcat( *fstr, val );
+                       break;
+
+               default:
+                       Debug( LDAP_DEBUG_FILTER, "  unknown type\n", tag, 0,
+                           0 );
+                       return( LDAP_PROTOCOL_ERROR );
+               }
+       }
+       *fstr = ch_realloc( *fstr, strlen( *fstr ) + 3 );
+       if ( f->f_sub_final == NULL ) {
+               strcat( *fstr, "*" );
+       }
+       strcat( *fstr, ")" );
+
+       Debug( LDAP_DEBUG_FILTER, "end get_substring_filter\n", 0, 0, 0 );
+       return( 0 );
+}
+
+void
+filter_free( Filter *f )
+{
+       Filter  *p, *next;
+
+       if ( f == NULL ) {
+               return;
+       }
+
+       switch ( f->f_choice ) {
+       case LDAP_FILTER_EQUALITY:
+       case LDAP_FILTER_GE:
+       case LDAP_FILTER_LE:
+       case LDAP_FILTER_APPROX:
+               ava_free( &f->f_ava, 0 );
+               break;
+
+       case LDAP_FILTER_SUBSTRINGS:
+               if ( f->f_sub_type != NULL ) {
+                       free( f->f_sub_type );
+               }
+               if ( f->f_sub_initial != NULL ) {
+                       free( f->f_sub_initial );
+               }
+               charray_free( f->f_sub_any );
+               if ( f->f_sub_final != NULL ) {
+                       free( f->f_sub_final );
+               }
+               break;
+
+       case LDAP_FILTER_PRESENT:
+               if ( f->f_type != NULL ) {
+                       free( f->f_type );
+               }
+               break;
+
+       case LDAP_FILTER_AND:
+       case LDAP_FILTER_OR:
+       case LDAP_FILTER_NOT:
+               for ( p = f->f_list; p != NULL; p = next ) {
+                       next = p->f_next;
+                       filter_free( p );
+               }
+               break;
+
+       default:
+               Debug( LDAP_DEBUG_ANY, "unknown filter type %d\n", f->f_choice,
+                   0, 0 );
+               break;
+       }
+       free( f );
+}
+
+#ifdef LDAP_DEBUG
+
+void
+filter_print( Filter *f )
+{
+       int     i;
+       Filter  *p;
+
+       if ( f == NULL ) {
+               printf( "NULL" );
+       }
+
+       switch ( f->f_choice ) {
+       case LDAP_FILTER_EQUALITY:
+               printf( "(%s=%s)", f->f_ava.ava_type,
+                   f->f_ava.ava_value.bv_val );
+               break;
+
+       case LDAP_FILTER_GE:
+               printf( "(%s>=%s)", f->f_ava.ava_type,
+                   f->f_ava.ava_value.bv_val );
+               break;
+
+       case LDAP_FILTER_LE:
+               printf( "(%s<=%s)", f->f_ava.ava_type,
+                   f->f_ava.ava_value.bv_val );
+               break;
+
+       case LDAP_FILTER_APPROX:
+               printf( "(%s~=%s)", f->f_ava.ava_type,
+                   f->f_ava.ava_value.bv_val );
+               break;
+
+       case LDAP_FILTER_SUBSTRINGS:
+               printf( "(%s=", f->f_sub_type );
+               if ( f->f_sub_initial != NULL ) {
+                       printf( "%s", f->f_sub_initial );
+               }
+               if ( f->f_sub_any != NULL ) {
+                       for ( i = 0; f->f_sub_any[i] != NULL; i++ ) {
+                               printf( "*%s", f->f_sub_any[i] );
+                       }
+               }
+               charray_free( f->f_sub_any );
+               if ( f->f_sub_final != NULL ) {
+                       printf( "*%s", f->f_sub_final );
+               }
+               break;
+
+       case LDAP_FILTER_PRESENT:
+               printf( "%s=*", f->f_type );
+               break;
+
+       case LDAP_FILTER_AND:
+       case LDAP_FILTER_OR:
+       case LDAP_FILTER_NOT:
+               printf( "(%c", f->f_choice == LDAP_FILTER_AND ? '&' :
+                   f->f_choice == LDAP_FILTER_OR ? '|' : '!' );
+               for ( p = f->f_list; p != NULL; p = p->f_next ) {
+                       filter_print( p );
+               }
+               printf( ")" );
+               break;
+
+       default:
+               printf( "unknown type %d", f->f_choice );
+               break;
+       }
+}
+
+#endif /* ldap_debug */
diff --git a/servers/slapd/filterentry.c b/servers/slapd/filterentry.c
new file mode 100644 (file)
index 0000000..712ff22
--- /dev/null
@@ -0,0 +1,446 @@
+/* filterentry.c - apply a filter to an entry */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#ifdef sunos5
+#include "regexpr.h"
+#else
+#include "regex.h"
+#endif
+#include "slap.h"
+
+extern Attribute       *attr_find();
+extern char            *first_word();
+extern char            *next_word();
+extern char            *phonetic();
+extern char            *re_comp();
+
+#ifndef sunos5
+extern pthread_mutex_t regex_mutex;
+#endif
+
+static int     test_filter_list();
+static int     test_substring_filter();
+static int     test_ava_filter();
+static int     test_approx_filter();
+static int     test_presence_filter();
+
+/*
+ * test_filter - test a filter against a single entry.
+ * returns     0       filter matched
+ *             -1      filter did not match
+ *             >0      an ldap error code
+ */
+
+int
+test_filter(
+    Backend    *be,
+    Connection *conn,
+    Operation  *op,
+    Entry      *e,
+    Filter     *f
+)
+{
+       int     rc;
+
+       Debug( LDAP_DEBUG_FILTER, "=> test_filter\n", 0, 0, 0 );
+
+       switch ( f->f_choice ) {
+       case LDAP_FILTER_EQUALITY:
+               Debug( LDAP_DEBUG_FILTER, "    EQUALITY\n", 0, 0, 0 );
+               rc = test_ava_filter( be, conn, op, e, &f->f_ava,
+                   LDAP_FILTER_EQUALITY );
+               break;
+
+       case LDAP_FILTER_SUBSTRINGS:
+               Debug( LDAP_DEBUG_FILTER, "    SUBSTRINGS\n", 0, 0, 0 );
+               rc = test_substring_filter( be, conn, op, e, f );
+               break;
+
+       case LDAP_FILTER_GE:
+               Debug( LDAP_DEBUG_FILTER, "    GE\n", 0, 0, 0 );
+               rc = test_ava_filter( be, conn, op, e, &f->f_ava,
+                   LDAP_FILTER_GE );
+               break;
+
+       case LDAP_FILTER_LE:
+               Debug( LDAP_DEBUG_FILTER, "    LE\n", 0, 0, 0 );
+               rc = test_ava_filter( be, conn, op, e, &f->f_ava,
+                   LDAP_FILTER_LE );
+               break;
+
+       case LDAP_FILTER_PRESENT:
+               Debug( LDAP_DEBUG_FILTER, "    PRESENT\n", 0, 0, 0 );
+               rc = test_presence_filter( be, conn, op, e, f->f_type );
+               break;
+
+       case LDAP_FILTER_APPROX:
+               Debug( LDAP_DEBUG_FILTER, "    APPROX\n", 0, 0, 0 );
+               rc = test_approx_filter( be, conn, op, e, &f->f_ava );
+               break;
+
+       case LDAP_FILTER_AND:
+               Debug( LDAP_DEBUG_FILTER, "    AND\n", 0, 0, 0 );
+               rc = test_filter_list( be, conn, op, e, f->f_and,
+                   LDAP_FILTER_AND );
+               break;
+
+       case LDAP_FILTER_OR:
+               Debug( LDAP_DEBUG_FILTER, "    OR\n", 0, 0, 0 );
+               rc = test_filter_list( be, conn, op, e, f->f_or,
+                   LDAP_FILTER_OR );
+               break;
+
+       case LDAP_FILTER_NOT:
+               Debug( LDAP_DEBUG_FILTER, "    NOT\n", 0, 0, 0 );
+               rc = (! test_filter( be, conn, op, e, f->f_not ) );
+               break;
+
+       default:
+               Debug( LDAP_DEBUG_ANY, "    unknown filter type %d\n",
+                   f->f_choice, 0, 0 );
+               rc = -1;
+       }
+
+       Debug( LDAP_DEBUG_FILTER, "<= test_filter %d\n", rc, 0, 0 );
+       return( rc );
+}
+
+static int
+test_ava_filter(
+    Backend    *be,
+    Connection *conn,
+    Operation  *op,
+    Entry      *e,
+    Ava                *ava,
+    int                type
+)
+{
+       int             i, rc;
+       Attribute       *a;
+
+       if ( be != NULL && ! access_allowed( be, conn, op, e, ava->ava_type,
+           &ava->ava_value, op->o_dn, ACL_SEARCH ) ) {
+               return( -2 );
+       }
+
+       if ( (a = attr_find( e->e_attrs, ava->ava_type )) == NULL ) {
+               return( -1 );
+       }
+
+       if ( a->a_syntax == 0 ) {
+               a->a_syntax = attr_syntax( ava->ava_type );
+       }
+       for ( i = 0; a->a_vals[i] != NULL; i++ ) {
+               rc = value_cmp( a->a_vals[i], &ava->ava_value, a->a_syntax,
+                   3 );
+
+               switch ( type ) {
+               case LDAP_FILTER_EQUALITY:
+                       if ( rc == 0 ) {
+                               return( 0 );
+                       }
+                       break;
+
+               case LDAP_FILTER_GE:
+                       if ( rc > 0 ) {
+                               return( 0 );
+                       }
+                       break;
+
+               case LDAP_FILTER_LE:
+                       if ( rc < 0 ) {
+                               return( 0 );
+                       }
+                       break;
+               }
+       }
+
+       return( 1 );
+}
+
+static int
+test_presence_filter(
+    Backend    *be,
+    Connection *conn,
+    Operation  *op,
+    Entry      *e,
+    char       *type
+)
+{
+       if ( be != NULL && ! access_allowed( be, conn, op, e, type, NULL,
+           op->o_dn, ACL_SEARCH ) ) {
+               return( -2 );
+       }
+
+       return( attr_find( e->e_attrs, type ) != NULL ? 0 : -1 );
+}
+
+static int
+test_approx_filter(
+    Backend    *be,
+    Connection *conn,
+    Operation  *op,
+    Entry      *e,
+    Ava                *ava
+)
+{
+       char            *w1, *w2, *c1, *c2;
+       int             i, rc, match;
+       Attribute       *a;
+
+       if ( be != NULL && ! access_allowed( be, conn, op, e, ava->ava_type,
+           NULL, op->o_dn, ACL_SEARCH ) ) {
+               return( -2 );
+       }
+
+       if ( (a = attr_find( e->e_attrs, ava->ava_type )) == NULL ) {
+               return( -1 );
+       }
+
+       /* for each value in the attribute */
+       for ( i = 0; a->a_vals[i] != NULL; i++ ) {
+               /*
+                * try to match words in the filter value in order
+                * in the attribute value.
+                */
+
+               w2 = a->a_vals[i]->bv_val;
+               /* for each word in the filter value */
+               for ( w1 = first_word( ava->ava_value.bv_val ); w1 != NULL;
+                   w1 = next_word( w1 ) ) {
+                       if ( (c1 = phonetic( w1 )) == NULL ) {
+                               break;
+                       }
+
+                       /*
+                        * for each word in the attribute value from
+                        * where we left off...
+                        */
+                       for ( w2 = first_word( w2 ); w2 != NULL;
+                           w2 = next_word( w2 ) ) {
+                               c2 = phonetic( w2 );
+                               if ( strcmp( c1, c2 ) == 0 ) {
+                                       break;
+                               }
+                       }
+                       free( c1 );
+                       free( c2 );
+
+                       /*
+                        * if we stopped because we ran out of words
+                        * before making a match, go on to the next
+                        * value.  otherwise try to keep matching
+                        * words in this value from where we left off.
+                        */
+                       if ( w2 == NULL ) {
+                               break;
+                       } else {
+                               w2 = next_word( w2 );
+                       }
+               }
+               /*
+                * if we stopped because we ran out of words we
+                * have a match.
+                */
+               if ( w1 == NULL ) {
+                       return( 0 );
+               }
+       }
+
+       return( 1 );
+}
+
+static int
+test_filter_list(
+    Backend    *be,
+    Connection *conn,
+    Operation  *op,
+    Entry      *e,
+    Filter     *flist,
+    int                ftype
+)
+{
+       int     rc, nomatch;
+       Filter  *f;
+
+       Debug( LDAP_DEBUG_FILTER, "=> test_filter_list\n", 0, 0, 0 );
+
+       nomatch = 1;
+       for ( f = flist; f != NULL; f = f->f_next ) {
+               if ( test_filter( be, conn, op, e, f ) != 0 ) {
+                       if ( ftype == LDAP_FILTER_AND ) {
+                               Debug( LDAP_DEBUG_FILTER,
+                                   "<= test_filter_list 1\n", 0, 0, 0 );
+                               return( 1 );
+                       }
+               } else {
+                       nomatch = 0;
+               }
+       }
+
+       Debug( LDAP_DEBUG_FILTER, "<= test_filter_list %d\n", nomatch, 0, 0 );
+       return( nomatch );
+}
+
+static void
+strcpy_special( char *d, char *s )
+{
+       for ( ; *s; s++ ) {
+               switch ( *s ) {
+               case '.':
+               case '\\':
+               case '[':
+               case ']':
+               case '*':
+               case '+':
+               case '^':
+               case '$':
+                       *d++ = '\\';
+                       /* FALL */
+               default:
+                       *d++ = *s;
+               }
+       }
+       *d = '\0';
+}
+
+static int
+test_substring_filter(
+    Backend    *be,
+    Connection *conn,
+    Operation  *op,
+    Entry      *e,
+    Filter     *f
+)
+{
+       Attribute       *a;
+       int             i, rc;
+       char            *p, *end, *realval, *tmp;
+       char            pat[BUFSIZ];
+       char            buf[BUFSIZ];
+       struct berval   *val;
+
+       Debug( LDAP_DEBUG_FILTER, "begin test_substring_filter\n", 0, 0, 0 );
+
+       if ( be != NULL && ! access_allowed( be, conn, op, e, f->f_sub_type,
+           NULL, op->o_dn, ACL_SEARCH ) ) {
+               return( -2 );
+       }
+
+       if ( (a = attr_find( e->e_attrs, f->f_sub_type )) == NULL ) {
+               return( -1 );
+       }
+
+       if ( a->a_syntax & SYNTAX_BIN ) {
+               Debug( LDAP_DEBUG_FILTER, "test_substring_filter bin attr\n",
+                   0, 0, 0 );
+               return( -1 );
+       }
+
+       /*
+        * construct a regular expression corresponding to the
+        * filter and let regex do the work
+        */
+
+       pat[0] = '\0';
+       p = pat;
+       end = pat + sizeof(pat) - 2;    /* leave room for null */
+       if ( f->f_sub_initial != NULL ) {
+               strcpy( p, "^" );
+               p = strchr( p, '\0' );
+               /* 2 * in case every char is special */
+               if ( p + 2 * strlen( f->f_sub_initial ) > end ) {
+                       Debug( LDAP_DEBUG_ANY, "not enough pattern space\n",
+                           0, 0, 0 );
+                       return( -1 );
+               }
+               strcpy_special( p, f->f_sub_initial );
+               p = strchr( p, '\0' );
+       }
+       if ( f->f_sub_any != NULL ) {
+               for ( i = 0; f->f_sub_any[i] != NULL; i++ ) {
+                       /* ".*" + value */
+                       if ( p + 2 * strlen( f->f_sub_any[i] ) + 2 > end ) {
+                               Debug( LDAP_DEBUG_ANY,
+                                   "not enough pattern space\n", 0, 0, 0 );
+                               return( -1 );
+                       }
+                       strcpy( p, ".*" );
+                       p = strchr( p, '\0' );
+                       strcpy_special( p, f->f_sub_any[i] );
+                       p = strchr( p, '\0' );
+               }
+       }
+       if ( f->f_sub_final != NULL ) {
+               /* ".*" + value */
+               if ( p + 2 * strlen( f->f_sub_final ) + 2 > end ) {
+                       Debug( LDAP_DEBUG_ANY, "not enough pattern space\n",
+                           0, 0, 0 );
+                       return( -1 );
+               }
+               strcpy( p, ".*" );
+               p = strchr( p, '\0' );
+               strcpy_special( p, f->f_sub_final );
+               p = strchr( p, '\0' );
+               strcpy( p, "$" );
+       }
+
+       /* compile the regex */
+#ifdef sunos5
+       if ( (p = compile( pat, NULL, NULL )) == NULL ) {
+               Debug( LDAP_DEBUG_ANY, "compile failed (%s)\n", p, 0, 0 );
+               return( -1 );
+       }
+#else /* sunos5 */
+       pthread_mutex_lock( &regex_mutex );
+       if ( (p = re_comp( pat )) != 0 ) {
+               Debug( LDAP_DEBUG_ANY, "re_comp failed (%s)\n", p, 0, 0 );
+               pthread_mutex_unlock( &regex_mutex );
+               return( -1 );
+       }
+#endif /* sunos5 */
+
+       /* for each value in the attribute see if regex matches */
+       for ( i = 0; a->a_vals[i] != NULL; i++ ) {
+               val = a->a_vals[i];
+               tmp = NULL;
+               if ( val->bv_len < sizeof(buf) ) {
+                       strcpy( buf, val->bv_val );
+                       realval = buf;
+               } else {
+                       tmp = (char *) ch_malloc( val->bv_len + 1 );
+                       strcpy( tmp, val->bv_val );
+                       realval = tmp;
+               }
+               value_normalize( realval, a->a_syntax );
+
+#ifdef sunos5
+               rc = step( realval, p );
+#else /* sunos5 */
+               rc = re_exec( realval );
+#endif /* sunos5 */
+
+               if ( tmp != NULL ) {
+                       free( tmp );
+               }
+               if ( rc == 1 ) {
+#ifdef sunos5
+                       free( p );
+#else /* sunos5 */
+                       pthread_mutex_unlock( &regex_mutex );
+#endif /* sunos5 */
+                       return( 0 );
+               }
+       }
+#ifdef sunos5
+       free( p );
+#else /* sunos5 */
+       pthread_mutex_unlock( &regex_mutex );
+#endif /* sunos5 */
+
+       Debug( LDAP_DEBUG_FILTER, "end test_substring_filter 1\n", 0, 0, 0 );
+       return( 1 );
+}
diff --git a/servers/slapd/init.c b/servers/slapd/init.c
new file mode 100644 (file)
index 0000000..03dd850
--- /dev/null
@@ -0,0 +1,37 @@
+/* init.c - initialize various things */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include "portable.h"
+#include "slap.h"
+
+extern pthread_mutex_t active_threads_mutex;
+extern pthread_mutex_t new_conn_mutex;
+extern pthread_mutex_t currenttime_mutex;
+extern pthread_mutex_t entry2str_mutex;
+extern pthread_mutex_t replog_mutex;
+extern pthread_mutex_t ops_mutex;
+extern pthread_mutex_t num_sent_mutex;
+#ifndef sunos5
+extern pthread_mutex_t regex_mutex;
+#endif
+
+init()
+{
+       pthread_mutex_init( &active_threads_mutex, pthread_mutexattr_default );
+       pthread_mutex_init( &new_conn_mutex, pthread_mutexattr_default );
+       pthread_mutex_init( &currenttime_mutex, pthread_mutexattr_default );
+       pthread_mutex_init( &entry2str_mutex, pthread_mutexattr_default );
+       pthread_mutex_init( &replog_mutex, pthread_mutexattr_default );
+       pthread_mutex_init( &ops_mutex, pthread_mutexattr_default );
+       pthread_mutex_init( &num_sent_mutex, pthread_mutexattr_default );
+#ifndef sunos5
+       pthread_mutex_init( &regex_mutex, pthread_mutexattr_default );
+#endif
+}
diff --git a/servers/slapd/lock.c b/servers/slapd/lock.c
new file mode 100644 (file)
index 0000000..305fb5b
--- /dev/null
@@ -0,0 +1,64 @@
+/* lock.c - routines to open and apply an advisory lock to a file */
+
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include "portable.h"
+#ifdef USE_LOCKF
+#include <unistd.h>
+#endif
+#include <sys/file.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include "slap.h"
+
+FILE *
+lock_fopen( char *fname, char *type, FILE **lfp )
+{
+       FILE    *fp;
+       char    buf[MAXPATHLEN];
+
+       /* open the lock file */
+       strcpy( buf, fname );
+       strcat( buf, ".lock" );
+       if ( (*lfp = fopen( buf, "w" )) == NULL ) {
+               Debug( LDAP_DEBUG_ANY, "could not open \"%s\"\n", buf, 0, 0 );
+               return( NULL );
+       }
+
+       /* acquire the lock */
+#ifdef USE_LOCKF
+       while ( lockf( fileno( *lfp ), F_LOCK, 0 ) != 0 ) {
+#else
+       while ( flock( fileno( *lfp ), LOCK_EX ) != 0 ) {
+#endif
+               ;       /* NULL */
+       }
+
+       /* open the log file */
+       if ( (fp = fopen( fname, type )) == NULL ) {
+               Debug( LDAP_DEBUG_ANY, "could not open \"%s\"\n", fname, 0, 0 );
+#ifdef USE_LOCKF
+               lockf( fileno( *lfp ), F_ULOCK, 0 );
+#else
+               flock( fileno( *lfp ), LOCK_UN );
+#endif
+               return( NULL );
+       }
+
+       return( fp );
+}
+
+int
+lock_fclose( FILE *fp, FILE *lfp )
+{
+       /* unlock */
+#ifdef USE_LOCKF
+       lockf( fileno( lfp ), F_ULOCK, 0 );
+#else
+       flock( fileno( lfp ), LOCK_UN );
+#endif
+       fclose( lfp );
+
+       return( fclose( fp ) );
+}
diff --git a/servers/slapd/main.c b/servers/slapd/main.c
new file mode 100644 (file)
index 0000000..01930b9
--- /dev/null
@@ -0,0 +1,273 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include "portable.h"
+#include "slap.h"
+#include "ldapconfig.h"
+
+extern void    daemon();
+extern int     lber_debug;
+
+extern char Versionstr[];
+
+/*
+ * read-only global variables or variables only written by the listener
+ * thread (after they are initialized) - no need to protect them with a mutex.
+ */
+int            ldap_debug;
+#ifdef LDAP_DEBUG
+int            ldap_syslog = LDAP_DEBUG_STATS;
+#else
+int            ldap_syslog;
+#endif
+int            ldap_syslog_level = LOG_DEBUG;
+int            udp;
+int            slapd_shutdown;
+char           *default_referral;
+char           *configfile;
+time_t         starttime;
+pthread_t      listener_tid;
+int            g_argc;
+char           **g_argv;
+/*
+ * global variables that need mutex protection
+ */
+time_t         currenttime;
+pthread_mutex_t        currenttime_mutex;
+int            active_threads;
+pthread_mutex_t        active_threads_mutex;
+pthread_mutex_t        new_conn_mutex;
+long           ops_initiated;
+long           ops_completed;
+int            num_conns;
+pthread_mutex_t        ops_mutex;
+long           num_entries_sent;
+long           num_bytes_sent;
+pthread_mutex_t        num_sent_mutex;
+/*
+ * these mutexes must be used when calling the entry2str()
+ * routine since it returns a pointer to static data.
+ */
+pthread_mutex_t        entry2str_mutex;
+pthread_mutex_t        replog_mutex;
+#ifndef sunos5
+pthread_mutex_t        regex_mutex;
+#endif
+
+static
+usage( name )
+    char       *name;
+{
+       fprintf( stderr, "usage: %s [-d debuglevel] [-f configfile] [-p portnumber] [-s sysloglevel]\n", name );
+}
+
+main( argc, argv )
+    int                argc;
+    char       **argv;
+{
+       int             i;
+       int             inetd = 0;
+       int             port;
+       char            *myname;
+       Backend         *be = NULL;
+       FILE            *fp = NULL;
+       extern char     *optarg;
+
+       configfile = SLAPD_DEFAULT_CONFIGFILE;
+       port = LDAP_PORT;
+       g_argc = argc;
+       g_argv = argv;
+
+       while ( (i = getopt( argc, argv, "d:f:ip:s:u" )) != EOF ) {
+               switch ( i ) {
+#ifdef LDAP_DEBUG
+               case 'd':       /* turn on debugging */
+                       if ( optarg[0] == '?' ) {
+                               printf( "Debug levels:\n" );
+                               printf( "\tLDAP_DEBUG_TRACE\t%d\n",
+                                   LDAP_DEBUG_TRACE );
+                               printf( "\tLDAP_DEBUG_PACKETS\t%d\n",
+                                   LDAP_DEBUG_PACKETS );
+                               printf( "\tLDAP_DEBUG_ARGS\t\t%d\n",
+                                   LDAP_DEBUG_ARGS );
+                               printf( "\tLDAP_DEBUG_CONNS\t%d\n",
+                                   LDAP_DEBUG_CONNS );
+                               printf( "\tLDAP_DEBUG_BER\t\t%d\n",
+                                   LDAP_DEBUG_BER );
+                               printf( "\tLDAP_DEBUG_FILTER\t%d\n",
+                                   LDAP_DEBUG_FILTER );
+                               printf( "\tLDAP_DEBUG_CONFIG\t%d\n",
+                                   LDAP_DEBUG_CONFIG );
+                               printf( "\tLDAP_DEBUG_ACL\t\t%d\n",
+                                   LDAP_DEBUG_ACL );
+                               printf( "\tLDAP_DEBUG_STATS\t\t%d\n",
+                                   LDAP_DEBUG_STATS );
+                               printf( "\tLDAP_DEBUG_STATS2\t\t%d\n",
+                                   LDAP_DEBUG_STATS2 );
+                               printf( "\tLDAP_DEBUG_SHELL\t\t%d\n",
+                                   LDAP_DEBUG_SHELL );
+                               printf( "\tLDAP_DEBUG_PARSE\t\t%d\n",
+                                   LDAP_DEBUG_PARSE );
+                               printf( "\tLDAP_DEBUG_ANY\t\t%d\n",
+                                   LDAP_DEBUG_ANY );
+                               exit( 0 );
+                       } else {
+                               ldap_debug = atoi( optarg );
+                               lber_debug = (ldap_debug & LDAP_DEBUG_BER);
+                       }
+                       break;
+#else
+               case 'd':       /* turn on debugging */
+                       fprintf( stderr,
+                           "must compile with LDAP_DEBUG for debugging\n" );
+                       break;
+#endif
+
+               case 'f':       /* read config file */
+                       configfile = strdup( optarg );
+                       break;
+
+               case 'i':       /* run from inetd */
+                       inetd = 1;
+                       break;
+
+               case 'p':       /* port on which to listen */
+                       port = atoi( optarg );
+                       break;
+
+               case 's':       /* set syslog level */
+                       ldap_syslog = atoi( optarg );
+                       break;
+
+               case 'u':       /* do udp */
+                       udp = 1;
+                       break;
+
+               default:
+                       usage( argv[0] );
+                       exit( 1 );
+               }
+       }
+
+       Debug( LDAP_DEBUG_TRACE, "%s", Versionstr, 0, 0 );
+
+       if ( (myname = strrchr( argv[0], '/' )) == NULL ) {
+               myname = strdup( argv[0] );
+       } else {
+               myname = strdup( myname + 1 );
+       }
+
+       if ( ! inetd ) {
+               /* pre-open config file before detach in case it is a relative path */
+               fp = fopen( configfile, "r" );
+               detach();
+       }
+#ifdef LOG_LOCAL4
+       openlog( myname, OPENLOG_OPTIONS, LOG_LOCAL4 );
+#else
+       openlog( myname, OPENLOG_OPTIONS );
+#endif
+
+       init();
+       read_config( configfile, &be, fp );
+
+       if ( ! inetd ) {
+               pthread_attr_t  attr;
+               int             status;
+
+               time( &starttime );
+               pthread_attr_init( &attr );
+               pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED );
+
+               if ( pthread_create( &listener_tid, attr, (void *) daemon,
+                   (void *) port ) != 0 ) {
+                       Debug( LDAP_DEBUG_ANY,
+                           "listener pthread_create failed\n", 0, 0, 0 );
+                       exit( 1 );
+               }
+               pthread_attr_destroy( &attr );
+               pthread_join( listener_tid, (void *) &status );
+               pthread_exit( 0 );
+       } else {
+               Connection              c;
+               Operation               *o;
+               BerElement              ber;
+               unsigned long           len, tag;
+               long                    msgid;
+               int                     flen;
+               struct sockaddr_in      from;
+               struct hostent          *hp;
+
+               c.c_dn = NULL;
+               c.c_ops = NULL;
+               c.c_sb.sb_sd = 0;
+               c.c_sb.sb_options = 0;
+               c.c_sb.sb_naddr = udp ? 1 : 0;
+               c.c_sb.sb_ber.ber_buf = NULL;
+               c.c_sb.sb_ber.ber_ptr = NULL;
+               c.c_sb.sb_ber.ber_end = NULL;
+               pthread_mutex_init( &c.c_dnmutex, pthread_mutexattr_default );
+               pthread_mutex_init( &c.c_opsmutex, pthread_mutexattr_default );
+               pthread_mutex_init( &c.c_pdumutex, pthread_mutexattr_default );
+#ifdef notdefcldap
+               c.c_sb.sb_addrs = (void **) saddrlist;
+               c.c_sb.sb_fromaddr = &faddr;
+               c.c_sb.sb_useaddr = saddrlist[ 0 ] = &saddr;
+#endif
+               flen = sizeof(from);
+               if ( getpeername( 0, (struct sockaddr *) &from, &flen ) == 0 ) {
+#ifdef REVERSE_LOOKUP
+                       hp = gethostbyaddr( (char *) &(from.sin_addr.s_addr),
+                           sizeof(from.sin_addr.s_addr), AF_INET );
+#else
+                       hp = NULL;
+#endif
+
+                       Debug( LDAP_DEBUG_ARGS, "connection from %s (%s)\n",
+                           hp == NULL ? "unknown" : hp->h_name,
+                           inet_ntoa( from.sin_addr ), 0 );
+
+                       c.c_addr = inet_ntoa( from.sin_addr );
+                       c.c_domain = strdup( hp == NULL ? "" : hp->h_name );
+               } else {
+                       Debug( LDAP_DEBUG_ARGS, "connection from unknown\n",
+                           0, 0, 0 );
+               }
+
+               ber_init( &ber, 0 );
+               while ( (tag = ber_get_next( &c.c_sb, &len, &ber ))
+                   == LDAP_TAG_MESSAGE ) {
+                       pthread_mutex_lock( &currenttime_mutex );
+                       time( &currenttime );
+                       pthread_mutex_unlock( &currenttime_mutex );
+
+                       if ( (tag = ber_get_int( &ber, &msgid ))
+                           != LDAP_TAG_MSGID ) {
+                               /* log and send error */
+                               Debug( LDAP_DEBUG_ANY,
+                                   "ber_get_int returns 0x%x\n", tag, 0, 0 );
+                               return;
+                       }
+
+                       if ( (tag = ber_peek_tag( &ber, &len ))
+                           == LBER_ERROR ) {
+                               /* log, close and send error */
+                               Debug( LDAP_DEBUG_ANY,
+                                   "ber_peek_tag returns 0x%x\n", tag, 0, 0 );
+                               ber_free( &ber, 1 );
+                               close( c.c_sb.sb_sd );
+                               c.c_sb.sb_sd = -1;
+                               return;
+                       }
+
+                       connection_activity( &c );
+
+                       ber_free( &ber, 1 );
+               }
+       }
+}
diff --git a/servers/slapd/modify.c b/servers/slapd/modify.c
new file mode 100644 (file)
index 0000000..6575fe3
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+
+extern Backend *select_backend();
+
+extern char            *default_referral;
+extern time_t          currenttime;
+extern pthread_mutex_t currenttime_mutex;
+extern int             global_lastmod;
+
+static void    modlist_free();
+static void    add_lastmods();
+
+void
+do_modify(
+    Connection *conn,
+    Operation  *op
+)
+{
+       char            *dn, *odn;
+       char            *last;
+       unsigned long   tag, len;
+       LDAPMod         *mods, *tmp;
+       LDAPMod         **modtail;
+       Backend         *be;
+
+       Debug( LDAP_DEBUG_TRACE, "do_modify\n", 0, 0, 0 );
+
+       /*
+        * Parse the modify request.  It looks like this:
+        *
+        *      ModifyRequest := [APPLICATION 6] SEQUENCE {
+        *              name    DistinguishedName,
+        *              mods    SEQUENCE OF SEQUENCE {
+        *                      operation       ENUMERATED {
+        *                              add     (0),
+        *                              delete  (1),
+        *                              replace (2)
+        *                      },
+        *                      modification    SEQUENCE {
+        *                              type    AttributeType,
+        *                              values  SET OF AttributeValue
+        *                      }
+        *              }
+        *      }
+        */
+
+       if ( ber_scanf( op->o_ber, "{a", &dn ) == LBER_ERROR ) {
+               Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
+               send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL, "" );
+               return;
+       }
+       odn = strdup( dn );
+       dn_normalize( dn );
+
+       Debug( LDAP_DEBUG_ARGS, "do_modify: dn (%s)\n", dn, 0, 0 );
+
+       /* collect modifications & save for later */
+       mods = NULL;
+       modtail = &mods;
+       for ( tag = ber_first_element( op->o_ber, &len, &last );
+           tag != LBER_DEFAULT;
+           tag = ber_next_element( op->o_ber, &len, last ) )
+       {
+               (*modtail) = (LDAPMod *) ch_calloc( 1, sizeof(LDAPMod) );
+
+               if ( ber_scanf( op->o_ber, "{i{a[V]}}", &(*modtail)->mod_op,
+                   &(*modtail)->mod_type, &(*modtail)->mod_bvalues )
+                   == LBER_ERROR )
+               {
+                       send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
+                           "decoding error" );
+                       free( dn );
+                       free( odn );
+                       free( *modtail );
+                       modlist_free( mods );
+                       return;
+               }
+
+               if ( (*modtail)->mod_op != LDAP_MOD_ADD &&
+                   (*modtail)->mod_op != LDAP_MOD_DELETE &&
+                   (*modtail)->mod_op != LDAP_MOD_REPLACE )
+               {
+                       send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
+                           "unrecognized modify operation" );
+                       free( dn );
+                       free( odn );
+                       modlist_free( mods );
+                       return;
+               }
+
+               if ( (*modtail)->mod_bvalues == NULL && (*modtail)->mod_op
+                 != LDAP_MOD_DELETE ) {
+                       send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
+                           "no values given" );
+                       free( dn );
+                       free( odn );
+                       modlist_free( mods );
+                       return;
+               }
+               attr_normalize( (*modtail)->mod_type );
+
+               modtail = &(*modtail)->mod_next;
+       }
+       *modtail = NULL;
+
+#ifdef LDAP_DEBUG
+       Debug( LDAP_DEBUG_ARGS, "modifications:\n", 0, 0, 0 );
+       for ( tmp = mods; tmp != NULL; tmp = tmp->mod_next ) {
+               Debug( LDAP_DEBUG_ARGS, "\t%s: %s\n", tmp->mod_op
+                   == LDAP_MOD_ADD ? "add" : (tmp->mod_op == LDAP_MOD_DELETE ?
+                   "delete" : "replace"), tmp->mod_type, 0 );
+       }
+#endif
+
+       Statslog( LDAP_DEBUG_STATS, "conn=%d op=%d MOD dn=\"%s\"\n",
+           conn->c_connid, op->o_opid, dn, 0, 0 );
+
+       /*
+        * We could be serving multiple database backends.  Select the
+        * appropriate one, or send a referral to our "referral server"
+        * if we don't hold it.
+        */
+       if ( (be = select_backend( dn )) == NULL ) {
+               free( dn );
+               free( odn );
+               modlist_free( mods );
+               send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
+                   default_referral );
+               return;
+       }
+
+       /*
+        * do the modify if 1 && (2 || 3)
+        * 1) there is a modify function implemented in this backend;
+        * 2) this backend is master for what it holds;
+        * 3) it's a replica and the dn supplied is the updatedn.
+        */
+       if ( be->be_modify != NULL ) {
+               /* do the update here */
+               if ( be->be_updatedn == NULL || strcasecmp( be->be_updatedn,
+                   op->o_dn ) == 0 ) {
+                       if ( (be->be_lastmod == ON || be->be_lastmod == 0 &&
+                           global_lastmod == ON) && be->be_updatedn == NULL ) {
+                               add_lastmods( op, &mods );
+                       }
+                       if ( (*be->be_modify)( be, conn, op, odn, mods )
+                           == 0 ) {
+                               replog( be, LDAP_REQ_MODIFY, dn, mods, 0 );
+                       }
+
+               /* send a referral */
+               } else {
+                       send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
+                           default_referral );
+               }
+       } else {
+               send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
+                   "Function not implemented" );
+       }
+
+       free( dn );
+       free( odn );
+       modlist_free( mods );
+}
+
+static void
+modlist_free(
+    LDAPMod    *mods
+)
+{
+       LDAPMod *next;
+
+       for ( ; mods != NULL; mods = next ) {
+               next = mods->mod_next;
+               free( mods->mod_type );
+               if ( mods->mod_bvalues != NULL )
+                       ber_bvecfree( mods->mod_bvalues );
+               free( mods );
+       }
+}
+
+static void
+add_lastmods( Operation *op, LDAPMod **mods )
+{
+       char            buf[20];
+       struct berval   bv;
+       struct berval   *bvals[2];
+       LDAPMod         **m;
+       LDAPMod         *tmp;
+       struct tm       *ltm;
+
+       Debug( LDAP_DEBUG_TRACE, "add_lastmods\n", 0, 0, 0 );
+
+       bvals[0] = &bv;
+       bvals[1] = NULL;
+
+       /* remove any attempts by the user to modify these attrs */
+       for ( m = mods; *m != NULL; m = &(*m)->mod_next ) {
+               if ( strcasecmp( (*m)->mod_type, "modifytimestamp" ) == 0
+                   || strcasecmp( (*m)->mod_type, "modifiersname" ) == 0 ) {
+                       tmp = *m;
+                       *m = (*m)->mod_next;
+                       free( tmp->mod_type );
+                       if ( tmp->mod_bvalues != NULL ) {
+                               ber_bvecfree( tmp->mod_bvalues );
+                       }
+                       free( tmp );
+               }
+       }
+
+       if ( op->o_dn == NULL || op->o_dn[0] == '\0' ) {
+               bv.bv_val = "NULLDN";
+               bv.bv_len = strlen( bv.bv_val );
+       } else {
+               bv.bv_val = op->o_dn;
+               bv.bv_len = strlen( bv.bv_val );
+       }
+       tmp = (LDAPMod *) ch_calloc( 1, sizeof(LDAPMod) );
+       tmp->mod_type = strdup( "modifiersname" );
+       tmp->mod_op = LDAP_MOD_REPLACE;
+       tmp->mod_bvalues = (struct berval **) ch_calloc( 1,
+           2 * sizeof(struct berval *) );
+       tmp->mod_bvalues[0] = ber_bvdup( &bv );
+       tmp->mod_next = *mods;
+       *mods = tmp;
+
+       pthread_mutex_lock( &currenttime_mutex );
+        ltm = localtime( &currenttime );
+        strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm );
+       pthread_mutex_unlock( &currenttime_mutex );
+       bv.bv_val = buf;
+       bv.bv_len = strlen( bv.bv_val );
+       tmp = (LDAPMod *) ch_calloc( 1, sizeof(LDAPMod) );
+       tmp->mod_type = strdup( "modifytimestamp" );
+       tmp->mod_op = LDAP_MOD_REPLACE;
+       tmp->mod_bvalues = (struct berval **) ch_calloc( 1,
+           2 * sizeof(struct berval *) );
+       tmp->mod_bvalues[0] = ber_bvdup( &bv );
+       tmp->mod_next = *mods;
+       *mods = tmp;
+}
diff --git a/servers/slapd/modrdn.c b/servers/slapd/modrdn.c
new file mode 100644 (file)
index 0000000..802dda5
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+
+extern Backend *select_backend();
+
+extern char    *default_referral;
+
+void
+do_modrdn(
+    Connection *conn,
+    Operation  *op
+)
+{
+       char    *dn, *odn, *newrdn;
+       int     deloldrdn;
+       Backend *be;
+
+       Debug( LDAP_DEBUG_TRACE, "do_modrdn\n", 0, 0, 0 );
+
+       /*
+        * Parse the modrdn request.  It looks like this:
+        *
+        *      ModifyRDNRequest := SEQUENCE {
+        *              entry   DistinguishedName,
+        *              newrdn  RelativeDistinguishedName
+        *      }
+        */
+
+       if ( ber_scanf( op->o_ber, "{aab}", &dn, &newrdn, &deloldrdn )
+           == LBER_ERROR ) {
+               Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
+               send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL, "" );
+               return;
+       }
+       odn = strdup( dn );
+       dn_normalize( dn );
+
+       Debug( LDAP_DEBUG_ARGS,
+           "do_modrdn: dn (%s) newrdn (%s) deloldrdn (%d)\n", dn, newrdn,
+           deloldrdn );
+
+       Statslog( LDAP_DEBUG_STATS, "conn=%d op=%d MODRDN dn=\"%s\"\n",
+           conn->c_connid, op->o_opid, dn, 0, 0 );
+
+       /*
+        * We could be serving multiple database backends.  Select the
+        * appropriate one, or send a referral to our "referral server"
+        * if we don't hold it.
+        */
+
+       if ( (be = select_backend( dn )) == NULL ) {
+               free( dn );
+               free( odn );
+               free( newrdn );
+               send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
+                   default_referral );
+               return;
+       }
+
+       /*
+        * do the add if 1 && (2 || 3)
+        * 1) there is an add function implemented in this backend;
+        * 2) this backend is master for what it holds;
+        * 3) it's a replica and the dn supplied is the updatedn.
+        */
+       if ( be->be_modrdn != NULL ) {
+               /* do the update here */
+               if ( be->be_updatedn == NULL || strcasecmp( be->be_updatedn,
+                   op->o_dn ) == 0 ) {
+                       if ( (*be->be_modrdn)( be, conn, op, dn, newrdn,
+                           deloldrdn ) == 0 ) {
+                               replog( be, LDAP_REQ_MODRDN, odn, newrdn,
+                                   deloldrdn );
+                       }
+               } else {
+                       send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
+                           default_referral );
+               }
+       } else {
+               send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
+                   "Function not implemented" );
+       }
+
+       free( dn );
+       free( odn );
+       free( newrdn );
+}
diff --git a/servers/slapd/monitor.c b/servers/slapd/monitor.c
new file mode 100644 (file)
index 0000000..7dbabc9
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "ldapconfig.h"
+
+#if defined( SLAPD_MONITOR_DN )
+
+extern int             nbackends;
+extern Backend         *backends;
+extern int             active_threads;
+extern int             dtblsize;
+extern Connection      *c;
+extern long            ops_initiated;
+extern long            ops_completed;
+extern long            num_entries_sent;
+extern long            num_bytes_sent;
+extern time_t          currenttime;
+extern time_t          starttime;
+extern int             num_conns;
+
+
+extern char Versionstr[];
+
+/*
+ * no mutex protection in here - take our chances!
+ */
+
+void
+monitor_info( Connection *conn, Operation *op )
+{
+       Entry           *e;
+       char            buf[BUFSIZ], buf2[20];
+       struct berval   val;
+       struct berval   *vals[2];
+       int             i, nconns, nwritewaiters, nreadwaiters;
+       struct tm       *ltm;
+       char            *p, *tmpdn;
+
+       vals[0] = &val;
+       vals[1] = NULL;
+
+       e = (Entry *) ch_calloc( 1, sizeof(Entry) );
+       e->e_attrs = NULL;
+       e->e_dn = strdup( SLAPD_MONITOR_DN );
+
+       val.bv_val = Versionstr;
+       if (( p = strchr( Versionstr, '\n' )) == NULL ) {
+               val.bv_len = strlen( Versionstr );
+       } else {
+               val.bv_len = p - Versionstr;
+       }
+       attr_merge( e, "version", vals );
+
+       sprintf( buf, "%d", active_threads );
+       val.bv_val = buf;
+       val.bv_len = strlen( buf );
+       attr_merge( e, "threads", vals );
+
+       nconns = 0;
+       nwritewaiters = 0;
+       nreadwaiters = 0;
+       for ( i = 0; i < dtblsize; i++ ) {
+               if ( c[i].c_sb.sb_sd != -1 ) {
+                       nconns++;
+                       if ( c[i].c_writewaiter ) {
+                               nwritewaiters++;
+                       }
+                       if ( c[i].c_gettingber ) {
+                               nreadwaiters++;
+                       }
+                       ltm = localtime( &c[i].c_starttime );
+                       strftime( buf2, sizeof(buf2), "%y%m%d%H%M%SZ", ltm );
+                       pthread_mutex_lock( &c[i].c_dnmutex );
+                       sprintf( buf, "%d : %s : %ld : %ld : %s : %s%s", i,
+                           buf2, c[i].c_opsinitiated, c[i].c_opscompleted,
+                           c[i].c_dn ? c[i].c_dn : "NULLDN",
+                           c[i].c_gettingber ? "r" : "",
+                           c[i].c_writewaiter ? "w" : "" );
+                       pthread_mutex_unlock( &c[i].c_dnmutex );
+                       val.bv_val = buf;
+                       val.bv_len = strlen( buf );
+                       attr_merge( e, "connection", vals );
+               }
+       }
+       sprintf( buf, "%d", nconns );
+       val.bv_val = buf;
+       val.bv_len = strlen( buf );
+       attr_merge( e, "currentconnections", vals );
+
+       sprintf( buf, "%d", num_conns );
+       val.bv_val = buf;
+       val.bv_len = strlen( buf );
+       attr_merge( e, "totalconnections", vals );
+
+       sprintf( buf, "%d", dtblsize );
+       val.bv_val = buf;
+       val.bv_len = strlen( buf );
+       attr_merge( e, "dtablesize", vals );
+
+       sprintf( buf, "%d", nwritewaiters );
+       val.bv_val = buf;
+       val.bv_len = strlen( buf );
+       attr_merge( e, "writewaiters", vals );
+
+       sprintf( buf, "%d", nreadwaiters );
+       val.bv_val = buf;
+       val.bv_len = strlen( buf );
+       attr_merge( e, "readwaiters", vals );
+
+       sprintf( buf, "%ld", ops_initiated );
+       val.bv_val = buf;
+       val.bv_len = strlen( buf );
+       attr_merge( e, "opsinitiated", vals );
+
+       sprintf( buf, "%ld", ops_completed );
+       val.bv_val = buf;
+       val.bv_len = strlen( buf );
+       attr_merge( e, "opscompleted", vals );
+
+       sprintf( buf, "%ld", num_entries_sent );
+       val.bv_val = buf;
+       val.bv_len = strlen( buf );
+       attr_merge( e, "entriessent", vals );
+
+       sprintf( buf, "%ld", num_bytes_sent );
+       val.bv_val = buf;
+       val.bv_len = strlen( buf );
+       attr_merge( e, "bytessent", vals );
+
+        ltm = localtime( &currenttime );
+        strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm );
+       val.bv_val = buf;
+       val.bv_len = strlen( buf );
+       attr_merge( e, "currenttime", vals );
+
+        ltm = localtime( &starttime );
+        strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm );
+       val.bv_val = buf;
+       val.bv_len = strlen( buf );
+       attr_merge( e, "starttime", vals );
+
+       sprintf( buf, "%d", nbackends );
+       val.bv_val = buf;
+       val.bv_len = strlen( buf );
+       attr_merge( e, "nbackends", vals );
+
+#ifdef THREAD_SUNOS5_LWP
+       sprintf( buf, "%d", thr_getconcurrency() );
+       val.bv_val = buf;
+       val.bv_len = strlen( buf );
+       attr_merge( e, "concurrency", vals );
+#endif
+
+       send_search_entry( &backends[0], conn, op, e, NULL, 0 );
+       send_ldap_search_result( conn, op, LDAP_SUCCESS, NULL, NULL, 1 );
+
+       entry_free( e );
+}
+
+#endif /* slapd_monitor_dn */
diff --git a/servers/slapd/operation.c b/servers/slapd/operation.c
new file mode 100644 (file)
index 0000000..0c62e21
--- /dev/null
@@ -0,0 +1,74 @@
+/* operation.c - routines to deal with pending ldap operations */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+
+extern time_t          currenttime;
+extern pthread_mutex_t currenttime_mutex;
+
+void
+op_free( Operation *op )
+{
+       if ( op->o_ber != NULL )
+               ber_free( op->o_ber, 1 );
+       if ( op->o_dn != NULL ) {
+               free( op->o_dn );
+       }
+       /* pthread_mutex_destroy( &op->o_abandonmutex ); */
+       free( (char *) op );
+}
+
+Operation *
+op_add(
+    Operation          **olist,
+    BerElement         *ber,
+    unsigned long      msgid,
+    unsigned long      tag,
+    char                       *dn,
+    int                                id,
+    int                                connid
+)
+{
+       Operation       **tmp;
+
+       for ( tmp = olist; *tmp != NULL; tmp = &(*tmp)->o_next )
+               ;       /* NULL */
+
+       *tmp = (Operation *) calloc( 1, sizeof(Operation) );
+       pthread_mutex_init( &(*tmp)->o_abandonmutex,
+           pthread_mutexattr_default );
+       (*tmp)->o_ber = ber;
+       (*tmp)->o_msgid = msgid;
+       (*tmp)->o_tag = tag;
+       (*tmp)->o_abandon = 0;
+       (*tmp)->o_dn = strdup( dn != NULL ? dn : "" );
+       pthread_mutex_lock( &currenttime_mutex );
+       (*tmp)->o_time = currenttime;
+       pthread_mutex_unlock( &currenttime_mutex );
+       (*tmp)->o_opid = id;
+       (*tmp)->o_connid = connid;
+       (*tmp)->o_next = NULL;
+
+       return( *tmp );
+}
+
+void
+op_delete( Operation **olist, Operation *op )
+{
+       Operation       **tmp;
+
+       for ( tmp = olist; *tmp != NULL && *tmp != op; tmp = &(*tmp)->o_next )
+               ;       /* NULL */
+
+       if ( *tmp == NULL ) {
+               Debug( LDAP_DEBUG_ANY, "op_delete: can't find op %d\n",
+                   op->o_msgid, 0, 0 );
+               return; 
+       }
+
+       *tmp = (*tmp)->o_next;
+       op_free( op );
+}
diff --git a/servers/slapd/phonetic.c b/servers/slapd/phonetic.c
new file mode 100644 (file)
index 0000000..959e06e
--- /dev/null
@@ -0,0 +1,431 @@
+/* phonetic.c - routines to do phonetic matching */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "portable.h"
+#include "slap.h"
+
+#if !defined(METAPHONE) && !defined(SOUNDEX)
+#define METAPHONE
+#endif
+
+#define iswordbreak(x)  (!isascii(x) || isspace((unsigned char) (x)) || \
+                        ispunct((unsigned char) (x)) || \
+                        isdigit((unsigned char) (x)) || x == '\0')
+
+char *
+first_word( char *s )
+{
+       if ( s == NULL ) {
+               return( NULL );
+       }
+
+       while ( iswordbreak( *s ) ) {
+               if ( *s == '\0' ) {
+                       return( NULL );
+               } else {
+                       s++;
+               }
+       }
+
+       return( s );
+}
+
+char *
+next_word( char *s )
+{
+       if ( s == NULL ) {
+               return( NULL );
+       }
+
+       while ( ! iswordbreak( *s ) ) {
+               s++;
+       }
+
+       while ( iswordbreak( *s ) ) {
+               if ( *s == '\0' ) {
+                       return( NULL );
+               } else {
+                       s++;
+               }
+       }
+
+       return( s );
+}
+
+char *
+word_dup( char *w )
+{
+       char    *s, *ret;
+       char    save;
+
+       for ( s = w; !iswordbreak( *s ); s++ )
+               ;       /* NULL */
+       save = *s;
+       *s = '\0';
+       ret = strdup( w );
+       *s = save;
+
+       return( ret );
+}
+
+#ifndef MAXPHONEMELEN
+#define MAXPHONEMELEN  4
+#endif
+
+#if defined(SOUNDEX)
+
+/* lifted from isode-8.0 */
+char *
+phonetic( char *s )
+{
+        char   code, adjacent, ch;
+       char    *p;
+       char    **c;
+        int    i, cmax;
+       char    phoneme[MAXPHONEMELEN + 1];
+
+        p = s;
+        if (  p == NULL || *p == '\0' ) {
+                return( NULL );
+        }
+
+        adjacent = '0';
+       phoneme[0] = TOUPPER(*p);
+
+       phoneme[1]  = '\0';
+        for ( i = 0; i < 99 && (! iswordbreak(*p)); p++ ) {
+               ch = TOUPPER (*p);
+
+                code = '0';
+
+                switch (ch) {
+                case 'B':
+                case 'F':
+               case 'P':
+                case 'V':
+                        code = (adjacent != '1') ? '1' : '0';
+                        break;
+                case 'S':
+                case 'C':
+                case 'G':
+                case 'J':
+                case 'K':
+                case 'Q':
+                case 'X':
+                case 'Z':
+                        code = (adjacent != '2') ? '2' : '0';
+                        break;
+                case 'D':
+                case 'T':
+                        code = (adjacent != '3') ? '3' : '0';
+                        break;
+                case 'L':
+                        code = (adjacent != '4') ? '4' : '0';
+                        break;
+                case 'M':
+                case 'N':
+                        code = (adjacent != '5') ? '5' : '0';
+                        break;
+                case 'R':
+                        code = (adjacent != '6') ? '6' : '0';
+                        break;
+                default:
+                        adjacent = '0';
+                }
+
+                if ( i == 0 ) {
+                       adjacent = code;
+                       i++;
+               } else if ( code != '0' ) {
+                       if ( i == MAXPHONEMELEN )
+                               break;
+                        adjacent = phoneme[i] = code;
+                        i++;
+                }
+        }
+
+       if ( i > 0 )
+               phoneme[i] = '\0';
+
+        return( strdup( phoneme ) );
+}
+
+#else
+#if defined(METAPHONE)
+
+/*
+ * Metaphone copied from C Gazette, June/July 1991, pp 56-57,
+ * author Gary A. Parker, with changes by Bernard Tiffany of the
+ * University of Michigan, and more changes by Tim Howes of the
+ * University of Michigan.
+ */
+
+/* Character coding array */
+static char     vsvfn[26] = {
+          1, 16, 4, 16, 9, 2, 4, 16, 9, 2, 0, 2, 2,
+       /* A   B  C   D  E  F  G   H  I  J  K  L  M  */
+          2, 1, 4, 0, 2, 4, 4, 1, 0, 0, 0, 8, 0};
+       /* N  O  P  Q  R  S  T  U  V  W  X  Y  Z  */
+
+/* Macros to access character coding array */
+#define vowel(x)        ((x) != '\0' && vsvfn[(x) - 'A'] & 1)  /* AEIOU */
+#define same(x)         ((x) != '\0' && vsvfn[(x) - 'A'] & 2)  /* FJLMNR */
+#define varson(x)       ((x) != '\0' && vsvfn[(x) - 'A'] & 4)  /* CGPST */
+#define frontv(x)       ((x) != '\0' && vsvfn[(x) - 'A'] & 8)  /* EIY */
+#define noghf(x)        ((x) != '\0' && vsvfn[(x) - 'A'] & 16) /* BDH */
+
+char *
+phonetic( char *Word )
+{
+       char           *n, *n_start, *n_end;    /* pointers to string */
+       char           *metaph, *metaph_end;    /* pointers to metaph */
+       char            ntrans[40];     /* word with uppercase letters */
+       char            newm[8];/* new metaph for comparison */
+       int             KSflag; /* state flag for X -> KS */
+       char            buf[MAXPHONEMELEN + 2];
+       char            *Metaph;
+
+       /*
+        * Copy Word to internal buffer, dropping non-alphabetic characters
+        * and converting to upper case
+        */
+
+       for (n = ntrans + 4, n_end = ntrans + 35; !iswordbreak( *Word ) &&
+           n < n_end; Word++) {
+               if (isalpha(*Word))
+                       *n++ = TOUPPER(*Word);
+       }
+       Metaph = buf;
+       *Metaph = '\0';
+       if (n == ntrans + 4) {
+               return( strdup( buf ) );                /* Return if null */
+       }
+       n_end = n;              /* Set n_end to end of string */
+
+       /* ntrans[0] will always be == 0 */
+       ntrans[0] = '\0';
+       ntrans[1] = '\0';
+       ntrans[2] = '\0';
+       ntrans[3] = '\0';
+       *n++ = 0;
+       *n++ = 0;
+       *n++ = 0;
+       *n = 0;                 /* Pad with nulls */
+       n = ntrans + 4;         /* Assign pointer to start */
+
+       /* Check for PN, KN, GN, AE, WR, WH, and X at start */
+       switch (*n) {
+       case 'P':
+       case 'K':
+       case 'G':
+               /* 'PN', 'KN', 'GN' becomes 'N' */
+               if (*(n + 1) == 'N')
+                       *n++ = 0;
+               break;
+       case 'A':
+               /* 'AE' becomes 'E' */
+               if (*(n + 1) == 'E')
+                       *n++ = 0;
+               break;
+       case 'W':
+               /* 'WR' becomes 'R', and 'WH' to 'H' */
+               if (*(n + 1) == 'R')
+                       *n++ = 0;
+               else if (*(n + 1) == 'H') {
+                       *(n + 1) = *n;
+                       *n++ = 0;
+               }
+               break;
+       case 'X':
+               /* 'X' becomes 'S' */
+               *n = 'S';
+               break;
+       }
+
+       /*
+        * Now, loop step through string, stopping at end of string or when
+        * the computed 'metaph' is MAXPHONEMELEN characters long
+        */
+
+       KSflag = 0;             /* state flag for KS translation */
+       for (metaph_end = Metaph + MAXPHONEMELEN, n_start = n;
+            n <= n_end && Metaph < metaph_end; n++) {
+               if (KSflag) {
+                       KSflag = 0;
+                       *Metaph++ = 'S';
+               } else {
+                       /* Drop duplicates except for CC */
+                       if (*(n - 1) == *n && *n != 'C')
+                               continue;
+                       /* Check for F J L M N R or first letter vowel */
+                       if (same(*n) || (n == n_start && vowel(*n)))
+                               *Metaph++ = *n;
+                       else
+                               switch (*n) {
+                               case 'B':
+
+                                       /*
+                                        * B unless in -MB
+                                        */
+                                       if (n == (n_end - 1) && *(n - 1) != 'M')
+                                               *Metaph++ = *n;
+                                       break;
+                               case 'C':
+
+                                       /*
+                                        * X if in -CIA-, -CH- else S if in
+                                        * -CI-, -CE-, -CY- else dropped if
+                                        * in -SCI-, -SCE-, -SCY- else K
+                                        */
+                                       if (*(n - 1) != 'S' || !frontv(*(n + 1))) {
+                                               if (*(n + 1) == 'I' && *(n + 2) == 'A')
+                                                       *Metaph++ = 'X';
+                                               else if (frontv(*(n + 1)))
+                                                       *Metaph++ = 'S';
+                                               else if (*(n + 1) == 'H')
+                                                       *Metaph++ = ((n == n_start && !vowel(*(n + 2)))
+                                                        || *(n - 1) == 'S')
+                                                           ? (char) 'K' : (char) 'X';
+                                               else
+                                                       *Metaph++ = 'K';
+                                       }
+                                       break;
+                               case 'D':
+
+                                       /*
+                                        * J if in DGE or DGI or DGY else T
+                                        */
+                                       *Metaph++ = (*(n + 1) == 'G' && frontv(*(n + 2)))
+                                           ? (char) 'J' : (char) 'T';
+                                       break;
+                               case 'G':
+
+                                       /*
+                                        * F if in -GH and not B--GH, D--GH,
+                                        * -H--GH, -H---GH else dropped if
+                                        * -GNED, -GN, -DGE-, -DGI-, -DGY-
+                                        * else J if in -GE-, -GI-, -GY- and
+                                        * not GG else K
+                                        */
+                                       if ((*(n + 1) != 'J' || vowel(*(n + 2))) &&
+                                           (*(n + 1) != 'N' || ((n + 1) < n_end &&
+                                                                (*(n + 2) != 'E' || *(n + 3) != 'D'))) &&
+                                           (*(n - 1) != 'D' || !frontv(*(n + 1))))
+                                               *Metaph++ = (frontv(*(n + 1)) &&
+                                                            *(n + 2) != 'G') ? (char) 'G' : (char) 'K';
+                                       else if (*(n + 1) == 'H' && !noghf(*(n - 3)) &&
+                                                *(n - 4) != 'H')
+                                               *Metaph++ = 'F';
+                                       break;
+                               case 'H':
+
+                                       /*
+                                        * H if before a vowel and not after
+                                        * C, G, P, S, T else dropped
+                                        */
+                                       if (!varson(*(n - 1)) && (!vowel(*(n - 1)) ||
+                                                          vowel(*(n + 1))))
+                                               *Metaph++ = 'H';
+                                       break;
+                               case 'K':
+
+                                       /*
+                                        * dropped if after C else K
+                                        */
+                                       if (*(n - 1) != 'C')
+                                               *Metaph++ = 'K';
+                                       break;
+                               case 'P':
+
+                                       /*
+                                        * F if before H, else P
+                                        */
+                                       *Metaph++ = *(n + 1) == 'H' ?
+                                           (char) 'F' : (char) 'P';
+                                       break;
+                               case 'Q':
+
+                                       /*
+                                        * K
+                                        */
+                                       *Metaph++ = 'K';
+                                       break;
+                               case 'S':
+
+                                       /*
+                                        * X in -SH-, -SIO- or -SIA- else S
+                                        */
+                                       *Metaph++ = (*(n + 1) == 'H' ||
+                                                    (*(n + 1) == 'I' && (*(n + 2) == 'O' ||
+                                                         *(n + 2) == 'A')))
+                                           ? (char) 'X' : (char) 'S';
+                                       break;
+                               case 'T':
+
+                                       /*
+                                        * X in -TIA- or -TIO- else 0 (zero)
+                                        * before H else dropped if in -TCH-
+                                        * else T
+                                        */
+                                       if (*(n + 1) == 'I' && (*(n + 2) == 'O' ||
+                                                          *(n + 2) == 'A'))
+                                               *Metaph++ = 'X';
+                                       else if (*(n + 1) == 'H')
+                                               *Metaph++ = '0';
+                                       else if (*(n + 1) != 'C' || *(n + 2) != 'H')
+                                               *Metaph++ = 'T';
+                                       break;
+                               case 'V':
+
+                                       /*
+                                        * F
+                                        */
+                                       *Metaph++ = 'F';
+                                       break;
+                               case 'W':
+
+                                       /*
+                                        * W after a vowel, else dropped
+                                        */
+                               case 'Y':
+
+                                       /*
+                                        * Y unless followed by a vowel
+                                        */
+                                       if (vowel(*(n + 1)))
+                                               *Metaph++ = *n;
+                                       break;
+                               case 'X':
+
+                                       /*
+                                        * KS
+                                        */
+                                       if (n == n_start)
+                                               *Metaph++ = 'S';
+                                       else {
+                                               *Metaph++ = 'K';        /* Insert K, then S */
+                                               KSflag = 1;
+                                       }
+                                       break;
+                               case 'Z':
+
+                                       /*
+                                        * S
+                                        */
+                                       *Metaph++ = 'S';
+                                       break;
+                               }
+               }
+       }
+
+       *Metaph = 0;            /* Null terminate */
+       return( strdup( buf ) );
+}
+
+#endif /* metaphone */
+#endif /* soundex */
diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h
new file mode 100644 (file)
index 0000000..a1ff6e5
--- /dev/null
@@ -0,0 +1,202 @@
+#ifndef _PROTO_SLAP
+#define _PROTO_SLAP
+
+/*
+ * acl.c
+ */
+
+int access_allowed( Backend *be, Connection *conn, Operation *op, Entry *e,
+       char *attr, struct berval *val, char *dn, int  access );
+struct acl * acl_get_applicable( Backend *be, Operation *op, Entry *e,
+       char *attr );
+int acl_access_allowed( struct acl *a, Backend *be, Connection *conn, Entry *e,
+       struct berval *val, Operation *op, int  access );
+int acl_check_mods( Backend *be, Connection *conn, Operation *op, Entry *e,
+       LDAPMod *mods );
+
+/*
+ * aclparse.c
+ */
+
+void parse_acl( Backend *be, char *fname, int lineno, int argc, char **argv );
+char * access2str( int access );
+int str2access( char *str );
+
+/*
+ * attr.c
+ */
+
+void attr_free( Attribute *a );
+char * attr_normalize( char *s );
+int attr_merge_fast( Entry *e, char *type, struct berval **vals, int  nvals,
+       int  naddvals, int  *maxvals, Attribute ***a );
+int attr_merge( Entry *e, char *type, struct berval **vals );
+Attribute * attr_find( Attribute *a, char *type );
+int attr_delete( Attribute **attrs, char *type );
+int attr_syntax( char *type );
+void attr_syntax_config( char *fname, int lineno, int argc, char **argv );
+
+/*
+ * ava.c
+ */
+
+int get_ava( BerElement *ber, Ava *ava );
+void ava_free( Ava *ava, int freeit );
+
+/*
+ * backend.c
+ */
+
+Backend * new_backend( char *type );
+Backend * select_backend( char * dn );
+int be_issuffix( Backend *be, char *suffix );
+int be_isroot( Backend *be, char *dn );
+int be_isroot_pw( Backend *be, char *dn, struct berval *cred );
+void be_close();
+
+/*
+ * ch_malloc.c
+ */
+
+char * ch_malloc( unsigned long size );
+char * ch_realloc( char *block, unsigned long size );
+char * ch_calloc( unsigned long nelem, unsigned long size );
+
+/*
+ * charray.c
+ */
+
+void charray_add( char ***a, char *s );
+void charray_merge( char ***a, char **s );
+void charray_free( char **array );
+int charray_inlist( char **a, char *s );
+char ** charray_dup( char **a );
+char ** str2charray( char *str, char *brkstr );
+
+/*
+ * config.c
+ */
+
+void read_config( char *fname, Backend **bep, FILE *pfp );
+
+/*
+ * connection.c
+ */
+
+void connection_activity( Connection *conn );
+
+/*
+ * dn.c
+ */
+
+char * dn_normalize( char *dn );
+char * dn_normalize_case( char *dn );
+char * dn_parent( Backend *be, char *dn );
+int dn_issuffix( char *dn, char *suffix );
+int dn_type( char *dn );
+char * dn_upcase( char *dn );
+
+/*
+ * entry.c
+ */
+
+Entry * str2entry( char        *s );
+char * entry2str( Entry *e, int *len, int printid );
+void entry_free( Entry *e );
+
+/*
+ * filter.c
+ */
+
+int get_filter( Connection *conn, BerElement *ber, Filter **filt, char **fstr );
+void filter_free( Filter *f );
+void filter_print( Filter *f );
+
+/*
+ * filterentry.c
+ */
+
+int test_filter( Backend *be, Connection *conn, Operation *op, Entry *e,
+       Filter  *f );
+
+/*
+ * lock.c
+ */
+
+FILE * lock_fopen( char *fname, char *type, FILE **lfp );
+int lock_fclose( FILE *fp, FILE *lfp );
+
+/*
+ * monitor.c
+ */
+
+void monitor_info( Connection *conn, Operation *op );
+
+/*
+ * operation.c
+ */
+
+void op_free( Operation *op );
+Operation * op_add( Operation **olist, BerElement *ber, unsigned long msgid,
+       unsigned long tag, char *dn, int id, int connid );
+void op_delete( Operation **olist, Operation *op );
+
+/*
+ * phonetic.c
+ */
+
+char * first_word( char *s );
+char * next_word( char *s );
+char * word_dup( char *w );
+char * phonetic( char *s );
+
+/*
+ * repl.c
+ */
+
+void replog( Backend *be, int optype, char *dn, void *change, int flag );
+
+/*
+ * result.c
+ */
+
+void send_ldap_result( Connection *conn, Operation *op, int err, char *matched,
+       char *text );
+void send_ldap_search_result( Connection *conn, Operation *op, int err,
+       char *matched, char *text, int nentries );
+void close_connection( Connection *conn, int opconnid, int opid );
+
+/*
+ * schema.c
+ */
+
+int oc_schema_check( Entry *e );
+
+/*
+ * schemaparse.c
+ */
+
+void parse_oc( Backend *be, char *fname, int lineno, int argc, char **argv );
+
+/*
+ * str2filter.c
+ */
+
+Filter * str2filter( char *str );
+
+/*
+ * value.c
+ */
+
+int value_add_fast( struct berval ***vals, struct berval **addvals, int nvals,
+       int naddvals, int *maxvals );
+int value_add( struct berval ***vals, struct berval **addvals );
+void value_normalize( char *s, int syntax );
+int value_cmp( struct berval *v1, struct berval *v2, int syntax,
+       int normalize );
+int value_ncmp( struct berval *v1, struct berval *v2, int syntax, int len,
+       int normalize );
+int value_find( struct berval **vals, struct berval *v, int syntax,
+       int normalize );
+
+#endif /* _proto_slap */
diff --git a/servers/slapd/regex.c b/servers/slapd/regex.c
new file mode 100644 (file)
index 0000000..42d2f41
--- /dev/null
@@ -0,0 +1,909 @@
+#include "portable.h"
+
+#if defined( MACOS ) || defined( DOS ) || defined( _WIN32 ) || defined( NEED_BSDREGEX )
+#include "regex.h"
+
+/*
+ * regex - Regular expression pattern matching  and replacement
+ *
+ * By:  Ozan S. Yigit (oz)
+ *      Dept. of Computer Science
+ *      York University
+ *
+ * These routines are the PUBLIC DOMAIN equivalents of regex
+ * routines as found in 4.nBSD UN*X, with minor extensions.
+ *
+ * These routines are derived from various implementations found
+ * in software tools books, and Conroy's grep. They are NOT derived
+ * from licensed/restricted software.
+ * For more interesting/academic/complicated implementations,
+ * see Henry Spencer's regexp routines, or GNU Emacs pattern
+ * matching module.
+ *
+ * Modification history:
+ *
+ * $Log: regex.c,v $
+ * Revision 1.2  1996/04/25  16:24:11  mcs
+ * make re_exec() match "" with ".*" and similar patterns
+ * hopefully this change doesn't break anything else!
+ *
+ * Revision 1.1  1995/02/03  15:56:52  tim
+ * Initial revision
+ *
+ * Revision 1.11  1994/12/14  21:33:45  mcs
+ * use new NEED_BSDREGEX
+ * fix pmatch() prototype
+ *
+ * Revision 1.10  1994/12/12  18:16:39  mcs
+ * use on NetBSD
+ *
+ * Revision 1.9  1994/11/15  19:16:35  mcs
+ * add (CHAR) cast to make VisualC++ happy
+ *
+ * Revision 1.8  1994/11/08  21:14:32  mcs
+ * WIN32 changes
+ *
+ * Revision 1.7  1994/07/23  19:51:24  mcs
+ * use ANSI-style inline function parameters
+ *
+ * Revision 1.6  1993/10/18  01:52:32  tim
+ * include for VMS
+ *
+ * Revision 1.5  1993/09/28  21:37:54  mcs
+ * HP/UX needs the regex we include (not in its libc)
+ *
+ * Revision 1.4  1993/08/27  15:59:52  mcs
+ * use CHAR for deftab
+ *
+ * Revision 1.3  1993/08/27  15:49:47  mcs
+ * added missing 0 to octal constants
+ * use unsigned char for CHAR under DOS
+ *
+ * Revision 1.2  1993/08/27  14:57:48  mcs
+ * add proto. for pmatch
+ *
+ * Revision 1.1  1993/08/18  21:20:02  mcs
+ * Initial revision
+ *
+ * Revision 1.4  1991/10/17  03:56:42  oz
+ * miscellaneous changes, small cleanups etc.
+ *
+ * Revision 1.3  1989/04/01  14:18:09  oz
+ * Change all references to a dfa: this is actually an nfa.
+ *
+ * Revision 1.2  88/08/28  15:36:04  oz
+ * Use a complement bitmap to represent NCL.
+ * This removes the need to have seperate 
+ * code in the pmatch case block - it is 
+ * just CCL code now.
+ * 
+ * Use the actual CCL code in the CLO
+ * section of pmatch. No need for a recursive
+ * pmatch call.
+ * 
+ * Use a bitmap table to set char bits in an
+ * 8-bit chunk.
+ * 
+ * Interfaces:
+ *      re_comp:        compile a regular expression into a NFA.
+ *
+ *                     char *re_comp(s)
+ *                     char *s;
+ *
+ *      re_exec:        execute the NFA to match a pattern.
+ *
+ *                     int re_exec(s)
+ *                     char *s;
+ *
+ *     re_modw         change re_exec's understanding of what a "word"
+ *                     looks like (for \< and \>) by adding into the
+ *                     hidden word-syntax table.
+ *
+ *                     void re_modw(s)
+ *                     char *s;
+ *
+ *      re_subs:       substitute the matched portions in a new string.
+ *
+ *                     int re_subs(src, dst)
+ *                     char *src;
+ *                     char *dst;
+ *
+ *     re_fail:        failure routine for re_exec.
+ *
+ *                     void re_fail(msg, op)
+ *                     char *msg;
+ *                     char op;
+ *  
+ * Regular Expressions:
+ *
+ *      [1]     char    matches itself, unless it is a special
+ *                      character (metachar): . \ [ ] * + ^ $
+ *
+ *      [2]     .       matches any character.
+ *
+ *      [3]     \       matches the character following it, except
+ *                     when followed by a left or right round bracket,
+ *                     a digit 1 to 9 or a left or right angle bracket. 
+ *                     (see [7], [8] and [9])
+ *                     It is used as an escape character for all 
+ *                     other meta-characters, and itself. When used
+ *                     in a set ([4]), it is treated as an ordinary
+ *                     character.
+ *
+ *      [4]     [set]   matches one of the characters in the set.
+ *                      If the first character in the set is "^",
+ *                      it matches a character NOT in the set, i.e. 
+ *                     complements the set. A shorthand S-E is 
+ *                     used to specify a set of characters S upto 
+ *                     E, inclusive. The special characters "]" and 
+ *                     "-" have no special meaning if they appear 
+ *                     as the first chars in the set.
+ *                      examples:        match:
+ *
+ *                              [a-z]    any lowercase alpha
+ *
+ *                              [^]-]    any char except ] and -
+ *
+ *                              [^A-Z]   any char except uppercase
+ *                                       alpha
+ *
+ *                              [a-zA-Z] any alpha
+ *
+ *      [5]     *       any regular expression form [1] to [4], followed by
+ *                      closure char (*) matches zero or more matches of
+ *                      that form.
+ *
+ *      [6]     +       same as [5], except it matches one or more.
+ *
+ *      [7]             a regular expression in the form [1] to [10], enclosed
+ *                      as \(form\) matches what form matches. The enclosure
+ *                      creates a set of tags, used for [8] and for
+ *                      pattern substution. The tagged forms are numbered
+ *                     starting from 1.
+ *
+ *      [8]             a \ followed by a digit 1 to 9 matches whatever a
+ *                      previously tagged regular expression ([7]) matched.
+ *
+ *     [9]     \<      a regular expression starting with a \< construct
+ *             \>      and/or ending with a \> construct, restricts the
+ *                     pattern matching to the beginning of a word, and/or
+ *                     the end of a word. A word is defined to be a character
+ *                     string beginning and/or ending with the characters
+ *                     A-Z a-z 0-9 and _. It must also be preceded and/or
+ *                     followed by any character outside those mentioned.
+ *
+ *      [10]            a composite regular expression xy where x and y
+ *                      are in the form [1] to [10] matches the longest
+ *                      match of x followed by a match for y.
+ *
+ *      [11]   ^       a regular expression starting with a ^ character
+ *             $       and/or ending with a $ character, restricts the
+ *                      pattern matching to the beginning of the line,
+ *                      or the end of line. [anchors] Elsewhere in the
+ *                     pattern, ^ and $ are treated as ordinary characters.
+ *
+ *
+ * Acknowledgements:
+ *
+ *     HCR's Hugh Redelmeier has been most helpful in various
+ *     stages of development. He convinced me to include BOW
+ *     and EOW constructs, originally invented by Rob Pike at
+ *     the University of Toronto.
+ *
+ * References:
+ *              Software tools                 Kernighan & Plauger
+ *              Software tools in Pascal        Kernighan & Plauger
+ *              Grep [rsx-11 C dist]            David Conroy
+ *             ed - text editor                Un*x Programmer's Manual
+ *             Advanced editing on Un*x        B. W. Kernighan
+ *             RegExp routines                 Henry Spencer
+ *
+ * Notes:
+ *
+ *     This implementation uses a bit-set representation for character
+ *     classes for speed and compactness. Each character is represented 
+ *     by one bit in a 128-bit block. Thus, CCL always takes a 
+ *     constant 16 bytes in the internal nfa, and re_exec does a single
+ *     bit comparison to locate the character in the set.
+ *
+ * Examples:
+ *
+ *     pattern:        foo*.*
+ *     compile:        CHR f CHR o CLO CHR o END CLO ANY END END
+ *     matches:        fo foo fooo foobar fobar foxx ...
+ *
+ *     pattern:        fo[ob]a[rz]     
+ *     compile:        CHR f CHR o CCL bitset CHR a CCL bitset END
+ *     matches:        fobar fooar fobaz fooaz
+ *
+ *     pattern:        foo\\+
+ *     compile:        CHR f CHR o CHR o CHR \ CLO CHR \ END END
+ *     matches:        foo\ foo\\ foo\\\  ...
+ *
+ *     pattern:        \(foo\)[1-3]\1  (same as foo[1-3]foo)
+ *     compile:        BOT 1 CHR f CHR o CHR o EOT 1 CCL bitset REF 1 END
+ *     matches:        foo1foo foo2foo foo3foo
+ *
+ *     pattern:        \(fo.*\)-\1
+ *     compile:        BOT 1 CHR f CHR o CLO ANY END EOT 1 CHR - REF 1 END
+ *     matches:        foo-foo fo-fo fob-fob foobar-foobar ...
+ */
+
+#define MAXNFA  1024
+#define MAXTAG  10
+
+#define OKP     1
+#define NOP     0
+
+#define CHR     1
+#define ANY     2
+#define CCL     3
+#define BOL     4
+#define EOL     5
+#define BOT     6
+#define EOT     7
+#define BOW    8
+#define EOW    9
+#define REF     10
+#define CLO     11
+
+#define END     0
+
+/*
+ * The following defines are not meant to be changeable.
+ * They are for readability only.
+ */
+#define MAXCHR 128
+#define CHRBIT 8
+#define BITBLK MAXCHR/CHRBIT
+#define BLKIND 0170
+#define BITIND 07
+
+#define ASCIIB 0177
+
+#if defined( DOS ) || defined( _WIN32 )
+typedef unsigned char CHAR;
+#else /* DOS */
+typedef /*unsigned*/ char CHAR;
+#endif /* DOS */
+
+static int  tagstk[MAXTAG];             /* subpat tag stack..*/
+static CHAR nfa[MAXNFA];               /* automaton..       */
+static int  sta = NOP;                 /* status of lastpat */
+
+static CHAR bittab[BITBLK];            /* bit table for CCL */
+                                       /* pre-set bits...   */
+static CHAR bitarr[] = {1,2,4,8,16,32,64,128};
+
+static void
+chset(CHAR c)
+{
+       bittab[((c) & BLKIND) >> 3] |= bitarr[(c) & BITIND];
+}
+
+#define badpat(x)      (*nfa = END, x)
+#define store(x)       *mp++ = x
+char *     
+re_comp( char *pat )
+{
+       register char *p;               /* pattern pointer   */
+       register CHAR *mp=nfa;          /* nfa pointer       */
+       register CHAR *lp;              /* saved pointer..   */
+       register CHAR *sp=nfa;          /* another one..     */
+
+       register int tagi = 0;          /* tag stack index   */
+       register int tagc = 1;          /* actual tag count  */
+
+       register int n;
+       register CHAR mask;             /* xor mask -CCL/NCL */
+       int c1, c2;
+               
+       if (!pat || !*pat)
+               if (sta)
+                       return 0;
+               else
+                       return badpat("No previous regular expression");
+       sta = NOP;
+
+       for (p = pat; *p; p++) {
+               lp = mp;
+               switch(*p) {
+
+               case '.':               /* match any char..  */
+                       store(ANY);
+                       break;
+
+               case '^':               /* match beginning.. */
+                       if (p == pat)
+                               store(BOL);
+                       else {
+                               store(CHR);
+                               store(*p);
+                       }
+                       break;
+
+               case '$':               /* match endofline.. */
+                       if (!*(p+1))
+                               store(EOL);
+                       else {
+                               store(CHR);
+                               store(*p);
+                       }
+                       break;
+
+               case '[':               /* match char class..*/
+                       store(CCL);
+
+                       if (*++p == '^') {
+                               mask = 0377;    
+                               p++;
+                       }
+                       else
+                               mask = 0;
+
+                       if (*p == '-')          /* real dash */
+                               chset(*p++);
+                       if (*p == ']')          /* real brac */
+                               chset(*p++);
+                       while (*p && *p != ']') {
+                               if (*p == '-' && *(p+1) && *(p+1) != ']') {
+                                       p++;
+                                       c1 = *(p-2) + 1;
+                                       c2 = *p++;
+                                       while (c1 <= c2)
+                                               chset((CHAR)c1++);
+                               }
+#ifdef EXTEND
+                               else if (*p == '\\' && *(p+1)) {
+                                       p++;
+                                       chset(*p++);
+                               }
+#endif
+                               else
+                                       chset(*p++);
+                       }
+                       if (!*p)
+                               return badpat("Missing ]");
+
+                       for (n = 0; n < BITBLK; bittab[n++] = (char) 0)
+                               store(mask ^ bittab[n]);
+       
+                       break;
+
+               case '*':               /* match 0 or more.. */
+               case '+':               /* match 1 or more.. */
+                       if (p == pat)
+                               return badpat("Empty closure");
+                       lp = sp;                /* previous opcode */
+                       if (*lp == CLO)         /* equivalence..   */
+                               break;
+                       switch(*lp) {
+
+                       case BOL:
+                       case BOT:
+                       case EOT:
+                       case BOW:
+                       case EOW:
+                       case REF:
+                               return badpat("Illegal closure");
+                       default:
+                               break;
+                       }
+
+                       if (*p == '+')
+                               for (sp = mp; lp < sp; lp++)
+                                       store(*lp);
+
+                       store(END);
+                       store(END);
+                       sp = mp;
+                       while (--mp > lp)
+                               *mp = mp[-1];
+                       store(CLO);
+                       mp = sp;
+                       break;
+
+               case '\\':              /* tags, backrefs .. */
+                       switch(*++p) {
+
+                       case '(':
+                               if (tagc < MAXTAG) {
+                                       tagstk[++tagi] = tagc;
+                                       store(BOT);
+                                       store(tagc++);
+                               }
+                               else
+                                       return badpat("Too many \\(\\) pairs");
+                               break;
+                       case ')':
+                               if (*sp == BOT)
+                                       return badpat("Null pattern inside \\(\\)");
+                               if (tagi > 0) {
+                                       store(EOT);
+                                       store(tagstk[tagi--]);
+                               }
+                               else
+                                       return badpat("Unmatched \\)");
+                               break;
+                       case '<':
+                               store(BOW);
+                               break;
+                       case '>':
+                               if (*sp == BOW)
+                                       return badpat("Null pattern inside \\<\\>");
+                               store(EOW);
+                               break;
+                       case '1':
+                       case '2':
+                       case '3':
+                       case '4':
+                       case '5':
+                       case '6':
+                       case '7':
+                       case '8':
+                       case '9':
+                               n = *p-'0';
+                               if (tagi > 0 && tagstk[tagi] == n)
+                                       return badpat("Cyclical reference");
+                               if (tagc > n) {
+                                       store(REF);
+                                       store(n);
+                               }
+                               else
+                                       return badpat("Undetermined reference");
+                               break;
+#ifdef EXTEND
+                       case 'b':
+                               store(CHR);
+                               store('\b');
+                               break;
+                       case 'n':
+                               store(CHR);
+                               store('\n');
+                               break;
+                       case 'f':
+                               store(CHR);
+                               store('\f');
+                               break;
+                       case 'r':
+                               store(CHR);
+                               store('\r');
+                               break;
+                       case 't':
+                               store(CHR);
+                               store('\t');
+                               break;
+#endif
+                       default:
+                               store(CHR);
+                               store(*p);
+                       }
+                       break;
+
+               default :               /* an ordinary char  */
+                       store(CHR);
+                       store(*p);
+                       break;
+               }
+               sp = lp;
+       }
+       if (tagi > 0)
+               return badpat("Unmatched \\(");
+       store(END);
+       sta = OKP;
+       return 0;
+}
+
+
+static char *bol;
+char *bopat[MAXTAG];
+char *eopat[MAXTAG];
+#ifdef NEEDPROTOS
+static char *pmatch( char *lp, CHAR *ap );
+#else /* NEEDPROTOS */
+static char *pmatch();
+#endif /* NEEDPROTOS */
+
+/*
+ * re_exec:
+ *     execute nfa to find a match.
+ *
+ *     special cases: (nfa[0]) 
+ *             BOL
+ *                     Match only once, starting from the
+ *                     beginning.
+ *             CHR
+ *                     First locate the character without
+ *                     calling pmatch, and if found, call
+ *                     pmatch for the remaining string.
+ *             END
+ *                     re_comp failed, poor luser did not
+ *                     check for it. Fail fast.
+ *
+ *     If a match is found, bopat[0] and eopat[0] are set
+ *     to the beginning and the end of the matched fragment,
+ *     respectively.
+ *
+ */
+
+int
+re_exec( char *lp )
+{
+       register char c;
+       register char *ep = 0;
+       register CHAR *ap = nfa;
+
+       bol = lp;
+
+       bopat[0] = 0;
+       bopat[1] = 0;
+       bopat[2] = 0;
+       bopat[3] = 0;
+       bopat[4] = 0;
+       bopat[5] = 0;
+       bopat[6] = 0;
+       bopat[7] = 0;
+       bopat[8] = 0;
+       bopat[9] = 0;
+
+       switch(*ap) {
+
+       case BOL:                       /* anchored: match from BOL only */
+               ep = pmatch(lp,ap);
+               break;
+       case CHR:                       /* ordinary char: locate it fast */
+               c = *(ap+1);
+               while (*lp && *lp != c)
+                       lp++;
+               if (!*lp)               /* if EOS, fail, else fall thru. */
+                       return 0;
+       default:                        /* regular matching all the way. */
+               do {
+                       if ((ep = pmatch(lp,ap)))
+                               break;
+                       lp++;
+               } while (*lp);
+
+               break;
+       case END:                       /* munged automaton. fail always */
+               return 0;
+       }
+       if (!ep)
+               return 0;
+
+       bopat[0] = lp;
+       eopat[0] = ep;
+       return 1;
+}
+
+/* 
+ * pmatch: internal routine for the hard part
+ *
+ *     This code is partly snarfed from an early grep written by
+ *     David Conroy. The backref and tag stuff, and various other
+ *     innovations are by oz.
+ *
+ *     special case optimizations: (nfa[n], nfa[n+1])
+ *             CLO ANY
+ *                     We KNOW .* will match everything upto the
+ *                     end of line. Thus, directly go to the end of
+ *                     line, without recursive pmatch calls. As in
+ *                     the other closure cases, the remaining pattern
+ *                     must be matched by moving backwards on the
+ *                     string recursively, to find a match for xy
+ *                     (x is ".*" and y is the remaining pattern)
+ *                     where the match satisfies the LONGEST match for
+ *                     x followed by a match for y.
+ *             CLO CHR
+ *                     We can again scan the string forward for the
+ *                     single char and at the point of failure, we
+ *                     execute the remaining nfa recursively, same as
+ *                     above.
+ *
+ *     At the end of a successful match, bopat[n] and eopat[n]
+ *     are set to the beginning and end of subpatterns matched
+ *     by tagged expressions (n = 1 to 9).     
+ *
+ */
+
+#ifndef re_fail
+extern void re_fail();
+#endif /* re_fail */
+
+/*
+ * character classification table for word boundary operators BOW
+ * and EOW. the reason for not using ctype macros is that we can
+ * let the user add into our own table. see re_modw. This table
+ * is not in the bitset form, since we may wish to extend it in the
+ * future for other character classifications. 
+ *
+ *     TRUE for 0-9 A-Z a-z _
+ */
+static char chrtyp[MAXCHR] = {
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 
+       0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 0, 0, 0, 0, 0
+       };
+
+#define inascii(x)     (0177&(x))
+#define iswordc(x)     chrtyp[inascii(x)]
+#define isinset(x,y)   ((x)[((y)&BLKIND)>>3] & bitarr[(y)&BITIND])
+
+/*
+ * skip values for CLO XXX to skip past the closure
+ */
+
+#define ANYSKIP        2       /* [CLO] ANY END ...         */
+#define CHRSKIP        3       /* [CLO] CHR chr END ...     */
+#define CCLSKIP 18     /* [CLO] CCL 16bytes END ... */
+
+static char *
+pmatch( char *lp, CHAR *ap)
+{
+       register int op, c, n;
+       register char *e;               /* extra pointer for CLO */
+       register char *bp;              /* beginning of subpat.. */
+       register char *ep;              /* ending of subpat..    */
+       char *are;                      /* to save the line ptr. */
+
+       while ((op = *ap++) != END)
+               switch(op) {
+
+               case CHR:
+                       if (*lp++ != *ap++)
+                               return 0;
+                       break;
+               case ANY:
+                       if (!*lp++)
+                               return 0;
+                       break;
+               case CCL:
+                       c = *lp++;
+                       if (!isinset(ap,c))
+                               return 0;
+                       ap += BITBLK;
+                       break;
+               case BOL:
+                       if (lp != bol)
+                               return 0;
+                       break;
+               case EOL:
+                       if (*lp)
+                               return 0;
+                       break;
+               case BOT:
+                       bopat[*ap++] = lp;
+                       break;
+               case EOT:
+                       eopat[*ap++] = lp;
+                       break;
+               case BOW:
+                       if (lp!=bol && iswordc(lp[-1]) || !iswordc(*lp))
+                               return 0;
+                       break;
+               case EOW:
+                       if (lp==bol || !iswordc(lp[-1]) || iswordc(*lp))
+                               return 0;
+                       break;
+               case REF:
+                       n = *ap++;
+                       bp = bopat[n];
+                       ep = eopat[n];
+                       while (bp < ep)
+                               if (*bp++ != *lp++)
+                                       return 0;
+                       break;
+               case CLO:
+                       are = lp;
+                       switch(*ap) {
+
+                       case ANY:
+                               while (*lp)
+                                       lp++;
+                               n = ANYSKIP;
+                               break;
+                       case CHR:
+                               c = *(ap+1);
+                               while (*lp && c == *lp)
+                                       lp++;
+                               n = CHRSKIP;
+                               break;
+                       case CCL:
+                               while ((c = *lp) && isinset(ap+1,c))
+                                       lp++;
+                               n = CCLSKIP;
+                               break;
+                       default:
+                               re_fail("closure: bad nfa.", *ap);
+                               return 0;
+                       }
+
+                       ap += n;
+
+                       while (lp >= are) {
+                               if (e = pmatch(lp, ap))
+                                       return e;
+                               --lp;
+                       }
+                       return 0;
+               default:
+                       re_fail("re_exec: bad nfa.", op);
+                       return 0;
+               }
+       return lp;
+}
+
+/*
+ * re_modw:
+ *     add new characters into the word table to change re_exec's
+ *     understanding of what a word should look like. Note that we
+ *     only accept additions into the word definition.
+ *
+ *     If the string parameter is 0 or null string, the table is
+ *     reset back to the default containing A-Z a-z 0-9 _. [We use
+ *     the compact bitset representation for the default table]
+ */
+
+static CHAR deftab[16] = {     
+       0, 0, 0, 0, 0, 0, 0377, 003, 0376, 0377, 0377, 0207,  
+       0376, 0377, 0377, 007 
+}; 
+
+void
+re_modw( char *s )
+{
+       register int i;
+
+       if (!s || !*s) {
+               for (i = 0; i < MAXCHR; i++)
+                       if (!isinset(deftab,i))
+                               iswordc(i) = 0;
+       }
+       else
+               while(*s)
+                       iswordc(*s++) = 1;
+}
+
+/*
+ * re_subs:
+ *     substitute the matched portions of the src in dst.
+ *
+ *     &       substitute the entire matched pattern.
+ *
+ *     \digit  substitute a subpattern, with the given tag number.
+ *             Tags are numbered from 1 to 9. If the particular
+ *             tagged subpattern does not exist, null is substituted.
+ */
+int
+re_subs( char *src, char *dst)
+{
+       register char c;
+       register int  pin;
+       register char *bp;
+       register char *ep;
+
+       if (!*src || !bopat[0])
+               return 0;
+
+       while (c = *src++) {
+               switch(c) {
+
+               case '&':
+                       pin = 0;
+                       break;
+
+               case '\\':
+                       c = *src++;
+                       if (c >= '0' && c <= '9') {
+                               pin = c - '0';
+                               break;
+                       }
+                       
+               default:
+                       *dst++ = c;
+                       continue;
+               }
+
+               if ((bp = bopat[pin]) && (ep = eopat[pin])) {
+                       while (*bp && bp < ep)
+                               *dst++ = *bp++;
+                       if (bp < ep)
+                               return 0;
+               }
+       }
+       *dst = (char) 0;
+       return 1;
+}
+                       
+#ifdef DEBUG
+/*
+ * symbolic - produce a symbolic dump of the nfa
+ */
+symbolic( char *s ) 
+{
+       printf("pattern: %s\n", s);
+       printf("nfacode:\n");
+       nfadump(nfa);
+}
+
+static 
+nfadump( CHAR *ap)
+{
+       register int n;
+
+       while (*ap != END)
+               switch(*ap++) {
+               case CLO:
+                       printf("CLOSURE");
+                       nfadump(ap);
+                       switch(*ap) {
+                       case CHR:
+                               n = CHRSKIP;
+                               break;
+                       case ANY:
+                               n = ANYSKIP;
+                               break;
+                       case CCL:
+                               n = CCLSKIP;
+                               break;
+                       }
+                       ap += n;
+                       break;
+               case CHR:
+                       printf("\tCHR %c\n",*ap++);
+                       break;
+               case ANY:
+                       printf("\tANY .\n");
+                       break;
+               case BOL:
+                       printf("\tBOL -\n");
+                       break;
+               case EOL:
+                       printf("\tEOL -\n");
+                       break;
+               case BOT:
+                       printf("BOT: %d\n",*ap++);
+                       break;
+               case EOT:
+                       printf("EOT: %d\n",*ap++);
+                       break;
+               case BOW:
+                       printf("BOW\n");
+                       break;
+               case EOW:
+                       printf("EOW\n");
+                       break;
+               case REF:
+                       printf("REF: %d\n",*ap++);
+                       break;
+               case CCL:
+                       printf("\tCCL [");
+                       for (n = 0; n < MAXCHR; n++)
+                               if (isinset(ap,(CHAR)n)) {
+                                       if (n < ' ')
+                                               printf("^%c", n ^ 0x040);
+                                       else
+                                               printf("%c", n);
+                               }
+                       printf("]\n");
+                       ap += BITBLK;
+                       break;
+               default:
+                       printf("bad nfa. opcode %o\n", ap[-1]);
+                       exit(1);
+                       break;
+               }
+}
+#endif
+#endif /* MACOS or DOS or NEED_BSDREGEX */
diff --git a/servers/slapd/repl.c b/servers/slapd/repl.c
new file mode 100644 (file)
index 0000000..028b191
--- /dev/null
@@ -0,0 +1,124 @@
+/* repl.c - log modifications for replication purposes */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <slap.h>
+
+extern pthread_mutex_t replog_mutex;
+extern pthread_mutex_t entry2str_mutex;
+extern time_t          currenttime;
+extern char            *replogfile;
+
+extern FILE    *lock_fopen();
+extern int     lock_fclose();
+extern char    *ch_malloc();
+extern char    *entry2str();
+
+void
+replog(
+    Backend    *be,
+    int                optype,
+    char       *dn,
+    void       *change,
+    int                flag
+)
+{
+       LDAPMod *mods;
+       Entry   *e;
+       char    *newrdn, *tmp;
+       int     deleteoldrdn;
+       FILE    *fp, *lfp;
+       int     len, i;
+
+       if ( be->be_replogfile == NULL && replogfile == NULL ) {
+               return;
+       }
+
+       pthread_mutex_lock( &replog_mutex );
+       if ( (fp = lock_fopen( be->be_replogfile ? be->be_replogfile :
+           replogfile, "a", &lfp )) == NULL ) {
+               pthread_mutex_unlock( &replog_mutex );
+               return;
+       }
+
+       for ( i = 0; be->be_replica != NULL && be->be_replica[i] != NULL;
+           i++ ) {
+               fprintf( fp, "replica: %s\n", be->be_replica[i] );
+       }
+       fprintf( fp, "time: %ld\n", currenttime );
+       fprintf( fp, "dn: %s\n", dn );
+
+       switch ( optype ) {
+       case LDAP_REQ_MODIFY:
+               fprintf( fp, "changetype: modify\n" );
+               mods = change;
+               for ( ; mods != NULL; mods = mods->mod_next ) {
+                       switch ( mods->mod_op & ~LDAP_MOD_BVALUES ) {
+                       case LDAP_MOD_ADD:
+                               fprintf( fp, "add: %s\n", mods->mod_type );
+                               break;
+
+                       case LDAP_MOD_DELETE:
+                               fprintf( fp, "delete: %s\n", mods->mod_type );
+                               break;
+
+                       case LDAP_MOD_REPLACE:
+                               fprintf( fp, "replace: %s\n", mods->mod_type );
+                               break;
+                       }
+
+                       for ( i = 0; mods->mod_bvalues != NULL &&
+                           mods->mod_bvalues[i] != NULL; i++ ) {
+                               char    *buf, *bufp;
+
+                               len = strlen( mods->mod_type );
+                               len = LDIF_SIZE_NEEDED( len,
+                                   mods->mod_bvalues[i]->bv_len ) + 1;
+                               buf = ch_malloc( len );
+
+                               bufp = buf;
+                               put_type_and_value( &bufp, mods->mod_type,
+                                   mods->mod_bvalues[i]->bv_val,
+                                   mods->mod_bvalues[i]->bv_len );
+                               *bufp = '\0';
+
+                               fputs( buf, fp );
+
+                               free( buf );
+                       }
+                       fprintf( fp, "-\n" );
+               }
+               break;
+
+       case LDAP_REQ_ADD:
+               e = change;
+               fprintf( fp, "changetype: add\n" );
+               pthread_mutex_lock( &entry2str_mutex );
+               tmp = entry2str( e, &len, 0 );
+               while ( (tmp = strchr( tmp, '\n' )) != NULL ) {
+                       tmp++;
+                       if ( ! isspace( *tmp ) )
+                               break;
+               }
+               fprintf( fp, "%s", tmp );
+               pthread_mutex_unlock( &entry2str_mutex );
+               break;
+
+       case LDAP_REQ_DELETE:
+               fprintf( fp, "changetype: delete\n" );
+               break;
+
+       case LDAP_REQ_MODRDN:
+               newrdn = change;
+               fprintf( fp, "changetype: modrdn\n" );
+               fprintf( fp, "newrdn: %s\n", newrdn );
+               fprintf( fp, "deleteoldrdn: %d\n", flag ? 1 : 0 );
+       }
+       fprintf( fp, "\n" );
+
+       lock_fclose( fp, lfp );
+       pthread_mutex_unlock( &replog_mutex );
+}
diff --git a/servers/slapd/result.c b/servers/slapd/result.c
new file mode 100644 (file)
index 0000000..0ef82a7
--- /dev/null
@@ -0,0 +1,434 @@
+/* result.c - routines to send ldap results, errors, and referrals */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <signal.h>
+#include "portable.h"
+#include "slap.h"
+
+#ifndef SYSERRLIST_IN_STDIO
+extern int             sys_nerr;
+extern char            *sys_errlist[];
+#endif
+extern int             active_threads;
+extern pthread_mutex_t active_threads_mutex;
+extern pthread_mutex_t new_conn_mutex;
+extern pthread_t       listener_tid;
+extern struct acl      *acl_get_applicable();
+extern long            num_entries_sent;
+extern long            num_bytes_sent;
+extern pthread_mutex_t num_sent_mutex;
+
+void   close_connection();
+
+static void
+send_ldap_result2(
+    Connection *conn,
+    Operation  *op,
+    int                err,
+    char       *matched,
+    char       *text,
+    int                nentries
+)
+{
+       BerElement      *ber;
+       int             rc, sd;
+       unsigned long   tag, bytes;
+
+       Debug( LDAP_DEBUG_TRACE, "send_ldap_result %d:%s:%s\n", err, matched ?
+           matched : "", text ? text : "" );
+
+       switch ( op->o_tag ) {
+       case LBER_DEFAULT:
+               tag = LBER_SEQUENCE;
+               break;
+
+       case LDAP_REQ_SEARCH:
+               tag = LDAP_RES_SEARCH_RESULT;
+               break;
+
+       case LDAP_REQ_DELETE:
+               tag = LDAP_RES_DELETE;
+               break;
+
+       default:
+               tag = op->o_tag + 1;
+               break;
+       }
+
+#ifdef COMPAT30
+       if ( (ber = ber_alloc_t( conn->c_version == 30 ? 0 : LBER_USE_DER ))
+           == NULLBER ) {
+#else
+       if ( (ber = der_alloc()) == NULLBER ) {
+#endif
+               Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
+               return;
+       }
+
+#ifdef CLDAP
+       if ( op->o_cldap ) {
+               rc = ber_printf( ber, "{is{t{ess}}}", op->o_msgid, "", tag,
+                   err, matched ? matched : "", text ? text : "" );
+       } else
+#endif
+#ifdef COMPAT30
+       if ( conn->c_version == 30 ) {
+               rc = ber_printf( ber, "{it{{ess}}}", op->o_msgid, tag, err,
+                   matched ? matched : "", text ? text : "" );
+       } else
+#endif
+               rc = ber_printf( ber, "{it{ess}}", op->o_msgid, tag, err,
+                   matched ? matched : "", text ? text : "" );
+
+       if ( rc == -1 ) {
+               Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
+               return;
+       }
+
+       /* write only one pdu at a time - wait til it's our turn */
+       pthread_mutex_lock( &conn->c_pdumutex );
+
+       /* write the pdu */
+       bytes = ber->ber_ptr - ber->ber_buf;
+       pthread_mutex_lock( &new_conn_mutex );
+       while ( conn->c_connid == op->o_connid && ber_flush( &conn->c_sb, ber,
+           1 ) != 0 ) {
+               pthread_mutex_unlock( &new_conn_mutex );
+               /*
+                * we got an error.  if it's ewouldblock, we need to
+                * wait on the socket being writable.  otherwise, figure
+                * it's a hard error and return.
+                */
+
+               Debug( LDAP_DEBUG_CONNS, "ber_flush failed errno %d msg (%s)\n",
+                   errno, errno > -1 && errno < sys_nerr ? sys_errlist[errno]
+                   : "unknown", 0 );
+
+               if ( errno != EWOULDBLOCK && errno != EAGAIN ) {
+                       close_connection( conn, op->o_connid, op->o_opid );
+
+                       pthread_mutex_unlock( &conn->c_pdumutex );
+                       return;
+               }
+
+               /* wait for socket to be write-ready */
+               pthread_mutex_lock( &active_threads_mutex );
+               active_threads--;
+               conn->c_writewaiter = 1;
+               pthread_kill( listener_tid, SIGUSR1 );
+               pthread_cond_wait( &conn->c_wcv, &active_threads_mutex );
+               pthread_mutex_unlock( &active_threads_mutex );
+
+               pthread_yield();
+               pthread_mutex_lock( &new_conn_mutex );
+       }
+       pthread_mutex_unlock( &new_conn_mutex );
+       pthread_mutex_unlock( &conn->c_pdumutex );
+
+       pthread_mutex_lock( &num_sent_mutex );
+       num_bytes_sent += bytes;
+       pthread_mutex_unlock( &num_sent_mutex );
+
+       Statslog( LDAP_DEBUG_STATS,
+           "conn=%d op=%d RESULT err=%d tag=%d nentries=%d\n", conn->c_connid,
+           op->o_opid, err, tag, nentries );
+
+       return;
+}
+
+void
+send_ldap_result(
+    Connection *conn,
+    Operation  *op,
+    int                err,
+    char       *matched,
+    char       *text
+)
+{
+#ifdef CLDAP
+       if ( op->o_cldap ) {
+               SAFEMEMCPY( (char *)conn->c_sb.sb_useaddr, &op->o_clientaddr,
+                   sizeof( struct sockaddr ));
+               Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
+                   inet_ntoa(((struct sockaddr_in *)
+                   conn->c_sb.sb_useaddr)->sin_addr ),
+                   ((struct sockaddr_in *) conn->c_sb.sb_useaddr)->sin_port,
+                   0 );
+       }
+#endif
+       send_ldap_result2( conn, op, err, matched, text, 0 );
+}
+
+void
+send_ldap_search_result(
+    Connection *conn,
+    Operation  *op,
+    int                err,
+    char       *matched,
+    char       *text,
+    int                nentries
+)
+{
+       send_ldap_result2( conn, op, err, matched, text, nentries );
+}
+
+int
+send_search_entry(
+    Backend    *be,
+    Connection *conn,
+    Operation  *op,
+    Entry      *e,
+    char       **attrs,
+    int                attrsonly
+)
+{
+       BerElement      *ber;
+       Attribute       *a;
+       int             i, rc, bytes, sd;
+       struct acl      *acl;
+
+       Debug( LDAP_DEBUG_TRACE, "=> send_search_entry (%s)\n", e->e_dn, 0, 0 );
+
+       if ( ! access_allowed( be, conn, op, e, "entry", NULL, op->o_dn,
+           ACL_READ ) ) {
+               Debug( LDAP_DEBUG_ACL, "acl: access to entry not allowed\n",
+                   0, 0, 0 );
+               return( 1 );
+       }
+
+#ifdef COMPAT30
+       if ( (ber = ber_alloc_t( conn->c_version == 30 ? 0 : LBER_USE_DER ))
+           == NULLBER ) {
+#else
+       if ( (ber = der_alloc()) == NULLBER ) {
+#endif
+               Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL,
+                   "ber_alloc" );
+               return( 1 );
+       }
+
+#ifdef COMPAT30
+       if ( conn->c_version == 30 ) {
+               rc = ber_printf( ber, "{it{{s{", op->o_msgid,
+                   LDAP_RES_SEARCH_ENTRY, e->e_dn );
+       } else
+#endif
+               rc = ber_printf( ber, "{it{s{", op->o_msgid,
+                   LDAP_RES_SEARCH_ENTRY, e->e_dn );
+
+       if ( rc == -1 ) {
+               Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
+               ber_free( ber, 1 );
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL,
+                   "ber_printf dn" );
+               return( 1 );
+       }
+
+       for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
+               if ( attrs != NULL && ! charray_inlist( attrs, a->a_type ) ) {
+                       continue;
+               }
+
+               acl = acl_get_applicable( be, op, e, a->a_type );
+
+               if ( ! acl_access_allowed( acl, be, conn, e, NULL, op,
+                   ACL_READ ) ) {
+                       continue;
+               }
+
+               if ( ber_printf( ber, "{s[", a->a_type ) == -1 ) {
+                       Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
+                       ber_free( ber, 1 );
+                       send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+                           NULL, "ber_printf type" );
+                       return( 1 );
+               }
+
+               if ( ! attrsonly ) {
+                       for ( i = 0; a->a_vals[i] != NULL; i++ ) {
+                               if ( a->a_syntax & SYNTAX_DN &&
+                                   ! acl_access_allowed( acl, be, conn, e,
+                                   a->a_vals[i], op, ACL_READ ) )
+                               {
+                                       continue;
+                               }
+
+                               if ( ber_printf( ber, "o",
+                                   a->a_vals[i]->bv_val,
+                                   a->a_vals[i]->bv_len ) == -1 )
+                               {
+                                       Debug( LDAP_DEBUG_ANY,
+                                           "ber_printf failed\n", 0, 0, 0 );
+                                       ber_free( ber, 1 );
+                                       send_ldap_result( conn, op,
+                                           LDAP_OPERATIONS_ERROR, NULL,
+                                           "ber_printf value" );
+                                       return( 1 );
+                               }
+                       }
+               }
+
+               if ( ber_printf( ber, "]}" ) == -1 ) {
+                       Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
+                       ber_free( ber, 1 );
+                       send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+                           NULL, "ber_printf type end" );
+                       return( 1 );
+               }
+       }
+
+#ifdef COMPAT30
+       if ( conn->c_version == 30 ) {
+               rc = ber_printf( ber, "}}}}" );
+       } else
+#endif
+               rc = ber_printf( ber, "}}}" );
+
+       if ( rc == -1 ) {
+               Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
+               ber_free( ber, 1 );
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL,
+                   "ber_printf entry end" );
+               return( 1 );
+       }
+
+       /* write only one pdu at a time - wait til it's our turn */
+       pthread_mutex_lock( &conn->c_pdumutex );
+
+       bytes = ber->ber_ptr - ber->ber_buf;
+       pthread_mutex_lock( &new_conn_mutex );
+       while ( conn->c_connid == op->o_connid && ber_flush( &conn->c_sb, ber,
+           1 ) != 0 ) {
+               pthread_mutex_unlock( &new_conn_mutex );
+               /*
+                * we got an error.  if it's ewouldblock, we need to
+                * wait on the socket being writable.  otherwise, figure
+                * it's a hard error and return.
+                */
+
+               Debug( LDAP_DEBUG_CONNS, "ber_flush failed errno %d msg (%s)\n",
+                   errno, errno > -1 && errno < sys_nerr ? sys_errlist[errno]
+                   : "unknown", 0 );
+
+               if ( errno != EWOULDBLOCK && errno != EAGAIN ) {
+                       close_connection( conn, op->o_connid, op->o_opid );
+
+                       pthread_mutex_unlock( &conn->c_pdumutex );
+                       return( -1 );
+               }
+
+               /* wait for socket to be write-ready */
+               pthread_mutex_lock( &active_threads_mutex );
+               active_threads--;
+               conn->c_writewaiter = 1;
+               pthread_kill( listener_tid, SIGUSR1 );
+               pthread_cond_wait( &conn->c_wcv, &active_threads_mutex );
+               pthread_mutex_unlock( &active_threads_mutex );
+
+               pthread_yield();
+               pthread_mutex_lock( &new_conn_mutex );
+       }
+       pthread_mutex_unlock( &new_conn_mutex );
+       pthread_mutex_unlock( &conn->c_pdumutex );
+
+       pthread_mutex_lock( &num_sent_mutex );
+       num_bytes_sent += bytes;
+       num_entries_sent++;
+       pthread_mutex_unlock( &num_sent_mutex );
+
+       pthread_mutex_lock( &new_conn_mutex );
+       if ( conn->c_connid == op->o_connid ) {
+               rc = 0;
+               Statslog( LDAP_DEBUG_STATS2, "conn=%d op=%d ENTRY dn=\"%s\"\n",
+                   conn->c_connid, op->o_opid, e->e_dn, 0, 0 );
+       } else {
+               rc = -1;
+       }
+       pthread_mutex_unlock( &new_conn_mutex );
+
+       Debug( LDAP_DEBUG_TRACE, "<= send_search_entry\n", 0, 0, 0 );
+
+       return( rc );
+}
+
+int
+str2result(
+    char       *s,
+    int                *code,
+    char       **matched,
+    char       **info
+)
+{
+       int     rc;
+       char    *c;
+
+       *code = LDAP_SUCCESS;
+       *matched = NULL;
+       *info = NULL;
+
+       if ( strncasecmp( s, "RESULT", 6 ) != 0 ) {
+               Debug( LDAP_DEBUG_ANY, "str2result (%s) expecting \"RESULT\"\n",
+                   s, 0, 0 );
+
+               return( -1 );
+       }
+
+       rc = 0;
+       while ( (s = strchr( s, '\n' )) != NULL ) {
+               *s++ = '\0';
+               if ( *s == '\0' ) {
+                       break;
+               }
+               if ( (c = strchr( s, ':' )) != NULL ) {
+                       c++;
+               }
+
+               if ( strncasecmp( s, "code", 4 ) == 0 ) {
+                       if ( c != NULL ) {
+                               *code = atoi( c );
+                       }
+               } else if ( strncasecmp( s, "matched", 7 ) == 0 ) {
+                       if ( c != NULL ) {
+                               *matched = c;
+                       }
+               } else if ( strncasecmp( s, "info", 4 ) == 0 ) {
+                       if ( c != NULL ) {
+                               *info = c;
+                       }
+               } else {
+                       Debug( LDAP_DEBUG_ANY, "str2result (%s) unknown\n",
+                           s, 0, 0 );
+                       rc = -1;
+               }
+       }
+
+       return( rc );
+}
+
+/*
+ * close_connection - close a connection. takes the connection to close,
+ * the connid associated with the operation generating the close (so we
+ * don't accidentally close a connection that's not ours), and the opid
+ * of the operation generating the close (for logging purposes).
+ */
+void
+close_connection( Connection *conn, int opconnid, int opid )
+{
+       pthread_mutex_lock( &new_conn_mutex );
+       if ( conn->c_sb.sb_sd != -1 && conn->c_connid == opconnid ) {
+               Statslog( LDAP_DEBUG_STATS,
+                   "conn=%d op=%d fd=%d closed errno=%d\n", conn->c_connid,
+                   opid, conn->c_sb.sb_sd, errno, 0 );
+               close( conn->c_sb.sb_sd );
+               conn->c_sb.sb_sd = -1;
+               conn->c_version = 0;
+       }
+       pthread_mutex_unlock( &new_conn_mutex );
+}
diff --git a/servers/slapd/schema.c b/servers/slapd/schema.c
new file mode 100644 (file)
index 0000000..ba16d9b
--- /dev/null
@@ -0,0 +1,179 @@
+/* schema.c - routines to enforce schema definitions */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+
+extern Attribute       *attr_find();
+extern char            **str2charray();
+extern void            charray_merge();
+
+extern struct objclass *global_oc;
+extern int             global_schemacheck;
+
+static struct objclass *oc_find();
+static int             oc_check_required();
+static int             oc_check_allowed();
+
+/*
+ * oc_check - check that entry e conforms to the schema required by
+ * its object class(es). returns 0 if so, non-zero otherwise.
+ */
+
+int
+oc_schema_check( Entry *e )
+{
+       Attribute       *a, *aoc;
+       struct objclass *oc;
+       int             i;
+       int             ret = 0;
+
+       /* find the object class attribute - could error out here */
+       if ( (aoc = attr_find( e->e_attrs, "objectclass" )) == NULL ) {
+               Debug( LDAP_DEBUG_ANY, "No object class for entry (%s)\n",
+                   e->e_dn, 0, 0 );
+               return( 0 );
+       }
+
+       /* check that the entry has required attrs for each oc */
+       for ( i = 0; aoc->a_vals[i] != NULL; i++ ) {
+               if ( oc_check_required( e, aoc->a_vals[i]->bv_val ) != 0 ) {
+                       Debug( LDAP_DEBUG_ANY,
+                           "Entry (%s), required attr (%s) missing\n",
+                           e->e_dn, aoc->a_vals[i]->bv_val, 0 );
+                       ret = 1;
+               }
+       }
+
+       if ( ret != 0 ) {
+           return( ret );
+       }
+
+       /* check that each attr in the entry is allowed by some oc */
+       for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
+               if ( oc_check_allowed( a->a_type, aoc->a_vals ) != 0 ) {
+                       Debug( LDAP_DEBUG_ANY,
+                           "Entry (%s), attr (%s) not allowed\n",
+                           e->e_dn, a->a_type, 0 );
+                       ret = 1;
+               }
+       }
+
+       return( ret );
+}
+
+static int
+oc_check_required( Entry *e, char *ocname )
+{
+       struct objclass *oc;
+       int             i;
+       Attribute       *a;
+
+       /* find global oc defn. it we don't know about it assume it's ok */
+       if ( (oc = oc_find( ocname )) == NULL ) {
+               return( 0 );
+       }
+
+       /* for each required attribute */
+       for ( i = 0; oc->oc_required[i] != NULL; i++ ) {
+               /* see if it's in the entry */
+               for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
+                       if ( strcasecmp( a->a_type, oc->oc_required[i] )
+                           == 0 ) {
+                               break;
+                       }
+               }
+
+               /* not there => schema violation */
+               if ( a == NULL ) {
+                       return( 1 );
+               }
+       }
+
+       return( 0 );
+}
+
+static int
+oc_check_allowed( char *type, struct berval **ocl )
+{
+       struct objclass *oc;
+       int             i, j;
+
+       /* always allow objectclass attribute */
+       if ( strcasecmp( type, "objectclass" ) == 0 ) {
+               return( 0 );
+       }
+
+       /* check that the type appears as req or opt in at least one oc */
+       for ( i = 0; ocl[i] != NULL; i++ ) {
+               /* if we know about the oc */
+               if ( (oc = oc_find( ocl[i]->bv_val )) != NULL ) {
+                       /* does it require the type? */
+                       for ( j = 0; oc->oc_required[j] != NULL; j++ ) {
+                               if ( strcasecmp( oc->oc_required[j], type )
+                                   == 0 ) {
+                                       return( 0 );
+                               }
+                       }
+                       /* does it allow the type? */
+                       for ( j = 0; oc->oc_allowed[j] != NULL; j++ ) {
+                               if ( strcasecmp( oc->oc_allowed[j], type )
+                                   == 0 || strcmp( oc->oc_allowed[j], "*" )
+                                   == 0 )
+                               {
+                                       return( 0 );
+                               }
+                       }
+                       /* maybe the next oc allows it */
+
+               /* we don't know about the oc. assume it allows it */
+               } else {
+                       return( 0 );
+               }
+       }
+
+       /* not allowed by any oc */
+       return( 1 );
+}
+
+static struct objclass *
+oc_find( char *ocname )
+{
+       struct objclass *oc;
+
+       for ( oc = global_oc; oc != NULL; oc = oc->oc_next ) {
+               if ( strcasecmp( oc->oc_name, ocname ) == 0 ) {
+                       return( oc );
+               }
+       }
+
+       return( NULL );
+}
+
+#ifdef LDAP_DEBUG
+
+static
+oc_print( struct objclass *oc )
+{
+       int     i;
+
+       printf( "objectclass %s\n", oc->oc_name );
+       if ( oc->oc_required != NULL ) {
+               printf( "\trequires %s", oc->oc_required[0] );
+               for ( i = 1; oc->oc_required[i] != NULL; i++ ) {
+                       printf( ",%s", oc->oc_required[i] );
+               }
+               printf( "\n" );
+       }
+       if ( oc->oc_allowed != NULL ) {
+               printf( "\tallows %s", oc->oc_allowed[0] );
+               for ( i = 1; oc->oc_allowed[i] != NULL; i++ ) {
+                       printf( ",%s", oc->oc_allowed[i] );
+               }
+               printf( "\n" );
+       }
+}
+
+#endif
diff --git a/servers/slapd/schemaparse.c b/servers/slapd/schemaparse.c
new file mode 100644 (file)
index 0000000..180ed71
--- /dev/null
@@ -0,0 +1,79 @@
+/* schemaparse.c - routines to parse config file objectclass definitions */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+
+extern char            **str2charray();
+extern void            charray_merge();
+
+struct objclass                *global_oc;
+int                    global_schemacheck;
+
+static void            oc_usage();
+
+void
+parse_oc(
+    Backend    *be,
+    char       *fname,
+    int                lineno,
+    int                argc,
+    char       **argv
+)
+{
+       int             i;
+       char            last;
+       struct objclass *oc;
+       struct objclass **ocp;
+
+       oc = (struct objclass *) ch_calloc( 1, sizeof(struct objclass) );
+       oc->oc_name = strdup( argv[1] );
+       for ( i = 2; i < argc; i++ ) {
+               /* required attributes */
+               if ( strcasecmp( argv[i], "requires" ) == 0 ) {
+                       do {
+                               i++;
+                               if ( i < argc ) {
+                                       last = argv[i][strlen( argv[i] ) - 1];
+                                       charray_merge( &oc->oc_required,
+                                               str2charray( argv[i], "," ) );
+                               }
+                       } while ( i < argc && last == ',' );
+
+               /* optional attributes */
+               } else if ( strcasecmp( argv[i], "allows" ) == 0 ) {
+                       do {
+                               i++;
+                               if ( i < argc ) {
+                                       last = argv[i][strlen( argv[i] ) - 1];
+                                       charray_merge( &oc->oc_allowed,
+                                               str2charray( argv[i], "," ) );
+                               }
+                       } while ( i < argc && last == ',' );
+
+               } else {
+                       fprintf( stderr,
+           "%s: line %d: expecting \"requires\" or \"allows\" got \"%s\"\n",
+                           fname, lineno, argv[i] );
+                       oc_usage();
+               }
+       }
+
+       ocp = &global_oc;
+       while ( *ocp != NULL ) {
+               ocp = &(*ocp)->oc_next;
+       }
+       *ocp = oc;
+}
+
+static void
+oc_usage()
+{
+       fprintf( stderr, "<oc clause> ::= objectclass <ocname>\n" );
+       fprintf( stderr, "                [ requires <attrlist> ]\n" );
+       fprintf( stderr, "                [ allows <attrlist> ]\n" );
+       exit( 1 );
+}
+
diff --git a/servers/slapd/search.c b/servers/slapd/search.c
new file mode 100644 (file)
index 0000000..fc96d2f
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+#include "ldapconfig.h"
+
+extern int     get_filter();
+extern Backend *select_backend();
+
+extern char    *default_referral;
+
+void
+do_search( conn, op )
+    Connection *conn;  /* where to send results                       */
+    Operation  *op;    /* info about the op to which we're responding */
+{
+       int             i, err;
+       int             scope, deref, attrsonly;
+       int             sizelimit, timelimit;
+       char            *base, *fstr;
+       Filter          *filter;
+       char            **attrs;
+       Backend         *be;
+
+       Debug( LDAP_DEBUG_TRACE, "do_search\n", 0, 0, 0 );
+
+       /*
+        * Parse the search request.  It looks like this:
+        *
+        *      SearchRequest := [APPLICATION 3] SEQUENCE {
+        *              baseObject      DistinguishedName,
+        *              scope           ENUMERATED {
+        *                      baseObject      (0),
+        *                      singleLevel     (1),
+        *                      wholeSubtree    (2)
+        *              },
+        *              derefAliases    ENUMERATED {
+        *                      neverDerefaliases       (0),
+        *                      derefInSearching        (1),
+        *                      derefFindingBaseObj     (2),
+        *                      alwaysDerefAliases      (3)
+        *              },
+        *              sizelimit       INTEGER (0 .. 65535),
+        *              timelimit       INTEGER (0 .. 65535),
+        *              attrsOnly       BOOLEAN,
+        *              filter          Filter,
+        *              attributes      SEQUENCE OF AttributeType
+        *      }
+        */
+
+       /* baseObject, scope, derefAliases, sizelimit, timelimit, attrsOnly */
+       if ( ber_scanf( op->o_ber, "{aiiiib", &base, &scope, &deref, &sizelimit,
+           &timelimit, &attrsonly ) == LBER_ERROR ) {
+               send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL, "" );
+               return;
+       }
+       if ( scope != LDAP_SCOPE_BASE && scope != LDAP_SCOPE_ONELEVEL
+           && scope != LDAP_SCOPE_SUBTREE ) {
+               free( base );
+               send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
+                   "Unknown search scope" );
+               return;
+       }
+       (void) dn_normalize( base );
+
+       Debug( LDAP_DEBUG_ARGS, "SRCH \"%s\" %d %d", base, scope, deref );
+       Debug( LDAP_DEBUG_ARGS, "    %d %d %d\n", sizelimit, timelimit,
+           attrsonly);
+
+       /* filter - returns a "normalized" version */
+       filter = NULL;
+       fstr = NULL;
+       if ( (err = get_filter( conn, op->o_ber, &filter, &fstr )) != 0 ) {
+               if ( fstr != NULL ) {
+                       free( fstr );
+               }
+               free( base );
+               send_ldap_result( conn, op, err, NULL, "Bad search filter" );
+               return;
+       }
+       Debug( LDAP_DEBUG_ARGS, "    filter: %s\n", fstr, 0, 0 );
+
+       /* attributes */
+       attrs = NULL;
+       if ( ber_scanf( op->o_ber, "{v}}", &attrs ) == LBER_ERROR ) {
+               free( base );
+               free( fstr );
+               send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL, "" );
+               return;
+       }
+       Debug( LDAP_DEBUG_ARGS, "    attrs:", 0, 0, 0 );
+       if ( attrs != NULL ) {
+               for ( i = 0; attrs[i] != NULL; i++ ) {
+                       attr_normalize( attrs[i] );
+                       Debug( LDAP_DEBUG_ARGS, " %s", attrs[i], 0, 0 );
+               }
+       }
+       Debug( LDAP_DEBUG_ARGS, "\n", 0, 0, 0 );
+
+       Statslog( LDAP_DEBUG_STATS,
+           "conn=%d op=%d SRCH base=\"%s\" scope=%d filter=\"%s\"\n",
+           conn->c_connid, op->o_opid, base, scope, fstr );
+
+#if defined( SLAPD_MONITOR_DN ) || defined( SLAPD_CONFIG_DN ) || defined( SLAPD_SCHEMA_DN )
+       if ( scope == LDAP_SCOPE_BASE ) {
+#if defined( SLAPD_MONITOR_DN )
+               if ( strcasecmp( base, SLAPD_MONITOR_DN ) == 0 ) {
+                       free( base );
+                       free( fstr );
+                       monitor_info( conn, op );
+                       return;
+               }
+#endif
+#if defined( SLAPD_CONFIG_DN )
+               if ( strcasecmp( base, SLAPD_CONFIG_DN ) == 0 ) {
+                       free( base );
+                       free( fstr );
+                       config_info( conn, op );
+                       return;
+               }
+#endif
+#if defined( SLAPD_SCHEMA_DN )
+               if ( strcasecmp( base, SLAPD_SCHEMA_DN ) == 0 ) {
+                       free( base );
+                       free( fstr );
+                       schema_info( conn, op );
+                       return;
+               }
+#endif
+       }
+#endif /* monitor or config or schema dn */
+
+       /*
+        * We could be serving multiple database backends.  Select the
+        * appropriate one, or send a referral to our "referral server"
+        * if we don't hold it.
+        */
+       if ( (be = select_backend( base )) == NULL ) {
+               send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
+                   default_referral );
+
+               free( base );
+               free( fstr );
+               filter_free( filter );
+               if ( attrs != NULL ) {
+                       charray_free( attrs );
+               }
+               return;
+       }
+
+       /* actually do the search and send the result(s) */
+       if ( be->be_search != NULL ) {
+               (*be->be_search)( be, conn, op, base, scope, deref, sizelimit,
+                   timelimit, filter, fstr, attrs, attrsonly );
+       } else {
+               send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
+                   "Function not implemented" );
+       }
+
+       free( base );
+       free( fstr );
+       filter_free( filter );
+       if ( attrs != NULL ) {
+               charray_free( attrs );
+       }
+}
diff --git a/servers/slapd/shell-backends/Make-template b/servers/slapd/shell-backends/Make-template
new file mode 100644 (file)
index 0000000..473c30d
--- /dev/null
@@ -0,0 +1,66 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1995 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       makefile for shell backends to use with stand-alone LDAP server
+#
+#-----------------------------------------------------------------------------
+LDAPSRC        = ../../..
+HDIR   = $(LDAPSRC)/include
+LDIR   = $(LDAPSRC)/libraries
+VERSIONFILE = $(LDAPSRC)/build/version
+
+CMNSRCS        = shellutil.c
+CMNOBJS        = shellutil.o
+
+PWDSRCS        = passwd-shell.c
+PWDOBJS        = passwd-shell.o pwd-version.o
+
+INCLUDES= -I. -I.. -I$(HDIR)
+DEFINES = $(DEFS) $(THREADS)
+CFLAGS = $(INCLUDES) $(THREADSINCLUDE) $(DEFINES) $(ACFLAGS)
+LDFLAGS        = -L$(LDIR) $(KRBLIBFLAG)
+LIBS   = -llber $(KRBLIBS) $(ALIBS)
+
+all:   passwd-shell
+
+passwd-shell:  $(PWDOBJS) $(CMNOBJS)
+       $(CC) $(ALDFLAGS) -o $@ $(PWDOBJS) $(CMNOBJS) \
+               $(LDFLAGS) $(LIBS)
+
+pwd-version.c: $(OBJS)
+       $(RM) $@
+       (u=$${USER-root} v=`$(CAT) $(VERSIONFILE)` d=`$(PWD)` h=`$(HOSTNAME)` \
+       t=`$(DATE)`; $(SED) -e "s|%WHEN%|$${t}|" \
+       -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+       -e "s|%VERSION%|$${v}|" \
+       < pwd-Version.c > $@)
+
+install:       FORCE
+
+lint:  FORCE
+       $(LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+5lint: FORCE
+       $(5LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+clean: FORCE
+       $(RM) passwd-shell pwd-version.c *.o core a.out version.c
+
+depend:        FORCE
+       $(MKDEP) $(INCLUDES) $(DEFINES) $(SRCS)
+
+links:
+       @$(LN) .src/*.[ch] .
+
+# DO NOT DELETE THIS LINE -- mkdep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/servers/slapd/shell-backends/passwd-shell.c b/servers/slapd/shell-backends/passwd-shell.c
new file mode 100644 (file)
index 0000000..2210651
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ passwd-shell.c - /etc/passwd shell-based backend for standalone ldap server
+
+ Copyright (c) 1995 Regents of the University of Michigan.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms are permitted
+ provided that this notice is preserved and that due credit is given
+ to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+*/
+
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <varargs.h>
+#include <lber.h>
+#include <ldap.h>
+#include "shellutil.h"
+#include "passwd-shell.h"
+
+
+#ifdef LDAP_DEBUG
+void debug_printf();
+#else /* LDAP_DEBUG */
+#define debug_printf()
+#endif /* LDAP_DEBUG */
+
+
+static void pwdfile_search( struct ldop *op, FILE *ofp );
+static struct ldentry *pw2entry( struct ldop *op, struct passwd *pw );
+
+static char    tmpbuf[ MAXLINELEN * 2 ];
+
+
+main( int argc, char **argv )
+{
+    int                        c, errflg;
+    struct ldop                op;
+    extern int         optind;
+    extern char                *optarg;
+
+    if (( progname = strrchr( argv[ 0 ], '/' )) == NULL ) {
+       progname = estrdup( argv[ 0 ] );
+    } else {
+       progname = estrdup( progname + 1 );
+    }
+
+    errflg = debugflg = 0;
+
+    while (( c = getopt( argc, argv, "d" )) != EOF ) {
+       switch( c ) {
+       case 'd':
+#ifdef LDAP_DEBUG
+           ++debugflg;
+#else /* LDAP_DEBUG */
+           fprintf( stderr, "%s: compile with -DLDAP_DEBUG for debugging\n",
+                   progname );
+#endif /* LDAP_DEBUG */
+           break;
+       default:
+           ++errflg;
+       }
+    }
+
+    if ( errflg || optind < argc ) {
+       fprintf( stderr, "usage: %s [-d]\n", progname );
+       exit( 1 );
+    }
+
+    debug_printf( "started\n" );
+
+    (void) memset( (char *)&op, '\0', sizeof( op ));
+
+    if ( parse_input( stdin, stdout, &op ) < 0 ) {
+       exit( 0 );
+    }
+
+    if ( op.ldop_op != LDOP_SEARCH ) {
+       write_result( stdout, LDAP_UNWILLING_TO_PERFORM, NULL,
+               "Command Not Implemented" );
+       exit( 0 );
+    }
+
+#ifdef LDAP_DEBUG
+    dump_ldop( &op );
+#endif /* LDAP_DEBUG */
+
+    pwdfile_search( &op, stdout );
+
+    exit( 0 );
+}
+
+
+static void
+pwdfile_search( struct ldop *op, FILE *ofp )
+{
+    struct passwd      *pw;
+    struct ldentry     *entry;
+    int                        oneentry;
+
+    oneentry = ( strchr( op->ldop_dn, '@' ) != NULL );
+
+    for ( pw = getpwent(); pw != NULL; pw = getpwent()) {
+       if (( entry = pw2entry( op, pw )) != NULL ) {
+           if ( oneentry ) {
+               if ( strcasecmp( op->ldop_dn, entry->lde_dn ) == 0 ) {
+                   write_entry( op, entry, ofp );
+                   break;
+               }
+           } else if ( test_filter( op, entry )) {
+               write_entry( op, entry, ofp );
+           }
+           free_entry( entry );
+       }
+    }
+    endpwent();
+
+    write_result( ofp, LDAP_SUCCESS, NULL, NULL );
+}
+
+
+static struct ldentry *
+pw2entry( struct ldop *op, struct passwd *pw )
+{
+    struct ldentry     *entry;
+    struct ldattr      *attr;
+    int                        i;
+
+    entry = (struct ldentry *) ecalloc( 1, sizeof( struct ldentry ));
+
+    /* 
+     * construct the DN from pw_name
+     */
+    if ( strchr( op->ldop_suffixes[ 0 ], '=' ) != NULL ) {
+       /*
+        * X.500 style DN
+        */
+       sprintf( tmpbuf, "cn=%s, %s", pw->pw_name, op->ldop_suffixes[ 0 ] );
+    } else {
+       /*
+        * RFC-822 style DN
+        */
+       sprintf( tmpbuf, "%s@%s", pw->pw_name, op->ldop_suffixes[ 0 ] );
+    }
+    entry->lde_dn = estrdup( tmpbuf );
+
+    /*
+     * for now, we simply derive the LDAP attribute values as follows:
+     *  objectClass = person
+     *  uid = pw_name
+     *  sn = pw_name
+     *  cn = pw_name
+     *  cn = pw_gecos  (second common name)
+     */
+    entry->lde_attrs = (struct ldattr **)ecalloc( 5, sizeof( struct ldattr * ));
+    i = 0;
+    attr = (struct ldattr *)ecalloc( 1, sizeof( struct ldattr ));
+    attr->lda_name = estrdup( "objectClass" );
+    attr->lda_values = (char **)ecalloc( 2, sizeof( char * ));
+    attr->lda_values[ 0 ] = estrdup( "person" );
+    entry->lde_attrs[ i++ ] = attr;
+
+    attr = (struct ldattr *)ecalloc( 1, sizeof( struct ldattr ));
+    attr->lda_name = estrdup( "uid" );
+    attr->lda_values = (char **)ecalloc( 2, sizeof( char * ));
+    attr->lda_values[ 0 ] = estrdup( pw->pw_name );
+    entry->lde_attrs[ i++ ] = attr;
+
+    attr = (struct ldattr *)ecalloc( 1, sizeof( struct ldattr ));
+    attr->lda_name = estrdup( "sn" );
+    attr->lda_values = (char **)ecalloc( 2, sizeof( char * ));
+    attr->lda_values[ 0 ] = estrdup( pw->pw_name );
+    entry->lde_attrs[ i++ ] = attr;
+
+    attr = (struct ldattr *)ecalloc( 1, sizeof( struct ldattr ));
+    attr->lda_name = estrdup( "cn" );
+    attr->lda_values = (char **)ecalloc( 3, sizeof( char * ));
+    attr->lda_values[ 0 ] = estrdup( pw->pw_name );
+    if ( pw->pw_gecos != NULL && *pw->pw_gecos != '\0' ) {
+       attr->lda_values[ 1 ] = estrdup( pw->pw_gecos );
+    }
+    entry->lde_attrs[ i++ ] = attr;
+
+    return( entry );
+}
diff --git a/servers/slapd/shell-backends/passwd-shell.h b/servers/slapd/shell-backends/passwd-shell.h
new file mode 100644 (file)
index 0000000..a90e021
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ passwd-shell.h
+
+ Copyright (c) 1995 Regents of the University of Michigan.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms are permitted
+ provided that this notice is preserved and that due credit is given
+ to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+*/
diff --git a/servers/slapd/shell-backends/pwd-Version.c b/servers/slapd/shell-backends/pwd-Version.c
new file mode 100644 (file)
index 0000000..51d88f1
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+char Versionstr[] = "  shell passwd backend %VERSION% (%WHEN%)\n\t%WHOANDWHERE%\n";
diff --git a/servers/slapd/shell-backends/shellutil.c b/servers/slapd/shell-backends/shellutil.c
new file mode 100644 (file)
index 0000000..82eea16
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ shellutil.c - common routines useful when building shell-based backends
+                for the standalone ldap server
+
+ Copyright (c) 1995 Regents of the University of Michigan.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms are permitted
+ provided that this notice is preserved and that due credit is given
+ to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+*/
+
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <varargs.h>
+#include <lber.h>
+#include <ldap.h>
+#include "shellutil.h"
+
+
+int    debugflg;
+char   *progname;
+
+static struct inputparams      ips[] = {
+    IP_TYPE_SUFFIX,    "suffix",
+    IP_TYPE_BASE,      "base",
+    IP_TYPE_SCOPE,     "scope",
+    IP_TYPE_ALIASDEREF,        "deref",
+    IP_TYPE_SIZELIMIT, "sizelimit",
+    IP_TYPE_TIMELIMIT, "timelimit",
+    IP_TYPE_FILTER,    "filter",
+    IP_TYPE_ATTRS,     "attrs",
+    IP_TYPE_ATTRSONLY, "attrsonly",
+    0,                 NULL
+};
+
+
+void
+write_result( FILE *fp, int code, char *matched, char *info )
+{
+    fprintf( fp, "RESULT\ncode: %d\n", code );
+    debug_printf( ">> RESULT\n" );
+    debug_printf( ">> code: %d\n", code );
+
+    if ( matched != NULL ) {
+       fprintf( fp, "matched: %s\n", matched );
+       debug_printf( ">> matched: %s\n", matched );
+    }
+
+    if ( info != NULL ) {
+       fprintf( fp, "info: %s\n", info );
+       debug_printf( ">> info: %s\n", info );
+    }
+}
+
+
+void
+write_entry( struct ldop *op, struct ldentry *entry, FILE *ofp )
+{
+    struct ldattr      **app;
+    char               **valp;
+
+    fprintf( ofp, "dn: %s\n", entry->lde_dn );
+    for ( app = entry->lde_attrs; *app != NULL; ++app ) {
+       if ( attr_requested( (*app)->lda_name, op )) {
+           for ( valp = (*app)->lda_values; *valp != NULL; ++valp ) {
+               fprintf( ofp, "%s: %s\n", (*app)->lda_name, *valp );
+           }
+       }
+    }
+    fputc( '\n', ofp );
+}
+
+
+int
+test_filter( struct ldop *op, struct ldentry *entry )
+{
+    return (( random() & 0x07 ) == 0x07 );     /* XXX random for now */
+}
+
+
+int
+attr_requested( char *name, struct ldop *op )
+{
+    char       **ap;
+
+    if ( op->ldop_srch.ldsp_attrs == NULL ) {  /* special case */
+       return( 1 );
+    }
+
+    for ( ap = op->ldop_srch.ldsp_attrs; *ap != NULL; ++ap ) {
+       if ( strcasecmp( name, *ap ) == 0 ) {
+           return( 1 );
+       }
+    }
+
+    return( 0 );
+}
+
+
+void
+free_entry( struct ldentry *entry )
+{
+    struct ldattr      **app;
+    char               **valp;
+
+    free( entry->lde_dn );
+
+    for ( app = entry->lde_attrs; *app != NULL; ++app ) {
+       for ( valp = (*app)->lda_values; *valp != NULL; ++valp ) {
+           free( *valp );
+       }
+       free( (*app)->lda_values );
+       free( (*app)->lda_name );
+    }
+
+    free( entry->lde_attrs );
+    free( entry );
+}
+
+
+int
+parse_input( FILE *ifp, FILE *ofp, struct ldop *op )
+{
+    char               *p, *args, line[ MAXLINELEN + 1 ];
+    struct inputparams *ip;
+
+    if ( fgets( line, MAXLINELEN, ifp ) == NULL ) {
+       write_result( ofp, LDAP_OPERATIONS_ERROR, NULL, "Empty Input" );
+    }
+    line[ strlen( line ) - 1 ] = '\0';
+    if ( strncasecmp( line, STR_OP_SEARCH, sizeof( STR_OP_SEARCH ) - 1 )
+           != 0 ) {
+       write_result( ofp, LDAP_UNWILLING_TO_PERFORM, NULL,
+               "Operation Not Supported" );
+       return( -1 );
+    }
+
+    op->ldop_op = LDOP_SEARCH;
+
+    while ( fgets( line, MAXLINELEN, ifp ) != NULL ) {
+       line[ strlen( line ) - 1 ] = '\0';
+       debug_printf( "<< %s\n", line );
+
+       args = line;
+       if (( ip = find_input_tag( &args )) == NULL ) {
+           debug_printf( "ignoring %s\n", line );
+           continue;
+       }
+
+       switch( ip->ip_type ) {
+       case IP_TYPE_SUFFIX:
+           add_strval( &op->ldop_suffixes, args );
+           break;
+       case IP_TYPE_BASE:
+           op->ldop_dn = estrdup( args );
+           break;
+       case IP_TYPE_SCOPE:
+           if (( op->ldop_srch.ldsp_scope = atoi( args )) != LDAP_SCOPE_BASE &&
+                   op->ldop_srch.ldsp_scope != LDAP_SCOPE_ONELEVEL &&
+                   op->ldop_srch.ldsp_scope != LDAP_SCOPE_SUBTREE ) {
+               write_result( ofp, LDAP_OPERATIONS_ERROR, NULL, "Bad scope" );
+               return( -1 );
+           }
+           break;
+       case IP_TYPE_ALIASDEREF:
+           op->ldop_srch.ldsp_aliasderef = atoi( args );
+           break;
+       case IP_TYPE_SIZELIMIT:
+           op->ldop_srch.ldsp_sizelimit = atoi( args );
+           break;
+       case IP_TYPE_TIMELIMIT:
+           op->ldop_srch.ldsp_timelimit = atoi( args );
+           break;
+       case IP_TYPE_FILTER:
+           op->ldop_srch.ldsp_filter = estrdup( args );
+           break;
+       case IP_TYPE_ATTRSONLY:
+           op->ldop_srch.ldsp_attrsonly = ( *args != '0' );
+           break;
+       case IP_TYPE_ATTRS:
+           if ( strcmp( args, "all" ) == 0 ) {
+               op->ldop_srch.ldsp_attrs = NULL;
+           } else {
+               while ( args != NULL ) {
+                   if (( p = strchr( args, ' ' )) != NULL ) {
+                       *p++ = '\0';
+                       while ( isspace( *p )) {
+                           ++p;
+                       }
+                   }
+                   add_strval( &op->ldop_srch.ldsp_attrs, args );
+                   args = p;
+               }
+           }
+           break;
+       }
+    }
+
+    if ( op->ldop_suffixes == NULL || op->ldop_dn == NULL ||
+               op->ldop_srch.ldsp_filter == NULL ) {
+       write_result( ofp, LDAP_OPERATIONS_ERROR, NULL,
+               "Required suffix:, base:, or filter: missing" );
+       return( -1 );
+    }
+
+    return( 0 );
+}
+
+
+struct inputparams *
+find_input_tag( char **linep ) /* linep is set to start of args */
+{
+    int                i;
+    char       *p;
+
+    if (( p = strchr( *linep, ':' )) == NULL || p == *linep ) {
+       return( NULL );
+    }
+
+    for ( i = 0; ips[ i ].ip_type != 0; ++i ) {
+       if ( strncasecmp( *linep, ips[ i ].ip_tag, p - *linep ) == 0 ) {
+           while ( isspace( *(++p) )) {
+               ;
+           }
+           *linep = p;
+           return( &ips[ i ] );
+       }
+    }
+
+    return( NULL );
+}
+
+
+void
+add_strval( char ***sp, char *val )
+{
+    int                i;
+    char       **vallist;
+
+    vallist = *sp;
+
+    if ( vallist == NULL ) {
+       i = 0;
+    } else {
+       for ( i = 0; vallist[ i ] != NULL; ++i ) {
+           ;
+       }
+    }
+
+    vallist = (char **)erealloc( vallist, ( i + 2 ) * sizeof( char * ));
+    vallist[ i ] = estrdup( val );
+    vallist[ ++i ] = NULL;
+    *sp = vallist;
+}
+
+
+char *
+estrdup( char *s )
+{
+    char       *p;
+
+    if (( p = strdup( s )) == NULL ) {
+       debug_printf( "strdup failed\n" );
+       exit( 1 );
+    }
+
+    return( p );
+}
+
+
+void *
+erealloc( void *s, unsigned size )
+{
+    char       *p;
+
+    if ( s == NULL ) {
+       p = malloc( size );
+    } else {
+       p = realloc( s, size );
+    }
+
+    if ( p == NULL ) {
+       debug_printf( "realloc( p, %d ) failed\n", size );
+       exit( 1 );
+    }
+
+    return( p );
+}
+
+
+char *
+ecalloc( unsigned nelem, unsigned elsize )
+{
+    char       *p;
+
+    if (( p = calloc( nelem, elsize )) == NULL ) {
+       debug_printf( "calloc( %d, %d ) failed\n", nelem, elsize );
+       exit( 1 );
+    }
+
+    return( p );
+}
+
+
+#ifdef LDAP_DEBUG
+
+/* VARARGS */
+void
+debug_printf( va_alist /* char *fmt, args... */ )
+    va_dcl
+{
+    char       *fmt;
+    va_list    ap;
+
+    if ( debugflg ) {
+       va_start( ap );
+       fmt = va_arg( ap, char * );
+       fprintf( stderr, "%s: ", progname );
+       vfprintf( stderr, fmt, ap );
+       va_end( ap );
+    }
+}
+
+
+void
+dump_ldop( struct ldop *op )
+{
+    if ( !debugflg ) {
+       return;
+    }
+
+    debug_printf( "SEARCH operation\n" );
+    if ( op->ldop_suffixes == NULL ) {
+       debug_printf( "    suffix: NONE\n" );
+    } else {
+       int     i;
+       for ( i = 0; op->ldop_suffixes[ i ] != NULL; ++i ) {
+           debug_printf( "    suffix: <%s>\n", op->ldop_suffixes[ i ] );
+       }
+    }
+    debug_printf( "        dn: <%s>\n", op->ldop_dn );
+    debug_printf( "     scope: <%d>\n", op->ldop_srch.ldsp_scope );
+    debug_printf( "    filter: <%s>\n", op->ldop_srch.ldsp_filter );
+    debug_printf( "aliasderef: <%d>\n", op->ldop_srch.ldsp_aliasderef );
+    debug_printf( " sizelimit: <%d>\n", op->ldop_srch.ldsp_sizelimit );
+    debug_printf( " timelimit: <%d>\n", op->ldop_srch.ldsp_timelimit );
+    debug_printf( " attrsonly: <%d>\n", op->ldop_srch.ldsp_attrsonly );
+    if ( op->ldop_srch.ldsp_attrs == NULL ) {
+       debug_printf( "     attrs: ALL\n" );
+    } else {
+       int     i;
+
+       for ( i = 0; op->ldop_srch.ldsp_attrs[ i ] != NULL; ++i ) {
+           debug_printf( "  attrs: <%s>\n", op->ldop_srch.ldsp_attrs[ i ] );
+       }
+    }
+}
+#endif /* LDAP_DEBUG */
diff --git a/servers/slapd/shell-backends/shellutil.h b/servers/slapd/shell-backends/shellutil.h
new file mode 100644 (file)
index 0000000..7ea0db0
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ shellutil.h
+
+ Copyright (c) 1995 Regents of the University of Michigan.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms are permitted
+ provided that this notice is preserved and that due credit is given
+ to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+*/
+
+
+#define MAXLINELEN     512
+
+#define STR_OP_SEARCH  "SEARCH"
+
+
+struct inputparams {
+    int                ip_type;
+#define IP_TYPE_SUFFIX         0x01
+#define IP_TYPE_BASE           0x02
+#define IP_TYPE_SCOPE          0x03
+#define IP_TYPE_ALIASDEREF     0x04
+#define IP_TYPE_SIZELIMIT      0x05
+#define IP_TYPE_TIMELIMIT      0x06
+#define IP_TYPE_FILTER         0x07
+#define IP_TYPE_ATTRSONLY      0x08
+#define IP_TYPE_ATTRS          0x09
+    char       *ip_tag;
+};
+
+
+struct ldsrchparms {
+    int                ldsp_scope;
+    int                ldsp_aliasderef;
+    int                ldsp_sizelimit;
+    int                ldsp_timelimit;
+    int                ldsp_attrsonly;
+    char       *ldsp_filter;
+    char       **ldsp_attrs;
+};
+
+
+struct ldop { 
+    int                ldop_op;
+#define LDOP_SEARCH    0x01
+    char       **ldop_suffixes;
+    char       *ldop_dn;
+    union {
+                   struct ldsrchparms LDsrchparams;
+         }     ldop_params;
+#define ldop_srch      ldop_params.LDsrchparams
+};
+
+
+struct ldattr {
+    char       *lda_name;
+    char       **lda_values;
+};
+
+
+struct ldentry {
+    char               *lde_dn;
+    struct ldattr      **lde_attrs;
+};
+
+
+#ifdef LDAP_DEBUG
+void debug_printf();
+#else /* LDAP_DEBUG */
+#define debug_printf()
+#endif /* LDAP_DEBUG */
+
+/*
+ * function prototypes
+ */
+void write_result( FILE *fp, int code, char *matched, char *info );
+void write_entry( struct ldop *op, struct ldentry *entry, FILE *ofp );
+int test_filter( struct ldop *op, struct ldentry *entry );
+void free_entry( struct ldentry *entry );
+int attr_requested( char *name, struct ldop *op );
+int parse_input( FILE *ifp, FILE *ofp, struct ldop *op );
+struct inputparams *find_input_tag( char **linep );
+void add_strval( char ***sp, char *val );
+char *ecalloc( unsigned nelem, unsigned elsize );
+void *erealloc( void *s, unsigned size );
+char *estrdup( char *s );
+
+/*
+ * global variables
+ */
+extern int     debugflg;
+extern char    *progname;
diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h
new file mode 100644 (file)
index 0000000..bf0c9c8
--- /dev/null
@@ -0,0 +1,265 @@
+/* slap.h - stand alone ldap server include file */
+
+#ifndef _SLDAPD_H_
+#define _SLDAPD_H_
+
+#define LDAP_SYSLOG
+
+#include <syslog.h>
+#include "avl.h"
+#include "lber.h"
+#include "ldap.h"
+#include "lthread.h"
+#include "ldif.h"
+
+#define DN_DNS 0
+#define DN_X500        1
+
+#define ON     1
+#define OFF    (-1)
+
+/*
+ * represents an attribute value assertion (i.e., attr=value)
+ */
+typedef struct ava {
+       char            *ava_type;
+       struct berval   ava_value;
+} Ava;
+
+/*
+ * represents a search filter
+ */
+typedef struct filter {
+       unsigned long   f_choice;       /* values taken from ldap.h */
+
+       union {
+               /* present */
+               char            *f_un_type;
+
+               /* equality, lessorequal, greaterorequal, approx */
+               Ava             f_un_ava;
+
+               /* and, or, not */
+               struct filter   *f_un_complex;
+
+               /* substrings */
+               struct sub {
+                       char    *f_un_sub_type;
+                       char    *f_un_sub_initial;
+                       char    **f_un_sub_any;
+                       char    *f_un_sub_final;
+               } f_un_sub;
+       } f_un;
+#define f_type         f_un.f_un_type
+#define f_ava          f_un.f_un_ava
+#define f_avtype       f_un.f_un_ava.ava_type
+#define f_avvalue      f_un.f_un_ava.ava_value
+#define f_and          f_un.f_un_complex
+#define f_or           f_un.f_un_complex
+#define f_not          f_un.f_un_complex
+#define f_list         f_un.f_un_complex
+#define f_sub          f_un.f_un_sub
+#define f_sub_type     f_un.f_un_sub.f_un_sub_type
+#define f_sub_initial  f_un.f_un_sub.f_un_sub_initial
+#define f_sub_any      f_un.f_un_sub.f_un_sub_any
+#define f_sub_final    f_un.f_un_sub.f_un_sub_final
+
+       struct filter   *f_next;
+} Filter;
+
+/*
+ * represents an attribute (type + values + syntax)
+ */
+typedef struct attr {
+       char            *a_type;
+       struct berval   **a_vals;
+       int             a_syntax;
+       struct attr     *a_next;
+} Attribute;
+
+/*
+ * the attr_syntax() routine returns one of these values
+ * telling what kind of syntax an attribute supports.
+ */
+#define SYNTAX_CIS     0x01    /* case insensitive string              */
+#define SYNTAX_CES     0x02    /* case sensitive string                */
+#define SYNTAX_BIN     0x04    /* binary data                          */
+#define SYNTAX_TEL     0x08    /* telephone number string              */
+#define SYNTAX_DN      0x10    /* dn string                            */
+
+/*
+ * the id used in the indexes to refer to an entry
+ */
+typedef unsigned long  ID;
+#define NOID   ((unsigned long)-1)
+
+/*
+ * represents an entry in core
+ */
+typedef struct entry {
+       char            *e_dn;          /* DN of this entry               */
+       Attribute       *e_attrs;       /* list of attributes + values    */
+
+       ID              e_id;           /* id of this entry - this should */
+                                       /* really be private to back-ldbm */
+       char            e_state;        /* for the cache                  */
+#define ENTRY_STATE_DELETED    1
+#define ENTRY_STATE_CREATING   2
+       int             e_refcnt;       /* # threads ref'ing this entry   */
+       struct entry    *e_lrunext;     /* for cache lru list             */
+       struct entry    *e_lruprev;
+} Entry;
+
+/*
+ * represents an access control list
+ */
+
+/* the "by" part */
+struct access {
+       char            *a_dnpat;
+       char            *a_addrpat;
+       char            *a_domainpat;
+       char            *a_dnattr;
+       long            a_access;
+#define ACL_NONE       0x01
+#define ACL_COMPARE    0x02
+#define ACL_SEARCH     0x04
+#define ACL_READ       0x08
+#define ACL_WRITE      0x10
+#define ACL_SELF       0x40
+       struct access   *a_next;
+};
+
+/* the "to" part */
+struct acl {
+       /* "to" part: the entries this acl applies to */
+       Filter          *acl_filter;
+       char            *acl_dnpat;
+       char            **acl_attrs;
+
+       /* "by" part: list of who has what access to the entries */
+       struct access   *acl_access;
+
+       struct acl      *acl_next;
+};
+
+/*
+ * represents schema information for a database
+ */
+
+struct objclass {
+       char            *oc_name;
+       char            **oc_required;
+       char            **oc_allowed;
+       struct objclass *oc_next;
+};
+
+/*
+ * represents a "database"
+ */
+
+typedef struct backend {
+       char    **be_suffix;    /* the DN suffixes of data in this backend */
+       char    *be_rootdn;     /* the magic "root" dn for this db         */
+       char    *be_rootpw;     /* the magic "root" password for this db   */
+       int     be_readonly;    /* 1 => db is in "read only" mode          */
+       int     be_sizelimit;   /* size limit for this backend             */
+       int     be_timelimit;   /* time limit for this backend             */
+       struct acl *be_acl;     /* access control list for this backend    */
+       int     be_dfltaccess;  /* access given if no acl matches          */
+       char    **be_replica;   /* replicas of this backend (in master)    */
+       char    *be_replogfile; /* replication log file (in master)        */
+       char    *be_updatedn;   /* allowed to make changes (in replicas)   */
+       int     be_lastmod;     /* keep track of lastmodified{by,time}     */
+       char    *be_type;       /* type of database                        */
+
+       void    *be_private;    /* anything the backend needs              */
+
+       IFP     be_bind;        /* backend bind routine                    */
+       IFP     be_unbind;      /* backend unbind routine                  */
+       IFP     be_search;      /* backend search routine                  */
+       IFP     be_compare;     /* backend compare routine                 */
+       IFP     be_modify;      /* backend modify routine                  */
+       IFP     be_modrdn;      /* backend modrdn routine                  */
+       IFP     be_add;         /* backend add routine                     */
+       IFP     be_delete;      /* backend delete routine                  */
+       IFP     be_abandon;     /* backend abandon routine                 */
+       IFP     be_config;      /* backend config routine                  */
+       IFP     be_init;        /* backend init routine                    */
+       IFP     be_close;       /* backend close routine                   */
+} Backend;
+
+/*
+ * represents an operation pending from an ldap client
+ */
+
+typedef struct op {
+       BerElement      *o_ber;         /* ber of the request             */
+       long            o_msgid;        /* msgid of the request           */
+       unsigned long   o_tag;          /* tag of the request             */
+       time_t          o_time;         /* time op was initiated          */
+       char            *o_dn;          /* dn bound when op was initiated */
+       int             o_authtype;     /* auth method used to bind dn    */
+                                       /* values taken from ldap.h       */
+                                       /* LDAP_AUTH_*                    */
+       int             o_opid;         /* id of this operation           */
+       int             o_connid;       /* id of conn initiating this op  */
+#ifdef CLDAP
+       int             o_cldap;        /* != 0 if this came in via CLDAP */
+       struct sockaddr o_clientaddr;   /* client address if via CLDAP    */
+       char            o_searchbase;   /* search base if via CLDAP       */
+#endif
+       struct op       *o_next;        /* next operation pending         */
+       pthread_t       o_tid;          /* thread handling this op        */
+       int             o_abandon;      /* signals op has been abandoned  */
+       pthread_mutex_t o_abandonmutex; /* signals op has been abandoned  */
+
+       int             o_private;      /* anything the backend needs     */
+} Operation;
+
+/*
+ * represents a connection from an ldap client
+ */
+
+typedef struct conn {
+       Sockbuf         c_sb;           /* ber connection stuff           */
+       char            *c_dn;          /* current DN bound to this conn  */
+       pthread_mutex_t c_dnmutex;      /* mutex for c_dn field           */
+       int             c_authtype;     /* auth method used to bind c_dn  */
+#ifdef COMPAT
+       int             c_version;      /* for compatibility w/2.0, 3.0   */
+#endif
+       char            *c_addr;        /* address of client on this conn */
+       char            *c_domain;      /* domain of client on this conn  */
+       Operation       *c_ops;         /* list of pending operations     */
+       pthread_mutex_t c_opsmutex;     /* mutex for c_ops list & stats   */
+       pthread_mutex_t c_pdumutex;     /* only one pdu written at a time */
+       pthread_cond_t  c_wcv;          /* used to wait for sd write-ready*/
+       int             c_gettingber;   /* in the middle of ber_get_next  */
+       BerElement      *c_currentber;  /* ber we're getting              */
+       int             c_writewaiter;  /* signals write-ready sd waiter  */
+       int             c_pduwaiters;   /* signals threads waiting 4 pdu  */
+       time_t          c_starttime;    /* when the connection was opened */
+       int             c_connid;       /* id of this connection for stats*/
+       int             c_opsinitiated; /* # ops initiated/next op id     */
+       int             c_opscompleted; /* # ops completed                */
+} Connection;
+
+#if defined(LDAP_SYSLOG) && defined(LDAP_DEBUG)
+#define Statslog( level, fmt, connid, opid, arg1, arg2, arg3 ) \
+       { \
+               if ( ldap_debug & level ) \
+                       fprintf( stderr, fmt, connid, opid, arg1, arg2, arg3 );\
+               if ( ldap_syslog & level ) \
+                       syslog( ldap_syslog_level, fmt, connid, opid, arg1, \
+                           arg2, arg3 ); \
+       }
+#else
+#define Statslog( level, fmt, connid, opid, arg1, arg2, arg3 )
+#endif
+
+#ifdef NEEDPROTOS
+#include "proto-slap.h"
+#endif
+
+#endif /* _slap_h_ */
diff --git a/servers/slapd/slapd.at.conf b/servers/slapd/slapd.at.conf
new file mode 100644 (file)
index 0000000..c3c8b13
--- /dev/null
@@ -0,0 +1,23 @@
+attribute      photo                                   bin
+attribute      personalsignature                       bin
+attribute      jpegphoto                               bin
+attribute      audio                                   bin
+attribute      labeledurl                              ces
+attribute      userpassword                            ces
+attribute      telephonenumber                         tel
+attribute      facsimiletelephonenumber        fax     tel
+attribute      pagertelephonenumber            pager   tel
+attribute      homephone                               tel
+attribute      mobiletelephonenumber           mobile  tel
+attribute      aliasedObjectName                       dn
+attribute      member                                  dn
+attribute      owner                                   dn
+attribute      seealso                                 dn
+attribute      manager                                 dn
+attribute      documentauthor                          dn
+attribute      secretary                               dn
+attribute      lastmodifiedby                          dn
+attribute      associatedname                          dn
+attribute      naminglink                              dn
+attribute      reciprocalnaminglink                    dn
+attribute      dn                                      dn
diff --git a/servers/slapd/slapd.conf b/servers/slapd/slapd.conf
new file mode 100644 (file)
index 0000000..c609a79
--- /dev/null
@@ -0,0 +1,14 @@
+include                %ETCDIR%/slapd.at.conf
+include                %ETCDIR%/slapd.oc.conf
+schemacheck    off
+referral       ldap://ldap.itd.umich.edu
+
+#######################################################################
+# ldbm database definitions
+#######################################################################
+
+database       ldbm
+suffix         "o=Your Organization Name, c=US"
+directory      /usr/tmp
+rootdn         "cn=root, o=Your Organization Name, c=US"
+rootpw         secret
diff --git a/servers/slapd/slapd.oc.conf b/servers/slapd/slapd.oc.conf
new file mode 100644 (file)
index 0000000..94f2349
--- /dev/null
@@ -0,0 +1,903 @@
+objectclass top
+       requires
+               objectClass
+
+objectclass alias
+       requires
+               aliasedObjectName,
+               objectClass
+
+objectclass country
+       requires
+               objectClass,
+               c
+       allows
+               searchGuide,
+               description
+
+objectclass locality
+       requires
+               objectClass
+       allows
+               description,
+               l,
+               searchGuide,
+               seeAlso,
+               st,
+               streetAddress
+
+objectclass organization
+       requires
+               objectClass,
+               o
+       allows
+               businessCategory,
+               description,
+               destinationIndicator,
+               facsimileTelephoneNumber,
+               internationaliSDNNumber,
+               l,
+               physicalDeliveryOfficeName,
+               postOfficeBox,
+               postalAddress,
+               postalCode,
+               preferredDeliveryMethod,
+               registeredAddress,
+               searchGuide,
+               seeAlso,
+               st,
+               streetAddress,
+               telephoneNumber,
+               teletexTerminalIdentifier,
+               telexNumber,
+               userPassword,
+               x121Address
+
+objectclass organizationalUnit
+       requires
+               objectClass,
+               ou
+       allows
+               businessCategory,
+               description,
+               destinationIndicator,
+               facsimileTelephoneNumber,
+               internationaliSDNNumber,
+               l,
+               physicalDeliveryOfficeName,
+               postOfficeBox,
+               postalAddress,
+               postalCode,
+               preferredDeliveryMethod,
+               registeredAddress,
+               searchGuide,
+               seeAlso,
+               st,
+               streetAddress,
+               telephoneNumber,
+               teletexTerminalIdentifier,
+               telexNumber,
+               userPassword,
+               x121Address
+
+objectclass person
+       requires
+               objectClass,
+               sn,
+               cn
+       allows
+               description,
+               seeAlso,
+               telephoneNumber,
+               userPassword
+
+objectclass organizationalPerson
+       requires
+               objectClass,
+               sn,
+               cn
+       allows
+               description,
+               destinationIndicator,
+               facsimileTelephoneNumber,
+               internationaliSDNNumber,
+               l,
+               ou,
+               physicalDeliveryOfficeName,
+               postOfficeBox,
+               postalAddress,
+               postalCode,
+               preferredDeliveryMethod,
+               registeredAddress,
+               seeAlso,
+               st,
+               streetAddress,
+               telephoneNumber,
+               teletexTerminalIdentifier,
+               telexNumber,
+               title,
+               userPassword,
+               x121Address
+
+objectclass organizationalRole
+       requires
+               objectClass,
+               cn
+       allows
+               description,
+               destinationIndicator,
+               facsimileTelephoneNumber,
+               internationaliSDNNumber,
+               l,
+               ou,
+               physicalDeliveryOfficeName,
+               postOfficeBox,
+               postalAddress,
+               postalCode,
+               preferredDeliveryMethod,
+               registeredAddress,
+               roleOccupant,
+               seeAlso,
+               st,
+               streetAddress,
+               telephoneNumber,
+               teletexTerminalIdentifier,
+               telexNumber,
+               x121Address
+
+objectclass groupOfNames
+       requires
+               objectClass,
+               member,
+               cn
+       allows
+               businessCategory,
+               description,
+               o,
+               ou,
+               owner,
+               seeAlso
+
+objectclass residentialPerson
+       requires
+               objectClass,
+               sn,
+               cn,
+               l
+       allows
+               businessCategory,
+               description,
+               destinationIndicator,
+               facsimileTelephoneNumber,
+               internationaliSDNNumber,
+               l,
+               physicalDeliveryOfficeName,
+               postOfficeBox,
+               postalAddress,
+               postalCode,
+               preferredDeliveryMethod,
+               registeredAddress,
+               seeAlso,
+               st,
+               streetAddress,
+               telephoneNumber,
+               teletexTerminalIdentifier,
+               telexNumber,
+               userPassword,
+               x121Address
+
+objectclass applicationProcess
+       requires
+               objectClass,
+               cn
+       allows
+               description,
+               l,
+               ou,
+               seeAlso
+
+objectclass applicationEntity
+       requires
+               objectClass,
+               presentationAddress,
+               cn
+       allows
+               description,
+               l,
+               o,
+               ou,
+               seeAlso,
+               supportedApplicationContext
+
+objectclass dSA
+       requires
+               objectClass,
+               presentationAddress,
+               cn
+       allows
+               knowledgeInformation
+
+objectclass device
+       requires
+               objectClass,
+               cn
+       allows
+               description,
+               l,
+               o,
+               ou,
+               owner,
+               seeAlso,
+               serialNumber
+
+objectclass strongAuthenticationUser
+       requires
+               objectClass,
+               userCertificate
+
+objectclass certificationAuthority
+       requires
+               objectClass,
+               authorityRevocationList,
+               certificateRevocationList,
+               cACertificate
+       allows
+               crossCertificatePair
+
+objectclass pilotObject
+       requires
+               objectClass
+       allows
+               audio,
+               dITRedirect,
+               info,
+               jpegPhoto,
+               lastModifiedBy,
+               lastModifiedTime,
+               manager,
+               photo,
+               uniqueIdentifier
+
+objectclass newPilotPerson
+       requires
+               objectClass,
+               sn,
+               cn
+       allows
+               businessCategory,
+               description,
+               drink,
+               homePhone,
+               homePostalAddress,
+               janetMailbox,
+               mail,
+               mailPreferenceOption,
+               mobile,
+               organizationalStatus,
+               otherMailbox,
+               pager,
+               personalSignature,
+               personalTitle,
+               preferredDeliveryMethod,
+               roomNumber,
+               secretary,
+               seeAlso,
+               telephoneNumber,
+               textEncodedORaddress,
+               uid,
+               userClass,
+               userPassword
+
+objectclass account
+       requires
+               objectClass,
+               uid
+       allows
+               description,
+               host,
+               l,
+               o,
+               ou,
+               seeAlso
+
+objectclass document
+       requires
+               objectClass,
+               documentIdentifier
+       allows
+               abstract,
+               audio,
+               authorCN,
+               authorSN,
+               cn,
+               dITRedirect,
+               description,
+               documentAuthor,
+               documentLocation,
+               documentPublisher,
+               documentStore,
+               documentTitle,
+               documentVersion,
+               info,
+               jpegPhoto,
+               keywords,
+               l,
+               lastModifiedBy,
+               lastModifiedTime,
+               manager,
+               o,
+               obsoletedByDocument,
+               obsoletesDocument,
+               ou,
+               photo,
+               seeAlso,
+               subject,
+               uniqueIdentifier,
+               updatedByDocument,
+               updatesDocument
+
+objectclass room
+       requires
+               objectClass,
+               cn
+       allows
+               description,
+               roomNumber,
+               seeAlso,
+               telephoneNumber
+
+objectclass documentSeries
+       requires
+               objectClass,
+               cn
+       allows
+               description,
+               l,
+               o,
+               ou,
+               seeAlso,
+               telephoneNumber
+
+objectclass domain
+       requires
+               objectClass,
+               dc
+       allows
+               associatedName,
+               businessCategory,
+               description,
+               destinationIndicator,
+               facsimileTelephoneNumber,
+               internationaliSDNNumber,
+               l,
+               o,
+               physicalDeliveryOfficeName,
+               postOfficeBox,
+               postalAddress,
+               postalCode,
+               preferredDeliveryMethod,
+               registeredAddress,
+               searchGuide,
+               seeAlso,
+               st,
+               streetAddress,
+               telephoneNumber,
+               teletexTerminalIdentifier,
+               telexNumber,
+               userPassword,
+               x121Address
+
+objectclass rFC822localPart
+       requires
+               objectClass,
+               dc
+       allows
+               associatedName,
+               businessCategory,
+               cn,
+               description,
+               destinationIndicator,
+               facsimileTelephoneNumber,
+               internationaliSDNNumber,
+               l,
+               o,
+               physicalDeliveryOfficeName,
+               postOfficeBox,
+               postalAddress,
+               postalCode,
+               preferredDeliveryMethod,
+               registeredAddress,
+               searchGuide,
+               seeAlso,
+               sn,
+               st,
+               streetAddress,
+               telephoneNumber,
+               teletexTerminalIdentifier,
+               telexNumber,
+               userPassword,
+               x121Address
+
+objectclass dNSDomain
+       requires
+               objectClass,
+               dc
+       allows
+               associatedName,
+               businessCategory,
+               dNSRecord,
+               description,
+               destinationIndicator,
+               facsimileTelephoneNumber,
+               internationaliSDNNumber,
+               l,
+               o,
+               physicalDeliveryOfficeName,
+               postOfficeBox,
+               postalAddress,
+               postalCode,
+               preferredDeliveryMethod,
+               registeredAddress,
+               searchGuide,
+               seeAlso,
+               st,
+               streetAddress,
+               telephoneNumber,
+               teletexTerminalIdentifier,
+               telexNumber,
+               userPassword,
+               x121Address
+
+objectclass domainRelatedObject
+       requires
+               objectClass,
+               associatedDomain
+
+objectclass friendlyCountry
+       requires
+               objectClass,
+               c,
+               co
+       allows
+               description,
+               searchGuide
+
+objectclass simpleSecurityObject
+       requires
+               objectClass,
+               userPassword
+
+objectclass pilotOrganization
+       requires
+               objectClass,
+               ou,
+               o
+       allows
+               buildingName,
+               businessCategory,
+               description,
+               destinationIndicator,
+               facsimileTelephoneNumber,
+               internationaliSDNNumber,
+               l,
+               physicalDeliveryOfficeName,
+               postOfficeBox,
+               postalAddress,
+               postalCode,
+               preferredDeliveryMethod,
+               registeredAddress,
+               searchGuide,
+               seeAlso,
+               st,
+               streetAddress,
+               telephoneNumber,
+               teletexTerminalIdentifier,
+               telexNumber,
+               userPassword,
+               x121Address
+
+objectclass nadfObject
+       requires
+               objectClass
+       allows
+               lastModifiedTime,
+               nadfSearchGuide,
+               supplementaryInformation
+
+objectclass usStateOrEquivalent
+       requires
+               objectClass,
+               st,
+               fipsStateAlphaCode,
+               fipsStateNumericCode,
+               l
+       allows
+               description,
+               lastModifiedTime,
+               nadfSearchGuide,
+               searchGuide,
+               seeAlso,
+               streetAddress,
+               supplementaryInformation
+
+objectclass usPlace
+       requires
+               objectClass,
+               fips55,
+               l
+       allows
+               description,
+               lastModifiedTime,
+               nadfSearchGuide,
+               searchGuide,
+               seeAlso,
+               st,
+               streetAddress,
+               supplementaryInformation
+
+objectclass usCountyOrEquivalent
+       requires
+               objectClass,
+               fipsCountyNumericCode,
+               fips55,
+               l
+       allows
+               description,
+               lastModifiedTime,
+               nadfSearchGuide,
+               searchGuide,
+               seeAlso,
+               st,
+               streetAddress,
+               supplementaryInformation
+
+objectclass ansiOrgObject
+       requires
+               objectClass,
+               ansiOrgNumericCode
+
+objectclass nadfApplicationEntity
+       requires
+               objectClass,
+               supportedApplicationContext,
+               presentationAddress,
+               cn
+       allows
+               description,
+               l,
+               o,
+               ou,
+               seeAlso,
+               supportedApplicationContext
+
+objectclass nadfADDMD
+       requires
+               objectClass,
+               ad
+       allows
+               businessCategory,
+               description,
+               destinationIndicator,
+               facsimileTelephoneNumber,
+               internationaliSDNNumber,
+               l,
+               lastModifiedTime,
+               nadfSearchGuide,
+               o,
+               physicalDeliveryOfficeName,
+               postOfficeBox,
+               postalAddress,
+               postalCode,
+               preferredDeliveryMethod,
+               registeredAddress,
+               searchGuide,
+               seeAlso,
+               st,
+               streetAddress,
+               supplementaryInformation,
+               telephoneNumber,
+               teletexTerminalIdentifier,
+               telexNumber,
+               userPassword,
+               x121Address
+
+objectclass publicObject
+       requires
+               objectClass,
+               namingLink
+
+objectclass providerObject
+       requires
+               objectClass,
+               reciprocalNamingLink
+
+objectclass nationalObject
+       requires
+               objectClass,
+               c
+
+objectclass fips55Object
+       requires
+               objectClass,
+               fips55
+       allows
+               st
+
+objectclass restaurant
+       requires
+               objectClass,
+               description,
+               telephoneNumber,
+               streetAddress
+       allows
+               Ambiance,
+               Appearance,
+               Average-price,
+               Closed,
+               CreditCardsAccepted,
+               Kosher,
+               Max-price,
+               MaximumInParty,
+               Min-price,
+               Music,
+               NotRecommended,
+               OutdoorSeating,
+               Parking,
+               QualityOfService,
+               QualityPriceRatio,
+               Recommended,
+               RecommendedBy,
+               Reservation,
+               ServiceSpeed,
+               Specialty,
+               Taux-de-frequentation,
+               TransportationMeans,
+               facsimileTelephoneNumber,
+               postalAddress
+
+objectclass kerberosSecurityObject
+       requires
+               objectClass,
+               krbName
+
+objectclass umichPerson
+       requires
+               objectClass,
+               sn,
+               cn,
+               universityID
+       allows
+               affiliationCode,
+               audio,
+               businessCategory,
+               classStanding,
+               description,
+               destinationIndicator,
+               doNotDelete,
+               doNotMove,
+               drink,
+               expire,
+               facsimileTelephoneNumber,
+               homePhone,
+               homePostalAddress,
+               internationaliSDNNumber,
+               janetMailbox,
+               jpegPhoto,
+               keepNames,
+               krbName,
+               l,
+               labeledURL,
+               mail,
+               mailPreferenceOption,
+               memberOfGroup,
+               mobile,
+               multiLineDescription,
+               noBatchUpdates,
+               notRegistered,
+               notice,
+               onVacation,
+               organizationalStatus,
+               otherMailbox,
+               ou,
+               pager,
+               personalSignature,
+               personalTitle,
+               photo,
+               physicalDeliveryOfficeName,
+               postOfficeBox,
+               postalAddress,
+               postalCode,
+               preferredDeliveryMethod,
+               proxy,
+               registeredAddress,
+               registrationStatus,
+               roomNumber,
+               secretary,
+               seeAlso,
+               st,
+               streetAddress,
+               telephoneNumber,
+               teletexTerminalIdentifier,
+               telexNumber,
+               textEncodedORaddress,
+               title,
+               uid,
+               updateSource,
+               userCertificate,
+               userClass,
+               userPassword,
+               vacationMessage,
+               x121Address,
+               xacl
+
+objectclass rfc822MailGroup
+       requires
+               objectClass,
+               owner,
+               cn
+       allows
+               associatedDomain,
+               autoMgt,
+               description,
+               destinationIndicator,
+               errorsTo,
+               facsimileTelephoneNumber,
+               internationaliSDNNumber,
+               joinable,
+               krbName,
+               labeledURL,
+               mail,
+               member,
+               memberOfGroup,
+               moderator,
+               multiLineDescription,
+               notice,
+               physicalDeliveryOfficeName,
+               postOfficeBox,
+               postalAddress,
+               postalCode,
+               preferredDeliveryMethod,
+               registeredAddress,
+               requestsTo,
+               rfc822ErrorsTo,
+               rfc822RequestsTo,
+               seeAlso,
+               streetAddress,
+               suppressNoEmailError,
+               telephoneNumber,
+               teletexTerminalIdentifier,
+               telexNumber,
+               userPassword,
+               x121Address,
+               xacl
+
+objectclass image
+       requires
+               objectClass,
+               cn
+       allows
+               citation,
+               copyright,
+               imageFiles,
+               jpegPhoto,
+               keywords,
+               multiLineDescription,
+               owner,
+               predominantColor
+
+objectclass imageFile
+       requires
+               objectClass,
+               cn
+       allows
+               colorDepth,
+               documentLocation,
+               fileFormat,
+               fileSize,
+               height,
+               resolution,
+               seeAlso,
+               width
+
+objectclass service
+       requires
+               objectClass,
+               cn
+       allows
+               category,
+               dependentUpon,
+               destinationIndicator,
+               facsimileTelephoneNumber,
+               hoursOfOperation,
+               internationaliSDNNumber,
+               jpegPhoto,
+               keywords,
+               labeledURL,
+               mail,
+               multiLineDescription,
+               owner,
+               physicalDeliveryOfficeName,
+               platform,
+               postOfficeBox,
+               postalAddress,
+               postalCode,
+               preferredDeliveryMethod,
+               product,
+               provider,
+               ratingDescription,
+               ratingTime,
+               registeredAddress,
+               seeAlso,
+               serviceArea,
+               serviceRating,
+               streetAddress,
+               telephoneNumber,
+               teletexTerminalIdentifier,
+               telexNumber,
+               x121Address
+
+objectclass umichDocument
+       requires
+               objectClass,
+               documentIdentifier
+       allows
+               abstract,
+               audio,
+               authorCN,
+               authorSN,
+               category,
+               cn,
+               dITRedirect,
+               description,
+               documentAuthor,
+               documentAvailable,
+               documentLocation,
+               documentPublisher,
+               documentSeriesTitle,
+               documentStore,
+               documentTitle,
+               documentVersion,
+               info,
+               jpegPhoto,
+               keywords,
+               l,
+               labeledURL,
+               lastModifiedBy,
+               lastModifiedTime,
+               manager,
+               multiLineAbstract,
+               o,
+               obsoletedByDocument,
+               obsoletesDocument,
+               ou,
+               owner,
+               photo,
+               platform,
+               product,
+               seeAlso,
+               serviceArea,
+               subject,
+               uniqueIdentifier,
+               updatedByDocument,
+               updatesDocument
+
+objectclass documentDescription
+       requires
+               objectClass,
+               cn
+       allows
+               labeledURL,
+               multiLineDescription,
+               owner
+
+objectclass labeledURLObject
+       requires
+               objectClass
+       allows
+               labeledURL
+
+objectclass cacheObject
+       requires
+               objectClass
+       allows
+               ttl
diff --git a/servers/slapd/str2filter.c b/servers/slapd/str2filter.c
new file mode 100644 (file)
index 0000000..aca9674
--- /dev/null
@@ -0,0 +1,250 @@
+/* str2filter.c - parse an rfc 1588 string filter */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+
+static char    *find_matching_paren();
+static Filter  *str2list();
+static Filter  *str2simple();
+static int     str2subvals();
+
+Filter *
+str2filter( char *str )
+{
+       Filter  *f;
+       char    *end;
+
+       Debug( LDAP_DEBUG_FILTER, "str2filter \"%s\"\n", str, 0, 0 );
+
+       if ( str == NULL || *str == '\0' ) {
+               return( NULL );
+       }
+
+       switch ( *str ) {
+       case '(':
+               if ( (end = find_matching_paren( str )) == NULL ) {
+                       filter_free( f );
+                       return( NULL );
+               }
+               *end = '\0';
+
+               str++;
+               switch ( *str ) {
+               case '&':
+                       Debug( LDAP_DEBUG_FILTER, "str2filter: AND\n",
+                           0, 0, 0 );
+
+                       str++;
+                       f = str2list( str, LDAP_FILTER_AND );
+                       break;
+
+               case '|':
+                       Debug( LDAP_DEBUG_FILTER, "put_filter: OR\n",
+                           0, 0, 0 );
+
+                       str++;
+                       f = str2list( str, LDAP_FILTER_OR );
+                       break;
+
+               case '!':
+                       Debug( LDAP_DEBUG_FILTER, "put_filter: NOT\n",
+                           0, 0, 0 );
+
+                       str++;
+                       f = str2list( str, LDAP_FILTER_NOT );
+                       break;
+
+               default:
+                       Debug( LDAP_DEBUG_FILTER, "str2filter: simple\n",
+                           0, 0, 0 );
+
+                       f = str2simple( str );
+                       break;
+               }
+               *end = ')';
+               break;
+
+       default:        /* assume it's a simple type=value filter */
+               Debug( LDAP_DEBUG_FILTER, "str2filter: default\n", 0, 0,
+                   0 );
+
+               f = str2simple( str );
+               break;
+       }
+
+       return( f );
+}
+
+/*
+ * Put a list of filters like this "(filter1)(filter2)..."
+ */
+
+static Filter *
+str2list( char *str, unsigned long ftype )
+{
+       Filter  *f;
+       Filter  **fp;
+       char    *next;
+       char    save;
+
+       Debug( LDAP_DEBUG_FILTER, "str2list \"%s\"\n", str, 0, 0 );
+
+       f = (Filter *) ch_calloc( 1, sizeof(Filter) );
+       f->f_choice = ftype;
+       fp = &f->f_list;
+
+       while ( *str ) {
+               while ( *str && isspace( *str ) )
+                       str++;
+               if ( *str == '\0' )
+                       break;
+
+               if ( (next = find_matching_paren( str )) == NULL ) {
+                       filter_free( f );
+                       return( NULL );
+               }
+               save = *++next;
+               *next = '\0';
+
+               /* now we have "(filter)" with str pointing to it */
+               if ( (*fp = str2filter( str )) == NULL ) {
+                       filter_free( f );
+                       *next = save;
+                       return( NULL );
+               }
+               *next = save;
+
+               str = next;
+               fp = &(*fp)->f_next;
+       }
+       *fp = NULL;
+
+       return( f );
+}
+
+static Filter *
+str2simple( char *str )
+{
+       Filter          *f;
+       char            *s;
+       char            *value, savechar;
+
+       Debug( LDAP_DEBUG_FILTER, "str2simple \"%s\"\n", str, 0, 0 );
+
+       if ( (s = strchr( str, '=' )) == NULL ) {
+               return( NULL );
+       }
+       value = s + 1;
+       *s-- = '\0';
+       savechar = *s;
+
+       f = (Filter *) ch_calloc( 1, sizeof(Filter) );
+
+       switch ( *s ) {
+       case '<':
+               f->f_choice = LDAP_FILTER_LE;
+               *s = '\0';
+               break;
+       case '>':
+               f->f_choice = LDAP_FILTER_GE;
+               *s = '\0';
+               break;
+       case '~':
+               f->f_choice = LDAP_FILTER_APPROX;
+               *s = '\0';
+               break;
+       default:
+               if ( strchr( value, '*' ) == NULL ) {
+                       f->f_choice = LDAP_FILTER_EQUALITY;
+               } else if ( strcmp( value, "*" ) == 0 ) {
+                       f->f_choice = LDAP_FILTER_PRESENT;
+               } else {
+                       f->f_choice = LDAP_FILTER_SUBSTRINGS;
+                       f->f_sub_type = strdup( str );
+                       if ( str2subvals( value, f ) != 0 ) {
+                               filter_free( f );
+                               *(value-1) = '=';
+                               return( NULL );
+                       }
+                       *(value-1) = '=';
+                       return( f );
+               }
+               break;
+       }
+
+       if ( f->f_choice == LDAP_FILTER_PRESENT ) {
+               f->f_type = strdup( str );
+       } else {
+               f->f_avtype = strdup( str );
+               f->f_avvalue.bv_val = strdup( value );
+               f->f_avvalue.bv_len = strlen( value );
+       }
+
+       *s = savechar;
+       *(value-1) = '=';
+       return( f );
+}
+
+static int
+str2subvals( char *val, Filter *f )
+{
+       char    *nextstar;
+       int     gotstar;
+
+       Debug( LDAP_DEBUG_FILTER, "str2subvals \"%s\"\n", val, 0, 0 );
+
+       gotstar = 0;
+       while ( val != NULL && *val ) {
+               if ( (nextstar = strchr( val, '*' )) != NULL )
+                       *nextstar++ = '\0';
+
+               if ( gotstar == 0 ) {
+                       f->f_sub_initial = strdup( val );
+               } else if ( nextstar == NULL ) {
+                       f->f_sub_final = strdup( val );
+               } else {
+                       charray_add( &f->f_sub_any, strdup( val ) );
+               }
+
+               gotstar = 1;
+               if ( nextstar != NULL )
+                       *(nextstar-1) = '*';
+               val = nextstar;
+       }
+
+       return( 0 );
+}
+
+/*
+ * find_matching_paren - return a pointer to the right paren in s matching
+ * the left paren to which *s currently points
+ */
+
+static char *
+find_matching_paren( char *s )
+{
+       int     balance, escape;
+
+       balance = 0;
+       escape = 0;
+       for ( ; *s; s++ ) {
+               if ( escape == 0 ) {
+                       if ( *s == '(' )
+                               balance++;
+                       else if ( *s == ')' )
+                               balance--;
+               }
+               if ( balance == 0 ) {
+                       return( s );
+               }
+               if ( *s == '\\' && ! escape )
+                       escape = 1;
+               else
+                       escape = 0;
+       }
+
+       return( NULL );
+}
diff --git a/servers/slapd/strdup.c b/servers/slapd/strdup.c
new file mode 100644 (file)
index 0000000..a16928a
--- /dev/null
@@ -0,0 +1,18 @@
+#if defined( ultrix ) || defined( nextstep )
+
+#include <string.h>
+
+
+char *strdup( char *s )
+{
+        char    *p;
+
+        if ( (p = (char *) malloc( strlen( s ) + 1 )) == NULL )
+                return( NULL );
+
+        strcpy( p, s );
+
+        return( p );
+}
+
+#endif /* ultrix || nextstep */
diff --git a/servers/slapd/tempnam.c b/servers/slapd/tempnam.c
new file mode 100644 (file)
index 0000000..20d108c
--- /dev/null
@@ -0,0 +1,38 @@
+#if defined( nextstep )
+
+#include <string.h>
+
+char *tempnam( char *dir, char *pfx );
+
+char *tempnam( char *dir, char *pfx )
+{
+    char       *s;
+
+    if ( dir == NULL ) {
+       dir = "/tmp";
+    }
+
+/*
+ * allocate space for dir + '/' + pfx (up to 5 chars) + 6 trailing 'X's + 0 byte
+ */
+    if (( s = (char *)malloc( strlen( dir ) + 14 )) == NULL ) {
+       return( NULL );
+    }
+
+    strcpy( s, dir );
+    strcat( s, "/" );
+    if ( pfx != NULL ) {
+       strcat( s, pfx );
+    }
+    strcat( s, "XXXXXX" );
+    mktemp( s );
+
+    if ( *s == '\0' ) {
+       free( s );
+       s = NULL;
+    }
+
+    return( s );
+}
+
+#endif /* nextstep */
diff --git a/servers/slapd/tools/Make-template b/servers/slapd/tools/Make-template
new file mode 100644 (file)
index 0000000..112c4ab
--- /dev/null
@@ -0,0 +1,219 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1995 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       Stand alone LDAP server tools makefile
+#
+#-----------------------------------------------------------------------------
+LDAPSRC        = ../../..
+HDIR   = $(LDAPSRC)/include
+LDIR   = $(LDAPSRC)/libraries
+VERSIONFILE = $(LDAPSRC)/build/version
+
+EDB2LDIFSRCS   = edb2ldif.c ldapsyntax.c
+EDB2LDIFOBJS   = edb2ldif.o ldapsyntax.o ../strdup.o
+
+OBJS2  = ../config.o ../ch_malloc.o ../backend.o ../charray.o \
+               ../aclparse.o ../schema.o ../result.o ../filterentry.o \
+               ../acl.o ../phonetic.o ../attr.o ../value.o ../entry.o \
+               ../dn.o ../filter.o ../str2filter.o ../ava.o ../init.o \
+               ../schemaparse.o ../regex.o ../strdup.o
+
+INCLUDES= -I. -I$(HDIR) $(EXINCLUDES)
+DEFINES = $(DEFS) $(SERVERDEFS) $(THREADS)
+CFLAGS = $(INCLUDES) $(DEFINES) $(ACFLAGS)
+LDFLAGS        = -L$(LDIR) $(EXLDFLAGS)
+LIBS   = -lldif -lldap -llber -lldbm -lavl $(LDBMLIB) $(EXLIBS) $(ALIBS)
+LIBS2  = -lldif -lldbm -lavl $(LDBMLIB) -llber $(KRBLIBFLAG) $(KRBLIBS) \
+               -llthread $(THREADSLIB) $(ALIBS)
+
+all:   build-edb2ldif ldif2index ldif2ldbm ldbmcat ldif2id2entry \
+               ldif2id2children centipede ldbmtest ldif
+
+build-edb2ldif:        FORCE
+       @if [ "$(HAVEISODE)" = "yes" ]; then \
+           $(MAKE) $(MFLAGS) CC=$(CC) EXINCLUDES="$(ISODEINCLUDEFLAG)" \
+               EXLDFLAGS="$(ISODELIBFLAG)" EXLIBS="$(ISODELIBS)" edb2ldif; \
+        else \
+            echo "uncomment the HAVEISODE=yes line in the Make-common file to build edb2ldif"; \
+        fi
+
+edb2ldif:      edb2-vers.o
+       $(CC) $(ALDFLAGS) -o $@ $(EDB2LDIFOBJS) edb2-vers.o \
+               $(LDFLAGS) $(LIBS)
+
+edb2-vers.c: $(EDB2LDIFOBJS)
+       $(RM) $@
+       (u=$${USER-root} v=`$(CAT) $(VERSIONFILE)` d=`$(PWD)` h=`$(HOSTNAME)` \
+       t=`$(DATE)`; $(SED) -e "s|%WHEN%|$${t}|" \
+       -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+       -e "s|%VERSION%|$${v}|" \
+       < Vers-edb2.c > $@)
+
+build-chlog2replog: FORCE
+       @if [ "$(HAVEISODE)" = "yes" ]; then \
+           $(MAKE) $(MFLAGS) CC=$(CC) EXINCLUDES="$(ISODEINCLUDEFLAG)" \
+               EXLDFLAGS="$(ISODELIBFLAG)" EXLIBS="$(ISODELIBS)" chlog2replog; \
+        else \
+            echo "uncomment the HAVEISODE=yes line in the Make-common file to build chlog2replog"; \
+        fi
+
+chlog2replog: chlog2replog.o ../lock.o ../ch_malloc.o
+       $(CC) $(ALDFLAGS) -o $@ chlog2replog.o ../lock.o ../ch_malloc.o \
+       $(LDFLAGS) $(LIBS)
+
+ldif2index:    ldif2index.o ../libbackends.a $(OBJS2)
+       $(CC) $(ALDFLAGS) -o $@ ldif2index.o $(OBJS2) \
+               ../libbackends.a $(LDFLAGS) $(LIBS2)
+
+ldif2ldbm:     ldif2ldbm.sed.o ../libbackends.a $(OBJS2)
+       $(CC) $(ALDFLAGS) -o $@ ldif2ldbm.sed.o $(OBJS2) \
+               ../libbackends.a $(LDFLAGS) $(LIBS2)
+
+ldif2ldbm.sed.c: ldif2ldbm.c
+       $(SED) -e 's;%ETCDIR%;$(RUNTIMEETCDIR);' ldif2ldbm.c > ldif2ldbm.sed.c
+
+ldif2id2entry: ldif2id2entry.o ../libbackends.a $(OBJS2)
+       $(CC) $(ALDFLAGS) -o $@ ldif2id2entry.o $(OBJS2) \
+               ../libbackends.a $(LDFLAGS) $(LIBS2)
+
+ldif2id2children:      ldif2id2children.o ../libbackends.a $(OBJS2)
+       $(CC) $(ALDFLAGS) -o $@ ldif2id2children.o $(OBJS2) \
+               ../libbackends.a $(LDFLAGS) $(LIBS2)
+
+ldbmcat:       ldbmcat.o
+       $(CC) $(ALDFLAGS) -o $@ ldbmcat.o $(LDFLAGS) $(LIBS)
+
+ldif:          ldif.o
+       $(CC) $(ALDFLAGS) -o $@ ldif.o $(LDFLAGS) $(LIBS) $(LIBS2)
+
+centipede:     centipede.o 
+       $(CC) $(ALDFLAGS) -o $@ centipede.o $(LDFLAGS) $(LIBS) \
+               $(KRBLIBFLAG) $(KRBLIBS)
+
+sizecount:     sizecount.o ../phonetic.o ../ch_malloc.o
+       $(CC) $(ALDFLAGS) -o $@ sizecount.o ../phonetic.o ../ch_malloc.o \
+               $(LDFLAGS) $(LIBS) $(KRBLIBFLAG) $(KRBLIBS)
+
+ldbmtest:      ldbmtest.o ../libbackends.a $(OBJS2)
+       $(CC) $(ALDFLAGS) -o ldbmtest ldbmtest.o $(OBJS2) \
+               ../libbackends.a $(LDFLAGS) $(LIBS2)
+
+install: $(ETCDIR) $(ETCDIR)/edb2ldif $(ETCDIR)/ldif2ldbm \
+       $(ETCDIR)/ldif2index $(ETCDIR)/ldif2id2entry \
+       $(ETCDIR)/ldif2id2children $(ETCDIR)/ldbmcat \
+       $(ETCDIR)/centipede $(ETCDIR)/ldbmtest \
+       $(ETCDIR)/ldif
+
+$(ETCDIR)/edb2ldif:    build-edb2ldif
+       @if [ "$(HAVEISODE)" = "yes" ]; then \
+               $(INSTALL) $(INSTALLFLAGS) -m 755 edb2ldif $(ETCDIR); \
+       else \
+               exit 0; \
+       fi
+
+$(ETCDIR)/chlog2replog:        build-chlog2replog
+       @if [ "$(HAVEISODE)" = "yes" ]; then \
+               $(INSTALL) $(INSTALLFLAGS) -m 755 chlog2replog $(ETCDIR); \
+       else \
+               exit 0; \
+       fi
+
+$(ETCDIR)/ldif2ldbm:   ldif2ldbm
+       $(INSTALL) $(INSTALLFLAGS) -m 755 ldif2ldbm $(ETCDIR)
+
+$(ETCDIR)/ldif2index:  ldif2index
+       $(INSTALL) $(INSTALLFLAGS) -m 755 ldif2index $(ETCDIR)
+
+$(ETCDIR)/ldif2id2entry:       ldif2id2entry
+       $(INSTALL) $(INSTALLFLAGS) -m 755 ldif2id2entry $(ETCDIR)
+
+$(ETCDIR)/ldif2id2children:    ldif2id2children
+       $(INSTALL) $(INSTALLFLAGS) -m 755 ldif2id2children $(ETCDIR)
+
+$(ETCDIR)/ldbmcat:     ldbmcat
+       $(INSTALL) $(INSTALLFLAGS) -m 755 ldbmcat $(ETCDIR)
+
+$(ETCDIR)/ldif:        ldif
+       $(INSTALL) $(INSTALLFLAGS) -m 755 ldif $(ETCDIR)
+
+$(ETCDIR)/centipede:   centipede
+       $(INSTALL) $(INSTALLFLAGS) -m 755 centipede $(ETCDIR)
+
+$(ETCDIR)/ldbmtest:    ldbmtest
+       $(INSTALL) $(INSTALLFLAGS) -m 755 ldbmtest $(ETCDIR)
+
+lint:  FORCE
+       $(LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+5lint: FORCE
+       $(5LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+clean: FORCE
+       @echo "making clean in `$(PWD)`"
+       $(RM) edb2ldif ldif2index *.o core a.out edb2-vers.c \
+               ldif2ldbm ldif2id2entry ldif2id2children ldbmcat ldif \
+               centipede chlog2replog sizecount ldif2ldbm.sed.c ldbmtest
+
+depend:        ldif2ldbm.sed.c FORCE
+       @if [ ! -z "$(HAVEISODE)" ]; then \
+           DEPENDEXTRAS="$(ISODEINCLUDEFLAG) chlog2replog.c $(EDB2LDIFSRCS)"; \
+       fi; \
+       $(MKDEP) $(INCLUDES) $(DEFINES) $$DEPENDEXTRAS ldif2index.c \
+           ldif2ldbm.c ldif2id2entry.c ldif2id2children.c ldbmcat.c \
+           centipede.c sizecount.c ldif2ldbm.sed.c ldbmtest.c ldif.c
+
+links:
+       @echo "making links in `$(PWD)`"
+       @$(LN) .src/*.[ch] .
+
+
+# DO NOT DELETE THIS LINE -- mkdep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+chlog2replog.o: chlog2replog.c ../../../include/ldif.h
+edb2ldif.o: edb2ldif.c
+ldapsyntax.o: ldapsyntax.c ../../../include/lber.h ../../../include/ldap.h
+ldapsyntax.o: ../../../include/ldif.h ldapsyntax.h
+ldif2index.o: ldif2index.c ../slap.h ../../../include/avl.h
+ldif2index.o: ../../../include/lber.h ../../../include/ldap.h
+ldif2index.o: ../../../include/lthread.h ../../../include/ldif.h
+ldif2ldbm.o: ldif2ldbm.c ../slap.h ../../../include/avl.h
+ldif2ldbm.o: ../../../include/lber.h ../../../include/ldap.h
+ldif2ldbm.o: ../../../include/lthread.h ../../../include/ldif.h
+ldif2ldbm.o: ../back-ldbm/back-ldbm.h ../../../include/ldbm.h
+ldif2id2entry.o: ldif2id2entry.c ../slap.h ../../../include/avl.h
+ldif2id2entry.o: ../../../include/lber.h ../../../include/ldap.h
+ldif2id2entry.o: ../../../include/lthread.h ../../../include/ldif.h
+ldif2id2entry.o: ../back-ldbm/back-ldbm.h ../../../include/ldbm.h
+ldif2id2children.o: ldif2id2children.c ../slap.h ../../../include/avl.h
+ldif2id2children.o: ../../../include/lber.h ../../../include/ldap.h
+ldif2id2children.o: ../../../include/lthread.h ../../../include/ldif.h
+ldif2id2children.o: ../back-ldbm/back-ldbm.h ../../../include/ldbm.h
+ldbmcat.o: ldbmcat.c ../../../include/ldbm.h ../slap.h ../../../include/avl.h
+ldbmcat.o: ../../../include/lber.h ../../../include/ldap.h
+ldbmcat.o: ../../../include/lthread.h ../../../include/ldif.h
+centipede.o: centipede.c ../../../include/lber.h ../../../include/ldap.h
+centipede.o: ../../../include/ldapconfig.h ../../../include/ldbm.h
+sizecount.o: sizecount.c ../../../include/ldbm.h ../../../include/lber.h
+sizecount.o: ../../../include/ldap.h ../../../include/portable.h
+ldif2ldbm.sed.o: ldif2ldbm.sed.c ../slap.h ../../../include/avl.h
+ldif2ldbm.sed.o: ../../../include/lber.h ../../../include/ldap.h
+ldif2ldbm.sed.o: ../../../include/lthread.h ../../../include/ldif.h
+ldif2ldbm.sed.o: ../back-ldbm/back-ldbm.h ../../../include/ldbm.h
+ldbmtest.o: ldbmtest.c ../../../include/portable.h
+ldbmtest.o: ../../../include/ldapconfig.h ../slap.h ../../../include/avl.h
+ldbmtest.o: ../../../include/lber.h ../../../include/ldap.h
+ldbmtest.o: ../../../include/lthread.h ../../../include/ldif.h
+ldbmtest.o: ../back-ldbm/back-ldbm.h ../../../include/ldbm.h
+ldif.o: ldif.c ../../../include/lber.h ../../../include/ldap.h
+ldif.o: ../../../include/ldif.h
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/servers/slapd/tools/Vers-edb2.c b/servers/slapd/tools/Vers-edb2.c
new file mode 100644 (file)
index 0000000..8484568
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+char Versionstr[] = "  edb2ldif %VERSION% (%WHEN%)\n\t%WHOANDWHERE%\n";
diff --git a/servers/slapd/tools/centipede.c b/servers/slapd/tools/centipede.c
new file mode 100644 (file)
index 0000000..9919232
--- /dev/null
@@ -0,0 +1,986 @@
+/* centipede.c - generate and install indexing information (view w/tabstop=4) */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/time.h>
+#include <lber.h>
+#include <ldap.h>
+#include <ldapconfig.h>
+#include <ldbm.h>
+
+#define DEFAULT_LDAPFILTER     "(objectclass=*)"
+
+#define CENTROID_VALUE 1
+#define CENTROID_WORD  2
+
+#define CENTROID_RELATIVE      1
+#define CENTROID_FULL          2
+
+#define WORD_BREAKS    " -',.()!;:&$%*\"/\\+_<>=?[]|^~"
+
+char   *centdir;
+int            ldbmcachesize;
+int            centroidvalues;
+int            centroidtype;
+int            doweights;
+char   *ldaphost;
+char   *srcldapbinddn;
+char   *srcldappasswd;
+char   *destldapbinddn;
+char   *destldappasswd;
+char   *ldapbase;
+int            srcldapauthmethod;
+int            destldapauthmethod;
+int            verbose;
+int            not;
+
+static LDAP            *start_ldap_search();
+static LDAP            *bind_to_destination_ldap();
+static int             create_tmp_files();
+static int             generate_new_centroids();
+static LDAPMod **diff_centroids();
+static LDAPMod **full_centroid();
+static char            **charray_add_dup();
+
+static void usage( char *name )
+{
+       fprintf( stderr, "usage: %s [options] -s url -d url attributes\n", name );
+       fprintf( stderr, "where:\n" );
+       fprintf( stderr, "\t-s url\t\t[[ldap://][host[:port]]/]searchbasedn\n");
+       fprintf( stderr, "\t-d url\t\t[[ldap://][host[:port]]/]centroidentrydn\n");
+       fprintf( stderr, "options:\n" );
+       fprintf( stderr, "\t-v \t\tturn on verbose mode\n" );
+       fprintf( stderr, "\t-n \t\tgenerate, but do not install index info\n" );
+       fprintf( stderr, "\t-f filter\tentry selection filter\n" );
+       fprintf( stderr, "\t-F \t\tgenerate a full centroid\n" );
+       fprintf( stderr, "\t-R \t\tgenerate a relative centroid\n" );
+       fprintf( stderr, "\t-w \t\tgenerate a word-based centroid\n" );
+       fprintf( stderr, "\t-t directory\tcentroid directory\n" );
+       fprintf( stderr, "\t-b binddn\tsource bind dn\n" );
+       fprintf( stderr, "\t-p passwd\tsource bind passwd (for simple auth)\n" );
+       fprintf( stderr, "\t-m authmethod\tsource authmethod \"simple\" or \"kerberos\"\n" );
+       fprintf( stderr, "\t-B binddn\tdestination bind dn\n" );
+       fprintf( stderr, "\t-P passwd\tdestination bind passwd (for simple auth)\n" );
+       fprintf( stderr, "\t-M authmethod\tdestination authmethod \"simple\" or \"kerberos\"\n" );
+       fprintf( stderr, "\t-c size\t\tldbm cache size\n" );
+}
+
+main( int argc, char **argv )
+{
+       char            *ldapfilter, *ldapref;
+       char            *ldapsrcurl, *ldapdesturl;
+       LDAP            *ld;
+       LDAPMod         **mods;
+       char            **attrs;
+       char            **tmpfile;
+       LDBM            *ldbm;
+       LDBM            oldbm;
+       char            buf[BUFSIZ];
+       int                     i, j, k, count;
+       char            *s;
+       extern int      optind;
+       extern char     *optarg;
+
+       ldapsrcurl = NULL;
+       ldapdesturl = NULL;
+       ldaphost = LDAPHOST;
+       ldapbase = DEFAULT_BASE;
+       srcldapauthmethod = LDAP_AUTH_SIMPLE;
+       destldapauthmethod = LDAP_AUTH_SIMPLE;
+       srcldapbinddn = NULL;
+       srcldappasswd = NULL;
+       destldapbinddn = NULL;
+       destldappasswd = NULL;
+       ldapfilter = DEFAULT_LDAPFILTER;
+       centroidvalues = CENTROID_VALUE;
+       centroidtype = CENTROID_RELATIVE;
+       centdir = NULL;
+       tmpfile = NULL;
+       ldbmcachesize = 0;
+
+       while ( (i = getopt( argc, argv, "s:d:c:b:B:f:FRWp:P:m:M:t:vwn" ))
+           != EOF ) {
+               switch ( i ) {
+               case 's':       /* source url [[ldap://][host[:port]]/]basedn */
+                       ldapsrcurl = strdup( optarg );
+                       break;
+
+               case 'd':       /* destination url [[ldap://][host[:port]]/]entrydn */
+                       ldapdesturl = strdup( optarg );
+                       break;
+
+               case 'f':       /* specify a filter */
+                       ldapfilter = strdup( optarg );
+                       break;
+
+               case 'F':       /* generate full centroid */
+                       centroidtype = CENTROID_FULL;
+                       break;
+
+               case 'R':       /* generate relative centroid */
+                       centroidtype = CENTROID_RELATIVE;
+                       break;
+
+               case 'w':       /* generate word centroid */
+                       centroidvalues = CENTROID_WORD;
+                       break;
+
+               case 'W':       /* generate weights */
+                       doweights = 1;
+                       break;
+
+               case 't':       /* temp file directory */
+                       centdir = strdup( optarg );
+                       break;
+
+               case 'b':       /* src bind dn */
+                       srcldapbinddn = strdup( optarg );
+                       break;
+
+               case 'p':       /* src bind password */
+                       srcldappasswd = strdup( optarg );
+                       while ( *optarg )
+                               *optarg++ = 'x';
+                       break;
+
+               case 'B':       /* dest bind dn */
+                       destldapbinddn = strdup( optarg );
+                       break;
+
+               case 'P':       /* dest bind password */
+                       destldappasswd = strdup( optarg );
+                       while ( *optarg )
+                               *optarg++ = 'x';
+                       break;
+
+               case 'm':       /* src bind method */
+                       if ( strcasecmp( optarg, "simple" ) == 0 ) {
+                               srcldapauthmethod = LDAP_AUTH_SIMPLE;
+                       } else if ( strcasecmp( optarg, "kerberos" ) == 0 ) {
+                               srcldapauthmethod = LDAP_AUTH_KRBV4;
+                       } else {
+                               fprintf( stderr, "%s: unknown auth method\n", optarg );
+                               fprintf( stderr, "expecting \"simple\" or \"kerberos\"\n",
+                                   optarg );
+                               exit( 1 );
+                       }
+                       break;
+
+               case 'M':       /* dest bind method */
+                       if ( strcasecmp( optarg, "simple" ) == 0 ) {
+                               destldapauthmethod = LDAP_AUTH_SIMPLE;
+                       } else if ( strcasecmp( optarg, "kerberos" ) == 0 ) {
+                               destldapauthmethod = LDAP_AUTH_KRBV4;
+                       } else {
+                               fprintf( stderr, "%s: unknown auth method\n", optarg );
+                               fprintf( stderr, "expecting \"simple\" or \"kerberos\"\n",
+                                   optarg );
+                               exit( 1 );
+                       }
+                       break;
+
+               case 'c':       /* ldbm cache size */
+                       ldbmcachesize = atoi( optarg );
+                       break;
+
+               case 'v':       /* turn on verbose mode */
+                       verbose++;
+                       break;
+
+               case 'n':       /* don't actually install index info */
+                       not++;
+                       break;
+
+               default:
+                       usage( argv[0] );
+                       exit( 1 );
+               }
+       }
+       if ( optind == argc || ldapsrcurl == NULL || ldapdesturl == NULL ) {
+               usage( argv[0] );
+               exit( 1 );
+       }
+       attrs = &argv[optind];
+
+       /*
+        * open the ldap connection and start searching for the entries
+        * we will use to generate the centroids.
+        */
+
+       if ( (ld = start_ldap_search( ldapsrcurl, ldapfilter, attrs )) == NULL ) {
+               fprintf( stderr, "could not initiate ldap search\n" );
+               exit( 1 );
+       }
+
+       if ( create_tmp_files( attrs, &tmpfile, &ldbm ) != 0 ) {
+               fprintf( stderr, "could not create temp files\n" );
+               exit( 1 );
+       }
+
+       /*
+        * go through the entries returned, building a centroid for each
+        * attribute as we go.
+        */
+
+       if ( (count = generate_new_centroids( ld, attrs, ldbm )) < 1 ) {
+               if ( count == 0 ) {
+                   fprintf( stderr, "no entries matched\n" );
+                   exit( 0 );
+               } else {
+                   fprintf( stderr, "could not generate new centroid\n" );
+                   exit( 1 );
+               }
+       }
+
+       /*
+        * for each centroid we generated above, compare to the existing
+        * centroid, if any, and produce adds and deletes, or produce
+        * an entirely new centroid. in either case, update the "current"
+        * centroid version with the new one we just generated.
+        */
+
+       if ( (ld = bind_to_destination_ldap( ldapsrcurl, ldapdesturl )) == NULL ) {
+               fprintf( stderr,
+                 "could not bind to index server, or could not create index entry\n" );
+               exit( 1 );
+       }
+
+       for ( i = 0; ldbm[i] != NULL; i++ ) {
+               /* generate the name of the existing centroid, if any */
+               s = strrchr( tmpfile[i], '/' );
+               *s = '\0';
+               sprintf( buf, "%s/cent.%s", tmpfile[i], attrs[i] );
+               *s = '/';
+
+               /* generate the full centroid changes */
+               if ( centroidtype == CENTROID_FULL || (oldbm = ldbm_open( buf,
+                 LDBM_WRITER, 0, ldbmcachesize )) == NULL ) {
+                       if ( (mods = full_centroid( attrs[i], ldbm[i], count )) == NULL ) {
+                               fprintf( stderr, "could not produce full centroid for %s\n",
+                                 attrs[i] );
+                               continue;
+                       }
+
+               /* generate the differential centroid changes */
+               } else {
+                       if ( (mods = diff_centroids( attrs[i], oldbm, ldbm[i], count ))
+                         == NULL ) {
+                               fprintf( stderr, "could not diff centroids\n" );
+                               ldbm_close( oldbm );
+                               continue;
+                       }
+                       ldbm_close( oldbm );
+               }
+
+               if ( verbose > 1 ) {
+                       printf("changes:\n");
+                       for ( j = 0; mods[j] != NULL; j++ ) {
+                               switch( mods[j]->mod_op ) {
+                               case LDAP_MOD_ADD:
+                                       printf( "\tadd: %s\n",mods[j]->mod_type );
+                                       break;
+                               case LDAP_MOD_DELETE:
+                                       printf( "\tdelete: %s\n",mods[j]->mod_type );
+                                       break;
+                               case LDAP_MOD_REPLACE:
+                                       printf( "\treplace: %s\n",mods[j]->mod_type );
+                                       break;
+                               }
+                               if ( mods[j]->mod_values != NULL ) {
+                                       for ( k = 0; mods[j]->mod_values[k] != NULL; k++ ) {
+                                               printf( "\t\t%s\n", mods[j]->mod_values[k] );
+                                       }
+                               }
+                       }
+                       printf("end changes:\n");
+               }
+
+               if ( verbose ) {
+                       printf( "%sModifying centroid...", not ? "Not " : "" );
+                       fflush( stdout );
+               }
+
+               /* attempt to make the changes to the index server entry */
+               if ( !not && ldap_modify_s( ld, ldapbase, mods ) != LDAP_SUCCESS ) {
+                       fprintf( stderr, "could not apply centroid modification for %s\n",
+                         attrs[i] );
+                       ldap_perror( ld, ldapbase );
+               }
+               ldap_mods_free( mods, 1 );
+
+               if ( verbose ) {
+                       printf( "\n" );
+                       fflush( stdout );
+               }
+
+               /* move the new centroid into the old one's place */
+               if ( ! not ) {
+                       (void) unlink( buf );
+                       if ( link( tmpfile[i], buf ) != 0 ) {
+                               perror( "link" );
+                               fprintf( stderr, "could not rename %s to %s\n", buf,
+                                 tmpfile[i] );
+                               continue;
+                       }
+               }
+               (void) unlink( tmpfile[i] );
+       }
+
+       /* clean up */
+       for ( i = 0; attrs[i] != NULL; i++ ) {
+               ldbm_close( ldbm[i] );
+               free( tmpfile[i] );
+       }
+       free( ldbm );
+       free( tmpfile );
+
+       exit( 0 );
+}
+
+/*
+ * open an ldap connection, bind, and initiate the search
+ */
+
+static LDAP *
+start_ldap_search(
+       char    *ldapsrcurl,
+       char    *ldapfilter,
+       char    **attrs
+)
+{
+       LDAP    *ld;
+       char    *s, *s2;
+       int             i;
+
+       if ( strncmp( ldapsrcurl, "ldap://", 7 ) == 0 ) {
+               s = ldapsrcurl + 7;
+       }
+       if ( (s2 = strchr( s, '/' )) == NULL ) {
+               ldapbase = strdup( s );
+       } else {
+               if ( *s != '/' ) {
+                       *s2 = '\0';
+                       ldaphost = strdup( s );
+                       *s2 = '/';
+               }
+               ldapbase = strdup( s2 + 1 );
+       }
+
+       if ( verbose ) {
+               printf( "Base: %s\n", ldapbase );
+               printf( "Attributes:" );
+               for ( i = 0; attrs[i] != NULL; i++ ) {
+                       printf( " %s", attrs[i] );
+               }
+               printf( "\n" );
+               printf( "Binding to source LDAP server..." );
+               fflush( stdout );
+       }
+
+       if ( (ld = ldap_open( ldaphost, LDAP_PORT )) == NULL ) {
+               perror( "ldap_open" );
+               return( NULL );
+       }
+
+       if ( ldap_bind_s( ld, srcldapbinddn, srcldappasswd, srcldapauthmethod )
+         != LDAP_SUCCESS) {
+               ldap_perror( ld, "ldap_bind_s" );
+               ldap_unbind( ld );
+               return( NULL );
+       }
+
+       printf( "\nInitiating search..." );
+       if ( ldap_search( ld, ldapbase, LDAP_SCOPE_SUBTREE, ldapfilter, attrs, 0 )
+         == -1 ) {
+               ldap_perror( ld, "ldap_search" );
+               ldap_unbind( ld );
+               return( NULL );
+       }
+
+       if ( verbose ) {
+               printf( "\n" );
+       }
+
+       return( ld );
+}
+
+/*
+ * create the temporary ldbm files we will use to hold the new centroids
+ */
+
+static int
+create_tmp_files(
+       char    **attrs,
+       char    ***tmpfile,
+       LDBM    **ldbm
+)
+{
+       int     i;
+
+       for ( i = 0; attrs[i] != NULL; i++ )
+               ;       /* NULL */
+       i++;
+
+       if ( (*tmpfile = (char **) malloc( i * sizeof(char *) )) == NULL ) {
+               perror( "malloc" );
+               return( -1 );
+       }
+       if ( (*ldbm = (LDBM *) malloc( i * sizeof(LDBM) )) == NULL ) {
+               perror( "malloc" );
+               return( -1 );
+       }
+       for ( i = 0; attrs[i] != NULL; i++ ) {
+               if ( ((*tmpfile)[i] = tempnam( centdir, NULL )) == NULL ) {
+                       perror( "tmpnam" );
+                       return( -1 );
+               }
+
+               if ( ((*ldbm)[i] = ldbm_open( (*tmpfile)[i], LDBM_WRCREAT, 0600,
+                 ldbmcachesize )) == NULL ) {
+                       fprintf( stderr, "ldbm_open of \"%s\" failed\n", (*tmpfile)[i] );
+                       perror( "ldbm_open" );
+                       return( -1 );
+               }
+       }
+       (*tmpfile)[i] = NULL;
+       (*ldbm)[i] = NULL;
+
+       return( 0 );
+}
+
+/*
+ * step through each entry returned from the search and generate
+ * the appropriate centroid values.
+ */
+
+static int
+generate_new_centroids(
+       LDAP    *ld,
+       char    **attrs,
+       LDBM    *ldbm
+)
+{
+       Datum           key, data;
+       int                     rc, i, j, count;
+       LDAPMessage     *res, *e;
+       char            *dn, *s, *w;
+       char            **val;
+       char            last;
+
+       if ( verbose ) {
+               printf( "Generating new centroids for..." );
+               fflush( stdout );
+       }
+
+       data.dptr = "";
+       data.dsize = 1;
+       count = 0;
+       while ( (rc = ldap_result( ld, LDAP_RES_ANY, 0, NULL, &res ))
+         == LDAP_RES_SEARCH_ENTRY ) {
+               count++;
+               e = ldap_first_entry( ld, res );
+               dn = ldap_get_dn( ld, e );
+
+               /* for each attr we want to generate a centroid for */
+               for ( i = 0; attrs[i] != NULL; i++ ) {
+                       if ( (val = ldap_get_values( ld, e, attrs[i] )) == NULL ) {
+                               continue;
+                       }
+
+                       /* for each value */
+                       for ( j = 0; val[j] != NULL; j++ ) {
+                               /* normalize the value */
+                               for ( s = val[j]; *s; s++ ) {
+                                       if ( isascii( *s ) ) {
+                                               *s = tolower( *s );
+                                       }
+                                       last = *s;
+                               }
+                               if ( isascii( last ) && isdigit( last ) ) {
+                                       continue;
+                               }
+
+                               /* generate a value-based centroid */
+                               if ( centroidvalues == CENTROID_VALUE ) {
+                                       key.dptr = val[j];
+                                       key.dsize = strlen( key.dptr ) + 1;
+                                       (void) ldbm_store( ldbm[i], key, data, LDBM_INSERT );
+
+                               /* generate a word-based centroid */
+                               } else {
+                                       for ( w = strtok( val[j], WORD_BREAKS ); w != NULL;
+                                         w = strtok( NULL, WORD_BREAKS ) ) {
+                                               key.dptr = w;
+                                               key.dsize = strlen( key.dptr ) + 1;
+                                               (void) ldbm_store( ldbm[i], key, data, LDBM_INSERT );
+                                       }
+                               }
+                       }
+                       ldap_value_free( val );
+               }
+               free( dn );
+               ldap_msgfree( res );
+       }
+       ldap_msgfree( res );
+       ldap_unbind( ld );
+
+       if ( verbose ) {
+               printf( "%d entries\n", count );
+       }
+
+       return( count );
+}
+
+/*
+ * compare the old and new centroids, generating the appropriate add
+ * and delete operations. if the underlying database is ordered, we
+ * can do this more efficiently.
+ */
+
+static LDAPMod **
+diff_centroids(
+       char    *attr,
+       LDBM    oldbm,
+       LDBM    nldbm,
+    int                nentries
+)
+{
+       Datum   okey, nkey;
+       Datum   olast, nlast;
+       Datum   lastkey, key;
+       Datum   data;
+       int             rc;
+       LDAPMod **mods;
+       char    **avals, **dvals;
+       int             amax, acur, dmax, dcur;
+       char    **vals;
+
+       if ( verbose ) {
+               printf( "Generating mods for differential %s centroid...", attr );
+               fflush( stdout );
+       }
+
+       if ( (mods = (LDAPMod **) malloc( sizeof(LDAPMod *) * 4 )) == NULL ||
+            (mods[0] = (LDAPMod *) malloc( sizeof(LDAPMod) )) == NULL ||
+            (mods[1] = (LDAPMod *) malloc( sizeof(LDAPMod) )) == NULL ||
+            (mods[2] = (LDAPMod *) malloc( sizeof(LDAPMod) )) == NULL ||
+            (vals = (char **) malloc( 2 * sizeof(char *) )) == NULL ||
+                (vals[0] = (char *) malloc( 20 )) == NULL )
+       {
+               perror( "malloc" );
+               exit( -1 );
+       }
+       /* add values in mods[0] */
+       mods[0]->mod_op = LDAP_MOD_ADD;
+       mods[0]->mod_type = attr;
+       mods[0]->mod_values = NULL;
+       avals = NULL;
+       acur = amax = 0;
+       /* delete values in mods[1] */
+       mods[1]->mod_op = LDAP_MOD_DELETE;
+       mods[1]->mod_type = attr;
+       mods[1]->mod_values = NULL;
+       dvals = NULL;
+       dcur = dmax = 0;
+       /* number of entries in mods[2] */
+       sprintf( vals[0], "%d", nentries );
+       vals[1] = NULL;
+       mods[2]->mod_op = LDAP_MOD_REPLACE;
+       mods[2]->mod_type = "nentries";
+       mods[2]->mod_values = vals;
+       /* null terminate list of mods */
+       mods[3] = NULL;
+
+#ifdef LDBM_ORDERED
+       /*
+        * if the underlying database is ordered, we can do a more efficient
+        * dual traversal, yielding O(N) performance.
+        */
+
+       olast.dptr = NULL;
+       nlast.dptr = NULL;
+       for ( okey = ldbm_firstkey( oldbm ), nkey = ldbm_firstkey( nldbm );
+             okey.dptr != NULL && nkey.dptr != NULL; )
+       {
+               rc = strcmp( okey.dptr, nkey.dptr );
+
+               if ( rc == 0 ) {
+                       /* value is in both places - leave it */
+                       if ( olast.dptr != NULL ) {
+                               ldbm_datum_free( oldbm, olast );
+                       }
+                       olast = okey;
+                       if ( nlast.dptr != NULL ) {
+                               ldbm_datum_free( nldbm, nlast );
+                       }
+                       nlast = nkey;
+
+                       okey = ldbm_nextkey( oldbm, olast );
+                       nkey = ldbm_nextkey( nldbm, nlast );
+               } else if ( rc > 0 ) {
+                       /* new value is not in old centroid - add it */
+                       if ( charray_add_dup( &avals, &acur, &amax, nkey.dptr ) == NULL ) {
+                               ldap_mods_free( mods, 1 );
+                               return( NULL );
+                       }
+
+                       if ( nlast.dptr != NULL ) {
+                               ldbm_datum_free( nldbm, nlast );
+                       }
+                       nlast = nkey;
+                       nkey = ldbm_nextkey( nldbm, nlast );
+               } else {
+                       /* old value is not in new centroid - delete it */
+                       if ( charray_add_dup( &dvals, &dcur, &dmax, okey.dptr ) == NULL ) {
+                               ldap_mods_free( mods, 1 );
+                               return( NULL );
+                       }
+
+                       if ( olast.dptr != NULL ) {
+                               ldbm_datum_free( oldbm, olast );
+                       }
+                       olast = okey;
+                       okey = ldbm_nextkey( oldbm, olast );
+               }
+       }
+
+       while ( okey.dptr != NULL ) {
+               if ( charray_add_dup( &dvals, &dcur, &dmax, okey.dptr ) == NULL ) {
+                       ldap_mods_free( mods, 1 );
+                       return( NULL );
+               }
+
+               okey = ldbm_nextkey( oldbm, olast );
+               if ( olast.dptr != NULL ) {
+                       ldbm_datum_free( oldbm, olast );
+               }
+               olast = okey;
+       }
+       if ( olast.dptr != NULL ) {
+               ldbm_datum_free( oldbm, olast );
+       }
+       while ( nkey.dptr != NULL ) {
+               if ( charray_add_dup( &avals, &acur, &amax, nkey.dptr ) == NULL ) {
+                       ldap_mods_free( mods, 1 );
+                       return( NULL );
+               }
+
+               nkey = ldbm_nextkey( nldbm, nlast );
+               if ( nlast.dptr != NULL ) {
+                       ldbm_datum_free( nldbm, nlast );
+               }
+               nlast = nkey;
+       }
+       if ( nlast.dptr != NULL ) {
+               ldbm_datum_free( nldbm, nlast );
+       }
+#else
+       /*
+        * if the underlying database is not ordered, we have to
+        * generate list of values to add by stepping through all new
+        * values and looking them up in the old centroid (not there => add),
+        * then stepping through all old values and looking them up in the
+        * new centroid (not there => delete). this yields O(Nf(N)) performance,
+        * where f(N) is the order to retrieve a single item.
+        */
+
+       /* generate list of values to add */
+       lastkey.dptr = NULL;
+       for ( key = ldbm_firstkey( nldbm ); key.dptr != NULL;
+         key = ldbm_nextkey( nldbm, lastkey ) ) {
+               /* see if it's in the old one */
+               data = ldbm_fetch( oldbm, key );
+
+               /* not there - add it */
+               if ( data.dptr == NULL ) {
+                       if ( charray_add_dup( &avals, &acur, &amax, key.dptr ) == NULL ) {
+                               ldap_mods_free( mods, 1 );
+                               return( NULL );
+                       }
+               } else {
+                       ldbm_datum_free( oldbm, data );
+               }
+               if ( lastkey.dptr != NULL ) {
+                       ldbm_datum_free( nldbm, lastkey );
+               }
+               lastkey = key;
+       }
+       if ( lastkey.dptr != NULL ) {
+               ldbm_datum_free( nldbm, lastkey );
+       }
+
+       /* generate list of values to delete */
+       lastkey.dptr = NULL;
+       for ( key = ldbm_firstkey( oldbm ); key.dptr != NULL;
+         key = ldbm_nextkey( oldbm, lastkey ) ) {
+               /* see if it's in the new one */
+               data = ldbm_fetch( nldbm, key );
+
+               /* not there - delete it */
+               if ( data.dptr == NULL ) {
+                       if ( charray_add_dup( &dvals, &dcur, &dmax, key.dptr ) == NULL ) {
+                               ldap_mods_free( mods, 1 );
+                               return( NULL );
+                       }
+               } else {
+                       ldbm_datum_free( nldbm, data );
+               }
+               if ( lastkey.dptr != NULL ) {
+                       ldbm_datum_free( oldbm, lastkey );
+               }
+               lastkey = key;
+       }
+       if ( lastkey.dptr != NULL ) {
+               ldbm_datum_free( oldbm, lastkey );
+       }
+#endif
+
+       mods[0]->mod_values = avals;
+       mods[1]->mod_values = dvals;
+
+       if ( verbose ) {
+               printf( "\n" );
+               fflush( stdout );
+       }
+
+       if ( mods[1]->mod_values == NULL ) {
+               free( (char *) mods[1] );
+               mods[1] = NULL;
+       }
+       if ( mods[0]->mod_values == NULL ) {
+               free( (char *) mods[0] );
+               mods[0] = mods[1];
+               mods[1] = NULL;
+       }
+       if ( mods[0] == NULL ) {
+               free( (char *) mods );
+               return( NULL );
+       } else {
+               return( mods );
+       }
+}
+
+static LDAPMod **
+full_centroid(
+       char    *attr,
+       LDBM    ldbm,
+    int                nentries
+)
+{
+       Datum   key, lastkey;
+       LDAPMod **mods;
+       char    **vals;
+       int             vcur, vmax;
+
+       if ( verbose ) {
+               printf( "Generating mods for full %s centroid...", attr );
+               fflush( stdout );
+       }
+
+       if ( (mods = (LDAPMod **) malloc( sizeof(LDAPMod *) * 3 )) == NULL ||
+            (mods[0] = (LDAPMod *) malloc( sizeof(LDAPMod) )) == NULL ||
+            (mods[1] = (LDAPMod *) malloc( sizeof(LDAPMod) )) == NULL ||
+            (vals = (char **) malloc( 2 * sizeof(char *) )) == NULL ||
+            (vals[0] = (char *) malloc( 20 )) == NULL )
+       {
+               perror( "malloc" );
+               exit( -1 );
+       }
+       mods[0]->mod_op = LDAP_MOD_REPLACE;
+       mods[0]->mod_type = attr;
+       mods[0]->mod_values = NULL;
+       sprintf( vals[0], "%d", nentries );
+       vals[1] = NULL;
+       mods[1]->mod_op = LDAP_MOD_REPLACE;
+       mods[1]->mod_type = "nentries";
+       mods[1]->mod_values = vals;
+       mods[2] = NULL;
+
+       lastkey.dptr = NULL;
+       vals = NULL;
+       vcur = vmax = 0;
+       for ( key = ldbm_firstkey( ldbm ); key.dptr != NULL;
+         key = ldbm_nextkey( ldbm, lastkey ) ) {
+               if ( charray_add_dup( &vals, &vcur, &vmax, key.dptr ) == NULL ) {
+                       ldap_mods_free( mods, 1 );
+                       return( NULL );
+               }
+
+               if ( lastkey.dptr != NULL ) {
+                       ldbm_datum_free( ldbm, lastkey );
+               }
+               lastkey = key;
+       }
+       if ( lastkey.dptr != NULL ) {
+               ldbm_datum_free( ldbm, lastkey );
+       }
+       mods[0]->mod_values = vals;
+
+       if ( verbose ) {
+               printf( "\n" );
+               fflush( stdout );
+       }
+
+       if ( mods[0]->mod_values == NULL ) {
+               free( (char *) mods[0] );
+               free( (char *) mods );
+               return( NULL );
+       } else {
+               return( mods );
+       }
+}
+
+/*
+ * extract the destination ldap host, port, and base object for the
+ * server to receive the index information. then, open a connection,
+ * bind, and see if the entry exists. if not, create it and set things
+ * up so the centroid full and diff routines can modify it to contain
+ * the new centroid information.
+ */
+
+static LDAP *
+bind_to_destination_ldap(
+       char    *ldapsrcurl,
+       char    *ldapdesturl
+)
+{
+       LDAP            *ld;
+       LDAPMessage     *res;
+       int                     rc;
+       char            *s, *s2, *d;
+       char            *attrs[2], *refvalues[2], *ocvalues[2];
+       LDAPMod         *mp[3];
+       LDAPMod         m[2];
+       char            buf[BUFSIZ];
+
+       if ( verbose ) {
+               printf( "Binding to destination LDAP server..." );
+               fflush( stdout );
+       }
+
+       /* first, pick out the destination ldap server info */
+       if ( ldapbase != NULL ) {
+               free( ldapbase );
+       }
+       if ( strncmp( ldapdesturl, "ldap://", 7 ) == 0 ) {
+               s = ldapdesturl + 7;
+       }
+       if ( (s2 = strchr( s, '/' )) == NULL ) {
+               ldapbase = strdup( s );
+       } else {
+               if ( *s != '/' ) {
+                       *s2 = '\0';
+                       if ( ldaphost != NULL )
+                               free( ldaphost );
+                       ldaphost = strdup( s );
+                       *s2 = '/';
+               }
+               ldapbase = strdup( s2 + 1 );
+       }
+       strcpy( buf, "ref=" );
+       if ( strpbrk( ldapsrcurl, " ,;" ) != NULL ) {
+               strcat( buf, "\"" );
+       }
+       for ( s = d = ldapsrcurl; *s; s++ ) {
+               if ( *s != '"' ) {
+                       *d++ = *s;
+               }
+       }
+       *d = '\0';
+       strcat( buf, ldapsrcurl );
+       if ( strpbrk( ldapsrcurl, " ,;" ) != NULL ) {
+               strcat( buf, "\"" );
+       }
+       strcat( buf, ", " );
+       strcat( buf, ldapbase );
+       free( ldapbase );
+       ldapbase = strdup( buf );
+
+       if ( (ld = ldap_open( ldaphost, LDAP_PORT )) == NULL ) {
+               perror( "ldap_open" );
+               return( NULL );
+       }
+
+       if ( ldap_bind_s( ld, destldapbinddn, destldappasswd, destldapauthmethod )
+         != LDAP_SUCCESS) {
+               ldap_perror( ld, "ldap_bind_s" );
+               ldap_unbind( ld );
+               return( NULL );
+       }
+       if ( verbose ) {
+               printf( "\n" );
+       }
+
+       attrs[0] = "c";
+       attrs[1] = NULL;
+       rc = ldap_search_s( ld, ldapbase, LDAP_SCOPE_BASE, "(objectclass=*)",
+         attrs, 0, &res );
+       ldap_msgfree( res );
+
+       if ( rc == LDAP_NO_SUCH_OBJECT ) {
+               if ( verbose ) {
+                       printf( "%sCreating centroid entry...", not ? "Not " : "" );
+                       fflush( stdout );
+               }
+
+               /* create the centroid index entry */
+               m[0].mod_op = 0;
+               m[0].mod_type = "ref";
+               refvalues[0] = ldapsrcurl;
+               refvalues[1] = NULL;
+               m[0].mod_values = refvalues;
+               m[1].mod_op = 0;
+               m[1].mod_type = "objectclass";
+               ocvalues[0] = "indexentry";
+               ocvalues[1] = NULL;
+               m[1].mod_values = ocvalues;
+               mp[0] = &m[0];
+               mp[1] = &m[1];
+               mp[2] = NULL;
+
+               if ( !not && ldap_add_s( ld, ldapbase, mp ) != LDAP_SUCCESS ) {
+                       ldap_perror( ld, ldapbase );
+                       ldap_unbind( ld );
+                       return( NULL );
+               }
+
+               if ( verbose ) {
+                       printf( "\n" );
+                       fflush( stdout );
+               }
+       } else if ( rc != LDAP_SUCCESS ) {
+               ldap_perror( ld, "ldap_search_s" );
+               ldap_unbind( ld );
+               return( NULL );
+       }
+
+       return( ld );
+}
+
+static char **
+charray_add_dup(
+       char    ***a,
+    int                *cur,
+    int                *max,
+       char    *s
+)
+{
+       int n;
+       if ( *a == NULL ) {
+               *a = (char **) malloc( (BUFSIZ + 1) * sizeof(char *) );
+               *cur = 0;
+               *max = BUFSIZ;
+       } else if ( *cur >= *max ) {
+               *max += BUFSIZ;
+               *a = (char **) realloc( *a, (*max + 1) * sizeof(char *) );
+       }
+       if ( *a == NULL ) {
+               return( NULL );
+       }
+
+       (*a)[(*cur)++] = strdup( s );
+       (*a)[*cur] = NULL;
+       return( *a );
+}
diff --git a/servers/slapd/tools/chlog2replog.c b/servers/slapd/tools/chlog2replog.c
new file mode 100644 (file)
index 0000000..f9f3b3c
--- /dev/null
@@ -0,0 +1,709 @@
+/*
+ * Copyright (c) 1990, 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+/*
+ * chlog2replog - read a quipu-style changelog on stdin and write a
+ * slapd-style replog on stdout, or write to a file, respecting
+ * slapd/slurpd locking conventions.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <quipu/commonarg.h>
+#include <quipu/attrvalue.h>
+
+#include "ldif.h"
+
+static int dn2ldif();
+static void de_t61();
+
+extern FILE *lock_fopen( char *, char *, FILE ** );
+extern int lock_fclose( FILE *, FILE * );
+extern char *ch_realloc( char *, unsigned long ); 
+
+short  ldap_dn_syntax;
+PS     rps;
+char   *progname;
+int    ldap_syslog = 0;
+int    ldap_syslog_level = 0;
+
+
+#define        ST_START        0
+#define ST_DN          2
+#define        ST_TYPE         3
+#define        ST_ARGS         4
+#define        ST_NL1          5
+#define        ST_PUNT         6
+#define        ST_BAD          7
+#define        ST_CONCAT       8
+
+#define TY_MODIFYTYPE  1
+#define        TY_ADD          2
+#define        TY_REMOVE       3
+#define TY_NEWRDN      4
+#define TY_PUNT                5
+#define TY_MODIFYARGS  6
+
+#define        MOD_ADDVALUES           1
+#define MOD_ADDATTRIBUTE       2
+#define MOD_REMOVEATTRIBUTE    3
+#define        MOD_REMOVEVALUES        4
+
+
+char *
+dn2ldap( char *edbdn )
+{
+    DN         dn;
+    PS         str_ps;
+    char       *ldapdn;
+    int                len;
+    static int inited = 0;
+
+    if ( !inited ) {
+       /* load & initialize quipu syntax handlers */
+       quipu_syntaxes();
+
+#ifdef LDAP_USE_PP
+       pp_quipu_init( progname );
+#endif
+
+       dsap_init( NULL, NULL );
+
+       if (( ldap_dn_syntax = str2syntax( "DN" )) == 0 ) {
+           return( NULL );
+       }
+       inited = 1;
+    }
+
+    if (( dn = str2dn( edbdn )) == NULLDN ) {
+       return( NULL );
+    }
+
+    if (( str_ps = ps_alloc( str_open )) == NULLPS ||
+           str_setup( str_ps, NULLCP, 0, 0 ) == NOTOK ) {
+       dn_free( dn );
+       return( NULL );
+    }
+
+    if ( dn2ldif( str_ps, dn ) != 0 ) {
+       ps_free( str_ps );
+       dn_free( dn );
+       return( NULL );
+    }
+
+    dn_free( dn );
+    len = ( str_ps->ps_ptr - str_ps->ps_base );
+
+    if (( ldapdn = malloc( len + 1 )) == NULL ) {
+       ps_free( str_ps );
+       return( NULL );
+    }
+
+    memcpy( ldapdn, str_ps->ps_base, len );
+    ldapdn[ len ] = '\0';
+    ps_free( str_ps );
+    return( ldapdn );
+}
+
+
+#define SEPARATOR(c)   (c == ',' || c == ';')
+#define SPACE(c)       (c == ' ' || c == '\n')
+
+static int
+dn2ldif( PS ps, DN dn )
+{
+    RDN        rdn;
+    int        firstrdn, rc;
+    char       *value;
+    PS rps;
+
+    if ( dn == NULLDN ) {
+       return( 0 );
+    }
+
+    if ( dn->dn_parent != NULLDN ) {
+       if (( rc = dn2ldif( ps, dn->dn_parent )) != 0 ) {
+           return( rc );
+       }
+       ps_print( ps, ", " );
+    }
+
+    if ( (rps = ps_alloc( str_open )) == NULLPS ||
+           str_setup( rps, NULLCP, 0, 0 ) == NOTOK ) {
+       return( -1 );
+    }
+
+    firstrdn = 1;
+    for ( rdn = dn->dn_rdn; rdn != NULLRDN; rdn = rdn->rdn_next ) {
+       if ( firstrdn ) {
+           firstrdn = 0;
+       } else {
+           ps_print( ps, " + " );
+       }
+
+       AttrT_print( ps, rdn->rdn_at, EDBOUT );
+       ps_print( ps, "=" );
+
+       if ( rdn->rdn_at->oa_syntax == ldap_dn_syntax ) {
+           if (( rc = dn2ldif( rps, (DN) rdn->rdn_av.av_struct )) != 0 ) {
+               return( rc );
+           }
+           *rps->ps_ptr = '\0';
+           value = rps->ps_base;
+       } else {
+           AttrV_print( rps, &rdn->rdn_av, EDBOUT );
+           *rps->ps_ptr = '\0';
+           value = rps->ps_base;
+           de_t61( value, 0 );
+       }
+
+       /*
+        * ,+="\\\n all go in quotes.  " and \\ need to
+        * be preceeded by \\.
+        */
+
+       if ( strpbrk( value, ",+=\"\\\n" ) != NULL || SPACE( value[0] )
+               || SPACE( value[max( strlen(value) - 1, 0 )] ) ) {
+           char        *p, *t, *tmp;
+           int specialcount;
+
+           ps_print( ps, "\"" );
+
+           specialcount = 0;
+           for ( p = value; *p != '\0'; p++ ) {
+               if ( *p == '"' || *p == '\\' ) {
+                   specialcount++;
+               }
+           }
+           if ( specialcount > 0 ) {
+               tmp = smalloc( strlen( value ) + specialcount + 1 );
+               for ( p = value, t = tmp; *p != '\0'; p++ ) {
+                   switch ( *p ) {
+                   case '"':
+                   case '\\':
+                           *t++ = '\\';
+                           /* FALL THROUGH */
+                   default:
+                           *t++ = *p;
+                   }
+               }
+               *t = '\0';
+               ps_print( ps, tmp );
+               free( tmp );
+           } else {
+               ps_print( ps, value );
+           }
+
+           ps_print( ps, "\"" );
+       } else {
+           ps_print( ps, value );
+       }
+
+       rps->ps_ptr = rps->ps_base;
+    }
+
+    ps_free( rps );
+
+    return( 0 );
+}
+
+#define T61    "{T.61}"
+#define T61LEN 6
+
+
+
+static void
+de_t61( s, t61mark )
+char   *s;
+int    t61mark;
+{
+       char    *next = s;
+       int     c, hex;
+
+       while ( *s ) {
+               switch ( *s ) {
+               case '{' :
+                       if ( strncasecmp( s, T61, T61LEN) == 0 ) {
+                               s += T61LEN;
+                               if ( t61mark )
+                                       *next++ = '@';
+                       } else {
+                               *next++ = *s++;
+                       }
+                       break;
+
+               case '\\':
+                       c = *(s + 1);
+                       if ( c == '\n' ) {
+                               s += 2;
+                               if ( *s == '\t' )
+                                       s++;
+                               break;
+                       }
+                       if ( isdigit( c ) )
+                               hex = c - '0';
+                       else if ( c >= 'A' && c <= 'F' )
+                               hex = c - 'A' + 10;
+                       else if ( c >= 'a' && c <= 'f' )
+                               hex = c - 'a' + 10;
+                       else {
+                               *next++ = *s++;
+                               break;
+                       }
+                       hex <<= 4;
+                       c = *(s + 2);
+                       if ( isdigit( c ) )
+                               hex += c - '0';
+                       else if ( c >= 'A' && c <= 'F' )
+                               hex += c - 'A' + 10;
+                       else if ( c >= 'a' && c <= 'f' )
+                               hex += c - 'a' + 10;
+                       else {
+                               *next++ = *s++;
+                               *next++ = *s++;
+                               break;
+                       }
+
+                       *next++ = hex;
+                       s += 3;
+                       break;
+
+               default:
+                       *next++ = *s++;
+                       break;
+               }
+       }
+       *next = '\0';
+}
+
+
+
+
+char *
+getattr( buf, sep )
+char *buf;
+char sep;
+{
+    char *val;
+#define RBSIZE 255
+    static char retbuf[ RBSIZE ];
+
+    if (( val = strchr( buf, sep )) != NULL ) {
+       strncpy( retbuf, buf, val - buf );
+       retbuf[ val - buf ] = '\0';
+    } else {
+       retbuf[ 0 ] = '\0';
+    }
+    return( retbuf );
+}
+
+
+char *
+getattr_ldif( buf )
+char *buf;
+{
+    return( getattr( buf, ':' ));
+}
+
+
+char *
+getattr_edb( buf )
+char *buf;
+{
+    return( getattr( buf, '=' ));
+}
+
+char *
+getval( buf, sep )
+char *buf;
+char sep;
+{
+    char *val;
+
+    if (( val = strchr( buf, sep )) != NULL ) {
+       return( strdup( ++val ));
+    } else {
+       return( NULL );
+    }
+}
+
+char *
+getval_ldif( buf )
+char *buf;
+{
+    return( getval( buf, ':' ));
+}
+
+
+char *
+getval_edb( buf )
+char *buf;
+{
+    return( getval( buf, '=' ));
+}
+
+
+
+
+int
+isDNsyntax( attr )
+char *attr;
+{
+    oid_table_attr *p, *name2attr();
+
+    p = name2attr( attr );
+    if ( p == ( oid_table_attr * ) 0 ) {
+       return( -1 );
+    }
+    if ( p->oa_syntax == ldap_dn_syntax ) {
+       return( 1 );
+    } else {
+       return( 0 );
+    }
+}
+
+
+
+void
+print_as( as, modtype, ofp )
+Attr_Sequence as;
+int modtype;
+FILE *ofp;
+{
+    Attr_Sequence p;
+    AV_Sequence        av;
+    char *attrname, *tmpdn, *obuf;
+
+    p = as;
+    for ( p = as; p != NULLATTR; p = p->attr_link) {
+       rps->ps_ptr = rps->ps_base;
+       AttrT_print( rps,  p->attr_type, EDBOUT );
+       *rps->ps_ptr = '\0';
+       attrname = strdup( rps->ps_base  );
+       if ( modtype != 0 ) {
+           switch ( modtype ) {
+           case MOD_ADDVALUES:
+           case MOD_ADDATTRIBUTE:
+               fprintf( ofp, "add: %s\n", attrname );
+               break;
+           case MOD_REMOVEATTRIBUTE:
+           case MOD_REMOVEVALUES:
+               fprintf( ofp, "delete: %s\n", attrname );
+               break;
+           default:
+               break;
+           }
+       }
+       for ( av = p->attr_value; av != NULLAV; av = av->avseq_next ) {
+           rps->ps_ptr = rps->ps_base;
+           AttrV_print( rps, &av->avseq_av, EDBOUT );
+           *rps->ps_ptr = '\0';
+           de_t61( rps->ps_base, 0 );
+           if ( isDNsyntax( attrname )) {
+               tmpdn = dn2ldap( rps->ps_base );
+               obuf = ldif_type_and_value( attrname, tmpdn,
+                       strlen( tmpdn ));
+               free( tmpdn );
+           } else {
+               obuf = ldif_type_and_value( attrname, rps->ps_base,
+                       strlen( rps->ps_base ));
+           }
+           if ( obuf != NULL ) {
+               fputs( obuf, ofp );
+               free( obuf );
+           }
+       }
+       if ( modtype != 0 ) {
+           fprintf( ofp, "-\n" );
+       }
+       free( attrname );
+    }
+}
+
+
+
+void
+usage( char *name )
+{
+    fprintf( stderr, "usage: %s -d dn-suffix -r replica:port ", name );
+    fprintf( stderr, "[-r replica:port...] [-o outputfile]\n" );
+}
+
+
+
+main( int argc, char **argv )
+{
+    char               *ldapdn, nbuf[ 4096 ], *buf, *p;
+    int                        state, prevstate, modstate, modtype, i;
+    int                        buflen, nbuflen;
+    Attr_Sequence      as;
+    PS                 std_ps;
+    int                        arg;
+    char               *ofile = NULL;
+    FILE               *ofp, *lfp;
+
+    extern char                *optarg;
+    char               **replicas = NULL;
+    int                        nreplicas = 0;
+    char               *dn_suffix = NULL;
+
+    if (( progname = strrchr( argv[ 0 ], '/' )) == NULL ) {
+       progname = argv[ 0 ];
+    } else {
+       ++progname;
+    }
+
+    while (( arg = getopt( argc, argv, "o:r:d:" )) != EOF ) {
+       switch( arg ) {
+       case 'o':
+           ofile = optarg;
+           break;
+       case 'r':
+           replicas = (char **) ch_realloc( (char *) replicas, (unsigned long)
+                   ( nreplicas + 2 ) * sizeof( char * ));
+           replicas[ nreplicas ] = optarg;
+           replicas[ nreplicas + 1 ] = NULL;
+           nreplicas++;
+           break;
+       case 'd':
+           dn_suffix = optarg;
+           break;
+       default:
+           usage( progname );
+           exit( 1 );
+       }
+    }
+
+    if (( dn_suffix == NULL ) || ( nreplicas == 0 )) {
+       usage( progname );
+       exit( 1 );
+    }
+
+    if ( ofile == NULL ) {
+       /* Just write to stdout */
+       ofp = stdout;
+    }
+
+
+    state = prevstate = ST_START;
+    buf = NULL;
+    as = NULL;
+    if (( std_ps = ps_alloc( std_open )) == NULLPS ||
+           std_setup( std_ps, ofp ) != OK ) {
+       fprintf( stderr, "std_ps setup failed - help!\n" );
+       exit( 1 );
+    }
+    if (( rps = ps_alloc( str_open )) == NULLPS ||
+           str_setup( rps, NULLCP, 0, 0 ) != OK ) {
+       fprintf( stderr, "rps setup failed - help!\n" );
+       exit( 1 );
+    }
+
+
+    while ( gets( nbuf ) != NULL ) {
+       if ( nbuf[ 0 ] == '\0' ) {
+           if ( state == ST_NL1 ) {
+               if ( prevstate == ST_ARGS ) {
+                   /* We've got an attribute sequence to print */
+                   if ( modtype == TY_ADD ) {
+                       print_as( as, 0, ofp ); 
+                   } else {
+                       print_as( as, modstate, ofp ); 
+                   }
+                   /* as_print( std_ps, as, EDBOUT ); */
+                   as_free( as );
+                   as = NULL;
+               }
+               state = ST_START;
+               fprintf( ofp, "\n" );
+               fflush( ofp );
+               /* If writing to a file, release the lock */
+               if ( ofile != NULL ) {
+                   lock_fclose( ofp, lfp );
+               }
+           } else {
+               prevstate = state;
+               state = ST_NL1;
+           }
+           continue;
+       }
+
+       /* See if we've got a line continuation to deal with */
+       nbuflen = strlen( nbuf );
+       if ( state == ST_CONCAT ) {
+           for ( p = nbuf; isspace( *p ); p++, nbuflen-- ); /* skip space */
+           buf = realloc( buf, buflen + nbuflen + 1 );
+           strcat( buf, p );
+           buflen += ( nbuflen );
+       } else {
+           if ( buf != NULL ) {
+               free( buf );
+           }
+           buf = strdup( nbuf );
+           buflen = nbuflen;
+       }
+       if ( buf[ buflen - 1 ] == '\\' ) {
+           if ( state != ST_CONCAT ) {
+               prevstate = state;
+           }
+           state = ST_CONCAT;
+           buf[ buflen - 1 ] = '\0';
+           buflen--;
+           continue;
+       } else if ( state == ST_CONCAT ) {
+           state = prevstate;
+       }
+
+       if ( state == ST_PUNT ) {
+           continue;
+       }
+
+       if ( state == ST_START ) {
+           /*
+            * Acquire the file lock if writing to a file.
+            */
+           if ( ofile != NULL ) {
+               if (( ofp = lock_fopen( ofile, "a", &lfp )) == NULL ) {
+                   perror( "open" );
+                   exit( 1 );
+               }
+           }
+           /*
+            * If we have a changelog entry, then go ahead
+            * and write the replica: lines for the replog entry.
+            */
+           for ( i = 0; replicas[ i ] != NULL; i++ ) {
+               fprintf( ofp, "replica: %s\n", replicas[ i ] );
+           }
+           fprintf( ofp, "time: %ld\n", time( NULL ));
+           state = ST_DN;
+           continue;
+       }
+
+       if ( state == ST_DN ) {
+           /* Second line - dn (quipu-style) of entry to be modified */
+           if (( ldapdn = dn2ldap( buf )) == NULL ) {
+               fprintf( ofp, "dn: (conversion failed)\n" );
+           } else {
+               fprintf( ofp, "dn: %s%s\n", ldapdn, dn_suffix );
+               free( ldapdn );
+           }
+           state = ST_TYPE;
+           continue;
+       }
+
+       if ( state == ST_TYPE ) {
+           state = ST_ARGS;
+           modstate = 0;
+           if ( !strcmp( buf, "modify" )) {
+               modtype = TY_MODIFYTYPE;
+               fprintf( ofp, "changetype: modify\n" );
+           } else if ( !strcmp( buf, "add" )) {
+               modtype = TY_ADD;
+               fprintf( ofp, "changetype: add\n" );
+               as = NULL;
+           } else if ( !strcmp( buf, "remove" )) {
+               modtype = TY_REMOVE;
+               fprintf( ofp, "changetype: delete\n" );
+           } else if ( !strcmp( buf, "newrdn" )) {
+               modtype = TY_NEWRDN;
+               fprintf( ofp, "changetype: modrdn\n" );
+           } else {
+               modtype = TY_PUNT;
+               state = ST_BAD;
+           }
+           continue;
+       }
+
+       if ( state == ST_ARGS ) {
+           switch ( modtype ) {
+           case TY_NEWRDN:
+               fprintf( ofp, "newrdn: %s\n", buf );
+               break;
+           case TY_REMOVE:     /* No additional args */
+               break;
+           case TY_ADD:
+               as = as_combine( as, buf, 0 );
+               break;
+           case TY_MODIFYTYPE:
+           case TY_MODIFYARGS:
+               if ( buf[ 0 ] == '\0' ) {
+                   state == ST_NL1;
+                   if ( as != NULL ) {
+                       print_as( as, modstate, ofp);
+                       as_free( as );
+                       as = NULL;
+                   }
+                   continue;
+               }
+               if (!strcmp( buf, "addvalues" )) {
+                   if ( as != NULL ) {
+                       print_as( as, modstate, ofp );
+                       as_free( as );
+                       as = NULL;
+                   }
+                   modstate = MOD_ADDVALUES;
+                   continue;
+               } else if (!strcmp( buf, "removevalues" )) {
+                   if ( as != NULL ) {
+                       print_as( as, modstate, ofp );
+                       as_free( as );
+                       as = NULL;
+                   }
+                   modstate = MOD_REMOVEVALUES;
+                   continue;
+               } else if (!strcmp( buf, "addattribute" )) {
+                   if ( as != NULL ) {
+                       print_as( as, modstate, ofp );
+                       as_free( as );
+                       as = NULL;
+                   }
+                   modstate = MOD_ADDATTRIBUTE;
+                   continue;
+               } else if (!strcmp( buf, "removeattribute" )) {
+                   if ( as != NULL ) {
+                       print_as( as, modstate, ofp );
+                       as_free( as );
+                       as = NULL;
+                   }
+                   modstate = MOD_REMOVEATTRIBUTE;
+                   continue;
+               } 
+               switch ( modstate ) {
+               case MOD_ADDVALUES:
+                   as = as_combine( as, buf, 0 );
+                   break;
+               case MOD_REMOVEVALUES:
+                   as = as_combine( as, buf, 0 );
+                   break;
+               case MOD_ADDATTRIBUTE:
+                   as = as_combine( as, buf, 0 );
+                   break;
+               case MOD_REMOVEATTRIBUTE:
+                   fprintf( ofp, "delete: %s\n-\n", buf);
+                   break;
+               }
+           }
+           continue;
+       }
+    }
+
+    if ( ofile != NULL ) {
+       lock_fclose( ofp, lfp );
+       sprintf( nbuf, "%s.lock", ofile );
+       (void) unlink( nbuf );
+    }
+    exit( 0 );
+}
diff --git a/servers/slapd/tools/edb2ldif.c b/servers/slapd/tools/edb2ldif.c
new file mode 100644 (file)
index 0000000..d46be1e
--- /dev/null
@@ -0,0 +1,916 @@
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <quipu/config.h>
+#include <quipu/entry.h>
+#include <quipu/commonarg.h>
+#include <quipu/attrvalue.h>
+
+#if ICRELEASE > 1
+#define HAVE_FILE_ATTR_DIR
+#endif
+
+#ifdef TURBO_DISK
+#define HAVE_PARSE_ENTRY
+#endif
+
+#define DEF_EDBFILENAME                "EDB"
+#define EDB_ROOT_FILENAME      "EDB.root"
+#define DEF_BASEDN             ""
+#define EDBMAP_FILENAME                "EDB.map"
+#define ADDVALS_FILENAME       ".add"
+
+#define MAX_LINE_SIZE  2048
+
+#define VERBOSE_ENTRY_REPORT_THRESHOLD 250
+
+
+/* data structures */
+struct edbmap {
+    char               *edbm_filename;
+    char               *edbm_rdn;
+    struct edbmap      *edbm_next;
+};
+
+/* prototypes */
+static int edb2ldif( FILE *outfp, char *edbfile, char *basedn, int recurse );
+static int convert_entry( FILE *fp, char *edbname, FILE *outfp,
+       char *basedn, char *loc_addvals, int loc_addlen, char *linebuf );
+static int read_edbmap( char *mapfile, struct edbmap **edbmapp );
+static char *file2rdn( struct edbmap *edbmap, char *filename );
+static void free_edbmap( struct edbmap *edbmap );
+static char *read_file( char *filename, int *lenp );
+static void print_err( char *msg );
+
+
+/* globals */
+#ifdef LDAP_DEBUG
+static int     debugflg;
+#endif
+static int     verboseflg;
+static int     override_add = 0;
+static int     entrycount;
+static char    **ignore_attr = NULL;
+static char    *always_addvals = NULL;
+static int     always_addlen;
+static char    *last_dn;
+static char    *edb_home = ".";
+char           *progname;
+int            ldap_syslog = 0;
+int            ldap_syslog_level = 0;
+
+
+main( argc, argv )
+    int                argc;
+    char       **argv;
+{
+    char       *usage = "usage: %s [-d] [-o] [-r] [-v] [-b basedn] [-a addvalsfile] [-f fileattrdir] [-i ignoreattr...] [edbfile...]\n";
+    char       edbfile[ MAXNAMLEN ], *basedn;
+    int                c, rc, errflg, ignore_count, recurse;
+    extern int  optind;
+    extern char        *optarg;
+    extern char        dsa_mode;
+#ifdef HAVE_FILE_ATTR_DIR
+    extern char        *file_attr_directory;
+#endif
+
+    if (( progname = strrchr( argv[ 0 ], '/' )) == NULL ) {
+       progname = argv[ 0 ];
+    } else {
+       ++progname;
+    }
+
+    errflg = recurse = 0;
+#ifdef LDAP_DEBUG
+    debugflg = 0;
+#endif
+    ignore_count = 0;
+    always_addvals = NULL;
+    basedn = NULL;
+
+    while (( c = getopt( argc, argv, "dorva:b:f:h:i:" )) != -1 ) {
+       switch( c ) {
+       case 'd':
+#ifdef LDAP_DEBUG
+           ++debugflg;
+#else
+           fprintf( stderr, "Ignoring -d:  compile with -DLDAP_DEBUG to enable this option.\n" );
+#endif
+           break;
+
+       case 'o':
+           ++override_add;     
+           break;
+
+       case 'r':
+           ++recurse;  
+           break;
+
+       case 'v':
+           ++verboseflg;
+           break;
+
+       case 'a':
+           if ( always_addvals != NULL ) {
+               ++errflg;
+           } else if (( always_addvals = read_file( optarg, &always_addlen ))
+                   == NULL ) {
+               print_err( optarg );
+               exit( 1 );
+           }
+           break;
+
+       case 'b':
+           if ( basedn != NULL ) {
+               ++errflg;
+           } else {
+               basedn = optarg;
+           }
+           break;
+
+       case 'f':
+#ifdef HAVE_FILE_ATTR_DIR
+           /* add trailing slash to directory name if missing */
+           if ( *( optarg + strlen( optarg ) - 1 ) == '/' ) {
+               file_attr_directory = strdup( optarg );
+           } else if (( file_attr_directory = (char *)malloc( strlen( optarg )
+                   + 2 )) != NULL ) {
+               sprintf( file_attr_directory, "%s/", optarg );
+       
+           }
+           if ( file_attr_directory == NULL ) {
+               print_err( "malloc" );
+               exit( 1 );
+           }
+#else /* HAVE_FILE_ATTR_DIR */
+           fprintf( stderr, "Ignoring -f:  this option requires a newer version of ISODE.\n" );
+#endif /* HAVE_FILE_ATTR_DIR */
+           break;
+
+       case 'h':
+           edb_home = optarg;
+           break;
+
+       case 'i':
+           if ( ignore_count == 0 ) {
+               ignore_attr = (char **)malloc( 2 * sizeof( char * ));
+           } else {
+               ignore_attr = (char **)realloc( ignore_attr,
+                   ( ignore_count + 2 ) * sizeof( char * ));
+           }
+           if ( ignore_attr == NULL ) {
+               print_err( "malloc/realloc" );
+               exit( 1 );
+           }
+           ignore_attr[ ignore_count ] = optarg;
+           ignore_attr[ ++ignore_count ] = NULL;
+           break;
+
+       default:
+           ++errflg;
+       }
+    }
+
+    if ( errflg ) {
+       fprintf( stderr, usage, progname );
+       exit( 1 );
+    }
+
+    if ( basedn == NULL ) {
+       basedn = DEF_BASEDN;
+    }
+
+    /* load & initialize quipu syntax handlers */
+    quipu_syntaxes();
+#ifdef LDAP_USE_PP
+    pp_quipu_init( progname );
+#endif
+    dsap_init( NULL, NULL );
+
+    dsa_mode = 1;      /* so {CRYPT} is accepted by EDB parse routines */
+
+    if ( init_syntaxes() < 0 ) {
+       fprintf( stderr, "%s: init_syntaxes failed -- check your oid tables \n",
+           progname );
+       exit( 1 );
+    }
+
+
+    entrycount = 0;
+
+    /* process EDB file(s) */
+    if ( optind >= argc ) {
+       *edbfile = '\0';
+       rc = edb2ldif( stdout, edbfile, basedn, recurse );
+    } else {
+       for ( rc = 0; rc >= 0 && optind < argc; ++optind ) {
+           if ( argv[ optind ][ 0 ] == '/' ) {
+               strcpy( edbfile, argv[ optind ] );
+           } else {
+               sprintf( edbfile, "%s/%s", edb_home, argv[ optind ] );
+           }
+           rc = edb2ldif( stdout, edbfile, basedn, recurse );
+       }
+    }
+
+    if ( last_dn != NULL ) {
+       free( last_dn );
+    }
+
+#ifdef LDAP_DEBUG
+    fprintf( stderr, "edb2ldif: exit( %d )\n", ( rc < 0 ) ? 1 : 0 );
+#endif
+
+    exit( ( rc < 0 ) ? 1 : 0 );
+}
+
+
+static int
+edb2ldif( outfp, edbfile, basedn, recurse )
+    FILE       *outfp;
+    char       *edbfile;
+    char       *basedn;
+    int                recurse;
+{
+    FILE       *fp;
+    char       *addvals, *p, *rdn, line[ MAX_LINE_SIZE + 1 ];
+    char       dirname[ MAXNAMLEN ], filename[ MAXNAMLEN ];
+    int                err, startcount, addvals_len;
+    struct stat        st;
+
+#ifdef LDAP_DEBUG
+    if ( debugflg ) {
+       fprintf( stderr, "edb2ldif( 0x%X, \"%s\", \"%s\", %d)\n",
+               outfp, edbfile, basedn, recurse );
+    }
+#endif
+
+    if ( *edbfile == '\0' ) {
+       sprintf( filename, "%s/%s", edb_home, EDB_ROOT_FILENAME );
+       if ( stat( filename, &st ) == 0 ) {
+           if (( err = edb2ldif( outfp, filename, basedn, 0 )) < 0 ) {
+#ifdef LDAP_DEBUG
+               if ( debugflg ) {
+                   fprintf( stderr, "edb2ldif: 0 return( %d )\n", err );
+               }
+#endif
+               return( err );
+           }
+           if (( basedn = strdup( last_dn )) == NULL ) {
+               print_err( "strdup" );
+#ifdef LDAP_DEBUG
+               if ( debugflg ) {
+                   fprintf( stderr, "edb2ldif: 1 return( -1 )\n" );
+               }
+#endif
+               return( -1 );
+           }
+       }
+       sprintf( edbfile, "%s/%s", edb_home, DEF_EDBFILENAME );
+    }
+
+    if ( verboseflg ) {
+       fprintf( stderr, "%s: converting EDB file: \"%s\"\n\tbasedn: \"%s\"\n",
+               progname, edbfile, basedn );
+    }
+
+    startcount = entrycount;
+    err = 0;
+
+
+    /* construct name of directory we are working in */
+    if (( p = strrchr( edbfile, '/' )) == NULL ) {
+       dirname[ 0 ] = '.';
+       dirname[ 1 ] = '\0';
+    } else {
+       strncpy( dirname, edbfile, p - edbfile );
+       dirname[ p - edbfile ] = '\0';
+    }
+
+    /* load local ".add" file (if any) */
+    sprintf( filename, "%s/%s", dirname, ADDVALS_FILENAME );
+    addvals_len = 0;
+    addvals = read_file( filename, &addvals_len );
+
+    /* read and convert this EDB file */
+    if (( fp = fopen( edbfile, "r" )) == NULL ) {
+       print_err( edbfile );
+       if ( addvals != NULL ) {
+           free( addvals );
+       }
+#ifdef LDAP_DEBUG
+       if ( debugflg ) {
+           fprintf( stderr, "edb2ldif: 2 return( -1 )\n" );
+       }
+#endif
+       return( -1 );
+    }
+
+    /* skip first two lines (type and timestamp) if they are present */
+    if ( fgets( line, MAX_LINE_SIZE, fp ) == NULL ) {
+       err = -1;
+    } else {
+       line[ strlen( line ) - 1 ] = '\0';
+       if ( strcmp( line, "MASTER" ) == 0 || strcmp( line, "SLAVE" ) == 0 ||
+               strcmp( line, "CACHE" ) == 0 ) {
+           if ( fgets( line, MAX_LINE_SIZE, fp ) == NULL ) {
+               err = -1;
+           }
+       } else {
+           rewind( fp );
+       }
+    }
+
+    if ( err != 0 ) {
+       fprintf( stderr, "%s: skipping empty EDB file %s\n", progname,
+               edbfile );
+       err = 0;        /* treat as a non-fatal error */
+    } else {
+       while ( !feof( fp ) && ( err = convert_entry( fp, edbfile, outfp,
+               basedn, addvals, addvals_len, line )) > 0 ) {
+           if ( verboseflg && (( entrycount - startcount ) %
+                   VERBOSE_ENTRY_REPORT_THRESHOLD ) == 0 ) {
+               fprintf( stderr, "\tworking... %d entries done...\n", 
+                       entrycount - startcount );
+           }
+       }
+    }
+
+    fclose( fp );
+    if ( addvals != NULL ) {
+       free( addvals );
+    }
+
+    if ( err < 0 ) {
+#ifdef LDAP_DEBUG
+       if ( debugflg ) {
+           fprintf( stderr, "edb2ldif: 3 return( %d )\n", err );
+       }
+#endif
+       return( err );
+    }
+
+    if ( verboseflg ) {
+       fprintf( stderr, "\t%d entries converted\n\n", 
+               entrycount - startcount );
+    }
+
+    /* optionally convert EDB file within sub-directories */
+    if ( recurse ) {
+       char            *newbase;
+       DIR             *dp;
+       struct dirent   *dep;
+       struct edbmap   *edbmap;
+
+       /* open this directory */
+       if (( dp = opendir( dirname )) == NULL ) {
+           print_err( dirname );
+#ifdef LDAP_DEBUG
+           if ( debugflg ) {
+               fprintf( stderr, "edb2ldif: 4 return( -1 )\n" );
+           }
+#endif
+           return( -1 );
+       }
+
+       /* check for EDB.map file and record contents for future reference */
+       sprintf( filename, "%s/%s", dirname, EDBMAP_FILENAME );
+       if ( read_edbmap( filename, &edbmap ) < 0 ) {
+           print_err( "read_edbmap" );
+           closedir( dp );
+#ifdef LDAP_DEBUG
+           if ( debugflg ) {
+               fprintf( stderr, "edb2ldif: 5 return( -1 )\n" );
+           }
+#endif
+           return( -1 );
+       }
+
+       p = dirname + strlen( dirname );
+       *p++ = '/';
+       *p = '\0';
+
+       /* scan looking for sub-directories w/EDB files in them */
+       err = 0;
+       while ( err >= 0 && ( dep = readdir( dp )) != NULL ) {
+           if ( dep->d_name[ 0 ] == '.' && ( dep->d_name[ 1 ] == '\0' ||
+                   ( dep->d_name[ 1 ] == '.' && dep->d_name[ 2 ] == '\0' ))) {
+               continue;       /* skip "." and ".." */
+           }
+
+           strcpy( p, dep->d_name );
+#ifdef LDAP_DEBUG
+           if ( debugflg ) {
+               fprintf( stderr, "edb2ldif: checking directory \"%s\"\n",
+                       dirname );
+           }
+#endif
+
+           if ( stat( dirname, &st ) != 0 ) {
+               print_err( dirname );
+           } else if ( S_ISDIR( st.st_mode )) {
+               sprintf( filename, "%s/%s", dirname, DEF_EDBFILENAME );
+
+               if ( stat( filename, &st ) == 0 && S_ISREG( st.st_mode )) {
+                   if (( newbase = malloc( strlen( basedn ) +
+                           strlen( dep->d_name ) + 3 )) == NULL ) {
+                       print_err( "malloc" );
+                       err = -1;
+                       continue;
+                   }
+
+                   sprintf( newbase, "%s@%s", basedn,
+                           file2rdn( edbmap, dep->d_name ));
+
+                   /* recurse */
+                   err = edb2ldif( outfp, filename, newbase, recurse );
+
+                   free( newbase );
+               }
+           }
+       }
+
+       free_edbmap( edbmap );
+       closedir( dp );
+
+       if ( verboseflg ) {
+           fprintf( stderr, "%s: %d total entries converted under \"%s\"\n\n",
+                   progname, entrycount - startcount, basedn );
+       }
+    }
+
+#ifdef LDAP_DEBUG
+    if ( debugflg ) {
+       fprintf( stderr, "edb2ldif: 6 return( %d )\n", err );
+    }
+#endif
+    return( err );
+}
+
+
+/*
+ * read one entry from fp and write to outfp.
+ * return > 0 if entry converted, 0 if end of file, < 0 if error occurs
+ */
+static int
+convert_entry( fp, edbname, outfp, basedn, loc_addvals, loc_addlen, linebuf )
+    FILE       *fp;
+    char       *edbname;
+    FILE       *outfp;
+    char       *basedn;
+    char       *loc_addvals;
+    int                loc_addlen;
+    char       *linebuf;
+{
+    Attr_Sequence      as, tmpas;
+    AV_Sequence                av;
+    PS                 attrtype_ps, val_ps;
+    char               *dnstr;
+    DN                 dn;
+    RDN                        rdn;
+    int                        valcnt;
+    extern int         parse_status;
+    extern char                *parse_file;
+    extern RDN         parse_rdn;
+#ifdef HAVE_PARSE_ENTRY
+    extern char                *parse_entry;
+    extern Attr_Sequence       fget_attributes();
+#else /* HAVE_PARSE_ENTRY */
+    extern Attr_Sequence       get_attributes();
+#endif /* HAVE_PARSE_ENTRY */
+
+#ifdef LDAP_DEBUG
+    if ( debugflg ) {
+       fprintf( stderr, "convert_entry( 0x%X, \"%s\", 0x%X, \"%s\", ...)\n",
+               fp, edbname, outfp, basedn );
+    }
+#endif
+
+    while (( dnstr = fgets( linebuf, MAX_LINE_SIZE, fp )) != NULL &&
+           *linebuf == '\n' ) {
+       ;
+    }
+
+    if ( dnstr == NULL ) {
+       return( feof( fp ) ? 0 : -1 );  /* end of file or error */
+    }
+
+    linebuf[ strlen( linebuf ) - 1 ] = '\0';
+
+    if (( dnstr = malloc( strlen( basedn ) + strlen( linebuf ) + 2 ))
+           == NULL ) {
+       print_err( "convert_entry" );
+       return( -1 );
+    }
+    sprintf( dnstr, "%s@%s", basedn, linebuf );
+    if ( last_dn != NULL ) {
+       free( last_dn );
+    }
+    last_dn = dnstr;
+
+    if ( entrycount > 0 ) {
+       fputc( '\n', outfp );
+    }
+
+    /*
+     * parse_entry, parse_file and parse_rdn are needed inside the
+     * libisode decoding routines, so we set it here.
+     */
+    parse_file = edbname;
+#ifdef HAVE_PARSE_ENTRY
+    parse_entry = dnstr;
+#endif
+    parse_rdn = rdn = str2rdn( linebuf );
+
+    if (( val_ps = ps_alloc( str_open )) == NULLPS ||
+           str_setup( val_ps, NULLCP, 0, 0 ) == NOTOK ) {
+       fprintf( stderr, "%s: ps_alloc/setup failed (EDB file %s)\n", progname,
+               edbname );
+       if ( rdn != NULLRDN ) {
+           rdn_free( rdn );
+       }
+       return( -1 );
+    }
+
+    if (( dn = str2dn( dnstr )) == NULLDN || av2ldif( outfp, NULL, dn,
+           0, "dn", val_ps ) < 0 ) {
+       sprintf( linebuf,
+               "str2dn or av2ldif of DN failed (EDB file %s, entry %s)\n", 
+               edbname, dnstr );
+       print_err( linebuf );
+       if ( dn != NULLDN ) {
+           dn_free( dn );
+       }
+       ps_free( val_ps );
+       if ( rdn != NULLRDN ) {
+           rdn_free( rdn );
+       }
+       return( -1 );
+    }
+    dn_free( dn );
+
+    ++entrycount;
+
+    if ( always_addvals != NULL && ( loc_addvals == NULL || !override_add )
+           && fwrite( always_addvals, always_addlen, 1, outfp ) != 1 ) {
+       sprintf( linebuf,
+               "write of additional values failed (EDB file %s, entry %s)\n", 
+               edbname, dnstr );
+       print_err( linebuf );
+       ps_free( val_ps );
+       if ( rdn != NULLRDN ) {
+           rdn_free( rdn );
+       }
+       return( -1 );
+    }
+
+    if ( loc_addvals != NULL && fwrite( loc_addvals, loc_addlen, 1,
+           outfp ) != 1 ) {
+       sprintf( linebuf,
+               "write of additional values failed (EDB file %s, entry %s)\n", 
+               edbname, dnstr );
+       print_err( linebuf );
+       ps_free( val_ps );
+       if ( rdn != NULLRDN ) {
+           rdn_free( rdn );
+       }
+       return( -1 );
+    }
+
+
+#ifdef HAVE_PARSE_ENTRY
+    as = fget_attributes( fp );
+#else /* HAVE_PARSE_ENTRY */
+    as = get_attributes( fp );
+#endif /* HAVE_PARSE_ENTRY */
+
+    if ( parse_status != 0 ) {
+       fprintf( stderr, "%s: problem parsing entry (EDB file %s)\n", progname,
+               edbname );
+       ps_free( val_ps );
+       if ( as != NULLATTR ) {
+           as_free( as );
+       }
+       if ( rdn != NULLRDN ) {
+           rdn_free( rdn );
+       }
+       return( -1 );
+    }
+
+    if ( add_rdn_values( as, rdn ) != 0 ) {
+       sprintf( linebuf,
+           "adding RDN values(s) failed (EDB file %s, entry %s)\n", 
+           edbname, dnstr );
+       print_err( linebuf );
+       if ( as != NULLATTR ) {
+           as_free( as );
+       }
+       if ( rdn != NULLRDN ) {
+           rdn_free( rdn );
+       }
+       return( -1 );
+    }
+
+    if (( attrtype_ps = ps_alloc( str_open )) == NULLPS ||
+           str_setup( attrtype_ps, NULLCP, 0, 0 ) == NOTOK ) {
+       fprintf( stderr, "%s: ps_alloc/setup failed (EDB file %s)\n", progname,
+               edbname );
+       if ( as != NULLATTR ) {
+           as_free( as );
+       }
+       if ( rdn != NULLRDN ) {
+           rdn_free( rdn );
+       }
+       return( -1 );
+    }
+
+    for ( tmpas = as; tmpas != NULLATTR; tmpas = tmpas->attr_link ) {
+       attrtype_ps->ps_ptr = attrtype_ps->ps_base;
+       AttrT_print( attrtype_ps, tmpas->attr_type, EDBOUT );
+       *attrtype_ps->ps_ptr = '\0';
+
+       if ( ignore_attr != NULL ) {
+           int i;
+
+           for ( i = 0; ignore_attr[ i ] != NULL; ++i ) {
+               if ( strcasecmp( attrtype_ps->ps_base, ignore_attr[ i ] )
+                       == 0 ) {
+                   break;
+               }
+           }
+           if ( ignore_attr[ i ] != NULL ) {
+               continue;       /* skip this attribute */
+           }
+       }
+
+       valcnt = 0;
+       for ( av = tmpas->attr_value; av != NULLAV; av = av->avseq_next ) {
+           ++valcnt;
+           if ( av2ldif( outfp, av, NULL, tmpas->attr_type->oa_syntax,
+                   attrtype_ps->ps_base, val_ps ) < 0 ) {
+               sprintf( linebuf,
+                       "av2ldif failed (EDB file %s, entry %s, attribute %s, value no. %d)\n", 
+                       edbname, dnstr, attrtype_ps->ps_base, valcnt );
+               print_err( linebuf );
+               ps_free( attrtype_ps );
+               ps_free( val_ps );
+               as_free( as );
+               if ( rdn != NULLRDN ) {
+                   rdn_free( rdn );
+               }
+               return( -1 );
+           }
+       }
+    }
+
+    ps_free( attrtype_ps );
+    ps_free( val_ps );
+    as_free( as );
+    if ( rdn != NULLRDN ) {
+       rdn_free( rdn );
+    }
+
+    return( 1 );
+}
+
+
+int
+add_rdn_values( entryas, rdn )
+    Attr_Sequence      entryas;
+    RDN                        rdn;
+{
+/*
+ * this routine is based on code from the real_unravel_attribute() routine
+ * found in isode-8.0/.dsap/common/attribute.c
+ */
+    AttributeType      at;
+    AV_Sequence        avs;
+    Attr_Sequence      as;
+
+    for (; rdn != NULLRDN; rdn = rdn->rdn_next ) {
+       if (( as = as_find_type( entryas, rdn->rdn_at )) == NULLATTR ) {
+           at = AttrT_cpy( rdn->rdn_at );
+           avs = avs_comp_new( AttrV_cpy(&rdn->rdn_av ));
+           as  = as_comp_new( at, avs, NULLACL_INFO );
+           entryas = as_merge( entryas, as );
+       } else {
+           for ( avs = as->attr_value; avs != NULLAV; avs = avs->avseq_next ) {
+               if ( AttrV_cmp( &rdn->rdn_av, &avs->avseq_av ) == 0 ) {
+                   break;
+               }
+           }
+
+           if ( avs == NULLAV ) {
+               avs = avs_comp_new( AttrV_cpy( &rdn->rdn_av ));
+               as->attr_value = avs_merge( as->attr_value, avs );
+           }
+       }
+    }
+
+    return( 0 );
+}
+
+
+/* read the EDB.map file and return a linked list of translations */
+static int
+read_edbmap( mapfile, edbmapp )
+    char               *mapfile;
+    struct edbmap      **edbmapp;
+{
+    FILE               *fp;
+    char               *p, *filename, *rdn, line[ MAX_LINE_SIZE + 1 ];
+    int                        err;
+    struct edbmap      *emp, *tmpemp;
+
+#ifdef LDAP_DEBUG
+    if ( debugflg ) {
+       fprintf( stderr, "read_edbmap( \"%s\", ...)\n", mapfile );
+    }
+#endif
+
+    if (( fp = fopen( mapfile, "r" )) == NULL ) {
+       *edbmapp = NULL;
+       return( 0 );    /* soft error -- no EDB.map file */
+    }
+
+    emp = NULL;
+
+    /*
+     * read all the lines in the file, looking for lines of the form:
+     * RDN # filename
+     */
+    err = 0;
+    while ( err == 0 && fgets( line, MAX_LINE_SIZE, fp ) != NULL ) {
+       line[ strlen( line ) - 1 ] = '\0';      /* remove trailing newline */
+       if (( filename = strchr( line, '#' )) == NULL ) {
+           continue;
+       }
+
+       *filename++ = '\0';
+       while ( isspace( *filename )) { /* strip leading whitespace */
+           ++filename;
+       }
+
+       if ( *filename == '\0' ) {
+           continue;
+       }
+
+       p = filename + strlen( filename ) - 1;
+       while ( isspace( *p )) {        /* strip trailing whitespace */
+           *p-- = '\0';
+       }
+
+       rdn = line;
+       while ( isspace( *rdn )) {      /* strip leading whitespace */
+           ++rdn;
+       }
+
+       if ( *rdn == '\0' ) {
+           continue;
+       }
+
+       p = rdn + strlen( rdn ) - 1;
+       while ( isspace( *p )) {        /* strip trailing whitespace */
+           *p-- = '\0';
+       }
+
+       if (( tmpemp = (struct edbmap *)calloc( 1, sizeof( struct edbmap )))
+               == NULL ||
+               ( tmpemp->edbm_filename = strdup( filename )) == NULL ||
+               ( tmpemp->edbm_rdn = strdup( rdn )) == NULL ) {
+           err = -1;
+       } else {
+           tmpemp->edbm_next = emp;
+           emp = tmpemp;
+       }
+    }
+
+    fclose( fp );
+
+    if ( err == 0 ) {
+       *edbmapp = emp;
+    } else {
+       free_edbmap( emp );
+    }
+
+    return( err );
+}
+
+
+static char *
+file2rdn( edbmap, filename )
+    struct edbmap      *edbmap;
+    char               *filename;
+{
+#ifdef LDAP_DEBUG
+    if ( debugflg ) {
+       fprintf( stderr, "file2rdn( 0x%X, \"%s\" )\n", edbmap, filename );
+    }
+#endif
+
+    while ( edbmap != NULL ) {
+       if ( strcmp( filename, edbmap->edbm_filename ) == 0 ) {
+           break;
+       }
+       edbmap = edbmap->edbm_next;
+    }
+
+    return(( edbmap == NULL ) ? filename : edbmap->edbm_rdn );
+}
+
+
+/* free the edbmap list */
+static void
+free_edbmap( edbmap )
+    struct edbmap      *edbmap;
+{
+    struct edbmap      *tmp;
+
+#ifdef LDAP_DEBUG
+    if ( debugflg ) {
+       fprintf( stderr, "free_edbmap( 0x%X )\n", edbmap );
+    }
+#endif
+
+    while ( edbmap != NULL ) {
+       if ( edbmap->edbm_filename != NULL ) free( edbmap->edbm_filename );
+       if ( edbmap->edbm_rdn != NULL ) free( edbmap->edbm_rdn );
+       tmp = edbmap;
+       edbmap = edbmap->edbm_next;
+       free( tmp );
+    }
+}
+
+
+static void
+print_err( msg )
+    char       *msg;
+{
+    extern int sys_nerr;
+    extern char        *sys_errlist[];
+    extern int errno;
+
+#ifdef LDAP_DEBUG
+    if ( debugflg ) {
+       fprintf( stderr, "print_err( \"%s\" )\n", msg );
+    }
+#endif
+
+    if ( errno > sys_nerr ) {
+       fprintf( stderr, "%s: %s: error %d\n", progname, msg, errno );
+    } else {
+       fprintf( stderr, "%s: %s: %s\n", progname, msg, sys_errlist[ errno ] );
+    }
+}
+
+
+static char *
+read_file( char *filename, int *lenp )
+{
+    FILE       *fp;
+    struct stat        st;
+    char       *buf;
+
+#ifdef LDAP_DEBUG
+    if ( debugflg ) {
+       fprintf( stderr, "read_file( \"%s\", 0x%X )\n", filename, lenp );
+    }
+#endif
+
+    if ( stat( filename, &st ) != 0 || !S_ISREG( st.st_mode ) ||
+           ( fp = fopen( filename, "r" )) == NULL ) {
+       return( NULL );
+    }
+
+    if (( buf = (char *)malloc( st.st_size )) == NULL ) {
+       fclose( fp );
+       return( NULL );
+    }
+
+    if ( fread( buf, st.st_size, 1, fp ) != 1 ) {
+       fclose( fp );
+       free( buf );
+       return( NULL );
+    }
+
+    fclose( fp );
+    *lenp = st.st_size;
+    return( buf );
+}
diff --git a/servers/slapd/tools/ldapsyntax.c b/servers/slapd/tools/ldapsyntax.c
new file mode 100644 (file)
index 0000000..4fa12c4
--- /dev/null
@@ -0,0 +1,457 @@
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <quipu/commonarg.h>
+#include <quipu/attrvalue.h>
+#include <quipu/ds_error.h>
+#include <quipu/ds_search.h>
+/* #include <quipu/dap2.h> */
+#include <quipu/dua.h>
+#include <sys/types.h>
+
+#include "lber.h"
+#include "ldap.h"
+#include "ldif.h"
+#include "ldapsyntax.h"
+
+short  ldap_dn_syntax;
+short   ldap_password_syntax;
+short  ldap_photo_syntax;
+short  ldap_jpeg_syntax;
+short  ldap_audio_syntax;
+
+static int     dn2ldif( PS ps, DN dn );
+static int     jpeg2ldif( PS ps, AttributeValue av );
+static int     audio2ldif( PS ps, AttributeValue av );
+static int     photo2ldif( PS ps, AttributeValue av );
+static int     fileattr2ldif( PS ps, AttributeValue av );
+static void    de_t61( char *s, int t61mark );
+static void    de_crypt( char *s );
+
+extern char    *progname;
+
+#define SEPARATOR(c)   (c == ',' || c == ';')
+#define SPACE(c)       (c == ' ' || c == '\n')
+
+
+int
+init_syntaxes()
+{
+    if (( ldap_dn_syntax = str2syntax( "DN" )) == 0 ) {
+       return( -1 );   /* must have this syntax handler */
+    }
+    ldap_password_syntax = str2syntax( "password" );
+    ldap_photo_syntax = str2syntax( "photo" );
+    ldap_jpeg_syntax = str2syntax( "jpeg" );
+    ldap_audio_syntax = str2syntax( "audio" );
+
+    return( 0 );
+}
+
+
+/*
+ * av2ldif:  convert attribute value contained in "av" to ldif format
+ * and write to "outfp".  If "dn" is not NULL, convert it instead of "av".
+ */
+int
+av2ldif( FILE *outfp, AV_Sequence av, DN dn, short syntax, char *attrname,
+    PS str_ps )
+{
+    char               *buf;
+    int                        rc;
+    struct file_syntax *fsyntax;
+
+    if ( av != NULLAV ) {
+       fsyntax = (struct file_syntax *) av->avseq_av.av_struct;
+    }
+
+    rc = 0;    /* optimistic */
+    str_ps->ps_ptr = str_ps->ps_base;  /* reset string PS */
+
+    if ( dn != NULL || syntax == ldap_dn_syntax ) {    /* DNs */
+       rc = dn2ldif( str_ps, ( dn != NULLDN ) ? dn :
+               (DN)(av->avseq_av.av_struct));
+
+    } else if ( syntax == ldap_jpeg_syntax || ( syntax > AV_WRITE_FILE &&
+           fsyntax->fs_real_syntax == ldap_jpeg_syntax )) {
+       rc = jpeg2ldif( str_ps, &av->avseq_av );
+
+    } else if ( syntax == ldap_photo_syntax || ( syntax > AV_WRITE_FILE &&
+           fsyntax->fs_real_syntax == ldap_photo_syntax )) {
+       rc = photo2ldif( str_ps, &av->avseq_av );
+
+    } else if ( syntax == ldap_audio_syntax || ( syntax > AV_WRITE_FILE &&
+           fsyntax->fs_real_syntax == ldap_audio_syntax )) {
+       rc = audio2ldif( str_ps, &av->avseq_av );
+
+    } else if ( syntax > AV_WRITE_FILE ) {
+       rc = fileattr2ldif( str_ps, &av->avseq_av );
+
+    } else {
+       AttrV_print( str_ps, &av->avseq_av, EDBOUT );
+       *str_ps->ps_ptr = '\0';
+       de_t61( str_ps->ps_base, 0 );
+
+       if ( syntax == ldap_password_syntax ) {
+           de_crypt( str_ps->ps_base );
+       }
+
+       str_ps->ps_ptr = str_ps->ps_base + strlen( str_ps->ps_base );
+    }
+
+    if ( rc == 0 && str_ps->ps_ptr > str_ps->ps_base ) {
+       *str_ps->ps_ptr = '\0';
+       if (( buf = ldif_type_and_value( attrname, str_ps->ps_base,
+               str_ps->ps_ptr - str_ps->ps_base )) == NULL ) {
+           rc = -1;
+       } else {
+           if ( fputs( buf, outfp ) == EOF ) {
+               rc = -1;
+           }
+           free( buf );
+       }
+    }
+
+    if ( rc == -2 ) {
+       if ( syntax > AV_WRITE_FILE ) {
+           fprintf( stderr,
+                   "%s: attribute file '%s' not found (skipping value)\n",
+                    progname, fsyntax->fs_name );
+       }
+       rc = 0; /* treat as "soft" error -- keep going */
+    }
+
+    return( rc );
+}
+
+
+static int
+dn2ldif( PS ps, DN dn )
+{
+    RDN        rdn;
+    int        firstrdn, rc;
+    char       *value;
+    PS rps;
+
+    if ( dn == NULLDN ) {
+       return( 0 );
+    }
+
+    if ( dn->dn_parent != NULLDN ) {
+       if (( rc = dn2ldif( ps, dn->dn_parent )) != 0 ) {
+           return( rc );
+       }
+       ps_print( ps, ", " );
+    }
+
+    if ( (rps = ps_alloc( str_open )) == NULLPS ||
+           str_setup( rps, NULLCP, 0, 0 ) == NOTOK ) {
+       return( -1 );
+    }
+
+    firstrdn = 1;
+    for ( rdn = dn->dn_rdn; rdn != NULLRDN; rdn = rdn->rdn_next ) {
+       if ( firstrdn ) {
+           firstrdn = 0;
+       } else {
+           ps_print( ps, " + " );
+       }
+
+       AttrT_print( ps, rdn->rdn_at, EDBOUT );
+       ps_print( ps, "=" );
+
+       if ( rdn->rdn_at->oa_syntax == ldap_dn_syntax ) {
+           if (( rc = dn2ldif( rps, (DN) rdn->rdn_av.av_struct )) != 0 ) {
+               return( rc );
+           }
+           *rps->ps_ptr = '\0';
+           value = rps->ps_base;
+       } else {
+           AttrV_print( rps, &rdn->rdn_av, EDBOUT );
+           *rps->ps_ptr = '\0';
+           value = rps->ps_base;
+           de_t61( value, 0 );
+       }
+
+       /*
+        * ,+="\\\n all go in quotes.  " and \\ need to
+        * be preceeded by \\.
+        */
+
+       if ( strpbrk( value, ",+=\"\\\n" ) != NULL || SPACE( value[0] )
+               || SPACE( value[max( strlen(value) - 1, 0 )] ) ) {
+           char        *p, *t, *tmp;
+           int specialcount;
+
+           ps_print( ps, "\"" );
+
+           specialcount = 0;
+           for ( p = value; *p != '\0'; p++ ) {
+               if ( *p == '"' || *p == '\\' ) {
+                   specialcount++;
+               }
+           }
+           if ( specialcount > 0 ) {
+               tmp = smalloc( strlen( value ) + specialcount + 1 );
+               for ( p = value, t = tmp; *p != '\0'; p++ ) {
+                   switch ( *p ) {
+                   case '"':
+                   case '\\':
+                           *t++ = '\\';
+                           /* FALL THROUGH */
+                   default:
+                           *t++ = *p;
+                   }
+               }
+               *t = '\0';
+               ps_print( ps, tmp );
+               free( tmp );
+           } else {
+               ps_print( ps, value );
+           }
+
+           ps_print( ps, "\"" );
+       } else {
+           ps_print( ps, value );
+       }
+
+       rps->ps_ptr = rps->ps_base;
+    }
+
+    ps_free( rps );
+
+    return( 0 );
+}
+
+#define T61    "{T.61}"
+#define T61LEN 6
+
+static void
+de_t61( s, t61mark )
+char   *s;
+int    t61mark;
+{
+       char    *next = s;
+       int     c, hex;
+
+       while ( *s ) {
+               switch ( *s ) {
+               case '{' :
+                       if ( strncasecmp( s, T61, T61LEN) == 0 ) {
+                               s += T61LEN;
+                               if ( t61mark )
+                                       *next++ = '@';
+                       } else {
+                               *next++ = *s++;
+                       }
+                       break;
+
+               case '\\':
+                       c = *(s + 1);
+                       if ( c == '\n' ) {
+                               s += 2;
+                               if ( *s == '\t' )
+                                       s++;
+                               break;
+                       }
+                       if ( isdigit( c ) )
+                               hex = c - '0';
+                       else if ( c >= 'A' && c <= 'F' )
+                               hex = c - 'A' + 10;
+                       else if ( c >= 'a' && c <= 'f' )
+                               hex = c - 'a' + 10;
+                       else {
+                               *next++ = *s++;
+                               break;
+                       }
+                       hex <<= 4;
+                       c = *(s + 2);
+                       if ( isdigit( c ) )
+                               hex += c - '0';
+                       else if ( c >= 'A' && c <= 'F' )
+                               hex += c - 'A' + 10;
+                       else if ( c >= 'a' && c <= 'f' )
+                               hex += c - 'a' + 10;
+                       else {
+                               *next++ = *s++;
+                               *next++ = *s++;
+                               break;
+                       }
+
+                       *next++ = hex;
+                       s += 3;
+                       break;
+
+               default:
+                       *next++ = *s++;
+                       break;
+               }
+       }
+       *next = '\0';
+}
+
+
+#define CRYPT_MASK 0x23
+
+static void
+de_crypt( char *s )
+{
+    char *p;
+
+    if ( strncmp( s, "{CRYPT}", 7 ) == 0 ) {
+       strcpy( s, s + 7 );                     /* strip off "{CRYPT}" */
+
+       for ( p = s; *p != '\0'; ++p) {         /* "decrypt" each byte */
+           if ( *p != CRYPT_MASK ) {
+               *p ^= CRYPT_MASK;
+           }
+       }
+    }
+}
+
+
+static int
+jpeg2ldif( PS ps, AttributeValue av )
+{
+    PE pe;
+    int        len;
+
+    if (( pe = grab_pe( av )) == NULLPE || pe->pe_id == PE_PRIM_NULL ) {
+       return( -2 );   /* signal soft error */
+    }
+
+    if (( pe->pe_class != PE_CLASS_UNIV && pe->pe_class != PE_CLASS_CONT )
+           || pe->pe_form != PE_FORM_PRIM || pe->pe_id != PE_PRIM_OCTS ) {
+       return( -1 );
+    }
+
+    if ( pe_pullup( pe ) == NOTOK ) {
+       return( -1 );
+    }
+
+    len = ps_get_abs( pe );
+
+    if ( ps_write( ps, (PElementData)pe->pe_prim, len ) == NOTOK ) {
+       return( -1 );
+    }
+
+    return( 0 );
+}
+
+
+static int
+audio2ldif( PS ps, AttributeValue av )
+{
+    PE         pe;
+    struct qbuf        *qb, *p;
+    int                rc, len;
+    char       *buf;
+
+    return( 0 );       /* for now */
+
+    if (( pe = grab_pe( av )) == NULLPE || pe->pe_id == PE_PRIM_NULL ) {
+       return( -2 );   /* signal soft error */
+    }
+
+    qb = (struct qbuf *)pe;
+
+    len = 0;
+    for ( p = qb->qb_forw; p != qb; p = p->qb_forw ) {
+       len += p->qb_len;
+    }
+
+    if (( buf = (char *) malloc( len )) == NULL ) {
+       return( -1 );
+    }
+
+    len = 0;
+    for ( p = qb->qb_forw; p != qb; p = p->qb_forw ) {
+       SAFEMEMCPY( buf + len, p->qb_data, p->qb_len );
+       len += p->qb_len;
+    }
+
+    if ( ps_write( ps, (PElementData)buf, len ) == NOTOK ) {
+       rc = -1;
+    } else {
+       rc = 0;
+    }
+
+    free( buf );
+
+    return( rc );
+}
+
+
+static int
+photo2ldif( PS ps, AttributeValue av )
+{
+    PE         pe;
+    int                len;
+    char       *faxparamset = "\000\300\000\000";
+    BerElement *phber;
+
+    if (( pe = grab_pe( av )) == NULLPE || pe->pe_id == PE_PRIM_NULL ) {
+       return( -2 );   /* signal soft error */
+    }
+
+    /* old bit string-like format - only handle this for now */
+    if ( pe->pe_class == PE_CLASS_UNIV && pe->pe_form == PE_FORM_PRIM
+           && pe->pe_id == PE_PRIM_BITS ) {
+       len = ps_get_abs( pe );
+       if (( phber = der_alloc()) == NULLBER ) {
+           return( -1 );
+       }
+       if ( ber_printf( phber, "t{[tB]{B}}", 0xA3, 0x81, faxparamset,
+               31, (char *)pe->pe_prim, len * 8 ) == -1 ) {
+           ber_free( phber, 1 );
+           return( -1 );
+       }
+       if ( ps_write( ps, (PElementData)phber->ber_buf,
+               phber->ber_ptr - phber->ber_buf ) == NOTOK ) {
+           ber_free( phber, 1 );
+           return( -1 );
+       }
+       ber_free( phber, 1 );
+    } else {
+       /*
+        * try just writing this into a PS and sending it along
+        */
+       if ( pe2ps( ps, pe ) == NOTOK ) {
+           return( -1 );
+       }
+    }
+
+    return( 0 );
+}
+
+
+static int
+fileattr2ldif( PS ps, AttributeValue av )
+{
+    PE         pe;
+
+    if (( pe = grab_pe( av )) == NULLPE || pe->pe_id == PE_PRIM_NULL ) {
+       return( -2 );   /* signal soft error */
+    }
+
+    /*
+     * try just writing this into a PS and sending it along
+     */
+    if ( pe2ps( ps, pe ) == NOTOK ) {
+       return( -1 );
+    }
+
+    return( 0 );
+}
diff --git a/servers/slapd/tools/ldapsyntax.h b/servers/slapd/tools/ldapsyntax.h
new file mode 100644 (file)
index 0000000..ddcf1f2
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+
+/* XXX: the "master" LINE_WIDTH #define is in ../slap.h */
+#define LINE_WIDTH     76      /* for lines in string rep of an entry */
+
+#ifdef NEEDPROTOS
+/*
+ * function prototypes
+ */
+
+int init_syntaxes( void );
+int av2ldif( FILE *outfp, AV_Sequence av, DN dn, short syntax,
+    char *attrname, PS str_ps );
+
+#endif /* NEEDPROTOS */
diff --git a/servers/slapd/tools/ldbmcat.c b/servers/slapd/tools/ldbmcat.c
new file mode 100644 (file)
index 0000000..79465df
--- /dev/null
@@ -0,0 +1,66 @@
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "ldbm.h"
+#include "../slap.h"
+
+usage( name )
+char   *name;
+{
+       fprintf( stderr, "usage: %s [-n] <filename>\n", name );
+       exit( 1 );
+}
+
+main( argc, argv )
+    int                argc;
+    char       **argv;
+{
+       Datum           key, last, data;
+       LDBM            dbp;
+       int             rc, type;
+       long            id;
+       char            *file, *s;
+       int             printid = 1;
+
+       if ( argc < 2 || argc > 3 || ( argc == 3 && strcmp( argv[1], "-n" )
+           != 0 )) {
+               usage( argv[0] );
+       }
+       if ( argc == 3 && strcmp( argv[1], "-n" ) == 0 ) {
+               printid = 0;
+               file = argv[2];
+       } else {
+               file = argv[1];
+       }
+
+       if ( (dbp = ldbm_open( file, LDBM_READER, 0, 0 )) == NULL ) {
+               perror( file );
+               exit ( 1 );
+       }
+
+        last.dptr = NULL;
+        for ( key = ldbm_firstkey( dbp ); key.dptr != NULL;
+            key = ldbm_nextkey( dbp, last ) ) {
+                if ( last.dptr != NULL )
+                        ldbm_datum_free( dbp, last );
+                data = ldbm_fetch( dbp, key );
+               s = data.dptr;
+               if ( !printid && isdigit( *s )) {
+                       if (( s = strchr( s, '\n' )) != NULL ) {
+                               ++s;
+                       }
+               }
+               if ( s != NULL ) {
+                       puts( s );
+               }
+                ldbm_datum_free( dbp, data );
+                last = key;
+        }
+        if ( last.dptr != NULL )
+                ldbm_datum_free( dbp, last );
+       ldbm_close( dbp );
+
+       exit( 0 );
+}
diff --git a/servers/slapd/tools/ldbmtest.c b/servers/slapd/tools/ldbmtest.c
new file mode 100644 (file)
index 0000000..56513ab
--- /dev/null
@@ -0,0 +1,805 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include "portable.h"
+#include "ldapconfig.h"
+#include "../slap.h"
+#include "../back-ldbm/back-ldbm.h"
+
+#define EDITOR "/usr/ucb/vi"
+
+extern IDList          *idl_fetch();
+extern Backend         *select_backend();
+extern struct dbcache  *ldbm_cache_open();
+
+static struct dbcache  *openchoice();
+static void            print_entry();
+static void            free_and_close();
+static void            edit_entry();
+static void            get_keydata();
+
+struct dbcache *dbc;
+LDBM           dbp;
+char           *tailorfile;
+Backend                *be = NULL;
+int            ldap_debug;
+int            ldap_syslog;
+int            ldap_syslog_level;
+int            global_schemacheck;
+int            num_entries_sent;
+int            num_bytes_sent;
+int            active_threads;
+char           *default_referral;
+struct objclass        *global_oc;
+time_t         currenttime;
+pthread_t      listener_tid;
+pthread_mutex_t        num_sent_mutex;
+pthread_mutex_t        entry2str_mutex;
+pthread_mutex_t        active_threads_mutex;
+pthread_mutex_t        new_conn_mutex;
+pthread_mutex_t        currenttime_mutex;
+pthread_mutex_t        replog_mutex;
+pthread_mutex_t        ops_mutex;
+pthread_mutex_t        regex_mutex;
+
+main( argc, argv )
+    int                argc;
+    char       **argv;
+{
+       char            buf[256];
+       Datum           savekey, key, data, last;
+       char            *fname;
+       ID              id;
+       IDList          *idl;
+       Backend         *tbe;
+       int             i;
+       extern char     *optarg;
+
+       tailorfile = SLAPD_DEFAULT_CONFIGFILE;
+       while ( (i = getopt( argc, argv, "d:f:" )) != EOF ) {
+               switch ( i ) {
+               case 'd':       /* turn on debugging */
+                       ldap_debug = atoi( optarg );
+                       break;
+
+               case 'f':       /* specify a tailor file */
+                       tailorfile = strdup( optarg );
+                       break;
+
+               default:
+                       fprintf( stderr,
+                           "usage: %s [-d level] [-f slapdconfigfile]\n",
+                           argv[0] );
+                       exit( -1 );
+                       break;
+               }
+       }
+
+       /*
+        * initialize stuff and figure out which backend we're dealing with
+        */
+
+       init();
+       read_config( tailorfile, &be, NULL );
+
+       while ( 1 ) {
+               printf( "dbtest: " );
+
+               if ( fgets( buf, sizeof(buf), stdin ) == NULL )
+                       break;
+
+               switch ( buf[0] ) {
+               case 'c':       /* create an index */
+                       fname = NULL;
+                       if ( (dbc = openchoice( buf[1], LDBM_READER, 0,
+                           &fname )) != NULL ) {
+                               printf( "Already exists\n" );
+                               ldbm_close( dbc->dbc_db );
+                               break;
+                       }
+                       if ( (dbc = openchoice( buf[1], LDBM_WRCREAT, 1,
+                           &fname )) != NULL ) {
+                               ldbm_close( dbc->dbc_db );
+                       }
+                       break;
+
+               case 'l':       /* lookup somethig in an index */
+                       if ( (dbc = openchoice( buf[1], LDBM_READER, 1, NULL ))
+                           == NULL ) {
+                               continue;
+                       }
+
+                       get_keydata( stdin, buf[1], &key, NULL );
+                       data = ldbm_fetch( dbc->dbc_db, key );
+                       print_entry( stdout, buf[1], &key, "key: ", &data,
+                           "data:\n" );
+
+                       free_and_close( dbc, key, data );
+                       break;
+
+               case 'L':       /* get all blocks for a key from an index */
+                       if ( (dbc = openchoice( buf[1], LDBM_READER, 1, NULL ))
+                           == NULL ) {
+                               continue;
+                       }
+
+                       get_keydata( stdin, buf[1], &key, NULL );
+                       if ( (idl = idl_fetch( be, dbc, key )) != NULL ) {
+                               data.dptr = (char *) idl;
+                               data.dsize = (idl->b_nmax + 1) * sizeof(ID);
+                               print_entry( stdout, buf[1], &key, "key: ",
+                                   &data, "data:\n" );
+                       }
+                       free_and_close( dbc, key, data );
+                       break;
+
+               case 't':       /* traverse */
+               case 'T':       /* traverse - keys only */
+                       if ( (dbc = openchoice( buf[1], LDBM_READER, 1, NULL ))
+                           == NULL ) {
+                               perror( "openchoice" );
+                               continue;
+                       }
+
+                       savekey.dptr = NULL;
+                       for ( key = ldbm_firstkey( dbc->dbc_db );
+                           key.dptr != NULL;
+                           key = ldbm_nextkey( dbc->dbc_db, key ) ) {
+                               if ( savekey.dptr != NULL )
+                                       ldbm_datum_free( dbc->dbc_db, savekey );
+                               savekey = key;
+
+                               data = ldbm_fetch( dbc->dbc_db, key );
+
+                               if ( buf[0] == 't' ) {
+                                       print_entry( stdout, buf[1], &key,
+                                           "key: ", &data, "data:\n" );
+                               } else {
+                                       print_entry( stdout, buf[1], &key,
+                                           "key: ", NULL, NULL );
+                               }
+
+                               ldbm_datum_free( dbc->dbc_db, data );
+                       }
+                       if ( savekey.dptr != NULL )
+                               ldbm_datum_free( dbc->dbc_db, savekey );
+
+                       ldbm_close( dbc->dbc_db );
+                       break;
+
+               case 'x':       /* delete an entry */
+                       if ( (dbc = openchoice( buf[1], LDBM_WRITER, 1, NULL ))
+                           == NULL ) {
+                               continue;
+                       }
+
+                       get_keydata( stdin, buf[1], &key, NULL );
+
+                       if ( ldbm_delete( dbc->dbc_db, key ) != 0 ) {
+                               if ( ldbm_errno( dbc->dbc_db ) == 0 ) {
+                                       perror( "ldbm_delete" );
+                               } else {
+                                       fprintf( stderr, "db_errno %d",
+                                           ldbm_errno( dbc->dbc_db ) );
+                               }
+                       }
+
+                       data.dptr = NULL;
+                       free_and_close( dbc, key, data );
+                       break;
+
+               case 'e':       /* edit an entry */
+                       if ( (dbc = openchoice( buf[1], LDBM_WRITER, 1, NULL ))
+                           == NULL ) {
+                               continue;
+                       }
+
+                       get_keydata( stdin, buf[1], &key, NULL );
+
+                       data = ldbm_fetch( dbc->dbc_db, key );
+                       if ( data.dptr == NULL ) {
+                               if ( ldbm_errno( dbc->dbc_db ) == 0 ) {
+                                       perror( "ldbm_fetch" );
+                               } else {
+                                       fprintf( stderr, "db_errno %d\n",
+                                           ldbm_errno( dbc->dbc_db ) );
+                               }
+                               free_and_close( dbc, key, data );
+                               break;
+                       }
+
+                       edit_entry( buf[1], &data );
+
+                       if ( data.dptr == NULL ) {
+                               if ( ldbm_delete( dbc->dbc_db, key ) != 0 ) {
+                                       perror( "ldbm_delete" );
+                               }
+                       } else if ( ldbm_store( dbc->dbc_db, key, data,
+                           LDBM_REPLACE ) != 0 ) {
+                               if ( ldbm_errno( dbc->dbc_db ) == 0 ) {
+                                       perror( "ldbm_store" );
+                               } else {
+                                       fprintf( stderr, "db_errno %d\n",
+                                           ldbm_errno( dbc->dbc_db ) );
+                               }
+                       }
+
+                       free_and_close( dbc, key, data );
+                       break;
+
+               case 'a':       /* add an entry */
+                       if ( (dbc = openchoice( buf[1], LDBM_WRITER, 1, NULL ))
+                           == NULL ) {
+                               continue;
+                       }
+
+                       get_keydata( stdin, buf[1], &key, &data );
+
+                       if ( ldbm_store( dbc->dbc_db, key, data, LDBM_INSERT )
+                           != 0 ) {
+                               if ( ldbm_errno( dbc->dbc_db ) == 0 ) {
+                                       perror( "ldbm_store" );
+                               } else {
+                                       fprintf( stderr, "db_errno %d\n",
+                                           ldbm_errno( dbc->dbc_db ) );
+                               }
+                       }
+
+                       free_and_close( dbc, key, data );
+                       break;
+
+               case 'i':       /* insert an id into an index entry */
+                       if ( (dbc = openchoice( buf[1], LDBM_WRITER, 1, NULL ))
+                           == NULL ) {
+                               continue;
+                       }
+
+                       get_keydata( stdin, buf[1], &key, &data );
+
+                       idl = (IDList *) data.dptr;
+                       for ( id = idl_firstid( idl ); id != NOID;
+                           id = idl_nextid( idl, id ) ) {
+                               if ( idl_insert_key( be, dbc, key, id )
+                                   != 0 ) {
+                                       fprintf( stderr,
+                                           "idl_insert_key (%s) %d failed\n",
+                                           key.dptr, id );
+                                       continue;
+                               }
+                       }
+
+                       free_and_close( dbc, key, data );
+                       break;
+
+               case 'b':       /* select a backend by suffix */
+                       printf( "suffix: " );
+                       fflush( stdout );
+                       if ( fgets( buf, sizeof(buf), stdin ) == NULL ) {
+                               exit( 0 );
+                       } else {
+                               buf[strlen( buf ) - 1] = '\0';
+                       }
+                       (void) dn_normalize( buf );
+                       if ( (tbe = select_backend( buf )) == NULL ) {
+                               fprintf( stderr, "unknown suffix \"%s\"\n",
+                                   buf );
+                       } else {
+                               be = tbe;
+                       }
+                       break;
+
+               case 'B':       /* print current suffix */
+                       if ( be == NULL ) {
+                               printf( "no current backend\n" );
+                       } else {
+                               printf( "current backend has suffix \"%s\"\n",
+                                   be->be_suffix[0] );
+                       }
+                       break;
+
+               case 'C':       /* produce concordance of an index */
+                       if ( (dbc = openchoice( 'i', LDBM_READER, 1, NULL ))
+                           == NULL ) {
+                               continue;
+                       }
+
+                       last.dptr = NULL;
+                       for ( key = ldbm_firstkey( dbp ); key.dptr != NULL;
+                           key = ldbm_nextkey( dbp, last ) ) {
+                               if ( last.dptr != NULL ) {
+                                       ldbm_datum_free( dbp, last );
+                               }
+                               last = key;
+                               printf( "key(%d): (%s)\n", key.dsize,
+                                   key.dptr );
+                       }
+
+                       free_and_close( dbc, key, last );
+                       break;
+
+               default:
+                       printf( "commands: l<c> => lookup index\n" );
+                       printf( "          L<c> => lookup index (all)\n" );
+                       printf( "          t<c> => traverse index\n" );
+                       printf( "          T<c> => traverse index keys\n" );
+                       printf( "          x<c> => delete from index\n" );
+                       printf( "          e<c> => edit index entry\n" );
+                       printf( "          a<c> => add index entry\n" );
+                       printf( "          c<c> => create index\n" );
+                       printf( "          i<c> => insert ids into index\n" );
+                       printf( "          b    => change default backend\n" );
+                       printf( "          B    => print default backend\n" );
+                       printf( "where <c> is a char selecting the index:\n" );
+                       printf( "          c => id2children\n" );
+                       printf( "          d => dn2id\n" );
+                       printf( "          e => id2entry\n" );
+                       printf( "          f => arbitrary file\n" );
+                       printf( "          i => attribute index\n" );
+                       break;
+               }
+       }
+
+       return( 0 );
+}
+
+static void
+free_and_close( dbc, key, data )
+    struct dbcache     *dbc;
+    Datum              key;
+    Datum              data;
+{
+       ldbm_cache_really_close( be, dbc );
+       if ( key.dptr != NULL )
+               ldbm_datum_free( dbp, key );
+       if ( data.dptr != NULL )
+               ldbm_datum_free( dbp, data );
+}
+
+static int
+dnid_cmp( a, b )
+    long       *a;
+    long       *b;
+{
+       return( *a - *b );
+}
+
+static char *
+myrealloc( p, size )
+    char       *p;
+    int                size;
+{
+       if ( p == NULL )
+               return( (char *) malloc( size ) );
+       else
+               return( (char *) realloc( p, size ) );
+}
+
+static void
+get_idlist( fp, data )
+    FILE       *fp;
+    Datum      *data;
+{
+       char    buf[20];
+       int     i, j, fd, tty;
+       IDList  *p;
+       int     psize, pmax;
+       int     nmax, nids;
+
+       fd = fileno( fp );
+       tty = isatty( fd );
+
+       p = NULL;
+       psize = 2 * sizeof(ID);
+       pmax = 0;
+       nmax = 0;
+       nids = 0;
+       i = 0;
+       while ( 1 ) {
+               if ( tty )
+                       printf( "id? " );
+               if ( fgets( buf, sizeof(buf), fp ) == NULL || buf[0] == '\n' )
+                       break;
+               if ( strncmp( buf, "nmax=", 5 ) == 0 ) {
+                       nmax = atol( buf + 5 );
+                       continue;
+               }
+
+               if ( psize + sizeof(ID) > pmax ) {
+                       pmax += BUFSIZ;
+                       p = (IDList *) myrealloc( (char *) p, pmax );
+               }
+
+               if ( strncmp( buf, "nids=0", 6 ) == 0 ) {
+                       nids = NOID;
+                       continue;
+               }
+
+               p->b_ids[i++] = atol( buf );
+               psize += sizeof(ID);
+       }
+       if ( nmax == 0 ) {
+               if ( tty ) {
+                       nmax = i;
+                       printf( "%d IDs entered.  Max number of ids? [%d] ", i,
+                           i );
+                       if ( fgets( buf, sizeof(buf), fp ) != NULL &&
+                           isdigit( buf[0] ) ) {
+                               nmax = atol( buf );
+                       }
+               } else {
+                       nmax = i;
+               }
+       }
+       if ( i > 0 ) {
+               p->b_nmax = nmax;
+               if ( nids != 0 ) {
+                       p->b_nids = 0;
+                       p->b_ids[i] = NOID;
+               } else {
+                       p->b_nids = i;
+               }
+
+               qsort( (void *) p->b_ids, i, sizeof(ID), (void *) dnid_cmp );
+       }
+
+       data->dptr = (char *) p;
+       data->dsize = (nmax + 2) * sizeof(ID);
+}
+
+static void
+get_entry( fp, data )
+    FILE       *fp;
+    Datum      *data;
+{
+       char    buf[BUFSIZ];
+       char    *p;
+       int     pmax, psize, len;
+       int     fd;
+
+       fd = fileno( fp );
+       if ( isatty( fd ) )
+               printf( "Enter entry, <cr><cr> to end:\n" );
+
+       p = NULL;
+       pmax = psize = 0;
+       while ( fgets( buf, sizeof(buf), fp ) != NULL ) {
+               len = strlen( buf );
+               if ( psize + strlen( buf ) > pmax ) {
+                       pmax += BUFSIZ;
+                       p = myrealloc( p, pmax );
+               }
+               if ( psize == 0 )
+                       strcpy( p, buf );
+               else
+                       strcat( p, buf );
+               psize += len;
+
+               if ( buf[0] == '\n' )
+                       break;
+       }
+
+       data->dptr = p;
+       data->dsize = psize + 1;
+}
+
+static void
+edit_entry( c, data )
+    char       c;
+    Datum      *data;
+{
+       int             fd, pid;
+       char            tmpname[20];
+       FILE            *fp;
+       WAITSTATUSTYPE  status;
+
+       strcpy( tmpname, "/tmp/dbtestXXXXXX" );
+#ifdef ultrix
+       if ( (fd = open( mktemp( tmpname ), O_RDWR, 0600 )) == -1 ) {
+               perror( tmpname );
+               return;
+       }
+#else
+       if ( (fd = mkstemp( tmpname )) == -1 ) {
+               perror( tmpname );
+               return;
+       }
+#endif
+
+       fp = fdopen( fd, "w" );
+       print_entry( fp, c, NULL, NULL, data, NULL );
+       fflush( fp );
+
+       pid = fork();
+
+       if ( pid == -1 ) {
+               perror( "fork" );
+               return;
+       } else if ( pid == 0 ) {
+               char    *editor;
+
+               if ( (editor = getenv( "EDITOR" )) == NULL ) {
+                       editor = EDITOR;
+               }
+               execl( editor, editor, tmpname, NULL );
+               perror( "execl" );
+               exit( 1 );
+       }
+
+       fclose( fp );
+#ifdef USE_WAITPID
+       if ( waitpid( (pid_t) -1, 0, WAIT_FLAGS ) < 0 ) {
+#else
+       if ( wait3( &status, WAIT_FLAGS, 0 ) < 0 ) {
+#endif
+               perror( "wait" );
+               return;
+       }
+
+       if ( (fp = fopen( tmpname, "r" )) == NULL ) {
+               perror( tmpname );
+               return;
+       }
+       ldbm_datum_free( NULL, *data );
+       get_keydata( fp, c, NULL, data );
+       fclose( fp );
+       unlink( tmpname );
+}
+
+static struct dbcache *
+openfile( name, namesiz, mode, verbose, c )
+    char       *name;
+    int                namesiz;
+    int                mode;
+    int                verbose;
+    char       c;
+{
+       struct dbcache  *dbc;
+
+       if ( name == NULL || *name == '\0' ) {
+               if ( c == 'f' ) {
+                       printf( "  file: " );
+                       if ( fgets( name, namesiz, stdin ) == NULL )
+                               exit( 0 );
+                       name[strlen( name ) - 1] = '\0';
+               } else {
+                       printf( "  attr: " );
+                       if ( fgets( name, namesiz, stdin ) == NULL )
+                               exit( 0 );
+                       name[strlen( name ) - 1] = '\0';
+               }
+       }
+
+       if ( (dbc = ldbm_cache_open( be, name, (c == 'f') ? "" : LDBM_SUFFIX,
+           LDBM_READER )) == NULL ) {
+               perror( name );
+       } else {
+               dbp = dbc->dbc_db;
+       }
+
+       return( dbc );
+}
+
+static struct dbcache *
+openchoice( c, mode, verbose, fname )
+    char       c;
+    int                mode;
+    int                verbose;
+    char       **fname;
+{
+       static char     name[MAXPATHLEN];
+
+       switch ( c ) {
+       case 'c':       /* id2children */
+               sprintf( name, "id2children" );
+               break;
+       case 'd':       /* dn2id */
+               sprintf( name, "dn2id" );
+               break;
+       case 'e':       /* id2entry */
+               sprintf( name, "id2entry" );
+               break;
+       case 'f':       /* arbitrary file */
+       case 'i':       /* index */
+               if ( fname != NULL && *fname != NULL ) {
+                       strcpy( name, *fname );
+               } else {
+                       name[0] = '\0';
+               }
+               break;
+       default:
+               printf( "specify one of [fdeci] to select file\n" );
+               return( NULL );
+               break;
+       }
+       if ( fname != NULL ) {
+               *fname = name;
+       }
+
+       return( openfile( name, MAXPATHLEN, mode, verbose, c ) );
+}
+
+static void
+print_entry( fp, c, key, klabel, data, dlabel )
+    FILE       *fp;
+    char       c;
+    Datum      *key;
+    char       *klabel;
+    Datum      *data;
+    char       *dlabel;
+{
+       ID      id;
+       IDList  *idl;
+       int     i;
+       char    msg[2];
+
+       if ( data != NULL && data->dptr == NULL ) {
+               msg[0] = c;
+               msg[1] = '\0';
+
+               if ( ldbm_errno( dbp ) == 0 )
+                       perror( msg );
+               else
+                       fprintf( stderr, "%s: db_errno %d\n", msg,
+                           ldbm_errno( dbp ) );
+               return;
+       }
+
+       switch ( c ) {
+       case 'd':       /* dn2id - key is dn, data is dnid */
+               if ( key != NULL )
+                       fprintf( fp, "%s%s (len %d)\n", klabel, key->dptr,
+                           key->dsize );
+               if ( data != NULL ) {
+                       SAFEMEMCPY( (char *) &id, data->dptr, sizeof(ID) );
+                       fprintf( fp, "%s%d\n", dlabel ? dlabel : "", id );
+               }
+               break;
+
+       case 'e':       /* id2entry - key is dnid, data is entry */
+               if ( key != NULL ) {
+                       SAFEMEMCPY( (char *) &id, key->dptr, sizeof(ID) );
+                       fprintf( fp, "%s %d\n", klabel, id );
+               }
+               if ( data != NULL ) {
+                       if ( dlabel ) {
+                               fprintf( fp, "data length: %d\n", data->dsize );
+                               fputs( dlabel, fp );
+                       }
+                       fputs( data->dptr, fp );
+               }
+               break;
+
+       case 'c':
+       case 'i':       /* index - key is string, data is dnid[] */
+               if ( key != NULL )
+                       fprintf( fp, "%s%s (len %d)\n", klabel, key->dptr,
+                           key->dsize );
+               if ( data != NULL ) {
+                       idl = (IDList *) data->dptr;
+
+                       if ( dlabel )
+                               fprintf( fp, "%s\tnmax=%d\n\tncur=%d\n", dlabel,
+                                   idl->b_nmax, idl->b_nids );
+
+                       if ( INDIRECT_BLOCK( idl ) ) {
+                               for ( i = 0; idl->b_ids[i] != NOID; i++ ) {
+                                       fprintf( fp, "\t%d\n", idl->b_ids[i] );
+                               }
+                       } else if ( ALLIDS( idl ) ) {
+                               fprintf( fp, "\tALLIDS (1..%d)\n",
+                                   idl->b_nids - 1 );
+                       } else {
+                               for ( i = 0; i < idl->b_nids; i++ ) {
+                                       fprintf( fp, "\t%d\n", idl->b_ids[i] );
+                               }
+                       }
+               }
+               break;
+
+       case 'f':       /* arbitrary file - assume key & data are strings */
+               if ( key != NULL )
+                       fprintf( fp, "%s%s\n", klabel, key->dptr );
+               if ( data != NULL ) {
+                       fprintf( fp, "%s%s\n", dlabel ? dlabel : "",
+                           data->dptr );
+               }
+               break;
+
+       default:
+               fprintf( stderr, "specify [deci] to select a file\n" );
+               break;
+       }
+}
+
+static void
+get_keydata( fp, c, key, data )
+    FILE       *fp;
+    char       c;
+    Datum      *key;
+    Datum      *data;
+{
+       static char     kbuf[BUFSIZ], dbuf[BUFSIZ];
+       long            n;
+       int             fd, tty;
+
+       fd = fileno( fp );
+       tty = isatty( fd );
+
+       switch ( c ) {
+       case 'd':       /* dn2id - key is dn, data is dnid */
+               if ( key != NULL ) {
+                       if ( tty )
+                               printf( "  dn: " );
+                       if ( fgets( kbuf, sizeof(kbuf), fp ) == NULL ) {
+                               exit( 0 );
+                       }
+                       kbuf[strlen( kbuf ) - 1] = '\0';
+                       key->dptr = strdup( kbuf );
+                       key->dsize = strlen( kbuf ) + 1;
+               }
+
+               if ( data != NULL ) {
+                       if ( tty )
+                               printf( "  dnid: " );
+                       if ( fgets( dbuf, sizeof(dbuf), fp ) == NULL ) {
+                               exit( 0 );
+                       }
+                       n = atol( dbuf );
+                       data->dptr = (char *) malloc( sizeof(n) );
+                       memcpy( data->dptr, (char *) &n, sizeof(n) );
+                       data->dsize = sizeof(n);
+               }
+               break;
+
+       case 'e':       /* id2entry - key is dnid, data is entry */
+               if ( key != NULL ) {
+                       if ( tty )
+                               printf( "  dnid: " );
+                       if ( fgets( kbuf, sizeof(kbuf), fp ) == NULL ) {
+                               exit( 0 );
+                       }
+                       n = atol( kbuf );
+                       key->dptr = (char *) malloc( sizeof(n) );
+                       memcpy( key->dptr, (char *) &n, sizeof(n) );
+                       key->dsize = sizeof(n);
+               }
+
+               if ( data != NULL ) {
+                       get_entry( fp, data );
+               }
+               break;
+
+       case 'c':       /* id2children - key is string dnid, data is dnid[] */
+       case 'i':       /* index - key is string, data is dnid[] */
+               if ( key != NULL ) {
+                       if ( tty )
+                               printf( "  key: " );
+                       if ( fgets( kbuf, sizeof(kbuf), fp ) == NULL ) {
+                               exit( 0 );
+                       }
+                       kbuf[strlen( kbuf ) - 1] = '\0';
+                       key->dptr = strdup( kbuf );
+                       key->dsize = strlen( kbuf ) + 1;
+               }
+
+               if ( data != NULL ) {
+                       get_idlist( fp, data );
+               }
+               break;
+
+       default:
+               fprintf(stderr, "specify [deci] to select file type\n");
+               break;
+       }
+}
+
diff --git a/servers/slapd/tools/ldif.c b/servers/slapd/tools/ldif.c
new file mode 100644 (file)
index 0000000..dc9f25d
--- /dev/null
@@ -0,0 +1,93 @@
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "lber.h"
+#include "ldap.h"
+#include "ldif.h"
+
+int    ldap_syslog;
+int    ldap_syslog_level;
+
+
+usage( name )
+char   *name;
+{
+       fprintf( stderr, "usage: %s [-b] <attrtype>\n", name );
+       exit( 1 );
+}
+
+main( argc, argv )
+    int                argc;
+    char       **argv;
+{
+       char    buf[BUFSIZ];
+       char    *type, *out;
+       int     binary = 0;
+
+       if (argc < 2 || argc > 3 ) {
+               usage( argv[0] );
+       }
+       if ( argc == 3 ) {
+               if ( strcmp( argv[1], "-b" ) != 0 ) {
+                       usage( argv[0] );
+               } else {
+                       binary = 1;
+                       type = argv[2];
+               }
+       } else {
+               if ( strcmp( argv[1], "-b" ) == 0 ) {
+                       usage( argv[0] );
+               }
+               type = argv[1];
+       }
+
+       /* if the -b flag was used, read single binary value from stdin */
+       if ( binary ) {
+               char    *val;
+               int     nread, max, cur;
+
+               if (( val = (char *) malloc( BUFSIZ )) == NULL ) {
+                       perror( "malloc" );
+                       exit( 1 );
+               }
+               max = BUFSIZ;
+               cur = 0;
+               while ( (nread = read( 0, buf, BUFSIZ )) != 0 ) {
+                       if ( nread + cur > max ) {
+                               max += BUFSIZ;
+                               if (( val = (char *) realloc( val, max )) ==
+                                   NULL ) {
+                                       perror( "realloc" );
+                                       exit( 1 );
+                               }
+                       }
+                       memcpy( val + cur, buf, nread );
+                       cur += nread;
+               }
+
+               if (( out = ldif_type_and_value( type, val, cur )) == NULL ) {
+                       perror( "ldif_type_and_value" );
+                       exit( 1 );
+               }
+
+               fputs( out, stdout );
+               free( out );
+               free( val );
+               exit( 0 );
+       }
+
+       /* not binary:  one value per line... */
+       while ( gets( buf ) != NULL ) {
+               if (( out = ldif_type_and_value( type, buf, strlen( buf ) ))
+                   == NULL ) {
+                       perror( "ldif_type_and_value" );
+                       exit( 1 );
+               }
+               fputs( out, stdout );
+               free( out );
+       }
+
+       exit( 0 );
+}
diff --git a/servers/slapd/tools/ldif2id2children.c b/servers/slapd/tools/ldif2id2children.c
new file mode 100644 (file)
index 0000000..2fb2aaf
--- /dev/null
@@ -0,0 +1,312 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "../slap.h"
+#include "../back-ldbm/back-ldbm.h"
+
+#define DEFAULT_CONFIGFILE     "/usr/local/etc/slapd.conf"
+#define MAXARGS                100
+
+extern struct dbcache  *ldbm_cache_open();
+extern void            attr_index_config();
+extern char            *str_getline();
+extern char            *dn_parent();
+extern char            *dn_normalize_case();
+extern int             strcasecmp();
+extern int             nbackends;
+extern Backend         *backends;
+extern int             ldap_debug;
+
+int            lineno;
+int            ldap_debug;
+int            ldap_syslog;
+int            ldap_syslog_level;
+int            global_schemacheck;
+int            num_entries_sent;
+int            num_bytes_sent;
+int            active_threads;
+char           *default_referral;
+struct objclass        *global_oc;
+time_t         currenttime;
+pthread_t      listener_tid;
+pthread_mutex_t        num_sent_mutex;
+pthread_mutex_t        entry2str_mutex;
+pthread_mutex_t        active_threads_mutex;
+pthread_mutex_t        new_conn_mutex;
+pthread_mutex_t        currenttime_mutex;
+pthread_mutex_t        replog_mutex;
+pthread_mutex_t        ops_mutex;
+pthread_mutex_t        regex_mutex;
+
+static int     make_index();
+
+static char    *tailorfile;
+static char    *inputfile;
+static void
+usage( char *name )
+{
+       fprintf( stderr, "usage: %s -i inputfile [-d debuglevel] [-f configfile] [-n databasenumber]\n", name );
+       exit( 1 );
+}
+
+main( int argc, char **argv )
+{
+       int             i, cargc, indb, stop, status;
+       char            *cargv[MAXARGS];
+       char            *defargv[MAXARGS];
+       char            *linep, *buf;
+       char            line[BUFSIZ];
+       int             lineno, elineno;
+       int             lmax, lcur;
+       int             dbnum;
+       ID              id;
+       struct dbcache  *db, *db2;
+       Backend         *be;
+       struct berval   bv;
+       struct berval   *vals[2];
+       Avlnode         *avltypes = NULL;
+       extern char     *optarg;
+
+       tailorfile = DEFAULT_CONFIGFILE;
+       dbnum = -1;
+       while ( (i = getopt( argc, argv, "d:f:i:n:" )) != EOF ) {
+               switch ( i ) {
+               case 'd':       /* turn on debugging */
+                       ldap_debug = atoi( optarg );
+                       break;
+
+               case 'f':       /* specify a tailor file */
+                       tailorfile = strdup( optarg );
+                       break;
+
+               case 'i':       /* input file */
+                       inputfile = strdup( optarg );
+                       break;
+
+               case 'n':       /* which config file db to index */
+                       dbnum = atoi( optarg ) - 1;
+                       break;
+
+               default:
+                       usage( argv[0] );
+                       break;
+               }
+       }
+       if ( inputfile == NULL ) {
+               usage( argv[0] );
+       } else {
+               if ( freopen( inputfile, "r", stdin ) == NULL ) {
+                       perror( inputfile );
+                       exit( 1 );
+               }
+       }
+
+       /*
+        * initialize stuff and figure out which backend we're dealing with
+        */
+
+       init();
+       read_config( tailorfile, &be, NULL );
+
+       if ( dbnum == -1 ) {
+               for ( dbnum = 0; dbnum < nbackends; dbnum++ ) {
+                       if ( strcasecmp( backends[dbnum].be_type, "ldbm" )
+                           == 0 ) {
+                               break;
+                       }
+               }
+               if ( dbnum == nbackends ) {
+                       fprintf( stderr, "No ldbm database found in config file\n" );
+                       exit( 1 );
+               }
+       } else if ( dbnum < 1 || dbnum > nbackends ) {
+               fprintf( stderr, "Database number selected via -n is out of range\n" );
+               fprintf( stderr, "Must be in the range 1 to %d (number of databases in the config file)\n", nbackends );
+               exit( 1 );
+       } else if ( strcasecmp( backends[dbnum].be_type, "ldbm" ) != 0 ) {
+               fprintf( stderr, "Database number %d selected via -n is not an ldbm database\n", dbnum );
+               exit( 1 );
+       }
+       be = &backends[dbnum];
+
+       /*
+        * first, make the dn2id index
+        */
+
+       if ( (db = ldbm_cache_open( be, "dn2id", LDBM_SUFFIX, LDBM_NEWDB ))
+           == NULL ) {
+               perror( "dn2id file" );
+               exit( 1 );
+       }
+
+       id = 0;
+       stop = 0;
+       lineno = 0;
+       buf = NULL;
+       lcur = lmax = 0;
+       vals[0] = &bv;
+       vals[1] = NULL;
+       while ( ! stop ) {
+               char            *type, *val, *s;
+               int             vlen;
+               Datum           key, data;
+
+               if ( fgets( line, sizeof(line), stdin ) != NULL ) {
+                       int     len;
+
+                       lineno++;
+                       len = strlen( line );
+                       while ( lcur + len + 1 > lmax ) {
+                               lmax += BUFSIZ;
+                               buf = (char *) ch_realloc( buf, lmax );
+                       }
+                       strcpy( buf + lcur, line );
+                       lcur += len;
+               } else {
+                       stop = 1;
+               }
+               if ( line[0] == '\n' || stop && buf && *buf ) {
+                       if ( *buf != '\n' ) {
+                               id++;
+                               s = buf;
+                               elineno = 0;
+                               while ( (linep = str_getline( &s )) != NULL ) {
+                                       elineno++;
+                                       if ( str_parse_line( linep, &type, &val,
+                                           &vlen ) != 0 ) {
+                                               Debug( LDAP_DEBUG_PARSE,
+                           "bad line %d in entry ending at line %d ignored\n",
+                                                   elineno, lineno, 0 );
+                                               continue;
+                                       }
+
+                                       if ( strcmp( type, "dn" ) == 0 )
+                                               break;
+                               }
+
+                               if ( linep == NULL ) {
+                                       fprintf( stderr, "entry %d has no dn\n",
+                                           id );
+                               } else {
+                                       key.dptr = dn_normalize_case( val );
+                                       key.dsize = strlen( val ) + 1;
+                                       data.dptr = (char *) &id;
+                                       data.dsize = sizeof(ID);
+                                       if ( ldbm_store( db->dbc_db, key, data,
+                                           LDBM_REPLACE ) != 0 ) {
+                                               perror( "dn2id ldbm_store" );
+                                               exit( 1 );
+                                       }
+                               }
+                       }
+                       *buf = '\0';
+                       lcur = 0;
+                       line[0] = '\0';
+               }
+       }
+
+       /*
+        * next, make the id2children index
+        */
+
+       if ( (db2 = ldbm_cache_open( be, "id2children", LDBM_SUFFIX,
+           LDBM_NEWDB )) == NULL ) {
+               perror( "id2children file" );
+               exit( 1 );
+       }
+
+       rewind( stdin );
+       id = 0;
+       stop = 0;
+       buf = NULL;
+       lineno = 0;
+       lcur = lmax = 0;
+       vals[0] = &bv;
+       vals[1] = NULL;
+       while ( ! stop ) {
+               char    *type, *val, *s, *dn;
+               int     vlen;
+               ID      pid;
+               char    buf2[20];
+               Datum   key, data;
+
+               if ( fgets( line, sizeof(line), stdin ) != NULL ) {
+                       int     len;
+
+                       len = strlen( line );
+                       while ( lcur + len + 1 > lmax ) {
+                               lmax += BUFSIZ;
+                               buf = (char *) ch_realloc( buf, lmax );
+                       }
+                       strcpy( buf + lcur, line );
+                       lcur += len;
+               } else {
+                       stop = 1;
+               }
+               if ( line[0] == '\n' || stop && buf && *buf ) {
+                       if ( * buf != '\n' ) {
+                               id++;
+                               s = buf;
+                               while ( (linep = str_getline( &s )) != NULL ) {
+                                       if ( str_parse_line( linep, &type, &val,
+                                           &vlen ) != 0 ) {
+                                               Debug( LDAP_DEBUG_PARSE,
+                                                   "bad line %d ignored\n",
+                                                   lineno, 0, 0 );
+                                               continue;
+                                       }
+
+                                       if ( strcmp( type, "dn" ) == 0 )
+                                               break;
+                               }
+
+                               if ( linep == NULL ) {
+                                       fprintf( stderr, "entry %d has no dn\n",
+                                           id );
+                               } else {
+                                       if ( (dn = dn_parent( be, val ))
+                                           == NULL ) {
+                                               pid = 0;
+                                       } else {
+                                               key.dptr =
+                                                   dn_normalize_case( dn );
+                                               key.dsize = strlen( dn ) + 1;
+
+                                               data = ldbm_fetch( db->dbc_db,
+                                                   key );
+                                               if ( data.dptr == NULL ) {
+                                                       dn_normalize( val );
+                                                       if ( ! be_issuffix( be,
+                                                           val ) ) {
+       Debug( LDAP_DEBUG_PARSE, "no parent \"%s\" of \"%s\"\n", dn, val, 0 );
+                                                       }
+                                                       *buf = '\0';
+                                                       lcur = 0;
+                                                       line[0] = '\0';
+                                                       continue;
+                                               }
+                                               (void) memcpy( (char *) &pid,
+                                                   data.dptr, sizeof(ID) );
+                                       }
+
+                                       sprintf( buf2, "%c%d", EQ_PREFIX, pid );
+                                       key.dptr = buf2;
+                                       key.dsize = strlen( buf2 ) + 1;
+                                       if ( idl_insert_key( be, db2, key, id )
+                                           != 0 ) {
+                                               perror( "idl_insert_key" );
+                                               exit( 1 );
+                                       }
+                               }
+                       }
+                       *buf = '\0';
+                       lcur = 0;
+                       line[0] = '\0';
+               }
+       }
+       (*be->be_close)( be );
+
+       exit( 0 );
+}
diff --git a/servers/slapd/tools/ldif2id2entry.c b/servers/slapd/tools/ldif2id2entry.c
new file mode 100644 (file)
index 0000000..5c8874c
--- /dev/null
@@ -0,0 +1,204 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "../slap.h"
+#include "../back-ldbm/back-ldbm.h"
+
+#define DEFAULT_CONFIGFILE     "/usr/local/etc/slapd.conf"
+#define MAXARGS                100
+
+extern struct dbcache  *ldbm_cache_open();
+extern void            attr_index_config();
+extern int             strcasecmp();
+extern int             nbackends;
+extern Backend         *backends;
+extern int             ldap_debug;
+
+int            ldap_debug;
+int            ldap_syslog;
+int            ldap_syslog_level;
+int            global_schemacheck;
+int            num_entries_sent;
+int            num_bytes_sent;
+int            active_threads;
+char           *default_referral;
+struct objclass        *global_oc;
+time_t         currenttime;
+pthread_t      listener_tid;
+pthread_mutex_t        num_sent_mutex;
+pthread_mutex_t        entry2str_mutex;
+pthread_mutex_t        active_threads_mutex;
+pthread_mutex_t        new_conn_mutex;
+pthread_mutex_t        currenttime_mutex;
+pthread_mutex_t        replog_mutex;
+pthread_mutex_t        ops_mutex;
+pthread_mutex_t        regex_mutex;
+
+static int     make_index();
+
+static char    *tailorfile;
+static char    *inputfile;
+static void
+usage( char *name )
+{
+       fprintf( stderr, "usage: %s -i inputfile [-d debuglevel] [-f configfile] [-n databasenumber]\n", name );
+       exit( 1 );
+}
+
+main( int argc, char **argv )
+{
+       int             i, cargc, indb, stop, status;
+       char            *cargv[MAXARGS];
+       char            *defargv[MAXARGS];
+       char            *linep, *buf;
+       char            line[BUFSIZ], idbuf[BUFSIZ];
+       int             lmax, lcur;
+       int             dbnum;
+       ID              id;
+       struct dbcache  *db;
+       Backend         *be;
+       struct berval   bv;
+       struct berval   *vals[2];
+       Avlnode         *avltypes = NULL;
+       FILE            *fp;
+       extern char     *optarg;
+
+       tailorfile = DEFAULT_CONFIGFILE;
+       dbnum = -1;
+       while ( (i = getopt( argc, argv, "d:f:i:n:" )) != EOF ) {
+               switch ( i ) {
+               case 'd':       /* turn on debugging */
+                       ldap_debug = atoi( optarg );
+                       break;
+
+               case 'f':       /* specify a tailor file */
+                       tailorfile = strdup( optarg );
+                       break;
+
+               case 'i':       /* input file */
+                       inputfile = strdup( optarg );
+                       break;
+
+               case 'n':       /* which config file db to index */
+                       dbnum = atoi( optarg ) - 1;
+                       break;
+
+               default:
+                       usage( argv[0] );
+                       break;
+               }
+       }
+       if ( inputfile == NULL ) {
+               usage( argv[0] );
+       } else {
+               if ( freopen( inputfile, "r", stdin ) == NULL ) {
+                       perror( inputfile );
+                       exit( 1 );
+               }
+       }
+
+       /*
+        * initialize stuff and figure out which backend we're dealing with
+        */
+
+       init();
+       read_config( tailorfile, &be, NULL );
+
+       if ( dbnum == -1 ) {
+               for ( dbnum = 0; dbnum < nbackends; dbnum++ ) {
+                       if ( strcasecmp( backends[dbnum].be_type, "ldbm" )
+                           == 0 ) {
+                               break;
+                       }
+               }
+               if ( dbnum == nbackends ) {
+                       fprintf( stderr, "No ldbm database found in config file\n" );
+                       exit( 1 );
+               }
+       } else if ( dbnum < 1 || dbnum > nbackends ) {
+               fprintf( stderr, "Database number selected via -n is out of range\n" );
+               fprintf( stderr, "Must be in the range 1 to %d (number of databases in the config file)\n", nbackends );
+               exit( 1 );
+       } else if ( strcasecmp( backends[dbnum].be_type, "ldbm" ) != 0 ) {
+               fprintf( stderr, "Database number %d selected via -n is not an ldbm database\n", dbnum );
+               exit( 1 );
+       }
+       be = &backends[dbnum];
+
+       if ( (db = ldbm_cache_open( be, "id2entry", LDBM_SUFFIX, LDBM_NEWDB ))
+           == NULL ) {
+               perror( "id2entry file" );
+               exit( 1 );
+       }
+
+       id = 0;
+       stop = 0;
+       buf = NULL;
+       lcur = lmax = 0;
+       vals[0] = &bv;
+       vals[1] = NULL;
+       while ( ! stop ) {
+               char            *type, *val, *s;
+               int             vlen;
+               Datum           key, data;
+
+               if ( fgets( line, sizeof(line), stdin ) != NULL ) {
+                       int     len, idlen;
+
+                       len = strlen( line );
+                       if ( buf == NULL || *buf == '\0' ) {
+                               sprintf( idbuf, "%d\n", id + 1 );
+                               idlen = strlen( idbuf );
+                       } else {
+                               idlen = 0;
+                       }
+
+                       while ( lcur + len + idlen + 1 > lmax ) {
+                               lmax += BUFSIZ;
+                               buf = (char *) ch_realloc( buf, lmax );
+                       }
+
+                       if ( idlen > 0 ) {
+                               strcpy( buf + lcur, idbuf );
+                               lcur += idlen;
+                       }
+                       strcpy( buf + lcur, line );
+                       lcur += len;
+               } else {
+                       stop = 1;
+               }
+               if ( line[0] == '\n' || stop && buf && *buf ) {
+                       if ( *buf != '\n' ) {
+                               id++;
+                               key.dptr = (char *) &id;
+                               key.dsize = sizeof(ID);
+                               data.dptr = buf;
+                               data.dsize = strlen( buf ) + 1;
+                               if ( ldbm_store( db->dbc_db, key, data,
+                                   LDBM_INSERT ) != 0 ) {
+                                       perror( "id2entry ldbm_store" );
+                                       exit( 1 );
+                               }
+                       }
+                       *buf = '\0';
+                       lcur = 0;
+                       line[0] = '\0';
+               }
+       }
+       (*be->be_close)( be );
+
+       id++;
+       sprintf( line, "%s/NEXTID",
+           ((struct ldbminfo *) be->be_private)->li_directory );
+       if ( (fp = fopen( line, "w" )) == NULL ) {
+               perror( line );
+               fprintf( stderr, "Could not write next id %ld\n", id );
+       } else {
+               fprintf( fp, "%ld\n", id );
+               fclose( fp );
+       }
+
+       exit( 0 );
+}
diff --git a/servers/slapd/tools/ldif2index.c b/servers/slapd/tools/ldif2index.c
new file mode 100644 (file)
index 0000000..af377f6
--- /dev/null
@@ -0,0 +1,181 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "../slap.h"
+
+#define DEFAULT_CONFIGFILE      "/usr/local/etc/slapd.conf"
+#define MAXARGS                100
+
+extern void    attr_index_config();
+extern char    *str_getline();
+extern char    *attr_normalize();
+extern int     nbackends;
+extern Backend *backends;
+extern int     ldap_debug;
+
+int            ldap_debug;
+int            ldap_syslog;
+int            ldap_syslog_level;
+int            global_schemacheck;
+int            num_entries_sent;
+int            num_bytes_sent;
+int            active_threads;
+char           *default_referral;
+struct objclass        *global_oc;
+time_t         currenttime;
+pthread_t      listener_tid;
+pthread_mutex_t        num_sent_mutex;
+pthread_mutex_t        entry2str_mutex;
+pthread_mutex_t        active_threads_mutex;
+pthread_mutex_t        new_conn_mutex;
+pthread_mutex_t        currenttime_mutex;
+pthread_mutex_t        replog_mutex;
+pthread_mutex_t        ops_mutex;
+pthread_mutex_t        regex_mutex;
+
+static void
+usage( char *name )
+{
+       fprintf( stderr, "usage: %s -i inputfile [-d debuglevel] [-f configfile] [-n databasenumber] attr\n", name );
+       exit( 1 );
+}
+
+main( int argc, char **argv )
+{
+       int             i, cargc, indb, stop;
+       char            *cargv[MAXARGS];
+       char            *defargv[MAXARGS];
+       char            *tailorfile, *inputfile;
+       char            *linep, *buf, *attr;
+       char            line[BUFSIZ];
+       int             lineno, elineno;
+       int             lmax, lcur, indexmask, syntaxmask;
+       int             dbnum;
+       unsigned long   id;
+       Backend         *be;
+       struct berval   bv;
+       struct berval   *vals[2];
+       extern char     *optarg;
+
+       inputfile = NULL;
+       tailorfile = DEFAULT_CONFIGFILE;
+       dbnum = -1;
+       while ( (i = getopt( argc, argv, "d:f:i:n:" )) != EOF ) {
+               switch ( i ) {
+               case 'd':       /* turn on debugging */
+                       ldap_debug = atoi( optarg );
+                       break;
+
+               case 'f':       /* specify a tailor file */
+                       tailorfile = strdup( optarg );
+                       break;
+
+               case 'i':       /* input file */
+                       inputfile = strdup( optarg );
+                       break;
+
+               case 'n':       /* which config file db to index */
+                       dbnum = atoi( optarg ) - 1;
+                       break;
+
+               default:
+                       usage( argv[0] );
+                       break;
+               }
+       }
+       attr = attr_normalize( argv[argc - 1] );
+       if ( inputfile == NULL ) {
+               usage( argv[0] );
+       } else {
+               if ( freopen( inputfile, "r", stdin ) == NULL ) {
+                       perror( inputfile );
+                       exit( 1 );
+               }
+       }
+
+       init();
+       read_config( tailorfile, &be, NULL );
+
+       if ( dbnum == -1 ) {
+               for ( dbnum = 0; dbnum < nbackends; dbnum++ ) {
+                       if ( strcasecmp( backends[dbnum].be_type, "ldbm" )
+                           == 0 ) {
+                               break;
+                       }
+               }
+               if ( dbnum == nbackends ) {
+                       fprintf( stderr, "No ldbm database found in config file\n" );
+                       exit( 1 );
+               }
+       } else if ( dbnum < 1 || dbnum > nbackends ) {
+               fprintf( stderr, "Database number selected via -n is out of range\n" );
+               fprintf( stderr, "Must be in the range 1 to %d (number of databases in the config file)\n", nbackends );
+               exit( 1 );
+       } else if ( strcasecmp( backends[dbnum].be_type, "ldbm" ) != 0 ) {
+               fprintf( stderr, "Database number %d selected via -n is not an ldbm database\n", dbnum );
+               exit( 1 );
+       }
+       be = &backends[dbnum];
+
+       attr_masks( be->be_private, attr, &indexmask, &syntaxmask );
+       if ( indexmask == 0 ) {
+               exit( 0 );
+       }
+
+       id = 0;
+       stop = 0;
+       lineno = 0;
+       buf = NULL;
+       lcur = lmax = 0;
+       vals[0] = &bv;
+       vals[1] = NULL;
+       while ( ! stop ) {
+               char            *type, *val, *s;
+               int             vlen;
+
+               if ( fgets( line, sizeof(line), stdin ) != NULL ) {
+                       int     len;
+
+                       lineno++;
+                       len = strlen( line );
+                       while ( lcur + len + 1 > lmax ) {
+                               lmax += BUFSIZ;
+                               buf = (char *) ch_realloc( buf, lmax );
+                       }
+                       strcpy( buf + lcur, line );
+                       lcur += len;
+               } else {
+                       stop = 1;
+               }
+               if ( line[0] == '\n' || stop && buf && *buf ) {
+                       if ( *buf != '\n' ) {
+                               id++;
+                               s = buf;
+                               elineno = 0;
+                               while ( (linep = str_getline( &s )) != NULL ) {
+                                       elineno++;
+                                       if ( str_parse_line( linep, &type, &val,
+                                           &vlen ) != 0 ) {
+                                               Debug( LDAP_DEBUG_PARSE,
+                           "bad line %d in entry ending at line %d ignored\n",
+                                                   elineno, elineno, 0 );
+                                               continue;
+                                       }
+
+                                       if ( strcasecmp( type, attr ) == 0 ) {
+                                               bv.bv_val = val;
+                                               bv.bv_len = vlen;
+                                               index_add_values( be, attr,
+                                                   vals, id );
+                                       }
+                               }
+                       }
+                       *buf = '\0';
+                       lcur = 0;
+               }
+       }
+       (*be->be_close)( be );
+
+       exit( 0 );
+}
diff --git a/servers/slapd/tools/ldif2ldbm.c b/servers/slapd/tools/ldif2ldbm.c
new file mode 100644 (file)
index 0000000..b2caa7b
--- /dev/null
@@ -0,0 +1,334 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include "../slap.h"
+#include "../back-ldbm/back-ldbm.h"
+
+#define DEFAULT_CONFIGFILE     "%ETCDIR%/slapd.conf"
+#define DEFAULT_ETCDIR         "%ETCDIR%"
+#define INDEXCMD               "ldif2index"
+#define ID2ENTRYCMD            "ldif2id2entry"
+#define ID2CHILDRENCMD         "ldif2id2children"
+#define MAXARGS                100
+
+extern void            attr_index_config();
+extern char            *str_getline();
+extern int             strcasecmp();
+extern int             nbackends;
+extern Backend         *backends;
+extern int             ldap_debug;
+
+int            ldap_debug;
+int            ldap_syslog;
+int            ldap_syslog_level;
+int            global_schemacheck;
+int            num_entries_sent;
+int            num_bytes_sent;
+int            active_threads;
+char           *default_referral;
+struct objclass        *global_oc;
+time_t         currenttime;
+pthread_t      listener_tid;
+pthread_mutex_t        num_sent_mutex;
+pthread_mutex_t        entry2str_mutex;
+pthread_mutex_t        active_threads_mutex;
+pthread_mutex_t        new_conn_mutex;
+pthread_mutex_t        currenttime_mutex;
+pthread_mutex_t        replog_mutex;
+pthread_mutex_t        ops_mutex;
+pthread_mutex_t        regex_mutex;
+
+static void    fork_child();
+static void    wait4kids();
+
+static char    *indexcmd;
+static char    *tailorfile;
+static char    *inputfile;
+static int      maxkids = 1;
+static int      nkids;
+static void
+usage( char *name )
+{
+       fprintf( stderr, "usage: %s -i inputfile [-d debuglevel] [-f configfile] [-j #jobs] [-n databasenumber] [-e etcdir]\n", name );
+       exit( 1 );
+}
+
+main( int argc, char **argv )
+{
+       int             i, stop, status;
+       char            *linep, *buf, *etcdir;
+       char            *args[10];
+       char            buf2[20], buf3[20];
+       char            line[BUFSIZ];
+       char            cmd[MAXPATHLEN];
+       int             lineno, elineno;
+       int             lmax, lcur;
+       int             dbnum;
+       ID              id;
+       Backend         *be = NULL;
+       struct berval   bv;
+       struct berval   *vals[2];
+       Avlnode         *avltypes = NULL;
+       extern char     *optarg;
+
+       etcdir = DEFAULT_ETCDIR;
+       tailorfile = DEFAULT_CONFIGFILE;
+       dbnum = -1;
+       while ( (i = getopt( argc, argv, "d:e:f:i:j:n:" )) != EOF ) {
+               switch ( i ) {
+               case 'd':       /* turn on debugging */
+                       ldap_debug = atoi( optarg );
+                       break;
+
+               case 'e':       /* alternate etcdir (index cmd location) */
+                       etcdir = strdup( optarg );
+                       break;
+
+               case 'f':       /* specify a tailor file */
+                       tailorfile = strdup( optarg );
+                       break;
+
+               case 'i':       /* input file */
+                       inputfile = strdup( optarg );
+                       break;
+
+               case 'j':       /* number of parallel index procs */
+                       maxkids = atoi( optarg );
+                       break;
+
+               case 'n':       /* which config file db to index */
+                       dbnum = atoi( optarg ) - 1;
+                       break;
+
+               default:
+                       usage( argv[0] );
+                       break;
+               }
+       }
+       if ( inputfile == NULL ) {
+               usage( argv[0] );
+       } else {
+               if ( freopen( inputfile, "r", stdin ) == NULL ) {
+                       perror( inputfile );
+                       exit( 1 );
+               }
+       }
+
+       /*
+        * initialize stuff and figure out which backend we're dealing with
+        */
+
+       init();
+       read_config( tailorfile, &be, NULL );
+
+       if ( dbnum == -1 ) {
+               for ( dbnum = 0; dbnum < nbackends; dbnum++ ) {
+                       if ( strcasecmp( backends[dbnum].be_type, "ldbm" )
+                           == 0 ) {
+                               break;
+                       }
+               }
+               if ( dbnum == nbackends ) {
+                       fprintf( stderr, "No ldbm database found in config file\n" );
+                       exit( 1 );
+               }
+       } else if ( dbnum < 0 || dbnum > nbackends ) {
+               fprintf( stderr, "Database number selected via -n is out of range\n" );
+               fprintf( stderr, "Must be in the range 1 to %d (number of databases in the config file)\n", nbackends );
+               exit( 1 );
+       } else if ( strcasecmp( backends[dbnum].be_type, "ldbm" ) != 0 ) {
+               fprintf( stderr, "Database number %d selected via -n is not an ldbm database\n", dbnum );
+               exit( 1 );
+       }
+       be = &backends[dbnum];
+
+       /*
+        * generate the id2entry index
+        */
+
+       i = 0;
+       sprintf( cmd, "%s/%s", etcdir, ID2ENTRYCMD );
+       args[i++] = cmd;
+       args[i++] = "-i";
+       args[i++] = inputfile;
+       args[i++] = "-f";
+       args[i++] = tailorfile;
+       args[i++] = "-n";
+       sprintf( buf2, "%d", dbnum );
+       args[i++] = buf2;
+       if ( ldap_debug ) {
+               sprintf( buf3, "%d", ldap_debug );
+               args[i++] = "-d";
+               args[i++] = buf3;
+       }
+       args[i++] = NULL;
+       fork_child( cmd, args );
+
+       /*
+        * generate the dn2id and id2children indexes
+        */
+
+       i = 0;
+       sprintf( cmd, "%s/%s", etcdir, ID2CHILDRENCMD );
+       args[i++] = cmd;
+       args[i++] = "-i";
+       args[i++] = inputfile;
+       args[i++] = "-f";
+       args[i++] = tailorfile;
+       args[i++] = "-n";
+       sprintf( buf2, "%d", dbnum );
+       args[i++] = buf2;
+       if ( ldap_debug ) {
+               sprintf( buf3, "%d", ldap_debug );
+               args[i++] = "-d";
+               args[i++] = buf3;
+       }
+       args[i++] = NULL;
+       fork_child( cmd, args );
+
+       /*
+        * generate the attribute indexes
+        */
+
+       i = 0;
+       sprintf( cmd, "%s/%s", etcdir, INDEXCMD );
+       args[i++] = cmd;
+       args[i++] = "-i";
+       args[i++] = inputfile;
+       args[i++] = "-f";
+       args[i++] = tailorfile;
+       args[i++] = "-n";
+       sprintf( buf2, "%d", dbnum );
+       args[i++] = buf2;
+       if ( ldap_debug ) {
+               sprintf( buf3, "%d", ldap_debug );
+               args[i++] = "-d";
+               args[i++] = buf3;
+       }
+       args[i++] = NULL;               /* will hold the attribute name */
+       args[i++] = NULL;
+
+       id = 0;
+       stop = 0;
+       buf = NULL;
+       lineno = 0;
+       lcur = lmax = 0;
+       vals[0] = &bv;
+       vals[1] = NULL;
+       while ( ! stop ) {
+               char            *type, *val, *s;
+               int             vlen, indexmask, syntaxmask;
+               Datum           key, data;
+
+               if ( fgets( line, sizeof(line), stdin ) != NULL ) {
+                       int     len;
+
+                       lineno++;
+                       len = strlen( line );
+                       while ( lcur + len + 1 > lmax ) {
+                               lmax += BUFSIZ;
+                               buf = (char *) ch_realloc( buf, lmax );
+                       }
+                       strcpy( buf + lcur, line );
+                       lcur += len;
+               } else {
+                       stop = 1;
+               }
+               if ( line[0] == '\n' || stop && buf && *buf ) {
+                       id++;
+                       s = buf;
+                       elineno = 0;
+                       while ( (linep = str_getline( &s )) != NULL ) {
+                               elineno++;
+                               if ( str_parse_line( linep, &type, &val, &vlen )
+                                   != 0 ) {
+                                       Debug( LDAP_DEBUG_PARSE,
+                           "bad line %d in entry ending at line %d ignored\n",
+                                           elineno, lineno, 0 );
+                                       continue;
+                               }
+
+                               if ( !isascii( *type ) || isdigit( *type ) )
+                                       continue;
+
+                               type = strdup( type );
+                               if ( avl_insert( &avltypes, type, strcasecmp,
+                                   avl_dup_error ) != 0 ) {
+                                       free( type );
+                               } else {
+                                       attr_masks( be->be_private, type,
+                                           &indexmask, &syntaxmask );
+                                       if ( indexmask ) {
+                                               args[i - 2] = type;
+                                               fork_child( cmd, args );
+                                       }
+                               }
+                       }
+                       *buf = '\0';
+                       lcur = 0;
+               }
+       }
+       (*be->be_close)( be );
+
+       wait4kids( -1 );
+
+       exit( 0 );
+}
+
+static void
+fork_child( char *prog, char *args[] )
+{
+       int     status, pid;
+
+       wait4kids( maxkids );
+
+       switch ( pid = fork() ) {
+       case 0:         /* child */
+               execvp( prog, args );
+               fprintf( stderr, "%s: ", prog );
+               perror( "execv" );
+               exit( -1 );
+               break;
+
+       case -1:        /* trouble */
+               fprintf( stderr, "Could not fork to run %s\n", prog );
+               perror( "fork" );
+               break;
+
+       default:        /* parent */
+               nkids++;
+               break;
+       }
+}
+
+static void
+wait4kids( int nkidval )
+{
+       int             status;
+       unsigned char   *p;
+
+       while ( nkids >= nkidval ) {
+               wait( &status );
+               p = (unsigned char *) &status;
+               if ( p[sizeof(int) - 1] == 0177 ) {
+                       fprintf( stderr,
+                           "stopping: child stopped with signal %d\n",
+                           p[sizeof(int) - 2] );
+               } else if ( p[sizeof(int) - 1] != 0 ) {
+                       fprintf( stderr, 
+                           "stopping: child terminated with signal %d\n",
+                           p[sizeof(int) - 1] );
+                       exit( p[sizeof(int) - 1] );
+               } else if ( p[sizeof(int) - 2] != 0 ) {
+                       fprintf( stderr, 
+                           "stopping: child exited with status %d\n",
+                           p[sizeof(int) - 2] );
+                       exit( p[sizeof(int) - 2] );
+               } else {
+                       nkids--;
+               }
+       }
+}
diff --git a/servers/slapd/tools/sizecount.c b/servers/slapd/tools/sizecount.c
new file mode 100644 (file)
index 0000000..45d8230
--- /dev/null
@@ -0,0 +1,184 @@
+#include <stdio.h>
+#include <ldbm.h>
+#include <lber.h>
+#include <ldap.h>
+#include "portable.h"
+
+#define CACHE_SIZE     1000000
+#define MODE           0600
+#define DB_FLAGS       (LDBM_WRCREAT|LDBM_NEWDB)
+#define SUBLEN         3
+
+extern char    *first_word();
+extern char    *next_word();
+extern char    *word_dup();
+extern char    *phonetic();
+
+extern int ldap_debug;
+extern int lber_debug;
+
+int    ldap_syslog;
+int    ldap_syslog_level;
+
+static void    add();
+
+main( argc, argv )
+    int                argc;
+    char       **argv;
+{
+       LDAP                    *ld;
+       LDAPMessage             *res, *e;
+       int                             i, j, k, count, len, nentries;
+       int                             vcount, wcount, pcount, scount;
+       int                             vsize, wsize, psize, ssize;
+       struct berval   **bvals;
+       char                    **vals;
+       char                    *dn, *p, *val;
+       char                    buf[SUBLEN+1];
+       LDBM                    wldbm, pldbm, sldbm;
+       static char             *attrs[] = { "cn", "nentries", NULL };
+
+/*
+       ldap_debug = 255;
+       lber_debug = 255;
+*/
+       if ( (ld = ldap_open( "vertigo:5555", LDAP_PORT )) == NULL ) {
+               perror( "ldap_open" );
+               exit( 1 );
+       }
+
+       if ( ldap_search( ld, "cn=index", LDAP_SCOPE_ONELEVEL, "(objectclass=*)",
+         attrs, 0 ) == -1 ) {
+               ldap_perror( ld, "ldap_search" );
+               exit( 1 );
+       }
+
+       printf( "attr\tdn\tnentries\tvcount\tvsize\twcount\twsize\tpcount\tpsize\tscount\tssize\n" );
+       fflush( stdout );
+       count = 0;
+       while ( ldap_result( ld, LDAP_RES_ANY, 0, NULL, &res )
+         == LDAP_RES_SEARCH_ENTRY ) {
+               count++;
+               e = ldap_first_entry( ld, res );
+               dn = ldap_get_dn( ld, e );
+               if ( (vals = ldap_get_values( ld, e, "nentries" )) != NULL ) {
+                       nentries = atoi( vals[0] );
+                       ldap_value_free( vals );
+               } else {
+                       fprintf( stderr, "no nentries attribute for (%s)\n", dn );
+                       nentries = -1;
+               }
+
+               for ( i = 0; attrs[i] != NULL; i++ ) {
+                       if ( strcasecmp( attrs[i], "nentries" ) == 0 ) {
+                               continue;
+                       }
+                       if ( (wldbm = ldbm_open( "wcount.ldbm", DB_FLAGS, MODE,
+                         CACHE_SIZE )) == NULL || (pldbm = ldbm_open( "pcount.ldbm",
+                         DB_FLAGS, MODE, CACHE_SIZE )) == NULL || (sldbm = ldbm_open(
+                         "scount.ldbm", DB_FLAGS, MODE, CACHE_SIZE )) == NULL ) {
+                               perror( "ldbm_open" );
+                               exit( 1 );
+                       }
+                       vcount = 0; vsize = 0;
+                       wcount = 0; wsize = 0;
+                       pcount = 0; psize = 0;
+                       scount = 0; ssize = 0;
+                       if ( (bvals = ldap_get_values_len( ld, e, attrs[i] )) != NULL ) {
+                               for ( j = 0; bvals[j] != NULL; j++ ) {
+                                       Datum   key, data;
+                                       char    *w;
+
+                                       /* update value count */
+                                       vcount++;
+                                       vsize += bvals[j]->bv_len;
+
+                                       /* update word and phoneme counts */
+                                       for ( w = first_word( bvals[j]->bv_val ); w != NULL;
+                                         w = next_word( w ) ) {
+                                               add( wldbm, word_dup( w ), &wcount, &wsize, 1 );
+
+                                               add( pldbm, phonetic( w ), &pcount, &psize, 1 );
+                                       }
+
+                                       /* update substring count */
+                                       len = bvals[j]->bv_len;
+                                       val = bvals[j]->bv_val;
+                                       if ( len > SUBLEN - 2 ) {
+                                               buf[0] = '^';
+                                               for ( k = 0; k < SUBLEN - 1; k++ ) {
+                                                       buf[k + 1] = val[k];
+                                               }
+                                               buf[SUBLEN] = '\0';
+                                               add( sldbm, buf, &scount, &ssize, 0 );
+
+                                               p = val + len - SUBLEN + 1;
+                                               for ( k = 0; k < SUBLEN; k++ ) {
+                                                       buf[k] = p[k];
+                                               }
+                                               buf[SUBLEN - 1] = '$';
+                                               buf[SUBLEN] = '\0';
+                                               add( sldbm, buf, &scount, &ssize, 0 );
+                                       }
+                                       for ( p = val; p < (val + len - SUBLEN + 1); p++ ) {
+                                               for ( k = 0; k < SUBLEN; k++ ) {
+                                                       buf[k] = p[k];
+                                               }
+                                               buf[SUBLEN] = '\0';
+                                               add( sldbm, buf, &scount, &ssize, 0 );
+                                       }
+                               }
+                               ldap_value_free_len( bvals );
+                       }
+                       printf( "%s\t%s\t%d", attrs[i], dn, nentries );
+                       printf( "\t%d\t%d", vcount, vsize );
+                       printf( "\t%d\t%d", wcount, wsize );
+                       printf( "\t%d\t%d", pcount, psize );
+                       printf( "\t%d\t%d\n", scount, ssize );
+                       fflush( stdout );
+
+                       ldbm_close( wldbm );
+                       ldbm_close( pldbm );
+                       ldbm_close( sldbm );
+               }
+
+               free( dn );
+               ldap_msgfree( res );
+       }
+       printf( "%d entries\n", count );
+       fflush( stdout );
+
+       if ( ldap_result2error( ld, res, 1 ) != LDAP_SUCCESS ) {
+               ldap_perror( ld, "ldap_result" );
+       }
+       ldap_unbind( ld );
+
+       (void) unlink( "wcount.ldbm" );
+       (void) unlink( "pcount.ldbm" );
+       (void) unlink( "scount.ldbm" );
+
+       exit( 0 );
+}
+
+static void
+add(
+    LDBM       ldbm,
+    char       *s,
+    int                *count,
+    int                *size,
+    int                freeit
+)
+{
+       Datum   key, data;
+
+       key.dptr = s;
+       key.dsize = strlen( key.dptr ) + 1;
+       data.dptr = "";
+       data.dsize = 0;
+       if ( ldbm_store( ldbm, key, data, LDBM_INSERT ) == 0 ) {
+               (*count)++;
+               (*size) += strlen( key.dptr );
+       }
+       if ( freeit )
+               ldbm_datum_free( ldbm, key );
+}
diff --git a/servers/slapd/unbind.c b/servers/slapd/unbind.c
new file mode 100644 (file)
index 0000000..500006c
--- /dev/null
@@ -0,0 +1,49 @@
+/* unbind.c - decode an ldap unbind operation and pass it to a backend db */
+
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ *
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "slap.h"
+
+extern Backend *select_backend();
+extern void      be_unbind();
+
+extern char            *default_referral;
+extern pthread_mutex_t new_conn_mutex;
+
+void
+do_unbind(
+    Connection *conn,
+    Operation  *op
+)
+{
+       Debug( LDAP_DEBUG_TRACE, "do_unbind\n", 0, 0, 0 );
+
+       /*
+        * Parse the unbind request.  It looks like this:
+        *
+        *      UnBindRequest ::= NULL
+        */
+
+       Statslog( LDAP_DEBUG_STATS, "conn=%d op=%d UNBIND\n", conn->c_connid,
+           op->o_opid, 0, 0, 0 );
+
+       /* pass the unbind to all backends */
+       be_unbind( conn, op );
+       
+       /* close the connection to the client */
+       close_connection( conn, op->o_connid, op->o_opid );
+}
diff --git a/servers/slapd/value.c b/servers/slapd/value.c
new file mode 100644 (file)
index 0000000..c9e6fbb
--- /dev/null
@@ -0,0 +1,212 @@
+/* value.c - routines for dealing with values */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include "portable.h"
+#include "slap.h"
+
+int
+value_add_fast( 
+    struct berval      ***vals,
+    struct berval      **addvals,
+    int                        nvals,
+    int                        naddvals,
+    int                        *maxvals
+)
+{
+       int     need, i, j;
+
+       if ( *maxvals == 0 ) {
+               *maxvals = 1;
+       }
+       need = nvals + naddvals + 1;
+       while ( *maxvals < need ) {
+               *maxvals *= 2;
+               *vals = (struct berval **) ch_realloc( (char *) *vals,
+                   *maxvals * sizeof(struct berval *) );
+       }
+
+       for ( i = 0, j = 0; i < naddvals; i++, j++ ) {
+               if ( addvals[i]->bv_len > 0 ) {
+                       (*vals)[nvals + j] = ber_bvdup( addvals[i] );
+               }
+       }
+       (*vals)[nvals + j] = NULL;
+
+       return( 0 );
+}
+
+int
+value_add( 
+    struct berval      ***vals,
+    struct berval      **addvals
+)
+{
+       int     n, nn, i, j;
+
+       for ( nn = 0; addvals != NULL && addvals[nn] != NULL; nn++ )
+               ;       /* NULL */
+
+       if ( *vals == NULL ) {
+               *vals = (struct berval **) ch_malloc( (nn + 1)
+                   * sizeof(struct berval *) );
+               n = 0;
+       } else {
+               for ( n = 0; (*vals)[n] != NULL; n++ )
+                       ;       /* NULL */
+               *vals = (struct berval **) ch_realloc( (char *) *vals,
+                   (n + nn + 1) * sizeof(struct berval *) );
+       }
+
+       for ( i = 0, j = 0; i < nn; i++ ) {
+               if ( addvals[i]->bv_len > 0 ) {
+                       (*vals)[n + j++] = ber_bvdup( addvals[i] );
+               }
+       }
+       (*vals)[n + j] = NULL;
+
+       return( 0 );
+}
+
+void
+value_normalize(
+    char       *s,
+    int                syntax
+)
+{
+       char    *d, *save;
+
+       if ( ! (syntax & SYNTAX_CIS) ) {
+               return;
+       }
+
+       if ( syntax & SYNTAX_DN ) {
+               (void) dn_normalize_case( s );
+               return;
+       }
+
+       save = s;
+       for ( d = s; *s; s++ ) {
+               if ( (syntax & SYNTAX_TEL) && (*s == ' ' || *s == '-') ) {
+                       continue;
+               }
+               *d++ = TOUPPER( *s );
+       }
+       *d = '\0';
+}
+
+#define MIN( a, b )    (a < b ? a : b )
+
+int
+value_cmp(
+    struct berval      *v1,
+    struct berval      *v2,
+    int                        syntax,
+    int                        normalize       /* 1 => arg 1; 2 => arg 2; 3 => both */
+)
+{
+       int             rc;
+       struct stat     st1, st2;
+
+       if ( normalize & 1 ) {
+               v1 = ber_bvdup( v1 );
+               value_normalize( v1->bv_val, syntax );
+       }
+       if ( normalize & 2 ) {
+               v2 = ber_bvdup( v2 );
+               value_normalize( v2->bv_val, syntax );
+       }
+
+       switch ( syntax ) {
+       case SYNTAX_CIS:
+       case (SYNTAX_CIS | SYNTAX_TEL):
+       case (SYNTAX_CIS | SYNTAX_DN):
+               rc = strcasecmp( v1->bv_val, v2->bv_val );
+               break;
+
+       case SYNTAX_CES:
+               rc = strcmp( v1->bv_val, v2->bv_val );
+               break;
+
+       case SYNTAX_BIN:
+               rc = memcmp( v1->bv_val, v2->bv_val, MIN( v1->bv_len,
+                   v2->bv_len ) );
+               break;
+       }
+
+       if ( normalize & 1 ) {
+               ber_bvfree( v1 );
+       }
+       if ( normalize & 2 ) {
+               ber_bvfree( v2 );
+       }
+
+       return( rc );
+}
+
+int
+value_ncmp(
+    struct berval      *v1,
+    struct berval      *v2,
+    int                        syntax,
+    int                        len,
+    int                        normalize
+)
+{
+       int     rc;
+
+       if ( normalize & 1 ) {
+               v1 = ber_bvdup( v1 );
+               value_normalize( v1->bv_val, syntax );
+       }
+       if ( normalize & 2 ) {
+               v2 = ber_bvdup( v2 );
+               value_normalize( v2->bv_val, syntax );
+       }
+
+       switch ( syntax ) {
+       case SYNTAX_CIS:
+       case (SYNTAX_CIS | SYNTAX_TEL):
+               rc = strncasecmp( v1->bv_val, v2->bv_val, len );
+               break;
+
+       case SYNTAX_CES:
+               rc = strncmp( v1->bv_val, v2->bv_val, len );
+               break;
+
+       case SYNTAX_BIN:
+               rc = memcmp( v1->bv_val, v2->bv_val, len );
+       }
+
+       if ( normalize & 1 ) {
+               ber_bvfree( v1 );
+       }
+       if ( normalize & 2 ) {
+               ber_bvfree( v2 );
+       }
+
+       return( rc );
+}
+
+int
+value_find(
+    struct berval      **vals,
+    struct berval      *v,
+    int                        syntax,
+    int                        normalize
+)
+{
+       int     i;
+
+       for ( i = 0; vals[i] != NULL; i++ ) {
+               if ( value_cmp( vals[i], v, syntax, normalize ) == 0 ) {
+                       return( 0 );
+               }
+       }
+
+       return( 1 );
+}
diff --git a/servers/slurpd/DESIGN b/servers/slurpd/DESIGN
new file mode 100644 (file)
index 0000000..a436e35
--- /dev/null
@@ -0,0 +1,51 @@
+Design Notes: slurpd
+
+This new version differs significantly from previous versions:
+
+- It uses a multithreaded, single-process model.  Previous versions forked
+  a separate process for each replica.  This new design should facilitate
+  porting to NT, and is more straightforward.
+
+- Only one copy of the replication log is made.  Previous versions made
+one copy of the replication log for each replica
+
+- This newer version is more object-oriented.  Although still written in
+  ANSI C (and compilable on k&r compilers), it encapsulates within the
+  major data structures the methods used to access "private" data.
+
+General design overview:
+
+The main data structure in slurpd is a replication queue (struct rq).
+The rq data structure is currently implemented as a linked list of 
+replication entries (struct re).  The rq structure contains member functions
+used to initialize, add to, remove, and return the next re struct.
+
+In addition to the rq structure, there is one ri (replication information)
+struct for each replica.  The ri struct encapsulates all information
+about a particular replica, e.g. hostname, port, bind dn.  The single
+public member function, ri_process, is called to begin processing
+the replication entries in the queue.
+
+There is also a status structure (struct st) which contains the timestamp
+of the last successful replication operation for each replica.  The
+contents of the st struct are flushed to disk after every successful
+operation.  This disk file is read upon startup, and is used to allow
+slapd to "pick up where it left off".
+
+Threading notes:
+
+The LDAP liblthread quasi-pthreads interface is used for threading.  At
+this point, machines which do not support pthreads, sun threads or lwp
+will probably not be able to run slurpd.  Given the current threading
+method, discussed in the next paragraph, it will probably be necessary to
+have a separate hunk of code which handles non-threaded architectures
+(or we might just not worry about it).  This needs further discussion.
+
+Upon startup, command-line arguments and the slapd configuration file
+are processed.  One thread is started for each replica.  Thread replicas,
+when no more work exists, wait on a condition variable, and the main
+thread's file manager routine broadcasts on this condition variable
+when new work is added to the queue. 
+
+
+
diff --git a/servers/slurpd/Make-template b/servers/slurpd/Make-template
new file mode 100644 (file)
index 0000000..a434940
--- /dev/null
@@ -0,0 +1,147 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1995 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       Stand-alone LDAP Update RePlication Daemon makefile
+#
+#-----------------------------------------------------------------------------
+LDAPSRC        = ../..
+HDIR   = $(LDAPSRC)/include
+LDIR   = $(LDAPSRC)/libraries
+VERSIONFILE = $(LDAPSRC)/build/version
+
+SRCS   =       admin.c args.c ch_malloc.c config.c detach.c \
+               fm.c globals.c ldap_op.c lock.c main.c re.c \
+               reject.c replica.c replog.c ri.c rq.c sanity.c st.c \
+               tsleep.c
+
+OBJS   =       admin.o args.o ch_malloc.o config.o detach.o \
+               fm.o globals.o ldap_op.o lock.o main.o re.o \
+               reject.o replica.o replog.o ri.o rq.o sanity.o st.o \
+               tsleep.o
+
+INCLUDES= -I. -I$(HDIR) $(KRBINCLUDEFLAG)
+DEFINES = $(DEFS) $(SERVERDEFS)
+CFLAGS = $(INCLUDES) $(THREADSINCLUDE) $(DEFINES) $(ACFLAGS) $(THREADS)
+LDFLAGS        = -L$(LDIR) $(KRBLIBFLAG)
+LIBS   = -lldap -llber -lm -llthread -lldif $(THREADSLIB) $(KRBLIBS) \
+         $(ALIBS)
+
+all:   FORCE
+       @if [ -z "$(MAKESLAPD)" ]; then \
+               echo "uncomment the MAKESLAPD line in Make-common to make slurpd"; \
+               exit 0; \
+       else \
+               make slurpd; \
+       fi
+
+slurpd:        version.o
+       $(CC) $(ALDFLAGS) -o $@ $(OBJS) version.o $(LDFLAGS) $(LIBS)
+
+slurpd.pure:   version.o
+       purify $(CC) $(ALDFLAGS) -o $@ $(OBJS) version.o $(LDFLAGS) $(LIBS)
+
+version.c: $(OBJS) $(LDIR)/liblber/liblber.a $(LDIR)/libldap/libldap.a
+       $(RM) $@
+       (u=$${USER-root} v=`$(CAT) $(VERSIONFILE)` d=`$(PWD)` h=`$(HOSTNAME)` \
+       t=`$(DATE)`; $(SED) -e "s|%WHEN%|$${t}|" \
+       -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+       -e "s|%VERSION%|$${v}|" \
+       < Version.c > $@)
+
+install: $(ETCDIR) $(ETCDIR)/slurpd
+
+$(ETCDIR)/slurpd:      slurpd
+       $(INSTALL) $(INSTALLFLAGS) -m 755 slurpd $(ETCDIR)
+
+lint:  FORCE
+       $(LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+5lint: FORCE
+       $(5LINT) $(INCLUDES) $(DEFINES) $(SRCS)
+
+clean: FORCE
+       @echo "making clean in `$(PWD)`"
+       $(RM) slurpd *.o core a.out version.c
+
+depend:        FORCE
+       $(MKDEP) $(INCLUDES) $(DEFINES) $(SRCS)
+
+links:
+       @echo "making links in `$(PWD)`"
+       @$(LN) .src/*.[ch] .
+
+# DO NOT DELETE THIS LINE -- mkdep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+admin.o: admin.c slurp.h ../../include/lber.h ../../include/ldap.h
+admin.o: ../../include/lthread.h ../../include/portable.h
+admin.o: ../../include/ldapconfig.h ../../include/ldif.h globals.h slurp.h
+args.o: args.c ../../include/lber.h ../../include/ldap.h slurp.h
+args.o: ../../include/lber.h ../../include/ldap.h ../../include/lthread.h
+args.o: ../../include/portable.h ../../include/ldapconfig.h
+args.o: ../../include/ldif.h globals.h slurp.h
+ch_malloc.o: ch_malloc.c ../slapd/slap.h ../../include/avl.h
+ch_malloc.o: ../../include/lber.h ../../include/ldap.h ../../include/lthread.h
+ch_malloc.o: ../../include/ldif.h
+config.o: config.c ../../include/lber.h ../../include/ldap.h slurp.h
+config.o: ../../include/lber.h ../../include/ldap.h ../../include/lthread.h
+config.o: ../../include/portable.h ../../include/ldapconfig.h
+config.o: ../../include/ldif.h globals.h slurp.h
+detach.o: detach.c ../../include/portable.h
+fm.o: fm.c slurp.h ../../include/lber.h ../../include/ldap.h
+fm.o: ../../include/lthread.h ../../include/portable.h
+fm.o: ../../include/ldapconfig.h ../../include/ldif.h globals.h slurp.h
+globals.o: globals.c slurp.h ../../include/lber.h ../../include/ldap.h
+globals.o: ../../include/lthread.h ../../include/portable.h
+globals.o: ../../include/ldapconfig.h ../../include/ldif.h globals.h slurp.h
+ldap_op.o: ldap_op.c ../../include/lber.h ../../include/ldap.h
+ldap_op.o: ../../include/portable.h slurp.h ../../include/lber.h
+ldap_op.o: ../../include/ldap.h ../../include/lthread.h
+ldap_op.o: ../../include/portable.h ../../include/ldapconfig.h
+ldap_op.o: ../../include/ldif.h
+lock.o: lock.c ../../include/portable.h ../slapd/slap.h ../../include/avl.h
+lock.o: ../../include/lber.h ../../include/ldap.h ../../include/lthread.h
+lock.o: ../../include/ldif.h
+main.o: main.c slurp.h ../../include/lber.h ../../include/ldap.h
+main.o: ../../include/lthread.h ../../include/portable.h
+main.o: ../../include/ldapconfig.h ../../include/ldif.h globals.h slurp.h
+re.o: re.c ../slapd/slap.h ../../include/avl.h ../../include/lber.h
+re.o: ../../include/ldap.h ../../include/lthread.h ../../include/ldif.h slurp.h
+re.o: ../../include/lber.h ../../include/ldap.h ../../include/lthread.h
+re.o: ../../include/portable.h ../../include/ldapconfig.h ../../include/ldif.h
+re.o: globals.h slurp.h
+reject.o: reject.c slurp.h ../../include/lber.h ../../include/ldap.h
+reject.o: ../../include/lthread.h ../../include/portable.h
+reject.o: ../../include/ldapconfig.h ../../include/ldif.h globals.h slurp.h
+replica.o: replica.c slurp.h ../../include/lber.h ../../include/ldap.h
+replica.o: ../../include/lthread.h ../../include/portable.h
+replica.o: ../../include/ldapconfig.h ../../include/ldif.h globals.h slurp.h
+replog.o: replog.c ../../include/portable.h slurp.h ../../include/lber.h
+replog.o: ../../include/ldap.h ../../include/lthread.h ../../include/portable.h
+replog.o: ../../include/ldapconfig.h ../../include/ldif.h globals.h slurp.h
+ri.o: ri.c slurp.h ../../include/lber.h ../../include/ldap.h
+ri.o: ../../include/lthread.h ../../include/portable.h
+ri.o: ../../include/ldapconfig.h ../../include/ldif.h globals.h slurp.h
+rq.o: rq.c slurp.h ../../include/lber.h ../../include/ldap.h
+rq.o: ../../include/lthread.h ../../include/portable.h
+rq.o: ../../include/ldapconfig.h ../../include/ldif.h globals.h slurp.h
+sanity.o: sanity.c slurp.h ../../include/lber.h ../../include/ldap.h
+sanity.o: ../../include/lthread.h ../../include/portable.h
+sanity.o: ../../include/ldapconfig.h ../../include/ldif.h globals.h slurp.h
+sanity.o: ../../include/portable.h
+st.o: st.c slurp.h ../../include/lber.h ../../include/ldap.h
+st.o: ../../include/lthread.h ../../include/portable.h
+st.o: ../../include/ldapconfig.h ../../include/ldif.h globals.h slurp.h
+tsleep.o: tsleep.c slurp.h ../../include/lber.h ../../include/ldap.h
+tsleep.o: ../../include/lthread.h ../../include/portable.h
+tsleep.o: ../../include/ldapconfig.h ../../include/ldif.h globals.h slurp.h
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/servers/slurpd/Version.c b/servers/slurpd/Version.c
new file mode 100644 (file)
index 0000000..aef367c
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 1996 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+char Versionstr[] = "  slurpd %VERSION% (%WHEN%)\n\t%WHOANDWHERE%\n";
diff --git a/servers/slurpd/admin.c b/servers/slurpd/admin.c
new file mode 100644 (file)
index 0000000..6a58b40
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 1996 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+/*
+ * admin.c - routines for performing administrative tasks, e.g. on-the-fly
+ * reconfiguration of slurpd.
+ */
+
+
+#include <stdio.h>
+#include <signal.h>
+
+#include "slurp.h"
+#include "globals.h"
+
+
+/*
+ * Eventually, do_admin will be the entry point for performing
+ * administrative tasks.  General idea: put commands in a file
+ * somewhere, send slurpd a USR2 signal.  The handler for
+ * USR2 (this routine) reads the file and takes some action.
+ *
+ * For right now, this routine has been hijacked for debugging.  When
+ * slurpd receives a USR2 signal, it will dump its replication 
+ * queue to the disk file given by SLURPD_DUMPFILE.
+ */
+void
+do_admin()
+{
+    sglob->rq->rq_dump( sglob->rq );
+    (void) SIGNAL( SIGUSR2, (void *) do_admin );
+}
diff --git a/servers/slurpd/args.c b/servers/slurpd/args.c
new file mode 100644 (file)
index 0000000..b3cc935
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 1996 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+/*
+ * args.c - process command-line arguments, and set appropriate globals.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <lber.h>
+#include <ldap.h>
+
+#include "slurp.h"
+#include "globals.h"
+
+
+static int
+usage( char *name )
+{
+    fprintf( stderr, "usage: %s\t[-d debug-level] [-s syslog-level]\n", name );
+    fprintf( stderr, "\t\t[-f slapd-config-file] [-r replication-log-file]\n" );
+#ifdef KERBEROS
+    fprintf( stderr, "\t\t[-t tmp-dir] [-o] [-k srvtab-file]\n" );
+#else /* KERBEROS */
+    fprintf( stderr, "\t\t[-t tmp-dir] [-o]\n" );
+#endif /* KERBEROS */
+}
+
+
+
+/*
+ * Interpret argv, and fill in any appropriate globals.
+ */
+int
+doargs(
+    int                argc,
+    char       **argv,
+    Globals    *g
+)
+{
+    int                i;
+    extern char        *optarg;
+    int                rflag = 0;
+
+    if ( (g->myname = strrchr( argv[0], '/' )) == NULL ) {
+       g->myname = strdup( argv[0] );
+    } else {
+       g->myname = strdup( g->myname + 1 );
+    }
+
+    while ( (i = getopt( argc, argv, "hd:f:r:t:k:o" )) != EOF ) {
+       switch ( i ) {
+#ifdef LDAP_DEBUG
+       case 'd':       /* turn on debugging */
+           if ( optarg[0] == '?' ) {
+               printf( "Debug levels:\n" );
+               printf( "\tLDAP_DEBUG_TRACE\t%d\n",
+                       LDAP_DEBUG_TRACE );
+               printf( "\tLDAP_DEBUG_PACKETS\t%d\n",
+                       LDAP_DEBUG_PACKETS );
+               printf( "\tLDAP_DEBUG_ARGS\t\t%d\n",
+                       LDAP_DEBUG_ARGS );
+               printf( "\tLDAP_DEBUG_CONNS\t%d\n",
+                       LDAP_DEBUG_CONNS );
+               printf( "\tLDAP_DEBUG_BER\t\t%d\n",
+                       LDAP_DEBUG_BER );
+               printf( "\tLDAP_DEBUG_FILTER\t%d\n",
+                       LDAP_DEBUG_FILTER );
+               printf( "\tLDAP_DEBUG_CONFIG\t%d\n",
+                       LDAP_DEBUG_CONFIG );
+               printf( "\tLDAP_DEBUG_ACL\t\t%d\n",
+                       LDAP_DEBUG_ACL );
+               printf( "\tLDAP_DEBUG_ANY\t\t%d\n",
+                       LDAP_DEBUG_ANY );
+               return( -1 );
+           } else {
+               ldap_debug = atoi( optarg );
+           }
+           break;
+#else /* LDAP_DEBUG */
+       case 'd':       /* can't enable debugging - not built with debug code */
+           fprintf( stderr, "must compile with LDAP_DEBUG for debugging\n" );
+           break;
+#endif /* LDAP_DEBUG */
+       case 'f':       /* slapd config file */
+           g->slapd_configfile = strdup( optarg );
+           break;
+       case 'r':       /* slapd replog file */
+           strcpy( g->slapd_replogfile, optarg );
+           rflag++;
+           break;
+       case 't':       /* dir to use for our copies of replogs */
+           g->slurpd_rdir = strdup( optarg );
+           break;
+       case 'k':       /* name of kerberos srvtab file */
+#ifdef KERBEROS
+           g->default_srvtab = strdup( optarg );
+#else /* KERBEROS */
+           fprintf( stderr, "must compile with KERBEROS to use -k option\n" );
+#endif /* KERBEROS */
+           break;
+       case 'h':
+           usage( g->myname );
+           return( -1 );
+       case 'o':
+           g->one_shot_mode = 1;
+           break;
+       default:
+           usage( g->myname );
+           return( -1 );
+       }
+    }
+
+    if ( g->one_shot_mode && !rflag ) {
+       fprintf( stderr, "If -o flag is given, -r flag must also be given.\n" );
+       usage( g->myname );
+       return( -1 );
+    }
+
+    /* Set location/name of our private copy of the slapd replog file */
+    sprintf( g->slurpd_replogfile, "%s/%s", g->slurpd_rdir,
+           DEFAULT_SLURPD_REPLOGFILE );
+
+    /* Set location/name of the slurpd status file */
+    sprintf( g->slurpd_status_file, "%s/%s", g->slurpd_rdir,
+           DEFAULT_SLURPD_STATUS_FILE );
+
+#ifdef LOG_LOCAL4
+    openlog( g->myname, OPENLOG_OPTIONS, LOG_LOCAL4 );
+#else
+    openlog( g->myname, OPENLOG_OPTIONS );
+#endif
+
+    return 0;
+
+}
+
+
diff --git a/servers/slurpd/ch_malloc.c b/servers/slurpd/ch_malloc.c
new file mode 100644 (file)
index 0000000..298391e
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 1996 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+/*
+ * ch_malloc.c - malloc() and friends, with check for NULL return.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "../slapd/slap.h"
+
+
+
+/*
+ * Just like malloc, except we check the returned value and exit
+ * if anything goes wrong.
+ */
+char *
+ch_malloc(
+    unsigned long      size
+)
+{
+       char    *new;
+
+       if ( (new = (char *) malloc( size )) == NULL ) {
+               fprintf( stderr, "malloc of %d bytes failed\n", size );
+               exit( 1 );
+       }
+
+       return( new );
+}
+
+
+
+
+/*
+ * Just like realloc, except we check the returned value and exit
+ * if anything goes wrong.
+ */
+char *
+ch_realloc(
+    char               *block,
+    unsigned long      size
+)
+{
+       char    *new;
+
+       if ( block == NULL ) {
+               return( ch_malloc( size ) );
+       }
+
+       if ( (new = (char *) realloc( block, size )) == NULL ) {
+               fprintf( stderr, "realloc of %d bytes failed\n", size );
+               exit( 1 );
+       }
+
+       return( new );
+}
+
+
+
+
+/*
+ * Just like calloc, except we check the returned value and exit
+ * if anything goes wrong.
+ */
+char *
+ch_calloc(
+    unsigned long      nelem,
+    unsigned long      size
+)
+{
+       char    *new;
+
+       if ( (new = (char *) calloc( nelem, size )) == NULL ) {
+               fprintf( stderr, "calloc of %d elems of %d bytes failed\n",
+                   nelem, size );
+               exit( 1 );
+       }
+
+       return( new );
+}
+
+
+/*
+ * Just like free, except we check to see if p is null.
+ */
+void
+ch_free(
+    char *p
+)
+{
+    if ( p != NULL ) {
+       free( p );
+    }
+    return;
+}
+       
diff --git a/servers/slurpd/config.c b/servers/slurpd/config.c
new file mode 100644 (file)
index 0000000..7a8261e
--- /dev/null
@@ -0,0 +1,406 @@
+/*
+ * Copyright (c) 1996 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+
+/*
+ * config.c - configuration file handling routines
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <lber.h>
+#include <ldap.h>
+
+#include "slurp.h"
+#include "globals.h"
+
+#define MAXARGS        100
+
+/* Forward declarations */
+#ifdef NEEDPROTOS
+static void    add_replica( char **, int );
+static int     parse_replica_line( char **, int, Ri *);
+static void    parse_line( char *, int *, char ** );
+static char    *getline( FILE * );
+static char    *strtok_quote( char *, char * );
+#else /* NEEDPROTOS */
+static void    add_replica();
+static int     parse_replica_line();
+static void    parse_line();
+static char    *getline();
+static char    *strtok_quote();
+#endif /* NEEDPROTOS */
+
+/* current config file line # */
+static int     lineno;
+
+
+
+/*
+ * Read the slapd config file, looking only for config options we're
+ * interested in.  Since we haven't detached from the controlling
+ * terminal yet, we just perror() and fprintf here.
+ */
+int
+slurpd_read_config(
+    char       *fname
+)
+{
+    FILE       *fp;
+    char       buf[BUFSIZ];
+    char       *line, *p;
+    int                cargc;
+    char       *cargv[MAXARGS];
+
+    Debug( LDAP_DEBUG_CONFIG, "Config: opening config file \"%s\"\n",
+           fname, 0, 0 );
+
+    if ( (fp = fopen( fname, "r" )) == NULL ) {
+       perror( fname );
+       exit( 1 );
+    }
+
+    lineno = 0;
+    while ( (line = getline( fp )) != NULL ) {
+       /* skip comments and blank lines */
+       if ( line[0] == '#' || line[0] == '\0' ) {
+           continue;
+       }
+
+       Debug( LDAP_DEBUG_CONFIG, "Config: (%s)\n", line, 0, 0 );
+
+       parse_line( line, &cargc, cargv );
+
+       if ( cargc < 1 ) {
+           fprintf( stderr, "line %d: bad config line (ignored)\n", lineno );
+           continue;
+       }
+
+       /* replication log file to which changes are appended */
+       if ( strcasecmp( cargv[0], "replogfile" ) == 0 ) {
+           /* 
+            * if slapd_replogfile has a value, the -r option was given,
+            * so use that value.  If slapd_replogfile has length == 0,
+            * then we should use the value in the config file we're reading.
+            */
+           if ( sglob->slapd_replogfile[ 0 ] == '\0' ) {
+               if ( cargc < 2 ) {
+                   fprintf( stderr,
+                       "line %d: missing filename in \"replogfile ",
+                       lineno );
+                   fprintf( stderr, "<filename>\" line\n" );
+                   exit( 1 );
+               } else if ( cargc > 2 && *cargv[2] != '#' ) {
+                   fprintf( stderr,
+                       "line %d: extra cruft at the end of \"replogfile %s\"",
+                       lineno, cargv[1] );
+                   fprintf( stderr, "line (ignored)\n" );
+               }
+               sprintf( sglob->slapd_replogfile, cargv[1] );
+           }
+       } else if ( strcasecmp( cargv[0], "replica" ) == 0 ) {
+           add_replica( cargv, cargc );
+       }
+    }
+    fclose( fp );
+    Debug( LDAP_DEBUG_CONFIG,
+           "Config: ** configuration file successfully read and parsed\n",
+           0, 0, 0 );
+    return 0;
+}
+
+
+
+
+/*
+ * Parse one line of input.
+ */
+static void
+parse_line(
+    char       *line,
+    int                *argcp,
+    char       **argv
+)
+{
+    char *     token;
+
+    *argcp = 0;
+    for ( token = strtok_quote( line, " \t" ); token != NULL;
+       token = strtok_quote( NULL, " \t" ) ) {
+       argv[(*argcp)++] = token;
+    }
+    argv[*argcp] = NULL;
+}
+
+
+
+
+static char *
+strtok_quote(
+    char *line,
+    char *sep
+)
+{
+    int                inquote;
+    char       *tmp;
+    static char        *next;
+
+    if ( line != NULL ) {
+       next = line;
+    }
+    while ( *next && strchr( sep, *next ) ) {
+       next++;
+    }
+
+    if ( *next == '\0' ) {
+       next = NULL;
+       return( NULL );
+    }
+    tmp = next;
+
+    for ( inquote = 0; *next; ) {
+       switch ( *next ) {
+       case '"':
+           if ( inquote ) {
+               inquote = 0;
+           } else {
+               inquote = 1;
+           }
+           strcpy( next, next + 1 );
+           break;
+
+       case '\\':
+           strcpy( next, next + 1 );
+           break;
+
+       default:
+           if ( ! inquote ) {
+               if ( strchr( sep, *next ) != NULL ) {
+                   *next++ = '\0';
+                   return( tmp );
+               }
+           }
+           next++;
+           break;
+       }
+    }
+
+    return( tmp );
+}
+
+#define CATLINE( buf ) { \
+    int        len; \
+    len = strlen( buf ); \
+    while ( lcur + len + 1 > lmax ) { \
+       lmax += BUFSIZ; \
+       line = (char *) ch_realloc( line, lmax ); \
+    } \
+    strcpy( line + lcur, buf ); \
+    lcur += len; \
+}
+
+
+
+/*
+ * Get a line of input.
+ */
+static char *
+getline(
+    FILE *fp
+)
+{
+    char       *p;
+    static char        buf[BUFSIZ];
+    static char        *line;
+    static int lmax, lcur;
+
+    lcur = 0;
+    CATLINE( buf );
+    while ( fgets( buf, sizeof(buf), fp ) != NULL ) {
+       if ( (p = strchr( buf, '\n' )) != NULL ) {
+           *p = '\0';
+       }
+       lineno++;
+       if ( ! isspace( buf[0] ) ) {
+           return( line );
+       }
+
+       CATLINE( buf );
+    }
+    buf[0] = '\0';
+
+    return( line[0] ? line : NULL );
+}
+
+
+/*
+ * Add a node to the array of replicas.
+ */
+static void
+add_replica(
+    char       **cargv,
+    int                cargc
+)
+{
+    int        nr;
+
+    nr = ++sglob->num_replicas;
+    sglob->replicas = (Ri **) ch_realloc( sglob->replicas,
+           ( nr + 1 )  * sizeof( Re * ));
+    if ( sglob->replicas == NULL ) {
+       fprintf( stderr, "out of memory, add_replica\n" );
+       exit( 1 );
+    }
+    sglob->replicas[ nr ] = NULL; 
+
+    if ( Ri_init( &(sglob->replicas[ nr - 1 ])) < 0 ) {
+       fprintf( stderr, "out of memory, Ri_init\n" );
+       exit( 1 );
+    }
+    if ( parse_replica_line( cargv, cargc,
+           sglob->replicas[ nr - 1] ) < 0 ) {
+       /* Something bad happened - back out */
+       fprintf( stderr,
+           "Warning: failed to add replica \"%s:%d - ignoring replica\n",
+           sglob->replicas[ nr - 1 ]->ri_hostname == NULL ?
+           "(null)" : sglob->replicas[ nr - 1 ]->ri_hostname,
+           sglob->replicas[ nr - 1 ]->ri_port );
+       sglob->replicas[ nr - 1] = NULL;
+       sglob->num_replicas--;
+    } else {
+       Debug( LDAP_DEBUG_CONFIG,
+               "Config: ** successfully added replica \"%s:%d\"\n",
+               sglob->replicas[ nr - 1 ]->ri_hostname == NULL ?
+               "(null)" : sglob->replicas[ nr - 1 ]->ri_hostname,
+               sglob->replicas[ nr - 1 ]->ri_port, 0 );
+       sglob->replicas[ nr - 1]->ri_stel =
+               sglob->st->st_add( sglob->st,
+               sglob->replicas[ nr - 1 ] );
+       if ( sglob->replicas[ nr - 1]->ri_stel == NULL ) {
+           fprintf( stderr, "Failed to add status element structure\n" );
+           exit( 1 );
+       }
+    }
+}
+
+
+
+/* 
+ * Parse a "replica" line from the config file.  replica lines should be
+ * in the following format:
+ * replica    host=<hostname:portnumber> binddn=<binddn>
+ *            bindmethod="simple|kerberos" credentials=<creds>
+ *
+ * where:
+ * <hostname:portnumber> describes the host name and port number where the
+ * replica is running,
+ *
+ * <binddn> is the DN to bind to the replica slapd as,
+ *
+ * bindmethod is either "simple" or "kerberos", and
+ *
+ * <creds> are the credentials (e.g. password) for binddn.  <creds> are
+ * only used for bindmethod=simple.  For bindmethod=kerberos, the
+ * credentials= option should be omitted.  Credentials for kerberos
+ * authentication are in the system srvtab file.
+ *
+ * The "replica" config file line may be split across multiple lines.  If
+ * a line begins with whitespace, it is considered a continuation of the
+ * previous line.
+ */
+#define        GOT_HOST        1
+#define        GOT_DN          2
+#define        GOT_METHOD      4
+#define        GOT_ALL         ( GOT_HOST | GOT_DN | GOT_METHOD )
+static int
+parse_replica_line( 
+    char       **cargv,
+    int                cargc,
+    Ri         *ri
+)
+{
+    int                gots = 0;
+    int                i;
+    char       *hp, *val;
+
+    for ( i = 1; i < cargc; i++ ) {
+       if ( !strncasecmp( cargv[ i ], HOSTSTR, strlen( HOSTSTR ))) {
+           val = cargv[ i ] + strlen( HOSTSTR ) + 1;
+           if (( hp = strchr( val, ':' )) != NULL ) {
+               *hp = '\0';
+               hp++;
+               ri->ri_port = atoi( hp );
+           }
+           if ( ri->ri_port <= 0 ) {
+               ri->ri_port = LDAP_PORT;
+           }
+           ri->ri_hostname = strdup( val );
+           gots |= GOT_HOST;
+       } else if ( !strncasecmp( cargv[ i ],
+               BINDDNSTR, strlen( BINDDNSTR ))) { 
+           val = cargv[ i ] + strlen( BINDDNSTR ) + 1;
+           ri->ri_bind_dn = strdup( val );
+           gots |= GOT_DN;
+       } else if ( !strncasecmp( cargv[ i ], BINDMETHSTR,
+               strlen( BINDMETHSTR ))) {
+           val = cargv[ i ] + strlen( BINDMETHSTR ) + 1;
+           if ( !strcasecmp( val, KERBEROSSTR )) {
+#ifdef KERBEROS
+               ri->ri_bind_method = AUTH_KERBEROS;
+               if ( ri->ri_srvtab == NULL ) {
+                   ri->ri_srvtab = strdup( sglob->default_srvtab );
+               }
+               gots |= GOT_METHOD;
+#else /* KERBEROS */
+           fprintf( stderr, "Error: a bind method of \"kerberos\" was\n" );
+           fprintf( stderr, "specified in the slapd configuration file,\n" );
+           fprintf( stderr, "but slurpd was not built with kerberos.\n" );
+           fprintf( stderr, "You must rebuild the LDAP release with\n" );
+           fprintf( stderr, "kerberos support if you wish to use\n" );
+           fprintf( stderr, "bindmethod=kerberos\n" );
+           exit( 1 );
+#endif /* KERBEROS */
+           } else if ( !strcasecmp( val, SIMPLESTR )) {
+               ri->ri_bind_method = AUTH_SIMPLE;
+               gots |= GOT_METHOD;
+           } else {
+               ri->ri_bind_method = -1;
+           }
+       } else if ( !strncasecmp( cargv[ i ], CREDSTR, strlen( CREDSTR ))) {
+           val = cargv[ i ] + strlen( CREDSTR ) + 1;
+           ri->ri_password = strdup( val );
+       } else if ( !strncasecmp( cargv[ i ], BINDPSTR, strlen( BINDPSTR ))) {
+           val = cargv[ i ] + strlen( BINDPSTR ) + 1;
+           ri->ri_principal = strdup( val );
+       } else if ( !strncasecmp( cargv[ i ], SRVTABSTR, strlen( SRVTABSTR ))) {
+           val = cargv[ i ] + strlen( SRVTABSTR ) + 1;
+           if ( ri->ri_srvtab != NULL ) {
+               free( ri->ri_srvtab );
+           }
+           ri->ri_srvtab = strdup( val );
+       } else {
+           fprintf( stderr, 
+                   "Error: parse_replica_line: unknown keyword \"%s\"\n",
+                   cargv[ i ] );
+       }
+    }
+    if ( gots != GOT_ALL ) {
+           fprintf( stderr, "Error: Malformed \"replica\" line in slapd " );
+           fprintf( stderr, "config file, line %d\n", lineno );
+       return -1;
+    }
+    return 0;
+}
+
diff --git a/servers/slurpd/detach.c b/servers/slurpd/detach.c
new file mode 100644 (file)
index 0000000..7b3fdab
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 1990, 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef SVR4
+#include <sys/stat.h>
+#endif /* svr4 */
+#include <fcntl.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <signal.h>
+#include "portable.h"
+
+#ifdef USE_SYSCONF
+#include <unistd.h>
+#endif /* USE_SYSCONF */
+
+
+detach()
+{
+       int             i, sd, nbits;
+#ifdef LDAP_DEBUG
+       extern int      ldap_debug;
+#endif
+
+#ifdef USE_SYSCONF
+       nbits = sysconf( _SC_OPEN_MAX );
+#else /* USE_SYSCONF */
+       nbits = getdtablesize();
+#endif /* USE_SYSCONF */
+
+#ifdef LDAP_DEBUG
+       if ( ldap_debug == 0 ) {
+#endif
+               for ( i = 0; i < 5; i++ ) {
+#if defined( sunos5 ) && defined( THREAD_SUNOS5_LWP )
+                       switch ( fork1() ) {
+#else
+                       switch ( fork() ) {
+#endif
+                       case -1:
+                               sleep( 5 );
+                               continue;
+
+                       case 0:
+                               break;
+
+                       default:
+                               _exit( 0 );
+                       }
+                       break;
+               }
+
+/*
+               for ( i = 3; i < nbits; i++ )
+                       close( i );
+*/
+
+               (void) chdir( "/" );
+
+               if ( (sd = open( "/dev/null", O_RDWR )) == -1 ) {
+                       perror( "/dev/null" );
+                       exit( 1 );
+               }
+               if ( isatty( 0 ) )
+                       (void) dup2( sd, 0 );
+               if ( isatty( 1 ) )
+                       (void) dup2( sd, 1 );
+               if ( isatty(2) )
+                       (void) dup2( sd, 2 );
+               close( sd );
+
+#ifdef USE_SETSID
+               setsid();
+#else /* USE_SETSID */
+               if ( (sd = open( "/dev/tty", O_RDWR )) != -1 ) {
+                       (void) ioctl( sd, TIOCNOTTY, NULL );
+                       (void) close( sd );
+               }
+#endif /* USE_SETSID */
+#ifdef LDAP_DEBUG
+       } 
+#endif
+
+       (void) SIGNAL( SIGPIPE, SIG_IGN );
+}
diff --git a/servers/slurpd/fm.c b/servers/slurpd/fm.c
new file mode 100644 (file)
index 0000000..2d36838
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 1996 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+/*
+ * fm.c - file management routines.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+#include "slurp.h"
+#include "globals.h"
+
+extern void do_admin();
+
+static void set_shutdown();
+void do_nothing();
+
+/*
+ * Externs
+ */
+#ifdef NEEDPROTOS
+extern int file_nonempty( char * );
+extern int acquire_lock(char *, FILE **, FILE ** );
+extern int relinquish_lock(char *, FILE *, FILE * );
+#else /* NEEDPROTOS */
+extern int file_nonempty();
+extern int acquire_lock();
+extern int relinquish_lock();
+#endif /* NEEDPROTOS */
+
+/*
+ * Forward references
+ */
+#ifdef NEEDPROTOS
+static char *get_record( FILE * );
+static void populate_queue( char *f );
+static void set_shutdown();
+void do_nothing();
+#else /* NEEDPROTOS */
+static char *get_record();
+static void populate_queue();
+static void set_shutdown();
+void do_nothing();
+#endif /* NEEDPROTOS */
+
+#ifndef SYSERRLIST_IN_STDIO
+extern char *sys_errlist[];
+#endif /* SYSERRLIST_IN_STDIO */
+
+
+
+/*
+ * Main file manager routine.  Watches for new data to be appended to the
+ * slapd replication log.  When new data is appended, fm does the following:
+ *  - appends the data to slurpd's private copy of the replication log.
+ *  - truncates the slapd replog
+ *  - adds items to the internal queue of replication work to do
+ *  - signals the replication threads to let them know new work has arrived.
+ */
+void
+fm(
+    void *arg
+)
+{
+    int rc;
+
+    /* Set up our signal handlers:
+     * SIG{TERM,INT,HUP} causes a shutdown
+     * SIGUSR1 - does nothing, used to wake up sleeping threads.
+     * SIGUSR2 - causes slurpd to read its administrative interface file.
+     *           (not yet implemented).
+     */
+    (void) SIGNAL( SIGUSR1, (void *) do_nothing );
+    (void) SIGNAL( SIGUSR2, (void *) do_admin );
+    (void) SIGNAL( SIGTERM, (void *) set_shutdown );
+    (void) SIGNAL( SIGINT, (void *) set_shutdown );
+    (void) SIGNAL( SIGHUP, (void *) set_shutdown );
+
+    if ( sglob->one_shot_mode ) {
+       if ( file_nonempty( sglob->slapd_replogfile )) {
+           populate_queue( sglob->slapd_replogfile );
+       }
+       printf( "Processing in one-shot mode:\n" );
+       printf( "%d total replication records in file,\n",
+               sglob->rq->rq_getcount( sglob->rq, RQ_COUNT_ALL ));
+       printf( "%d replication records to process.\n",
+               sglob->rq->rq_getcount( sglob->rq, RQ_COUNT_NZRC ));
+       return;
+    }
+    /*
+     * There may be some leftover replication records in our own
+     * copy of the replication log.  If any exist, add them to the
+     * queue.
+     */
+    if ( file_nonempty( sglob->slurpd_replogfile )) {
+       populate_queue( sglob->slurpd_replogfile );
+    }
+
+
+    while ( !sglob->slurpd_shutdown ) {
+       if ( file_nonempty( sglob->slapd_replogfile )) {
+           /* New work found - copy to slurpd replog file */
+           Debug( LDAP_DEBUG_ARGS, "new work in %s\n",
+                   sglob->slapd_replogfile, 0, 0 );
+           if (( rc = copy_replog( sglob->slapd_replogfile,
+                   sglob->slurpd_replogfile )) == 0 )  {
+               populate_queue( sglob->slurpd_replogfile );
+           } else {
+               if ( rc < 0 ) {
+                   Debug( LDAP_DEBUG_ANY,
+                           "Fatal error while copying replication log\n",
+                           0, 0, 0 );
+                   sglob->slurpd_shutdown = 1;
+               }
+           }
+       } else {
+           tsleep( sglob->no_work_interval );
+       }
+
+       /* Garbage-collect queue */
+       sglob->rq->rq_gc( sglob->rq );
+
+       /* Trim replication log file, if needed */
+       if ( sglob->rq->rq_needtrim( sglob->rq )) {
+           FILE *fp, *lfp;
+           if (( rc = acquire_lock( sglob->slurpd_replogfile, &fp,
+                   &lfp )) < 0 ) {
+               Debug( LDAP_DEBUG_ANY,
+                       "Error: cannot acquire lock on \"%s\" for trimming\n",
+                       sglob->slurpd_replogfile, 0, 0 );
+           } else {
+               sglob->rq->rq_write( sglob->rq, fp );
+               (void) relinquish_lock( sglob->slurpd_replogfile, fp, lfp );
+           }
+       }
+    }
+    Debug( LDAP_DEBUG_ARGS, "fm: exiting\n", 0, 0, 0 );
+}
+
+
+
+
+/*
+ * Set a global flag which signals that we're shutting down.
+ */
+static void
+set_shutdown()
+{
+    int        i;
+
+    sglob->slurpd_shutdown = 1;                                /* set flag */
+    pthread_kill( sglob->fm_tid, SIGUSR1 );            /* wake up file mgr */
+    sglob->rq->rq_lock( sglob->rq );                   /* lock queue */
+    pthread_cond_broadcast( &(sglob->rq->rq_more) );   /* wake repl threads */
+    for ( i = 0; i < sglob->num_replicas; i++ ) {
+       (sglob->replicas[ i ])->ri_wake( sglob->replicas[ i ]);
+    }
+    sglob->rq->rq_unlock( sglob->rq );                 /* unlock queue */
+    (void) SIGNAL( SIGTERM, (void *) set_shutdown );   /* reinstall handlers */
+    (void) SIGNAL( SIGINT, (void *) set_shutdown );
+    (void) SIGNAL( SIGHUP, (void *) set_shutdown );
+}
+
+
+
+
+/*
+ * A do-nothing signal handler.
+ */
+void
+do_nothing()
+{
+    (void) SIGNAL( SIGUSR1, (void *) do_nothing );
+}
+
+
+
+
+/*
+ * Open the slurpd replication log, seek to our last known position, and
+ * process any pending replication entries.
+ */
+static void
+populate_queue(
+    char *f
+)
+{
+    FILE       *fp, *lfp;
+    Rq         *rq = sglob->rq;
+    char       *p;
+
+    if ( acquire_lock( f, &fp, &lfp ) < 0 ) {
+       Debug( LDAP_DEBUG_ANY,
+               "error: can't lock file \"%s\": %s\n",
+               f, sys_errlist[ errno ], 0 );
+       return;
+    }
+
+    /*
+     * Read replication records from fp and append them the
+     * the queue.
+     */
+    if ( fseek( fp, sglob->srpos, 0 ) < 0 ) {
+       Debug( LDAP_DEBUG_ANY,
+               "error: can't seek to offset %ld in file \"%s\"\n",
+               sglob->srpos, f, 0 );
+       return;
+    }
+    while (( p = get_record( fp )) != NULL ) {
+       if ( sglob->rq->rq_add( sglob->rq, p ) < 0 ) {
+           char *t;
+           /* Print an error message.  Only print first line.  */
+           if (( t = strchr( p, '\n' )) != NULL ) {
+               *t = '\0';
+           }
+           Debug( LDAP_DEBUG_ANY,
+                   "error: malformed replog entry (begins with \"%s\")\n",
+                   p, 0, 0 );
+       }
+       free( p );
+       pthread_yield();
+    }
+    sglob->srpos = ftell( fp );
+    (void) relinquish_lock( f, fp, lfp );
+}
+    
+
+
+
+/*
+ * Get the next "record" from the file pointed to by fp.  A "record"
+ * is delimited by two consecutive newlines.  Returns NULL on EOF.
+ */
+static char *
+get_record(
+    FILE *fp
+)
+{
+    int                len;
+    static char        line[BUFSIZ];
+    char       *buf = NULL;
+    static int lcur, lmax;
+
+    lcur = lmax = 0;
+
+    while (( fgets( line, sizeof(line), fp ) != NULL ) &&
+           (( len = strlen( line )) > 1 )) {
+       while ( lcur + len + 1 > lmax ) {
+           lmax += BUFSIZ;
+           buf = (char *) ch_realloc( buf, lmax );
+       }
+       strcpy( buf + lcur, line );
+       lcur += len;
+    }
+    return( buf );
+}
+
diff --git a/servers/slurpd/globals.c b/servers/slurpd/globals.c
new file mode 100644 (file)
index 0000000..f863032
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1996 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+/*
+ * globals.c - initialization code for global data
+ */
+
+#include <stdio.h>
+
+#include "slurp.h"
+#include "globals.h"
+
+Globals                 *sglob;
+
+int ldap_syslog = 0;
+int ldap_syslog_level = LOG_DEBUG;
+int ldap_debug = 0;
+
+
+/*
+ * Initialize the globals
+ */
+Globals *init_globals()
+{
+    Globals *g;
+
+    g = ( Globals * ) malloc( sizeof( Globals ));
+    if ( g == NULL ) {
+       return NULL;
+    }
+
+    g->slapd_configfile = SLAPD_DEFAULT_CONFIGFILE;
+    g->no_work_interval = DEFAULT_NO_WORK_INTERVAL;
+    g->slurpd_shutdown = 0;
+    g->num_replicas = 0;
+    g->replicas = NULL;
+    g->slurpd_rdir = DEFAULT_SLURPD_REPLICA_DIR;
+    strcpy( g->slurpd_status_file, DEFAULT_SLURPD_STATUS_FILE );
+    g->slapd_replogfile[ 0 ] = '\0';
+    g->slurpd_replogfile[ 0 ] = '\0';
+    g->slurpd_status_file[ 0 ] = '\0';
+    g->one_shot_mode = 0;
+    g->myname = NULL;
+    g->srpos = 0L;
+    if ( St_init( &(g->st)) < 0 ) {
+       fprintf( stderr, "Cannot initialize status data\n" );
+       exit( 1 );
+    }
+    pthread_mutex_init( &(g->rej_mutex), pthread_mutexattr_default );
+    if ( Rq_init( &(g->rq)) < 0 ) {
+       fprintf( stderr, "Cannot initialize queue\n" );
+       exit( 1 );
+    }
+#ifdef KERBEROS
+    g->default_srvtab = SRVTAB;
+#endif /* KERBEROS */
+#if defined( THREAD_SUNOS4_LWP )
+    g->tsl_list = NULL;
+    mon_create( &g->tsl_mon ); 
+#endif /* THREAD_SUNOS4_LWP */
+
+    return g;
+}
diff --git a/servers/slurpd/globals.h b/servers/slurpd/globals.h
new file mode 100644 (file)
index 0000000..5d976ff
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 1996 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+
+/*
+ * globals.h - definition of structure holding global data.
+ */
+
+#include "slurp.h"
+
+typedef struct globals {
+    /* Thread ID for file manager thread */
+    pthread_t fm_tid;
+    /* The name of the slapd config file (which is also our config file) */
+    char *slapd_configfile;
+    /* How long the master slurpd sleeps when there's no work to do */
+    int        no_work_interval;
+    /* We keep running until slurpd_shutdown is nonzero.  HUP signal set this */
+    int        slurpd_shutdown;
+    /* Number of replicas we're servicing */
+    int num_replicas;
+    /* Array of pointers to replica info */
+    Ri **replicas;
+    /* Directory where our replica files are written/read */
+    char *slurpd_rdir;
+    /* Name of slurpd status file (timestamp of last replog */
+    char slurpd_status_file[ MAXPATHLEN ];
+    /* Name of the replication log slapd is writing (and we are reading) */
+    char slapd_replogfile[ MAXPATHLEN ];
+    /* Name of local copy of replogfile we maintain */
+    char slurpd_replogfile[ MAXPATHLEN ];
+    /* Non-zero if we were given a replog file to process on command-line */
+    int        one_shot_mode;
+    /* Name of program */
+    char *myname;
+    /* Current offset into slurpd replica logfile */
+    off_t srpos;
+    /* mutex to serialize access to reject file */
+    pthread_mutex_t rej_mutex;
+    /* pointer to status struct */
+    St *st;
+    /* Pointer to replication queue */
+    Rq *rq;
+#ifdef KERBEROS
+    /* Default name of kerberos srvtab file */
+    char *default_srvtab;
+#endif /* KERBEROS */
+#if defined( THREAD_SUNOS4_LWP )
+    tl_t *tsl_list;
+    mon_t tsl_mon;
+#endif /* THREAD_SUNOS4_LWP */
+} Globals;
+
+
+extern Globals *sglob;
diff --git a/servers/slurpd/ldap_op.c b/servers/slurpd/ldap_op.c
new file mode 100644 (file)
index 0000000..0825392
--- /dev/null
@@ -0,0 +1,858 @@
+/*
+ * Copyright (c) 1996 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+/*
+ * ldap_op.c - routines to perform LDAP operations
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#ifdef KERBEROS
+#include <krb.h>
+#endif /* KERBEROS */
+
+#include <lber.h>
+#include <ldap.h>
+
+#include "portable.h"
+#include "slurp.h"
+
+/* Forward references */
+static int get_changetype( char * );
+static struct berval **make_singlevalued_berval( char  *, int );
+static int op_ldap_add( Ri *, Re *, char ** );
+static int op_ldap_modify( Ri *, Re *, char ** );
+static int op_ldap_delete( Ri *, Re *, char ** );
+static int op_ldap_modrdn( Ri *, Re *, char ** );
+static LDAPMod *alloc_ldapmod();
+static void free_ldapmod( LDAPMod * );
+static void free_ldmarr( LDAPMod ** );
+static int getmodtype( char * );
+static void dump_ldm_array( LDAPMod ** );
+static char **read_krbnames( Ri * );
+static void upcase( char * );
+static int do_bind( Ri *, int * );
+static int do_unbind( Ri * );
+
+
+/* External references */
+#ifndef SYSERRLIST_IN_STDIO
+extern char *sys_errlist[];
+#endif /* SYSERRLIST_IN_STDIO */
+
+extern char *ch_malloc( unsigned long );
+
+static char *kattrs[] = {"kerberosName", NULL };
+static struct timeval kst = {30L, 0L};
+
+
+
+/*
+ * Determine the type of ldap operation being performed and call the
+ * appropriate routine.
+ * - If successful, returns ERR_DO_LDAP_OK
+ * - If a retryable error occurs, ERR_DO_LDAP_RETRYABLE is returned.
+ *   The caller should wait a while and retry the operation.
+ * - If a fatal error occurs, ERR_DO_LDAP_FATAL is returned.  The caller
+ *   should reject the operation and continue with the next replication
+ *   entry.
+ */
+int
+do_ldap(
+    Ri         *ri,
+    Re         *re,
+    char       **errmsg
+)
+{
+    int        rc = 0;
+    int        lderr = LDAP_SUCCESS;
+    int        retry = 2;
+    char *msg;
+
+    *errmsg = NULL;
+
+    while ( retry > 0 ) {
+       if ( ri->ri_ldp == NULL ) {
+           rc = do_bind( ri, &lderr );
+           if ( rc != BIND_OK ) {
+               return DO_LDAP_ERR_RETRYABLE;
+           }
+       }
+
+       switch ( re->re_changetype ) {
+       case T_ADDCT:
+           lderr = op_ldap_add( ri, re, errmsg );
+           if ( lderr != LDAP_SUCCESS ) {
+               Debug( LDAP_DEBUG_ANY,
+                       "Error: ldap_add_s failed adding \"%s\": %s\n",
+                       *errmsg ? *errmsg : ldap_err2string( lderr ),
+                       re->re_dn, 0 );
+           }
+           break;
+       case T_MODIFYCT:
+           lderr = op_ldap_modify( ri, re, errmsg );
+           if ( lderr != LDAP_SUCCESS ) {
+               Debug( LDAP_DEBUG_ANY,
+                       "Error: ldap_modify_s failed modifying \"%s\": %s\n",
+                       *errmsg ? *errmsg : ldap_err2string( lderr ),
+                       re->re_dn, 0 );
+           }
+           break;
+       case T_DELETECT:
+           lderr = op_ldap_delete( ri, re, errmsg );
+           if ( lderr != LDAP_SUCCESS ) {
+               Debug( LDAP_DEBUG_ANY,
+                       "Error: ldap_delete_s failed deleting \"%s\": %s\n",
+                       *errmsg ? *errmsg : ldap_err2string( lderr ),
+                       re->re_dn, 0 );
+           }
+           break;
+       case T_MODRDNCT:
+           lderr = op_ldap_modrdn( ri, re, errmsg );
+           if ( lderr != LDAP_SUCCESS ) {
+               Debug( LDAP_DEBUG_ANY,
+                       "Error: ldap_modrdn_s failed modifying %s: %s\n",
+                       *errmsg ? *errmsg : ldap_err2string( lderr ),
+                       re->re_dn, 0 );
+           }
+           break;
+       default:
+           Debug( LDAP_DEBUG_ANY,
+                   "Error: do_ldap: bad op \"%d\", dn = \"%s\"\n",
+                   re->re_changetype, re->re_dn, 0 );
+           return DO_LDAP_ERR_FATAL;
+       }
+
+       /*
+        * Analyze return code.  If ok, just return.  If LDAP_SERVER_DOWN,
+        * we may have been idle long enough that the remote slapd timed
+        * us out.  Rebind and try again.
+        */
+       if ( lderr == LDAP_SUCCESS ) {
+           return DO_LDAP_OK;
+       } else if ( lderr == LDAP_SERVER_DOWN ) {
+           /* The LDAP server may have timed us out - rebind and try again */
+           (void) do_unbind( ri );
+           retry--;
+       } else {
+           return DO_LDAP_ERR_FATAL;
+       }
+    }
+    return DO_LDAP_ERR_FATAL;
+}
+
+
+
+
+/*
+ * Perform an ldap add operation.
+ */
+static int
+op_ldap_add(
+    Ri         *ri,
+    Re         *re,
+    char       **errmsg
+)
+{
+    Mi         *mi;
+    int                nattrs, rc = 0, i;
+    LDAPMod    *ldm, **ldmarr;
+    int                lderr = 0;
+
+    nattrs = i = 0;
+    ldmarr = NULL;
+
+    /*
+     * Construct a null-terminated array of LDAPMod structs.
+     */
+    mi = re->re_mods;
+    while ( mi[ i ].mi_type != NULL ) {
+       ldm = alloc_ldapmod();
+       ldmarr = ( LDAPMod ** ) ch_realloc( ldmarr,
+               ( nattrs + 2 ) * sizeof( LDAPMod * ));
+       ldmarr[ nattrs ] = ldm;
+       ldm->mod_op = LDAP_MOD_BVALUES;
+       ldm->mod_type = mi[ i ].mi_type;
+       ldm->mod_bvalues =
+               make_singlevalued_berval( mi[ i ].mi_val, mi[ i ].mi_len );
+       i++;
+       nattrs++;
+    }
+
+    if ( ldmarr != NULL ) {
+       ldmarr[ nattrs ] = NULL;
+
+       /* Perform the operation */
+       Debug( LDAP_DEBUG_ARGS, "replica %s:%d - add dn \"%s\"\n",
+               ri->ri_hostname, ri->ri_port, re->re_dn );
+       rc = ldap_add_s( ri->ri_ldp, re->re_dn, ldmarr );
+       lderr = ri->ri_ldp->ld_errno;
+    } else {
+       *errmsg = "No modifications to do";
+       Debug( LDAP_DEBUG_ANY,
+               "Error: op_ldap_add: no mods to do (%s)!", re->re_dn, 0, 0 );
+    }
+    free_ldmarr( ldmarr );
+    return( lderr ); 
+}
+
+
+
+
+/*
+ * Perform an ldap modify operation.
+ */
+#define        AWAITING_OP -1
+static int
+op_ldap_modify(
+    Ri         *ri,
+    Re         *re,
+    char       **errmsg
+)
+{
+    Mi         *mi;
+    int                state;  /* This code is a simple-minded state machine */
+    int                nvals;  /* Number of values we're modifying */
+    int                nops;   /* Number of LDAPMod structs in ldmarr */
+    LDAPMod    *ldm, *nldm, **ldmarr;
+    int                i, len;
+    char       *type, *value;
+    int                rc = 0;
+
+    state = AWAITING_OP;
+    nvals = 0;
+    nops = 0;
+    ldmarr = NULL;
+
+    if ( re->re_mods == NULL ) {
+       *errmsg = "No arguments given";
+       Debug( LDAP_DEBUG_ANY, "Error: op_ldap_modify: no arguments\n",
+               0, 0, 0 );
+           return -1;
+    }
+
+    /*
+     * Construct a null-terminated array of LDAPMod structs.
+     */
+    for ( mi = re->re_mods, i = 0; mi[ i ].mi_type != NULL; i++ ) {
+       type = mi[ i ].mi_type;
+       value = mi[ i ].mi_val;
+       len = mi[ i ].mi_len;
+       switch ( getmodtype( type )) {
+       case T_MODSEP:
+           state = T_MODSEP; /* Got a separator line "-\n" */
+           continue;
+       case T_MODOPADD:
+           state = T_MODOPADD;
+           ldmarr = ( LDAPMod ** )
+                   ch_realloc(ldmarr, (( nops + 2 ) * ( sizeof( LDAPMod * ))));
+           ldmarr[ nops ] = ldm = alloc_ldapmod();
+           ldm->mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
+           ldm->mod_type = value;
+           nvals = 0;
+           nops++;
+           break;
+       case T_MODOPREPLACE:
+           state = T_MODOPREPLACE;
+           ldmarr = ( LDAPMod ** )
+                   ch_realloc(ldmarr, (( nops + 2 ) * ( sizeof( LDAPMod * ))));
+           ldmarr[ nops ] = ldm = alloc_ldapmod();
+           ldm->mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
+           ldm->mod_type = value;
+           nvals = 0;
+           nops++;
+           break;
+       case T_MODOPDELETE:
+           state = T_MODOPDELETE;
+           ldmarr = ( LDAPMod ** )
+                   ch_realloc(ldmarr, (( nops + 2 ) * ( sizeof( LDAPMod * ))));
+           ldmarr[ nops ] = ldm = alloc_ldapmod();
+           ldm->mod_op = LDAP_MOD_DELETE | LDAP_MOD_BVALUES;
+           ldm->mod_type = value;
+           nvals = 0;
+           nops++;
+           break;
+       default:
+           if ( state == AWAITING_OP ) {
+               Debug( LDAP_DEBUG_ANY,
+                       "Error: op_ldap_modify: unknown mod type \"%s\"\n",
+                       type, 0, 0 );
+               continue;
+           }
+
+           /*
+            * We should have an attribute: value pair here.
+            * Construct the mod_bvalues part of the ldapmod struct.
+            */
+           if ( strcasecmp( type, ldm->mod_type )) {
+               Debug( LDAP_DEBUG_ANY,
+                       "Error: malformed modify op, %s: %s (expecting %s:)\n",
+                       type, value, ldm->mod_type );
+               continue;
+           }
+           ldm->mod_bvalues = ( struct berval ** )
+                   ch_realloc( ldm->mod_bvalues,
+                   ( nvals + 2 ) * sizeof( struct berval * ));
+           ldm->mod_bvalues[ nvals + 1 ] = NULL;
+           ldm->mod_bvalues[ nvals ] = ( struct berval * )
+                   ch_malloc( sizeof( struct berval ));
+           ldm->mod_bvalues[ nvals ]->bv_val = value;
+           ldm->mod_bvalues[ nvals ]->bv_len = len;
+           nvals++;
+       }
+    }
+    ldmarr[ nops ] = NULL;
+
+    if ( nops > 0 ) {
+       /* Actually perform the LDAP operation */
+       Debug( LDAP_DEBUG_ARGS, "replica %s:%d - modify dn \"%s\"\n",
+               ri->ri_hostname, ri->ri_port, re->re_dn );
+       rc = ldap_modify_s( ri->ri_ldp, re->re_dn, ldmarr );
+    }
+    free_ldmarr( ldmarr );
+    return( rc );
+}
+
+
+
+
+/*
+ * Perform an ldap delete operation.
+ */
+static int
+op_ldap_delete(
+    Ri         *ri,
+    Re         *re,
+    char       **errmsg
+)
+{
+    int                rc;
+
+    Debug( LDAP_DEBUG_ARGS, "replica %s:%d - delete dn \"%s\"\n",
+           ri->ri_hostname, ri->ri_port, re->re_dn );
+    rc = ldap_delete_s( ri->ri_ldp, re->re_dn );
+
+    return( rc );
+}
+
+
+
+
+/*
+ * Perform an ldap modrdn operation.
+ */
+#define        GOT_NEWRDN              1
+#define        GOT_DRDNFLAGSTR         2
+#define        GOT_ALLNEWRDNFLAGS      ( GOT_NEWRDN | GOT_DRDNFLAGSTR )
+static int
+op_ldap_modrdn(
+    Ri         *ri,
+    Re         *re,
+    char       **errmsg
+)
+{
+    int                rc = 0;
+    Mi         *mi;
+    int                i;
+    int                state = 0;
+    int                drdnflag = -1;
+    char       *newrdn;
+
+    if ( re->re_mods == NULL ) {
+       *errmsg = "No arguments given";
+       Debug( LDAP_DEBUG_ANY, "Error: op_ldap_modrdn: no arguments\n",
+               0, 0, 0 );
+           return -1;
+    }
+
+    /*
+     * Get the arguments: should see newrdn: and deleteoldrdn: args.
+     */
+    for ( mi = re->re_mods, i = 0; mi[ i ].mi_type != NULL; i++ ) {
+       if ( !strcmp( mi[ i ].mi_type, T_NEWRDNSTR )) {
+           newrdn = mi[ i ].mi_val;
+           state |= GOT_NEWRDN;
+       } else if ( !strcmp( mi[ i ].mi_type, T_DRDNFLAGSTR )) {
+           state |= GOT_DRDNFLAGSTR;
+           if ( !strcmp( mi[ i ].mi_val, "0" )) {
+               drdnflag = 0;
+           } else if ( !strcmp( mi[ i ].mi_val, "1" )) {
+               drdnflag = 1;
+           } else {
+               Debug( LDAP_DEBUG_ANY,
+                       "Error: op_ldap_modrdn: bad deleteoldrdn arg \"%s\"\n",
+                       mi[ i ].mi_val, 0, 0 );
+               *errmsg = "Incorrect argument to deleteoldrdn";
+               return -1;
+           }
+       } else {
+           Debug( LDAP_DEBUG_ANY, "Error: op_ldap_modrdn: bad type \"%s\"\n",
+                   mi[ i ].mi_type, 0, 0 );
+           *errmsg = "Bad value in replication log entry";
+           return -1;
+       }
+    }
+
+    /*
+     * Punt if we don't have all the args.
+     */
+    if ( state != GOT_ALLNEWRDNFLAGS ) {
+       Debug( LDAP_DEBUG_ANY, "Error: op_ldap_modrdn: missing arguments\n",
+               0, 0, 0 );
+       *errmsg = "Missing argument: requires \"newrdn\" and \"deleteoldrdn\"";
+       return -1;
+    }
+
+#ifdef LDAP_DEBUG
+    if ( ldap_debug & LDAP_DEBUG_ARGS ) {
+       char buf[ 256 ];
+       char *buf2;
+       sprintf( buf, "%s:%d", ri->ri_hostname, ri->ri_port );
+       buf2 = (char *) ch_malloc( strlen( re->re_dn ) + strlen( mi->mi_val )
+               + 10 );
+       sprintf( buf2, "(\"%s\" -> \"%s\")", re->re_dn, mi->mi_val );
+       Debug( LDAP_DEBUG_ARGS,
+               "replica %s - modify rdn %s (flag: %d)\n",
+               buf, buf2, drdnflag );
+       free( buf2 );
+    }
+#endif /* LDAP_DEBUG */
+
+    /* Do the modrdn */
+    rc = ldap_modrdn2_s( ri->ri_ldp, re->re_dn, mi->mi_val, drdnflag );
+
+    return( ri->ri_ldp->ld_errno );
+}
+
+
+
+/*
+ * Allocate and initialize an ldapmod struct.
+ */
+static LDAPMod *
+alloc_ldapmod()
+{
+    LDAPMod    *ldm;
+
+    ldm = ( struct ldapmod * ) ch_malloc( sizeof ( struct ldapmod ));
+    ldm->mod_type = NULL;
+    ldm->mod_bvalues = ( struct berval ** ) NULL;
+    return( ldm );
+}
+
+
+
+/*
+ * Free an ldapmod struct associated mod_bvalues.  NOTE - it is assumed
+ * that mod_bvalues and mod_type contain pointers to the same block of memory
+ * pointed to by the repl struct.  Therefore, it's not freed here.
+ */
+static void
+free_ldapmod(
+LDAPMod *ldm )
+{
+    int                i;
+
+    if ( ldm == NULL ) {
+       return;
+    }
+    if ( ldm->mod_bvalues != NULL ) {
+       for ( i = 0; ldm->mod_bvalues[ i ] != NULL; i++ ) {
+           free( ldm->mod_bvalues[ i ] );
+       }
+       free( ldm->mod_bvalues );
+    }
+    free( ldm );
+    return;
+}
+
+
+/*
+ * Free an an array of LDAPMod pointers and the LDAPMod structs they point
+ * to.
+ */
+static void
+free_ldmarr(
+LDAPMod **ldmarr )
+{
+    int        i;
+
+    for ( i = 0; ldmarr[ i ] != NULL; i++ ) {
+       free_ldapmod( ldmarr[ i ] );
+    }
+    free( ldmarr );
+}
+
+
+/*
+ * Create a berval with a single value. 
+ */
+static struct berval **
+make_singlevalued_berval( 
+char   *value,
+int    len )
+{
+    struct berval **p;
+
+    p = ( struct berval ** ) ch_malloc( 2 * sizeof( struct berval * ));
+    p[ 0 ] = ( struct berval * ) ch_malloc( sizeof( struct berval ));
+    p[ 1 ] = NULL;
+    p[ 0 ]->bv_val = value;
+    p[ 0 ]->bv_len = len;
+    return( p );
+}
+
+
+/*
+ * Given a modification type (string), return an enumerated type.
+ * Avoids ugly copy in op_ldap_modify - lets us use a switch statement
+ * there.
+ */
+static int
+getmodtype( 
+char *type )
+{
+    if ( !strcmp( type, T_MODSEPSTR )) {
+       return( T_MODSEP );
+    }
+    if ( !strcmp( type, T_MODOPADDSTR )) {
+       return( T_MODOPADD );
+    }
+    if ( !strcmp( type, T_MODOPREPLACESTR )) {
+       return( T_MODOPREPLACE );
+    }
+    if ( !strcmp( type, T_MODOPDELETESTR )) {
+       return( T_MODOPDELETE );
+    }
+    return( T_ERR );
+}
+
+
+/*
+ * Perform an LDAP unbind operation.  If replica is NULL, or the
+ * repl_ldp is NULL, just return LDAP_SUCCESS.  Otherwise, unbind,
+ * set the ldp to NULL, and return the result of the unbind call.
+ */
+static int
+do_unbind(
+    Ri *ri
+)
+{
+    int                rc = LDAP_SUCCESS;
+
+    if (( ri != NULL ) && ( ri->ri_ldp != NULL )) {
+       rc = ldap_unbind( ri->ri_ldp );
+       if ( rc != LDAP_SUCCESS ) {
+           Debug( LDAP_DEBUG_ANY,
+                   "Error: do_unbind: ldap_unbind failed for %s:%d: %s\n",
+                   ldap_err2string( rc ), ri->ri_hostname, ri->ri_port );
+       }
+       ri->ri_ldp = NULL;
+    }
+    return rc;
+}
+
+
+
+/*
+ * Perform an LDAP bind operation to the replication site given
+ * by replica.  If replica->repl_ldp is non-NULL, then we unbind
+ * from the replica before rebinding.  It should be safe to call
+ * this to re-connect if the replica's connection goes away
+ * for some reason.
+ *
+ * Returns 0 on success, -1 if an LDAP error occurred, and a return
+ * code > 0 if some other error occurred, e.g. invalid bind method.
+ * If an LDAP error occurs, the LDAP error is returned in lderr.
+ */
+static int
+do_bind( 
+    Ri *ri,
+    int        *lderr
+)
+{
+    int                rc;
+    int                ldrc;
+    char       msgbuf[ 1024];
+#ifdef KERBEROS
+    int retval = 0;
+    int kni, got_tgt;
+    char **krbnames;
+    char *skrbnames[ 2 ];
+    char realm[ REALM_SZ ];
+    char name[ ANAME_SZ ];
+    char instance[ INST_SZ ];
+#endif /* KERBEROS */
+
+    *lderr = 0;
+
+    if ( ri == NULL ) {
+       Debug( LDAP_DEBUG_ANY, "Error: do_bind: null ri ptr\n", 0, 0, 0 );
+       return( BIND_ERR_BADRI );
+    }
+
+    if ( ri->ri_ldp != NULL ) {
+       ldrc = ldap_unbind( ri->ri_ldp );
+       if ( ldrc != LDAP_SUCCESS ) {
+           Debug( LDAP_DEBUG_ANY,
+                   "Error: do_bind: ldap_unbind failed: %s\n",
+                   ldap_err2string( ldrc ), 0, 0 );
+       }
+       ri->ri_ldp = NULL;
+    }
+
+    Debug( LDAP_DEBUG_ARGS, "Open connection to %s:%d\n",
+           ri->ri_hostname, ri->ri_port, 0 );
+    ri->ri_ldp = ldap_open( ri->ri_hostname, ri->ri_port );
+    if ( ri->ri_ldp == NULL ) {
+       Debug( LDAP_DEBUG_ANY, "Error: ldap_open(%s, %d) failed: %s\n",
+               ri->ri_hostname, ri->ri_port, sys_errlist[ errno ] );
+       return( BIND_ERR_OPEN );
+    }
+
+    /*
+     * Set ldap library options to (1) not follow referrals, and 
+     * (2) restart the select() system call.
+     */
+#ifdef LDAP_REFERRALS
+    ri->ri_ldp->ld_options &= ~LDAP_OPT_REFERRALS;
+#endif /* LDAP_REFERRALS */
+    ri->ri_ldp->ld_options |= LDAP_OPT_RESTART;
+
+    switch ( ri->ri_bind_method ) {
+    case AUTH_KERBEROS:
+#ifndef KERBEROS
+       Debug( LDAP_DEBUG_ANY,
+           "Error: Kerberos bind for %s:%d, but not compiled w/kerberos\n",
+           ri->ri_hostname, ri->ri_port, 0 );
+       return( BIND_ERR_KERBEROS_FAILED );
+#else /* KERBEROS */
+       /*
+        * Bind using kerberos.
+        * If "bindprincipal" was given in the config file, then attempt
+        * to get a TGT for that principal (via the srvtab file).  If only
+        * a binddn was given, then we need to read that entry to get
+        * the kerberosName attributes, and try to get a TGT for one
+        * of them.  All are tried.  The first one which succeeds is
+        * returned.  XXX It might be a good idea to just require a
+        * bindprincipal.  Reading the entry every time might be a significant
+        * amount of overhead, if the connection is closed between most
+        * updates.
+        */
+
+       if ( ri->ri_principal != NULL ) {
+           skrbnames[ 0 ] = ri->ri_principal;
+           skrbnames[ 1 ] = NULL;
+           krbnames = skrbnames;
+       } else {
+           krbnames = read_krbnames( ri );
+       }       
+           
+       if (( krbnames == NULL ) || ( krbnames[ 0 ] == NULL )) {
+           Debug( LDAP_DEBUG_ANY,
+                   "Error: Can't find krbname for binddn \"%s\"\n",
+                   ri->ri_bind_dn, 0, 0 );
+           retval = BIND_ERR_KERBEROS_FAILED;
+           goto kexit;
+       }
+       /*
+        * Now we've got one or more kerberos principals.  See if any
+        * of them are in the srvtab file.
+        */
+       got_tgt = 0;
+       for ( kni = 0; krbnames[ kni ] != NULL; kni++ ) {
+           rc = kname_parse( name, instance, realm, krbnames[ kni ]);
+           if ( rc != KSUCCESS ) {
+               continue;
+           }
+           upcase( realm );
+           rc = krb_get_svc_in_tkt( name, instance, realm, "krbtgt", realm,
+                   1, ri->ri_srvtab );
+           if ( rc != KSUCCESS) {
+               Debug( LDAP_DEBUG_ANY, "Error: Can't get TGT for %s: %s\n",
+                       krbnames[ kni ], krb_err_txt[ rc ], 0 );
+           } else {
+               got_tgt = 1;
+               break;
+           }
+       }
+       if (!got_tgt) {
+           Debug( LDAP_DEBUG_ANY,
+                   "Error: Could not obtain TGT for DN \"%s\"\n", 
+                   ri->ri_bind_dn, 0, 0 );
+           retval = BIND_ERR_KERBEROS_FAILED;
+           goto kexit;
+       }
+       /*
+        * We've got a TGT.  Do a kerberos bind.
+        */
+       Debug( LDAP_DEBUG_ARGS, "bind to %s:%d as %s (kerberos)\n",
+               ri->ri_hostname, ri->ri_port, ri->ri_bind_dn );
+       ldrc = ldap_kerberos_bind_s( ri->ri_ldp, ri->ri_bind_dn );
+       ri->ri_principal = strdup( krbnames[ kni ] );
+       if ( ldrc != LDAP_SUCCESS ) {
+           Debug( LDAP_DEBUG_ANY, "Error: kerberos bind for %s:%dfailed: %s\n",
+               ri->ri_hostname, ri->ri_port, ldap_err2string( ldrc ));
+           *lderr = ldrc;
+           retval = BIND_ERR_KERBEROS_FAILED;
+           goto kexit;
+       }
+kexit: if ( krbnames != NULL ) {
+           ldap_value_free( krbnames );
+       }
+       return( retval);
+       break;
+#endif /* KERBEROS */
+    case AUTH_SIMPLE:
+       /*
+        * Bind with a plaintext password.
+        */
+       Debug( LDAP_DEBUG_ARGS, "bind to %s:%d as %s (simple)\n",
+               ri->ri_hostname, ri->ri_port, ri->ri_bind_dn );
+       ldrc = ldap_simple_bind_s( ri->ri_ldp, ri->ri_bind_dn,
+               ri->ri_password );
+       if ( ldrc != LDAP_SUCCESS ) {
+           Debug( LDAP_DEBUG_ANY,
+                   "Error: ldap_simple_bind_s for %s:%d failed: %s\n",
+                   ri->ri_hostname, ri->ri_port, ldap_err2string( ldrc ));
+           *lderr = ldrc;
+           return( BIND_ERR_SIMPLE_FAILED );
+       } else {
+           return( BIND_OK );
+       }
+       break;
+    default:
+       Debug(  LDAP_DEBUG_ANY,
+               "Error: do_bind: unknown auth type \"%d\" for %s:%d\n",
+               ri->ri_bind_method, ri->ri_hostname, ri->ri_port );
+       return( BIND_ERR_BAD_ATYPE );
+    }
+}
+
+
+
+
+
+/*
+ * For debugging.  Print the contents of an ldmarr array.
+ */
+static void
+dump_ldm_array(
+LDAPMod **ldmarr )
+{
+    int                         i, j;
+    LDAPMod            *ldm;
+    struct berval      *b;
+    char               *msgbuf;
+
+    for ( i = 0; ldmarr[ i ] != NULL; i++ ) {
+       ldm = ldmarr[ i ];
+       Debug( LDAP_DEBUG_TRACE,
+               "Trace (%d): *** ldmarr[ %d ] contents:\n",
+               getpid(), i, 0 );
+       Debug( LDAP_DEBUG_TRACE,
+               "Trace (%d): *** ldm->mod_op: %d\n",
+               getpid(), ldm->mod_op, 0 );
+       Debug( LDAP_DEBUG_TRACE,
+               "Trace (%d): *** ldm->mod_type: %s\n",
+               getpid(), ldm->mod_type, 0 );
+       if ( ldm->mod_bvalues != NULL ) {
+           for ( j = 0; ( b = ldm->mod_bvalues[ j ] ) != NULL; j++ ) {
+               msgbuf = ch_malloc( b->bv_len + 512 );
+               sprintf( msgbuf, "***** bv[ %d ] len = %d, val = <%s>",
+                       j, b->bv_len, b->bv_val );
+               Debug( LDAP_DEBUG_TRACE,
+                       "Trace (%d):%s\n", getpid(), msgbuf, 0 );
+               free( msgbuf );
+           }
+       }
+    }
+}
+
+
+/*
+ * Get the kerberos names from the binddn for "replica" via an ldap search.
+ * Returns a null-terminated array of char *, or NULL if the entry could
+ * not be found or there were no kerberosName attributes.  The caller is
+ * responsible for freeing the returned array and strings it points to.
+ */
+static char **
+read_krbnames(
+    Ri *ri
+)
+{
+    int rc;
+    char **krbnames;
+    int ne;
+    LDAPMessage *result, *entry;
+
+    /* First need to bind as NULL */
+    rc = ldap_simple_bind_s( ri->ri_ldp, NULL, NULL );
+    if ( rc != LDAP_SUCCESS ) {
+       Debug( LDAP_DEBUG_ANY,
+               "Error: null bind failed getting krbnames for %s:%d: %s\n",
+               ri->ri_hostname, ri->ri_port, ldap_err2string( rc ));
+       return( NULL );
+    }
+    rc = ldap_search_st( ri->ri_ldp, ri->ri_bind_dn, LDAP_SCOPE_BASE,
+           "objectclass=*", kattrs, 0, &kst, &result );
+    if ( rc != LDAP_SUCCESS ) {
+       Debug( LDAP_DEBUG_ANY,
+               "Error: search failed getting krbnames for %s:%d: %s\n",
+               ri->ri_hostname, ri->ri_port, ldap_err2string( rc ));
+       return( NULL );
+    }
+    ne = ldap_count_entries( ri->ri_ldp, result );
+    if ( ne == 0 ) {
+       Debug( LDAP_DEBUG_ANY,
+               "Error: Can't find entry \"%s\" for %s:%d kerberos bind\n",
+               ri->ri_bind_dn, ri->ri_hostname, ri->ri_port );
+           return( NULL );
+    }
+    if ( ne > 1 ) {
+       Debug( LDAP_DEBUG_ANY,
+               "Error: Kerberos binddn \"%s\" for %s:%dis ambiguous\n",
+               ri->ri_bind_dn, ri->ri_hostname, ri->ri_port );
+           return( NULL );
+    }
+    entry = ldap_first_entry( ri->ri_ldp, result );
+    if ( entry == NULL ) {
+       Debug( LDAP_DEBUG_ANY,
+               "Error: Can't find \"%s\" for kerberos binddn for %s:%d\n",
+                   ri->ri_bind_dn, ri->ri_hostname, ri->ri_port );
+       return( NULL );
+    }
+    krbnames = ldap_get_values( ri->ri_ldp, entry, "kerberosName" );
+    ldap_msgfree( result );
+    return( krbnames );
+}
+
+
+
+/*
+ * upcase a string
+ */
+static void
+upcase(
+char *s )
+{
+    char *p;
+
+    for ( p = s; ( p != NULL ) && ( *p != '\0' ); p++ ) {
+       if ( islower( *p )) {
+           *p = toupper( *p );
+       }
+    }
+}
diff --git a/servers/slurpd/lock.c b/servers/slurpd/lock.c
new file mode 100644 (file)
index 0000000..62aab06
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 1996 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+/*
+ * lock.c - routines to open and apply an advisory lock to a file
+ */
+
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include "portable.h"
+#ifdef USE_LOCKF
+#include <unistd.h>
+#endif
+#include "../slapd/slap.h"
+
+
+
+FILE *
+lock_fopen(
+    char       *fname,
+    char       *type,
+    FILE       **lfp
+)
+{
+       FILE    *fp;
+       char    buf[MAXPATHLEN];
+
+       /* open the lock file */
+       strcpy( buf, fname );
+       strcat( buf, ".lock" );
+       if ( (*lfp = fopen( buf, "w" )) == NULL ) {
+               Debug( LDAP_DEBUG_ANY,
+                       "Error: could not open \"%s\"\n", buf, 0, 0 );
+               return( NULL );
+       }
+
+       /* acquire the lock */
+#ifdef USE_LOCKF
+       while ( lockf( fileno( *lfp ), F_LOCK, 0 ) != 0 ) {
+#else
+       while ( flock( fileno( *lfp ), LOCK_EX ) != 0 ) {
+#endif
+               ;       /* NULL */
+       }
+
+       /* open the log file */
+       if ( (fp = fopen( fname, type )) == NULL ) {
+               Debug( LDAP_DEBUG_ANY,
+                       "Error: could not open \"%s\"\n", fname, 0, 0 );
+#ifdef USE_LOCKF
+               lockf( fileno( *lfp ), F_ULOCK, 0 );
+#else
+               flock( fileno( *lfp ), LOCK_UN );
+#endif
+               return( NULL );
+       }
+
+       return( fp );
+}
+
+
+
+int
+lock_fclose(
+    FILE       *fp,
+    FILE       *lfp
+)
+{
+       /* unlock */
+#ifdef USE_LOCKF
+       lockf( fileno( lfp ), F_ULOCK, 0 );
+#else
+       flock( fileno( lfp ), LOCK_UN );
+#endif
+       fclose( lfp );
+
+       return( fclose( fp ) );
+}
+
+
+
+/*
+ * Apply an advisory lock on a file.  Just calls lock_fopen()
+ */
+int
+acquire_lock(
+    char       *file,
+    FILE       **rfp,
+    FILE       **lfp
+)
+{
+    if (( *rfp = lock_fopen( file, "r+", lfp )) == NULL ) {
+       Debug( LDAP_DEBUG_ANY,
+               "Error: acquire_lock(%d): Could not acquire lock on \"%s\"\n",
+               getpid(), file, 0);
+       return( -1 );
+    }
+    return( 0 );
+}
+
+
+
+/*
+ * Relinquish a lock on a file.  Calls lock_fclose() and also removes the
+ * lock file.
+ */
+int
+relinquish_lock(
+    char       *file,
+    FILE       *rfp,
+    FILE       *lfp
+)
+{
+    if ( lock_fclose( rfp, lfp ) == EOF ) {
+       Debug( LDAP_DEBUG_ANY,
+               "Error: relinquish_lock (%d): Error closing \"%s\"\n",
+               getpid(), file, 0 );
+       return( -1 );
+    }
+    return( 0 );
+}
diff --git a/servers/slurpd/main.c b/servers/slurpd/main.c
new file mode 100644 (file)
index 0000000..a3b935f
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 1996 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+
+/* 
+ * main.c - main routine for slurpd.
+ */
+
+#include <stdio.h>
+
+#include "slurp.h"
+#include "globals.h"
+
+
+extern int             doargs( int, char **, Globals * );
+extern void            fm();
+extern int             start_replica_thread( Ri * );
+extern Globals         *init_globals();
+extern int             sanity();
+#if defined( THREAD_SUNOS4_LWP )
+extern void            start_lwp_scheduler();
+#endif /* THREAD_SUNOS4_LWP */
+
+main(
+    int                argc,
+    char       **argv
+)
+{
+    pthread_attr_t     attr;
+    int                        status;
+    int                        i;
+
+#ifndef _THREAD
+    /* Haven't yet written the non-threaded version */
+    fprintf( stderr, "slurpd currently requires threads support\n" );
+    exit( 1 );
+#endif /* !_THREAD */
+
+    /* 
+     * Create and initialize globals.  init_globals() also initializes
+     * the main replication queue.
+     */
+    if (( sglob = init_globals()) == NULL ) {
+       fprintf( stderr, "Out of memory initializing globals\n" );
+       exit( 1 );
+    }
+
+    /*
+     * Process command-line args and fill in globals.
+     */
+    if ( doargs( argc, argv, sglob ) < 0 ) {
+       exit( 1 );
+    }
+
+    /*
+     * Read slapd config file and initialize Re (per-replica) structs.
+     */
+    if ( slurpd_read_config( sglob->slapd_configfile ) < 0 ) {
+       fprintf( stderr,
+               "Errors encountered while processing config file \"%s\"\n",
+               sglob->slapd_configfile );
+       exit( 1 );
+    }
+
+    /*
+     * Get any saved state information off the disk.
+     */
+    if ( sglob->st->st_read( sglob->st )) {
+       fprintf( stderr, "Malformed slurpd status file \"%s\"\n",
+               sglob->slurpd_status_file, 0, 0 );
+       exit( 1 );
+    }
+
+    /*
+     * All readonly data should now be initialized. 
+     * Check for any fatal error conditions before we get started
+     */
+     if ( sanity() < 0 ) {
+       exit( 1 );
+    }
+
+    /*
+     * Detach from the controlling terminal, if debug level = 0,
+     * and if not in one-shot mode.
+     */
+#ifdef LDAP_DEBUG
+    if (( ldap_debug == 0 )  && !sglob->one_shot_mode ) {
+#else /* LDAP_DEBUG */
+    if ( !sglob->one_shot_mode ) {
+#endif /* LDAP_DEBUG */
+       detach();
+    }
+
+#ifdef _THREAD
+
+#if defined( THREAD_SUNOS4_LWP )
+    /*
+     * Need to start a scheduler thread under SunOS 4
+     */
+    start_lwp_scheduler();
+#endif /* THREAD_SUNOS4_LWP */
+
+
+    /*
+     * Start threads - one thread for each replica
+     */
+    for ( i = 0; sglob->replicas[ i ] != NULL; i++ ) {
+       start_replica_thread( sglob->replicas[ i ]);
+    }
+
+    /*
+     * Start the main file manager thread (in fm.c).
+     */
+    pthread_attr_init( &attr );
+    if ( pthread_create( &(sglob->fm_tid), attr, (void *) fm, (void *) NULL )
+           != 0 ) {
+       Debug( LDAP_DEBUG_ANY, "file manager pthread_create failed\n",
+               0, 0, 0 );
+       exit( 1 );
+
+    }
+    pthread_attr_destroy( &attr );
+
+    /*
+     * Wait for the fm thread to finish.
+     */
+    pthread_join( sglob->fm_tid, (void *) &status );
+    /*
+     * Wait for the replica threads to finish.
+     */
+    for ( i = 0; sglob->replicas[ i ] != NULL; i++ ) {
+       pthread_join( sglob->replicas[ i ]->ri_tid, (void *) &status );
+    }
+    Debug( LDAP_DEBUG_ANY, "slurpd: terminating normally\n", 0, 0, 0 );
+    sglob->slurpd_shutdown = 1;
+    pthread_exit( 0 );
+
+#else /* !_THREAD */
+    /*
+     * Non-threaded case.
+     */
+    exit( 0 );
+
+#endif /* !_THREAD */
+    
+}
diff --git a/servers/slurpd/re.c b/servers/slurpd/re.c
new file mode 100644 (file)
index 0000000..4a6dc38
--- /dev/null
@@ -0,0 +1,734 @@
+/*
+ * Copyright (c) 1996 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+/* 
+ * re.c - routines which deal with Re (Replication entry) structures.
+ * An Re struct is an in-core representation of one replication to
+ * be performed, along with member functions which are called by other
+ * routines.  The Re struct is defined in slurp.h.
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "../slapd/slap.h"
+#include "slurp.h"
+#include "globals.h"
+
+/* externs */
+extern char *str_getline( char **next );
+extern void ch_free( char *p );
+
+extern char *sys_errlist[];
+
+/* Forward references */
+static Rh      *get_repl_hosts( char *, int *, char ** );
+static int     gettype( char * );
+static int     getchangetype( char *);
+static int     Re_parse( Re *re, char *replbuf );
+static void    Re_dump( Re *re, FILE *fp );
+static void    warn_unknown_replica( char *, int port );
+
+/* Globals, scoped within this file */
+static int     nur = 0;        /* Number of unknown replicas */
+static Rh      *ur = NULL;     /* array of unknown replica names */
+
+
+/*
+ * Return the next Re in a linked list.
+ */
+static Re *
+Re_getnext(
+    Re *re
+)
+{
+    return(( re == NULL ) ? NULL :  re->re_next );
+}
+
+
+
+
+/*
+ * Free an Re
+ */
+static int
+Re_free(
+    Re *re
+)
+{
+    Rh *rh;
+    Mi *mi;
+    int        i;
+
+    if ( re == NULL ) {
+       return 0;
+    }
+    if ( re->re_refcnt > 0 ) {
+       Debug( LDAP_DEBUG_ANY,
+               "Warning: freeing re (dn: %s) with nonzero refcnt\n",
+               re->re_dn, 0, 0 );
+    }
+#if !defined( THREAD_SUNOS4_LWP )
+    /* This seems to have problems under SunOS lwp */
+    pthread_mutex_destroy( &re->re_mutex );
+#endif /* THREAD_SUNOS4_LWP */
+    ch_free( re->re_timestamp );
+    if (( rh = re->re_replicas ) != NULL ) {
+       for ( i = 0; rh[ i ].rh_hostname != NULL; i++ ) {
+           free( rh[ i ].rh_hostname );
+       }
+       free( rh );
+    }
+    ch_free( re->re_dn );
+    if (( mi = re->re_mods ) != NULL ) {
+       for ( i = 0; mi[ i ].mi_type != NULL; i++ ) {
+           free( mi[ i ].mi_type );
+           ch_free( mi[ i ].mi_val );
+       }
+       free( mi );
+    }
+    free( re );
+}
+
+
+
+
+/*
+ * Read a buffer of data from a replication log file and fill in
+ * an (already allocated) Re.
+ */
+
+#define        BEGIN           0
+#define        GOT_DN          1
+#define        GOT_TIME        2
+#define        GOT_CHANGETYPE  4
+#define        GOT_ALL         ( GOT_DN | GOT_TIME | GOT_CHANGETYPE )
+
+static int
+Re_parse(
+    Re         *re,
+    char       *replbuf
+)
+{
+    int                        state;
+    int                        nml;
+    char               *buf, *rp, *p;
+    long               buflen;
+    char               *type, *value;
+    int                        len;
+    int                        nreplicas;
+
+    if ( re == NULL ) {
+       Debug( LDAP_DEBUG_ANY, "Re_parse: error: re is NULL\n", 0, 0, 0 );
+       return -1;
+    }
+    if ( replbuf == NULL ) {
+       Debug( LDAP_DEBUG_ANY, "Re_parse: error: replbuf is NULL\n", 0, 0, 0 );
+       return -1;
+    }
+
+    state = BEGIN;
+    nml = 0;   /* number of modification information entries */
+    rp = replbuf;
+
+    re->re_replicas = get_repl_hosts( replbuf, &nreplicas, &rp );
+    re->re_refcnt = sglob->num_replicas;
+
+    for (;;) {
+       if (( state == GOT_ALL ) || ( buf = str_getline( &rp )) == NULL ) {
+           break;
+       }
+       /*
+        * If we're processing a rejection log, then the first line
+        * of each replication record will begin with "ERROR" - just
+        * ignore it.
+        */
+       if ( strncmp( buf, ERROR_STR, strlen( ERROR_STR )) == 0 ) {
+           continue;
+       }
+       buflen = ( long ) strlen( buf );
+       if ( str_parse_line( buf, &type, &value, &len ) < 0 ) {
+           Debug( LDAP_DEBUG_ANY,
+                   "Error: Re_parse: malformed replog file\n",
+                   0, 0, 0 );
+           return -1;
+       }
+       switch ( gettype( type )) {
+       case T_CHANGETYPE:
+           re->re_changetype = getchangetype( value );
+           state |= GOT_CHANGETYPE;
+           break;
+       case T_TIME:
+           if (( p = strchr( value, '.' )) != NULL ) {
+               /* there was a sequence number */
+               *p++ = '\0';
+           }
+           re->re_timestamp = strdup( value );
+           if ( p != NULL && isdigit( *p )) {
+               re->re_seq = atoi( p );
+           }
+           state |= GOT_TIME;
+           break;
+       case T_DN:
+           re->re_dn = strdup( value );
+           state |= GOT_DN;
+           break;
+       default:
+           if ( !( state == GOT_ALL )) {
+               Debug( LDAP_DEBUG_ANY,
+                       "Error: Re_parse: bad type <%s>\n",
+                       type, 0, 0 );
+               return -1;
+           }
+       }
+    }
+
+    if ( state != GOT_ALL ) {
+       Debug( LDAP_DEBUG_ANY,
+               "Error: Re_parse: malformed replog file\n",
+               0, 0, 0 );
+       return -1;
+    }
+
+    for (;;) {
+       if (( buf = str_getline( &rp )) == NULL ) {
+           break;
+       }
+       buflen = ( long ) strlen( buf );
+       if (( buflen == 1 ) && ( buf[ 0 ] == '-' )) {
+           type = "-";
+           value = NULL;
+       } else {
+           if ( str_parse_line( buf, &type, &value, &len ) < 0 ) {
+               Debug( LDAP_DEBUG_ANY,
+                       "Error: malformed replog line \"%s\"\n",
+                       buf, 0, 0 );
+               return -1;
+           }
+       }
+       re->re_mods = ( Mi  *) ch_realloc( (char *) re->re_mods,
+           sizeof( Mi ) * ( nml + 2 ));
+       re->re_mods[ nml ].mi_type = strdup( type );
+       if ( value != NULL ) {
+           re->re_mods[ nml ].mi_val = strdup( value );
+           re->re_mods[ nml ].mi_len = len;
+       } else {
+           re->re_mods[ nml ].mi_val = NULL;
+           re->re_mods[ nml ].mi_len = 0;
+       }
+       re->re_mods[ nml + 1 ].mi_type = NULL;
+       re->re_mods[ nml + 1 ].mi_val = NULL;
+       nml++;
+    }
+    return 0;
+}
+
+
+
+/*
+ * Extract the replication hosts from a repl buf.  Check to be sure that
+ * each replica host and port number are ones we know about (that is, they're
+ * in the slapd config file we read at startup).  Without that information
+ * from the config file, we won't have the appropriate credentials to
+ * make modifications.  If there are any unknown replica names, don't
+ * add them the the Re struct.  Instead, log a warning message.
+ */
+static Rh *
+get_repl_hosts(
+    char       *replbuf,
+    int                *r_nreplicas,
+    char       **r_rp
+)
+{
+    char               buf[ LINE_WIDTH + 1 ];
+    char               *type, *value, *line, *p;
+    Rh                 *rh = NULL;
+    int                        nreplicas, len;
+    int                        port;
+    int                        repl_ok;
+    int                        i;
+
+    if ( replbuf == NULL ) {
+       return( NULL );
+    }
+
+    nreplicas = 0;
+
+    /*
+     * Get the host names of the replicas
+     */
+    *r_nreplicas = 0;
+    *r_rp = replbuf;
+    for (;;) {
+       /* If this is a reject log, we need to skip over the ERROR: line */
+       if ( !strncmp( *r_rp, ERROR_STR, strlen( ERROR_STR ))) {
+           line = str_getline( r_rp );
+           if ( line == NULL ) {
+               break;
+           }
+       }
+       if ( strncasecmp( *r_rp, "replica:", 7 )) {
+           break;
+       }
+       line = str_getline( r_rp );
+       if ( line == NULL ) {
+           break;
+       }
+       if ( str_parse_line( line, &type, &value, &len ) < 0 ) {
+           return( NULL );
+       }
+       port = LDAP_PORT;
+       if (( p = strchr( value, ':' )) != NULL ) {
+           *p = '\0';
+           p++;
+           if ( *p != '\0' ) {
+               port = atoi( p );
+           }
+       }
+
+       /* Verify that we've heard of this replica before */
+       repl_ok = 0;
+       for ( i = 0; i < sglob->num_replicas; i++ ) {
+           if ( strcmp( sglob->replicas[ i ]->ri_hostname, value )) {
+               continue;
+           }
+           if ( sglob->replicas[ i ]->ri_port == port ) {
+               repl_ok = 1;
+               break;
+           }
+       }
+       if ( !repl_ok ) {
+           warn_unknown_replica( value, port );
+           continue;
+       }
+
+       rh = (Rh *) ch_realloc((char *) rh, ( nreplicas + 2 ) * sizeof( Rh ));
+       if ( rh == NULL ) {
+           Debug( LDAP_DEBUG_ANY, "Out of memory in get_repl_hosts\n",
+                   0, 0, 0 );
+           return NULL;
+       }
+       rh[ nreplicas ].rh_hostname = strdup( value );
+       rh[ nreplicas ].rh_port = port;
+       nreplicas++;
+    }
+
+    if ( nreplicas == 0 ) {
+       return( NULL );
+    }
+
+    rh[ nreplicas ].rh_hostname = NULL;
+    *r_nreplicas = nreplicas;
+
+    return( rh );
+}
+
+
+
+
+
+/*
+ * Convert "type" to an int.
+ */
+static int
+gettype(
+    char       *type
+)
+{
+    if ( !strcmp( type, T_CHANGETYPESTR )) {
+       return( T_CHANGETYPE );
+    }
+    if ( !strcmp( type, T_TIMESTR )) {
+       return( T_TIME );
+    }
+    if ( !strcmp( type, T_DNSTR )) {
+       return( T_DN );
+    }
+    return( T_ERR );
+}
+
+
+
+/*
+ * Convert "changetype" to an int.
+ */
+static int
+getchangetype(
+    char       *changetype
+)
+{
+    if ( !strcmp( changetype, T_ADDCTSTR )) {
+       return( T_ADDCT );
+    }
+    if ( !strcmp( changetype, T_MODIFYCTSTR )) {
+       return( T_MODIFYCT );
+    }
+    if ( !strcmp( changetype, T_DELETECTSTR )) {
+       return( T_DELETECT );
+    }
+    if ( !strcmp( changetype, T_MODRDNCTSTR )) {
+       return( T_MODRDNCT );
+    }
+    return( T_ERR );
+}
+
+
+
+
+/*
+ * Find the first line which is not a "replica:" line in buf.
+ * Returns a pointer to the line.  Returns NULL if there are
+ * only "replica:" lines in buf.
+ */
+static char *
+skip_replica_lines(
+    char       *buf
+)
+{
+    char *p = buf;
+    for (;;) {
+       if ( strncasecmp( p, "replica:", 8 )) {
+           return( p );
+       }
+       while (( *p != '\0' )  && ( *p != '\n' )) {
+           p++;
+       }
+       if ( *p == '\0' ) {
+           return ( NULL );
+       } else {
+           p++;
+       }
+    }
+}
+
+
+
+
+/*
+ * For debugging purposes: dump the contents of a replication entry.
+ * to the given stream.
+ */
+static void
+Re_dump(
+    Re         *re,
+    FILE       *fp
+)
+{
+    int i;
+    Mi *mi;
+
+    if ( re == NULL ) {
+       Debug( LDAP_DEBUG_TRACE, "Re_dump: re is NULL\n", 0, 0, 0 );
+       return;
+    }
+    fprintf( fp, "Re_dump: ******\n" );
+    fprintf( fp, "re_refcnt: %d\n", re->re_refcnt );
+    fprintf( fp, "re_timestamp: %s\n", re->re_timestamp );
+    fprintf( fp, "re_seq: %d\n", re->re_seq );
+    for ( i = 0; re->re_replicas && re->re_replicas[ i ].rh_hostname != NULL;
+               i++ ) {
+       fprintf( fp, "re_replicas[%d]: %s:%d\n", 
+               i, re->re_replicas[ i ].rh_hostname,
+               re->re_replicas[ i ].rh_port );
+    }
+    fprintf( fp, "re_dn: %s\n", re->re_dn );
+    switch ( re->re_changetype ) {
+    case T_ADDCT:
+       fprintf( fp, "re_changetype: add\n" );
+       break;
+    case T_MODIFYCT:
+       fprintf( fp, "re_changetype: modify\n" );
+       break;
+    case T_DELETECT:
+       fprintf( fp, "re_changetype: delete\n" );
+       break;
+    case T_MODRDNCT:
+       fprintf( fp, "re_changetype: modrdn\n" );
+       break;
+    default:
+       fprintf( fp, "re_changetype: (unknown, type = %d\n",
+               re->re_changetype );
+    }
+    if ( re->re_mods == NULL ) {
+       fprintf( fp, "re_mods: (none)\n" );
+    } else {
+       mi = re->re_mods;
+       fprintf( fp, "re_mods:\n" );
+       for ( i = 0; mi[ i ].mi_type != NULL; i++ ) {
+           fprintf( fp, "  %s, \"%s\", (%d bytes)\n",
+                   mi[ i ].mi_type,
+                   mi[ i ].mi_val == NULL ?  "(null)" : mi[ i ].mi_val,
+                   mi[ i ].mi_len );
+       }
+    }
+    return;
+}
+
+
+/* 
+ * Given an Ri, an Re, and a file pointer, write a replication record to
+ * the file pointer.  If ri is NULL, then include all replicas in the
+ * output.  If ri is non-NULL, then only include a single "replica:" line
+ * (used when writing rejection records).  Returns 0 on success, -1
+ * on failure.  Note that Re_write will not write anything out if the
+ * refcnt is zero.
+ */
+static int
+Re_write(
+    Ri         *ri,
+    Re         *re,
+    FILE       *fp )
+{
+    int                i;
+    char       *s;
+    int                rc = 0;
+    Rh         *rh;
+
+    if ( re == NULL || fp == NULL ) {
+       Debug( LDAP_DEBUG_ANY, "Internal error: Re_write: NULL argument\n",
+               0, 0, 0 );
+       return -1;
+    }
+
+    if ( re->re_refcnt < 1 ) {
+       return 0;               /* this is not an error */
+    }
+
+    if ( ri != NULL ) {                /* write a single "replica:" line */
+       if ( fprintf( fp, "replica: %s:%d\n", ri->ri_hostname,
+               ri->ri_port ) < 0 ) {
+           rc = -1;
+           goto bad;
+       }
+    } else {                   /* write multiple "replica:" lines */
+       for ( i = 0; re->re_replicas[ i ].rh_hostname != NULL; i++ ) {
+           if ( fprintf( fp, "replica: %s:%d\n",
+                   re->re_replicas[ i ].rh_hostname,
+                   re->re_replicas[ i ].rh_port ) < 0 ) {
+               rc = -1;
+               goto bad;
+           }
+       }
+    }
+    if ( fprintf( fp, "time: %s.%d\n", re->re_timestamp, re->re_seq ) < 0 ) {
+       rc = -1;
+       goto bad;
+    }
+    if ( fprintf( fp, "dn: %s\n", re->re_dn ) < 0 ) {
+       rc = -1;
+       goto bad;
+    }
+    if ( fprintf( fp, "changetype: " ) < 0 ) {
+       rc = -1;
+       goto bad;
+    }
+    switch ( re->re_changetype ) {
+    case T_ADDCT:
+       s = T_ADDCTSTR;
+       break;
+    case T_MODIFYCT:
+       s = T_MODIFYCTSTR;
+       break;
+    case T_DELETECT:
+       s = T_DELETECTSTR;
+       break;
+    case T_MODRDNCT:
+       s = T_MODRDNCTSTR;
+       break;
+    default:
+       s = "IllegalModifyType!!!";
+    }
+    if ( fprintf( fp, "%s\n", s ) < 0 ) {
+       rc = -1;
+       goto bad;
+    }
+    for ( i = 0; (( re->re_mods != NULL ) &&
+           ( re->re_mods[ i ].mi_type != NULL )); i++ ) {
+       if ( !strcmp( re->re_mods[ i ].mi_type, T_MODSEPSTR )) {
+           if ( fprintf( fp, "%s\n", T_MODSEPSTR ) < 0 ) {
+               rc = -1;
+               goto bad;
+           }
+       } else {
+           char *obuf;
+           obuf = ldif_type_and_value( re->re_mods[ i ].mi_type,
+                   re->re_mods[ i ].mi_val ? re->re_mods[ i ].mi_val : "",
+                   re->re_mods[ i ].mi_len );
+           if ( fputs( obuf, fp ) < 0 ) {
+               rc = -1;
+               free( obuf );
+               goto bad;
+           } else {
+               free( obuf );
+           }
+       }
+    }
+    if ( fprintf( fp, "\n" ) < 0 ) {
+       rc = -1;
+       goto bad;
+    }
+    if ( fflush( fp ) != 0 ) {
+       rc = -1;
+       goto bad;
+    }
+bad:
+    if ( rc != 0 ) {
+       Debug( LDAP_DEBUG_ANY, "Error while writing: %s\n",
+               sys_errlist[ errno ], 0, 0 );
+    }
+    return rc;
+}
+
+
+
+
+/*
+ * Decrement the refcnt.  Locking handled internally.
+ */
+static int
+Re_decrefcnt(
+    Re *re
+)
+{
+    re->re_lock( re );
+    re->re_refcnt--;
+    re->re_unlock( re );
+    return 0;
+}
+
+
+
+/*
+ * Get the refcnt.  Locking handled internally.
+ */
+static int
+Re_getrefcnt(
+    Re *re
+)
+{
+    int        ret;
+
+    re->re_lock( re );
+    ret = re->re_refcnt;
+    re->re_unlock( re );
+    return ret;
+}
+    
+    
+
+
+
+/*
+ * Lock this replication entry
+ */
+static int
+Re_lock(
+    Re *re
+)
+{
+    return( pthread_mutex_lock( &re->re_mutex ));
+}
+
+
+
+
+/*
+ * Unlock this replication entry
+ */
+static int
+Re_unlock(
+    Re *re
+)
+{
+    return( pthread_mutex_unlock( &re->re_mutex ));
+}
+
+
+
+
+/* 
+ * Instantiate and initialize an Re.
+ */
+int
+Re_init(
+    Re **re
+)
+{
+    /* Instantiate */
+    (*re) = (Re *) malloc( sizeof( Re ));
+    if ( *re == NULL ) {
+       return -1;
+    }
+
+    /* Fill in the member function pointers */
+    (*re)->re_free = Re_free;
+    (*re)->re_getnext = Re_getnext;
+    (*re)->re_parse = Re_parse;
+    (*re)->re_write = Re_write;
+    (*re)->re_dump = Re_dump;
+    (*re)->re_lock = Re_lock;
+    (*re)->re_unlock = Re_unlock;
+    (*re)->re_decrefcnt = Re_decrefcnt;
+    (*re)->re_getrefcnt = Re_getrefcnt;
+
+    /* Initialize private data */
+   (*re)->re_refcnt = sglob->num_replicas;
+   (*re)->re_timestamp = NULL;
+   (*re)->re_replicas = NULL;
+   (*re)->re_dn = NULL;
+   (*re)->re_changetype = 0;
+   (*re)->re_seq = 0;
+   (*re)->re_mods = NULL;
+   (*re)->re_next = NULL;
+
+   pthread_mutex_init( &((*re)->re_mutex), pthread_mutexattr_default );
+   return 0;
+}
+
+
+
+
+/*
+ * Given a host and port, generate a warning message iff we haven't already
+ * generated a message for this host:port combination.
+ */
+static void
+warn_unknown_replica( 
+    char       *host,
+    int                port
+)
+{
+    int        found = 0;
+    int        i;
+
+    for ( i = 0; i < nur; i++ ) {
+       if ( strcmp( ur[ i ].rh_hostname, host )) {
+           continue;
+       }
+       if ( ur[ i ].rh_port == port ) {
+           found = 1;
+           break;
+       }
+    }
+    if ( !found ) {
+       Debug( LDAP_DEBUG_ANY,
+               "Warning: unknown replica %s:%d found in replication log\n",
+               host, port, 0 );
+       nur++;
+       ur = (Rh *) ch_realloc( (char *) ur, ( nur * sizeof( Rh )));
+       ur[ nur - 1 ].rh_hostname = strdup( host );
+       ur[ nur - 1 ].rh_port = port;
+    }
+}
diff --git a/servers/slurpd/reject.c b/servers/slurpd/reject.c
new file mode 100644 (file)
index 0000000..8ae0dc6
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 1996 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+
+/*
+ * reject.c - routines to write replication records to reject files.
+ * An Re struct is writted to a reject file if it cannot be propagated
+ * to a replica LDAP server.
+ */
+
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "slurp.h"
+#include "globals.h"
+
+#ifndef SYSERRLIST_IN_STDIO
+extern char *sys_errlist[];
+#endif /* SYSERRLIST_IN_STDIO */
+
+
+/*
+ * Write a replication record to a reject file.  The reject file has the
+ * same name as the replica's private copy of the file but with ".rej"
+ * appended (e.g. "/usr/tmp/<hostname>:<port>.rej")
+ *
+ * If errmsg is non-NULL, use that as the error message in the reject
+ * file.  Otherwise, use ldap_err2string( lderr ).
+ */
+void
+write_reject(
+    Ri         *ri,
+    Re         *re,
+    int                lderr,
+    char       *errmsg
+)
+{
+    char       rejfile[ MAXPATHLEN ];
+    FILE       *rfp, *lfp;
+    int                rc;
+
+    pthread_mutex_lock( &sglob->rej_mutex );
+    sprintf( rejfile, "%s/%s:%d.rej", sglob->slurpd_rdir,
+           ri->ri_hostname, ri->ri_port );
+
+    if ( access( rejfile, F_OK ) < 0 ) {
+       /* Doesn't exist - try to create */
+       int rjfd;
+       if (( rjfd = open( rejfile, O_RDWR | O_APPEND | O_CREAT,
+               S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP )) < 0 ) {
+           Debug( LDAP_DEBUG_ANY,
+               "Error: write_reject: Cannot create \"%s\": %s\n",
+               rejfile, sys_errlist[ errno ], 0 );
+           pthread_mutex_unlock( &sglob->rej_mutex );
+           return;
+       } else {
+           close( rjfd );
+       }
+    }
+    if (( rc = acquire_lock( rejfile, &rfp, &lfp )) < 0 ) {
+       Debug( LDAP_DEBUG_ANY, "Error: cannot open reject file \"%s\"\n",
+               rejfile, 0, 0 );
+    } else {
+       fseek( rfp, 0, 2 );
+       if ( errmsg != NULL ) {
+           fprintf( rfp, "%s: %s\n", ERROR_STR, errmsg );
+       } else {
+           fprintf( rfp, "%s: %s\n", ERROR_STR, ldap_err2string( lderr ));
+       }
+       if ((rc = re->re_write( ri, re, rfp )) < 0 ) {
+           Debug( LDAP_DEBUG_ANY,
+                   "Error: cannot write reject file \"%s\"\n",
+                   rejfile, 0, 0 );
+       }
+       (void) relinquish_lock( rejfile, rfp, lfp );
+       Debug( LDAP_DEBUG_ANY,
+               "Error: ldap operation failed, data written to \"%s\"\n",
+               rejfile, 0, 0 );
+    }
+    pthread_mutex_unlock( &sglob->rej_mutex );
+    return;
+}
+
diff --git a/servers/slurpd/replica.c b/servers/slurpd/replica.c
new file mode 100644 (file)
index 0000000..ed25a62
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 1996 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+
+/*
+ * replica.c - code to start up replica threads.
+ */
+
+
+#include <stdio.h>
+
+#include "slurp.h"
+#include "globals.h"
+
+
+/*
+ * Just invoke the Ri's process() member function, and log the start and
+ * finish.
+ */
+void
+replicate(
+    Ri *ri
+)
+{
+    int i;
+    unsigned long seq;
+
+    Debug( LDAP_DEBUG_ARGS, "begin replication thread for %s:%d\n",
+           ri->ri_hostname, ri->ri_port, 0 );
+
+    ri->ri_process( ri );
+
+    Debug( LDAP_DEBUG_ARGS, "end replication thread for %s:%d\n",
+           ri->ri_hostname, ri->ri_port, 0 );
+    return;
+}
+
+
+
+/*
+ * Start a detached thread for the given replica.
+ */
+int
+start_replica_thread(
+    Ri *ri
+)
+{
+    pthread_attr_t     attr;
+
+    pthread_attr_init( &attr );
+    pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED );
+
+    if ( pthread_create( &(ri->ri_tid), attr, (void *) replicate,
+           (void *) ri ) != 0 ) {
+       Debug( LDAP_DEBUG_ANY, "replica \"%s:%d\" pthread_create failed\n",
+               ri->ri_hostname, ri->ri_port, 0 );
+       pthread_attr_destroy( &attr );
+       return -1;
+    }
+    pthread_attr_destroy( &attr );
+    return 0;
+}
diff --git a/servers/slurpd/replog.c b/servers/slurpd/replog.c
new file mode 100644 (file)
index 0000000..c3a855c
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 1996 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+
+/*
+ * replog.c - routines which read and write replication log files.
+ */
+
+
+#include <errno.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "portable.h"
+#include "slurp.h"
+#include "globals.h"
+
+/*
+ * Externs
+ */
+#ifdef NEEDPROTOS
+extern FILE *lock_fopen( char *, char *, FILE ** );
+extern char *ch_malloc( unsigned long );
+#else /* NEEDPROTOS */
+extern FILE *lock_fopen();
+extern char *ch_malloc();
+#endif /* NEEDPROTOS */
+
+/*
+ * Forward declarations
+ */
+#ifdef NEEDPROTOS
+int file_nonempty( char * );
+#else /* NEEDPROTOS */
+int file_nonempty();
+#endif /* NEEDPROTOS */
+
+
+#ifndef SYSERRLIST_IN_STDIO
+extern char *sys_errlist[];
+#endif
+
+/*
+ * Forward declarations
+ */
+static int duplicate_replog( char *, char * );
+
+
+
+
+/*
+ * Copy the replication log.  Returns 0 on success, 1 if a temporary
+ * error occurs, and -1 if a fatal error occurs.
+ */
+int
+copy_replog(
+    char       *src,
+    char       *dst
+)
+{
+    int                rc = 0;
+    FILE       *rfp;   /* replog fp */
+    FILE       *lfp;   /* replog lockfile fp */
+    FILE       *dfp;   /* duplicate replog fp */
+    FILE       *dlfp;  /* duplicate replog lockfile fp */
+    static char        buf[ MAXPATHLEN ];
+    static char        rbuf[ 1024 ];
+    char       *p;
+
+    Debug( LDAP_DEBUG_ARGS,
+           "copy replog \"%s\" to \"%s\"\n", 
+           src, dst, 0 );
+
+    /*
+     * Make sure the destination directory is writable.  If not, exit
+     * with a fatal error.
+     */
+    strcpy( buf, src );
+    if (( p = strrchr( buf, '/' )) == NULL ) {
+       strcpy( buf, "." );
+    } else {
+       *p = '\0';
+    }
+    if ( access( buf, W_OK ) < 0 ) {
+       Debug( LDAP_DEBUG_ANY,
+               "Error: copy_replog (%d): Directory %s is not writable\n",
+               getpid(), buf, 0 );
+       return( -1 );
+    }
+    strcpy( buf, dst );
+    if (( p = strrchr( buf, '/' )) == NULL ) {
+       strcpy( buf, "." );
+    } else {
+       *p = '\0';
+    }
+    if ( access( buf, W_OK ) < 0 ) {
+       Debug( LDAP_DEBUG_ANY,
+               "Error: copy_replog (%d): Directory %s is not writable\n",
+               getpid(), buf, 0 );
+       return( -1 );
+    }
+
+    /* lock src */
+    rfp = lock_fopen( src, "r", &lfp );
+    if ( rfp == NULL ) {
+       Debug( LDAP_DEBUG_ANY,
+               "Error: copy_replog: Can't lock replog \"%s\" for read: %s\n",
+               src, sys_errlist[ errno ], 0 );
+       return( 1 );
+    }
+
+    /* lock dst */
+    dfp = lock_fopen( dst, "a", &dlfp );
+    if ( dfp == NULL ) {
+       Debug( LDAP_DEBUG_ANY,
+               "Error: copy_replog: Can't lock replog \"%s\" for write: %s\n",
+               src, sys_errlist[ errno ], 0 );
+       lock_fclose( rfp );
+       return( 1 );
+    }
+
+    /*
+     * Make our own private copy of the replication log.
+     */
+    while (( p = fgets( rbuf, sizeof( buf ), rfp )) != NULL ) {
+       fputs( rbuf, dfp );
+    }
+    /* Only truncate the source file if we're not in one-shot mode */
+    if ( !sglob->one_shot_mode ) {
+       /* truncate replication log */
+       truncate( src, (off_t) 0 );
+    }
+
+    if ( lock_fclose( rfp, lfp ) == EOF ) {
+       Debug( LDAP_DEBUG_ANY,
+               "Error: copy_replog: Error closing \"%s\"\n",
+               src, 0, 0 );
+    }
+    if ( lock_fclose( dfp, dlfp ) == EOF ) {
+       Debug( LDAP_DEBUG_ANY,
+               "Error: copy_replog: Error closing \"%s\"\n",
+               src, 0, 0 );
+    }
+    return( rc );
+}
+
+
+
+
+/*
+ * Return 1 if the given file exists and has a nonzero size,
+ * 0 if it is empty or nonexistent.
+ */
+int
+file_nonempty(
+    char       *filename
+)
+{
+    static struct stat         stbuf;
+
+    if ( stat( filename, &stbuf ) < 0 ) {
+       return( 0 );
+    } else {
+       return( stbuf.st_size > (off_t ) 0 );
+    }
+}
diff --git a/servers/slurpd/ri.c b/servers/slurpd/ri.c
new file mode 100644 (file)
index 0000000..cc478d1
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 1996 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+/*
+ * ri.c - routines used to manipulate Ri structures.  An Ri (Replica
+ * information) struct contains all information about one replica
+ * instance.  The Ri struct is defined in slurp.h
+ */
+
+
+
+#include <stdio.h>
+#include <signal.h>
+
+#include "slurp.h"
+#include "globals.h"
+
+
+/* External references */
+#ifdef NEEDPROTOS
+extern void write_reject( Ri *, Re *, int, char * );
+extern void do_nothing();
+#else /* NEEDPROTOS */
+extern void write_reject();
+extern void do_nothing();
+#endif /* NEEDPROTOS */
+
+/* Forward references */
+#ifdef NEEDPROTOS
+static int ismine( Ri  *, Re  * );
+static int isnew( Ri  *, Re  * );
+void tsleep( time_t );
+#else /* NEEDPROTOS */
+static int ismine();
+static int isnew();
+void tsleep();
+#endif /* NEEDPROTOS */
+
+
+/*
+ * Process any unhandled replication entries in the queue.
+ */
+static int
+Ri_process(
+    Ri *ri
+)
+{
+    Rq         *rq = sglob->rq;
+    Re         *re, *new_re;
+    int                i;
+    int                rc ;
+    char       *errmsg;
+
+    (void) SIGNAL( SIGUSR1, (void *) do_nothing );
+    (void) SIGNAL( SIGPIPE, SIG_IGN );
+    if ( ri == NULL ) {
+       Debug( LDAP_DEBUG_ANY, "Error: Ri_process: ri == NULL!\n", 0, 0, 0 );
+       return -1;
+    }
+
+    /*
+     * Startup code.  See if there's any work to do.  If not, wait on the
+     * rq->rq_more condition variable.
+     */
+    rq->rq_lock( rq );
+    while ( !sglob->slurpd_shutdown &&
+           (( re = rq->rq_gethead( rq )) == NULL )) {
+       /* No work - wait on condition variable */
+       pthread_cond_wait( &rq->rq_more, &rq->rq_mutex );
+    }
+
+    /*
+     * When we get here, there's work in the queue, and we have the
+     * queue locked.  re should be pointing to the head of the queue.
+     */
+    rq->rq_unlock( rq );
+    while ( !sglob->slurpd_shutdown ) {
+       if ( re != NULL ) {
+           if ( !ismine( ri, re )) {
+               /* The Re doesn't list my host:port */
+               Debug( LDAP_DEBUG_TRACE,
+                       "Replica %s:%d, skip repl record for %s (not mine)\n",
+                       ri->ri_hostname, ri->ri_port, re->re_dn );
+           } else if ( !isnew( ri, re )) {
+               /* This Re is older than my saved status information */
+               Debug( LDAP_DEBUG_TRACE,
+                       "Replica %s:%d, skip repl record for %s (old)\n",
+                       ri->ri_hostname, ri->ri_port, re->re_dn );
+           } else {
+               rc = do_ldap( ri, re, &errmsg );
+               switch ( rc ) {
+               case DO_LDAP_ERR_RETRYABLE:
+                   tsleep( RETRY_SLEEP_TIME );
+                   Debug( LDAP_DEBUG_ANY,
+                           "Retrying operation for DN %s on replica %s:%d\n",
+                           re->re_dn, ri->ri_hostname, ri->ri_port );
+                   continue;
+                   break;
+               case DO_LDAP_ERR_FATAL:
+                   /* Non-retryable error.  Write rejection log. */
+                   write_reject( ri, re, ri->ri_ldp->ld_errno, errmsg );
+                   /* Update status ... */
+                   (void) sglob->st->st_update( sglob->st, ri->ri_stel, re );
+                   /* ... and write to disk */
+                   (void) sglob->st->st_write( sglob->st );
+                   break;
+               default:
+                   /* LDAP op completed ok - update status... */
+                   (void) sglob->st->st_update( sglob->st, ri->ri_stel, re );
+                   /* ... and write to disk */
+                   (void) sglob->st->st_write( sglob->st );
+                   break;
+               }
+           }
+       } else {
+           Debug( LDAP_DEBUG_ANY, "Error: re is null in Ri_process\n",
+                   0, 0, 0 );
+       }
+       rq->rq_lock( rq );
+       while ( !sglob->slurpd_shutdown &&
+               ((new_re = re->re_getnext( re )) == NULL )) {
+           if ( sglob->one_shot_mode ) {
+               return 0;
+           }
+           /* No work - wait on condition variable */
+           pthread_cond_wait( &rq->rq_more, &rq->rq_mutex );
+       }
+       re->re_decrefcnt( re );
+       re = new_re;
+       rq->rq_unlock( rq );
+       if ( sglob->slurpd_shutdown ) {
+           return 0;
+       }
+    }
+    return 0;
+}
+
+
+/*
+ * Wake a replication thread which may be sleeping.  Send it a SIGUSR1.
+ */
+static void
+Ri_wake(
+    Ri *ri
+) 
+{
+    if ( ri == NULL ) {
+       return;
+    }
+    pthread_kill( ri->ri_tid, SIGUSR1 );
+    (void) SIGNAL( SIGUSR1, (void *) do_nothing );
+}
+
+
+
+/* 
+ * Allocate and initialize an Ri struct.
+ */
+int
+Ri_init(
+    Ri **ri
+)
+{
+    (*ri) = ( Ri * ) malloc( sizeof( Ri ));
+    if ( *ri == NULL ) {
+       return -1;
+    }
+
+    /* Initialize member functions */
+    (*ri)->ri_process = Ri_process;
+    (*ri)->ri_wake = Ri_wake;
+
+    /* Initialize private data */
+    (*ri)->ri_hostname = NULL;
+    (*ri)->ri_port = 0;
+    (*ri)->ri_ldp = NULL;
+    (*ri)->ri_bind_method = 0;
+    (*ri)->ri_bind_dn = NULL;
+    (*ri)->ri_password = NULL;
+    (*ri)->ri_principal = NULL;
+    (*ri)->ri_srvtab = NULL;
+    (*ri)->ri_curr = NULL;
+
+    return 0;
+}
+
+
+
+
+/*
+ * Return 1 if the hostname and port in re match the hostname and port
+ * in ri, otherwise return zero.
+ */
+static int
+ismine(
+    Ri *ri,
+    Re *re
+)
+{
+    Rh *rh;
+    int        i;
+
+    if ( ri == NULL || re == NULL || ri->ri_hostname == NULL ||
+           re->re_replicas == NULL ) {
+       return 0;
+    }
+    rh = re->re_replicas;
+    for ( i = 0; rh[ i ].rh_hostname != NULL; i++ ) {
+       if ( !strcmp( rh[ i ].rh_hostname, ri->ri_hostname) &&
+               rh[ i ].rh_port == ri->ri_port ) {
+           return 1;
+       }
+    }
+    return 0;
+}
+
+
+
+
+/*
+ * Return 1 if the Re's timestamp/seq combination are greater than the
+ * timestamp and seq in the Ri's ri_stel member.  In other words, if we
+ * find replication entries in the log which we've already processed,
+ * don't process them.  If the re is "old," return 0.
+ * No check for NULL pointers is done.
+ */
+static int
+isnew(
+    Ri *ri,
+    Re *re
+)
+{
+    int        x;
+    int        ret;
+
+    /* Lock the St struct to avoid a race */
+    sglob->st->st_lock( sglob->st );
+    x = strcmp( re->re_timestamp, ri->ri_stel->last );
+    if ( x > 0 ) {
+       /* re timestamp is newer */
+       ret = 1;
+    } else if ( x < 0 ) {
+       ret = 0;
+    } else {
+       /* timestamps were equal */
+       if ( re->re_seq > ri->ri_stel->seq ) {
+           /* re seq is newer */
+           ret = 1;
+       } else {
+           ret = 0;
+       }
+    }
+    sglob->st->st_unlock( sglob->st );
+    return ret;
+}
+
+
diff --git a/servers/slurpd/rq.c b/servers/slurpd/rq.c
new file mode 100644 (file)
index 0000000..54adb4d
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+ * Copyright (c) 1996 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+/*
+ * rq.c - routines used to manage the queue of replication entries.
+ * An Rq (Replication queue) struct contains a linked list of Re
+ * (Replication entry) structures.
+ *
+ * Routines wishing to access the replication queue should do so through
+ * the Rq struct's member functions, e.g. rq->rq_gethead() and friends.
+ * For example, Re structs should be added to the queue by calling 
+ * the rq_add() member function.
+ *
+ * Access to the queue is serialized by a mutex.  Member functions which do
+ * not do their own locking should only be called after locking the queue
+ * using the rq_lock() member function.  The queue should be unlocked with
+ * the rq_unlock() member function.
+ *
+ * Note that some member functions handle their own locking internally.
+ * Callers should not lock the queue before calling these functions.
+ * See the comment block for each function below.
+ *
+ */
+
+#include <stdio.h>
+
+#include "slurp.h"
+#include "globals.h"
+
+
+/* externs */
+#ifdef NEEDPROTOS
+extern void Re_dump( Re *re );
+#else /* NEEDPROTOS */
+extern void Re_dump();
+#endif /* NEEDPROTOS */
+
+
+extern char *sys_errlist[];
+
+
+/*
+ * Lock the replication queue.
+ */
+static int
+Rq_lock(
+    Rq *rq
+)
+{
+    return( pthread_mutex_lock( &rq->rq_mutex ));
+}
+
+
+
+
+
+/*
+ * Unlock the replication queue.
+ */
+static int
+Rq_unlock(
+    Rq *rq
+)
+{
+    return( pthread_mutex_unlock( &rq->rq_mutex ));
+}
+
+
+
+/*
+ * Return the head of the queue.  Callers should lock the queue before
+ * calling this routine.
+ */
+static Re *
+Rq_gethead(
+    Rq *rq
+)
+{
+    return( rq == NULL ? NULL : rq->rq_head );
+}
+
+
+
+
+/*
+ * Return the next item in the queue.  Callers should lock the queue before
+ * calling this routine.
+ */
+static Re *
+Rq_getnext(
+    Re *re
+)
+{
+    if ( re == NULL ) {
+       return NULL;
+    } else {
+       return( re->re_getnext( re ));
+    }
+}
+
+
+
+
+/*
+ * Delete the item at the head of the list.  The queue should be locked
+ * by the caller before calling this routine.
+ */
+static int
+Rq_delhead(
+    Rq *rq
+)
+{
+    Re *savedhead;
+    int        rc;
+
+    if ( rq == NULL ) {
+       return( -1 );
+    }
+
+    savedhead = rq->rq_head;
+    if ( savedhead == NULL ) {
+       return( 0 );
+    }
+
+    if ( savedhead->re_getrefcnt( savedhead ) != 0 ) {
+       Debug( LDAP_DEBUG_ANY, "Warning: attempt to delete when refcnt != 0\n",
+               0, 0, 0 );
+       return( -1 );
+    }
+
+    rq->rq_head = rq->rq_head->re_getnext( rq->rq_head );
+    rc = savedhead->re_free( savedhead );
+    rq->rq_nre--;      /* decrement count of Re's in queue */
+    return( rc );
+}
+
+
+
+
+/* 
+ * Add an entry to the tail of the replication queue.  Locking is handled
+ * internally.  When items are added to the queue, this routine wakes
+ * up any threads which are waiting for more work by signaling on the
+ * rq->rq_more condition variable.
+ */
+static int
+Rq_add(
+    Rq         *rq,
+    char       *buf
+)
+{
+    Re *re;
+    int        wasempty = 0;
+
+    /* Lock the queue */
+    rq->rq_lock( rq );
+
+    /* Create a new Re */
+    if ( Re_init( &re ) < 0 ) {
+       rq->rq_unlock( rq );
+       return -1;
+    }
+
+    /* parse buf and fill in the re struct */
+    if ( re->re_parse( re, buf ) < 0 ) {
+       re->re_free( re );
+       rq->rq_unlock( rq );
+       return -1;
+    }
+
+    /* Insert into queue */
+    if ( rq->rq_head == NULL ) {
+       rq->rq_head = re;
+       rq->rq_tail = re;
+       wasempty = 1;
+    } else {
+       rq->rq_tail->re_next = re;
+    }
+
+    /* set the sequence number */
+    re->re_seq = 0;
+    if ( !wasempty && !strcmp(rq->rq_tail->re_timestamp, re->re_timestamp )) {
+       /*
+        * Our new re has the same timestamp as the tail's timestamp.
+        * Increment the seq number in the tail and use it as our seq number.
+        */
+       re->re_seq = rq->rq_tail->re_seq + 1;
+    }
+    rq->rq_tail = re;
+
+    /* Increment count of items in queue */
+    rq->rq_nre++;
+    /* wake up any threads waiting for more work */
+    pthread_cond_broadcast( &rq->rq_more );
+
+    /* ... and unlock the queue */
+    rq->rq_unlock( rq );
+
+    return 0;
+}
+
+
+
+
+/*
+ * Garbage-collect the replication queue.  Locking is handled internally.
+ */
+static void
+Rq_gc(
+    Rq *rq
+)
+{
+    if ( rq == NULL ) {
+       Debug( LDAP_DEBUG_ANY, "Rq_gc: rq is NULL!\n", 0, 0, 0 );
+       return;
+    }
+    rq->rq_lock( rq ); 
+    while (( rq->rq_head != NULL ) &&
+           ( rq->rq_head->re_getrefcnt( rq->rq_head ) == 0 )) {
+       rq->rq_delhead( rq );
+       rq->rq_ndel++;  /* increment count of deleted entries */
+    }
+    rq->rq_unlock( rq ); 
+    return;
+}
+
+
+
+/*
+ * For debugging: dump the contents of the replication queue to a file.
+ * Locking is handled internally.
+ */
+static void
+Rq_dump(
+    Rq *rq
+)
+{
+    Re         *re;
+    FILE       *fp;
+
+    if ( rq == NULL ) {
+       Debug( LDAP_DEBUG_ANY, "Rq_dump: rq is NULL!\n", 0, 0, 0 );
+       return;
+    }
+
+    if (( fp = fopen( SLURPD_DUMPFILE, "w" )) == NULL ) {
+       Debug( LDAP_DEBUG_ANY, "Rq_dump: cannot open \"%s\" for write\n",
+               SLURPD_DUMPFILE, 0, 0 );
+       return;
+    }
+
+    rq->rq_lock( rq );
+    for ( re = rq->rq_gethead( rq ); re != NULL; re = rq->rq_getnext( re )) {
+       re->re_dump( re, fp );
+    }
+    rq->rq_unlock( rq );
+    fclose( fp );
+    return;
+}
+
+
+
+/*
+ * Write the contents of a replication queue to a file.  Returns zero if
+ * successful, -1 if not.  Handles queue locking internally.  Callers should
+ * provide an open file pointer, which should refer to a locked file.
+ */
+static int
+Rq_write(
+    Rq         *rq,
+    FILE       *fp
+)
+{
+    Re         *re;
+    time_t     now;
+
+    if ( rq == NULL ) {
+       return -1;
+    }
+
+    Debug( LDAP_DEBUG_ARGS, "re-write on-disk replication log\n",
+           0, 0, 0 );
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+    fseek( fp, 0L, SEEK_SET ); /* Go to beginning of file */
+    rq->rq_lock( rq );
+
+    for ( re = rq->rq_gethead( rq ); re != NULL; re = rq->rq_getnext( re )) {
+       if ( re->re_write( NULL, re, fp ) < 0 ) {
+           fflush( fp );
+           rq->rq_unlock( rq );
+           return -1;
+       }
+    }
+    fflush( fp );
+    sglob->srpos = ftell( fp );        /* update replog file position */
+    /* and truncate to correct len */
+    if ( ftruncate( fileno( fp ), sglob->srpos ) < 0 ) {
+       Debug( LDAP_DEBUG_ANY, "Error truncating replication log: %s\n",
+               sys_errlist[ errno ], 0, 0 );
+    }
+    rq->rq_ndel = 0;   /* reset count of deleted re's */
+    time( &now );
+    rq->rq_lasttrim = now;     /* reset last trim time */
+    rq->rq_unlock( rq );
+    return 0;
+}
+
+
+
+
+/*
+ * Check to see if the private slurpd replication log needs trimming.
+ * The current criteria are:
+ *  - The last trim was more than 5 minutes ago, *and*
+ *  - We've finished with at least 50 replication log entries since the
+ *    last time we re-wrote the replication log.
+ *
+ * Return 1 if replogfile should be trimmed, 0 if not.
+ * Any different policy should be implemented by replacing this function.
+ */
+static int
+Rq_needtrim(
+    Rq *rq
+)
+{
+    int                rc = 0;
+    Re         *re;
+    int                nzrc = 0;       /* nzrc is count of entries with refcnt == 0 */
+    time_t     now;
+
+    if ( rq == NULL ) {
+       return 0;
+    }
+
+    rq->rq_lock( rq );
+
+    time( &now );
+
+    if ( now > ( rq->rq_lasttrim + TRIMCHECK_INTERVAL )) {
+       rc = ( rq->rq_ndel >= 50 );
+    } else {
+       rc = 0;
+    }
+    rq->rq_unlock( rq );
+    return rc;
+}
+
+
+/*
+ * Return counts of Re structs in the queue.
+ */
+static int
+Rq_getcount(
+    Rq *rq,
+    int        type
+)
+{
+    int        count = 0;
+    Re *re;
+
+    if ( rq == NULL ) {
+       return 0;
+    }
+
+    rq->rq_lock( rq );
+    if ( type == RQ_COUNT_ALL ) {
+       count = rq->rq_nre;
+    } else {
+       for ( re = rq->rq_gethead( rq ); re != NULL;
+               re = rq->rq_getnext( re )) {
+           if ( type == RQ_COUNT_NZRC ) {
+               if ( re->re_getrefcnt( re ) > 1 ) {
+                   count++;
+               }
+           }
+       }
+    }
+    rq->rq_unlock( rq );
+    return count;
+}
+
+
+
+
+/* 
+ * Allocate and initialize an Rq object.
+ */
+int
+Rq_init(
+    Rq **rq
+)
+{
+    /* Instantiate the struct */
+    (*rq) = (Rq *) malloc( sizeof( Rq ));
+    if ( *rq == NULL ) {
+       return -1;
+    }
+
+    /* Fill in all the function pointers */
+    (*rq)->rq_gethead = Rq_gethead;
+    (*rq)->rq_getnext = Rq_getnext;
+    (*rq)->rq_delhead = Rq_delhead;
+    (*rq)->rq_add = Rq_add;
+    (*rq)->rq_gc = Rq_gc;
+    (*rq)->rq_lock = Rq_lock;
+    (*rq)->rq_unlock = Rq_unlock;
+    (*rq)->rq_dump = Rq_dump;
+    (*rq)->rq_needtrim = Rq_needtrim;
+    (*rq)->rq_write = Rq_write;
+    (*rq)->rq_getcount = Rq_getcount;
+
+    /* Initialize private data */
+    pthread_mutex_init( &((*rq)->rq_mutex), pthread_mutexattr_default );
+    pthread_cond_init( &((*rq)->rq_more), pthread_condattr_default );
+    (*rq)->rq_head = NULL;
+    (*rq)->rq_tail = NULL;
+    (*rq)->rq_nre = 0;
+    (*rq)->rq_ndel = 0;
+    (*rq)->rq_lasttrim = (time_t) 0L;
+
+    return 0;
+}
+
diff --git a/servers/slurpd/sanity.c b/servers/slurpd/sanity.c
new file mode 100644 (file)
index 0000000..04be7db
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 1996 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+
+/*
+ * sanity.c - perform sanity checks on the environment at startup time,
+ * and report any errors before we disassociate from the controlling tty,
+ * start up our threads, and do other stuff which makes it hard to give
+ * feedback to the users.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "slurp.h"
+#include "globals.h"
+#include "portable.h"
+
+#define FC_DIRBAD      1
+#define FC_DIRUNREAD   2
+#define FC_DIRUNWRITE  4
+#define FC_FILEBAD     8
+#define FC_FILEUNREAD  16
+#define FC_FILEUNWRITE 32
+
+
+/*
+ * Forward declarations
+ */
+#ifdef NEEDPROTOS
+static unsigned int filecheck( char * );
+#else /* NEEDPROTOS */
+static unsigned int filecheck();
+#endif /* NEEDPROTOS */
+
+
+
+/*
+ * Take a look around to catch any fatal errors.  For example, make sure the
+ * destination directory for our working files exists, check that all
+ * pathnames make sense, and so on.  Returns 0 is everything's ok,
+ # -1 if there's something wrong which will keep us from functioning
+ * correctly.
+ *
+ * We do all these checks at startup so we can print a reasonable error
+ * message on stderr before we disassociate from the controlling tty.  This
+ * keeps some fatal error messages from "disappearing" into syslog.
+ */
+
+int
+sanity()
+{
+    int        err = 0;
+    int rc;
+
+    /*
+     * Are there any replicas listed in the slapd config file?
+     */
+    if ( sglob->replicas == NULL ) {
+       fprintf( stderr, "No replicas in slapd config file \"%s\"!\n",
+           sglob->slapd_configfile );
+       err++;
+    }
+
+    /*
+     * Make sure the directory housing the slapd replogfile exists, and
+     * that the slapd replogfile is readable, if it exists.
+     */
+    if ( sglob->slapd_replogfile == NULL ) {
+       fprintf( stderr, "Fatal error: no \"replogfile\" directive given\n" );
+       err++;
+    } else {
+       rc = filecheck( sglob->slapd_replogfile );
+       if ( rc & FC_DIRBAD ) {
+           fprintf( stderr, "Error: %s: directory does not exist\n", 
+                   sglob->slapd_replogfile );
+           err++;
+       } else if ( rc & FC_DIRUNREAD ) {
+           fprintf( stderr, "Error: %s: directory not readable\n", 
+                   sglob->slapd_replogfile );
+           err++;
+       } else if (!( rc & FC_FILEBAD) && ( rc & FC_FILEUNREAD )) {
+           fprintf( stderr, "Error: %s: file not readable\n", 
+                   sglob->slapd_replogfile );
+           err++;
+       }
+    }
+
+    /*
+     * Make sure the directory for the slurpd replogfile is there, and
+     * that the slurpd replogfile is readable and writable, if it exists.
+     */
+    if ( sglob->slurpd_replogfile == NULL ) {
+       fprintf( stderr, "Fatal error: no \"replogfile\" directive given\n" );
+       err++;
+    } else {
+       rc = filecheck( sglob->slurpd_replogfile );
+       if ( rc & FC_DIRBAD ) {
+           fprintf( stderr, "Error: %s: directory does not exist\n", 
+                   sglob->slurpd_replogfile );
+           err++;
+       } else if ( rc & FC_DIRUNREAD ) {
+           fprintf( stderr, "Error: %s: directory not readable\n", 
+                   sglob->slurpd_replogfile );
+           err++;
+       } else if ( !( rc & FC_FILEBAD ) && ( rc & FC_FILEUNREAD )) {
+           fprintf( stderr, "Error: %s: file not readable\n", 
+                   sglob->slurpd_replogfile );
+           err++;
+       } else if ( !( rc & FC_FILEBAD ) && ( rc & FC_FILEUNWRITE )) {
+           fprintf( stderr, "Error: %s: file not writeable\n", 
+                   sglob->slurpd_replogfile );
+           err++;
+       }
+    }
+
+    /*
+     * Make sure that the directory for the slurpd status file is there, and
+     * that the slurpd status file is writable, if it exists.
+     */
+    rc = filecheck( sglob->slurpd_status_file );
+    if ( rc & FC_DIRBAD ) {
+       fprintf( stderr, "Error: %s: directory does not exist\n", 
+               sglob->slurpd_status_file );
+       err++;
+    } else if ( rc & FC_DIRUNREAD ) {
+       fprintf( stderr, "Error: %s: directory not readable\n", 
+               sglob->slurpd_status_file );
+       err++;
+    } else if ( !( rc & FC_FILEBAD ) && ( rc & FC_FILEUNREAD )) {
+       fprintf( stderr, "Error: %s: file not readable\n", 
+               sglob->slurpd_status_file );
+       err++;
+    } else if ( !( rc & FC_FILEBAD ) && ( rc & FC_FILEUNWRITE )) {
+       fprintf( stderr, "Error: %s: file not writeable\n", 
+               sglob->slurpd_status_file );
+       err++;
+    }
+    
+    return ( err == 0 ? 0 : -1 );
+}
+
+
+
+/*
+ * Check for the existence of the file and directory leading to the file.
+ * Returns a bitmask which is the logical OR of the following flags:
+ *
+ *  FC_DIRBAD:         directory containing "f" does not exist.
+ *  FC_DIRUNREAD:      directory containing "f" exists but is not readable.
+ *  FC_DIRUNWRITE:     directory containing "f" exists but is not writable.
+ *  FC_FILEBAD:                "f" does not exist.
+ *  FC_FILEUNREAD:     "f" exists but is unreadable.
+ *  FC_FILEUNWRITE:    "f" exists but is unwritable.
+ *
+ * The calling routine is responsible for determining which, if any, of
+ * the returned flags is a problem for a particular file.
+ */
+static unsigned int
+filecheck(
+    char       *f
+)
+{
+    char               dir[ MAXPATHLEN ];
+    char               *p;
+    unsigned int       ret = 0;
+
+    strcpy( dir, sglob->slapd_replogfile );
+    p = strrchr( dir, '/' );
+    if ( p != NULL ) {
+       *p = '\0';
+    }
+    if ( access( dir, F_OK ) < 0 ) {
+       ret |= FC_DIRBAD;
+    }
+    if ( access( dir, R_OK ) < 0 ) {
+       ret |= FC_DIRUNREAD;
+    }
+    if ( access( dir, W_OK ) < 0 ) {
+       ret |= FC_DIRUNWRITE;
+    }
+    if ( access( f, F_OK ) < 0 ) {
+       ret |= FC_FILEBAD;
+    }
+    if ( access( f, R_OK ) < 0 ) {
+       ret |= FC_FILEUNREAD;
+    }
+    if ( access( f, W_OK ) < 0 ) {
+       ret |= FC_FILEUNWRITE;
+    }
+
+    return ret;
+}
+
diff --git a/servers/slurpd/slurp.h b/servers/slurpd/slurp.h
new file mode 100644 (file)
index 0000000..622cd38
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * Copyright (c) 1996 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+/* slurp.h - Standalone Ldap Update Replication Daemon (slurpd) */
+
+#ifndef _SLURPD_H_
+#define _SLURPD_H_
+
+#define LDAP_SYSLOG
+
+#include <syslog.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include "lber.h"
+#include "ldap.h"
+#include "lthread.h"
+#include "portable.h"
+#include "ldapconfig.h"
+#include "ldif.h"
+
+
+/* Default directory for slurpd's private copy of replication logs */
+#define        DEFAULT_SLURPD_REPLICA_DIR      "/usr/tmp"
+
+/* Default name for slurpd's private copy of the replication log */
+#define        DEFAULT_SLURPD_REPLOGFILE       "slurpd.replog"
+
+/* Name of file which stores saved slurpd state info, for restarting */
+#define        DEFAULT_SLURPD_STATUS_FILE      "slurpd.status"
+
+/* slurpd dump file - contents of rq struct are written here (debugging) */
+#define        SLURPD_DUMPFILE                 "/tmp/slurpd.dump"
+
+/* default srvtab file.  Can be overridden */
+#define        SRVTAB                          "/etc/srvtab"
+
+/* Amount of time to sleep if no more work to do */
+#define        DEFAULT_NO_WORK_INTERVAL        3
+
+/* The time we wait between checks to see if the replog file needs trimming */
+#define        TRIMCHECK_INTERVAL              ( 60 * 5 )
+
+/* Only try to trim slurpd replica files larger than this size */
+#define        MIN_TRIM_FILESIZE               ( 10L * 1024L )
+
+/* Maximum line length we can read from replication log */
+#define        REPLBUFLEN                      256
+
+/* We support simple (plaintext password) and kerberos authentication */
+#define        AUTH_SIMPLE     1
+#define        AUTH_KERBEROS   2
+
+/* Rejection records are prefaced with this string */
+#define        ERROR_STR       "ERROR"
+
+/* Strings found in replication entries */
+#define        T_CHANGETYPESTR         "changetype"
+#define        T_CHANGETYPE            1
+#define        T_TIMESTR               "time"
+#define        T_TIME                  2
+#define        T_DNSTR                 "dn"
+#define        T_DN                    3
+
+#define        T_ADDCTSTR              "add"
+#define        T_ADDCT                 4
+#define        T_MODIFYCTSTR           "modify"
+#define        T_MODIFYCT              5
+#define        T_DELETECTSTR           "delete"
+#define        T_DELETECT              6
+#define        T_MODRDNCTSTR           "modrdn"
+#define        T_MODRDNCT              7
+
+#define        T_MODOPADDSTR           "add"
+#define        T_MODOPADD              8
+#define        T_MODOPREPLACESTR       "replace"
+#define        T_MODOPREPLACE          9
+#define        T_MODOPDELETESTR        "delete"
+#define        T_MODOPDELETE           10
+#define        T_MODSEPSTR             "-"
+#define        T_MODSEP                11
+
+#define        T_NEWRDNSTR             "newrdn"
+#define        T_DRDNFLAGSTR           "deleteoldrdn"
+
+#define        T_ERR                   -1
+
+/* Config file keywords */
+#define        HOSTSTR                 "host"
+#define        BINDDNSTR               "binddn"
+#define        BINDMETHSTR             "bindmethod"
+#define        KERBEROSSTR             "kerberos"
+#define        SIMPLESTR               "simple"
+#define        CREDSTR                 "credentials"
+#define BINDPSTR               "bindprincipal"
+#define        SRVTABSTR               "srvtab"
+
+#define        REPLICA_SLEEP_TIME      ( 10 )
+
+/* Enumeration of various types of bind failures */
+#define BIND_OK                        0
+#define BIND_ERR_BADLDP                        1
+#define        BIND_ERR_OPEN                   2
+#define        BIND_ERR_BAD_ATYPE              3
+#define        BIND_ERR_SIMPLE_FAILED          4
+#define        BIND_ERR_KERBEROS_FAILED        5
+#define        BIND_ERR_BADRI                  6
+
+/* Return codes for do_ldap() */
+#define        DO_LDAP_OK                      0
+#define        DO_LDAP_ERR_RETRYABLE           1
+#define        DO_LDAP_ERR_FATAL               2
+
+/*
+ * Types of counts one can request from the Rq rq_getcount()
+ * member function
+ */
+/* all elements */
+#define        RQ_COUNT_ALL                    1
+/* all elements with nonzero refcnt */
+#define        RQ_COUNT_NZRC                   2
+
+/* Amount of time, in seconds, for a thread to sleep when it encounters
+ * a retryable error in do_ldap().
+ */
+#define        RETRY_SLEEP_TIME                60
+
+
+
+/*
+ * ****************************************************************************
+ * Data types for replication queue and queue elements.
+ * ****************************************************************************
+ */
+
+
+/*
+ * Replica host information.  An Ri struct will contain an array of these,
+ * with one entry for each replica.  The end of the array is signaled
+ * by a NULL value in the rh_hostname field.
+ */
+typedef struct rh {
+    char       *rh_hostname;           /* replica hostname  */
+    int                rh_port;                /* replica port */
+} Rh;
+
+
+/*
+ * Per-replica information.
+ *
+ * Notes:
+ *  - Private data should not be manipulated expect by Ri member functions.
+ */
+typedef struct ri {
+
+    /* Private data */
+    char       *ri_hostname;           /* canonical hostname of replica */
+    int                ri_port;                /* port where slave slapd running */
+    LDAP       *ri_ldp;                /* LDAP struct for this replica */
+    int                ri_bind_method;         /* AUTH_SIMPLE or AUTH_KERBEROS */
+    char       *ri_bind_dn;            /* DN to bind as when replicating */
+    char       *ri_password;           /* Password for AUTH_SIMPLE */
+    char       *ri_principal;          /* principal for kerberos bind */
+    char       *ri_srvtab;             /* srvtab file for kerberos bind */
+    struct re  *ri_curr;               /* current repl entry being processed */
+    struct stel        *ri_stel;               /* pointer to Stel for this replica */
+    unsigned long
+               ri_seq;                 /* seq number of last repl */
+    pthread_t  ri_tid;                 /* ID of thread for this replica */
+
+    /* Member functions */
+    int                (*ri_process)();        /* process the next repl entry */
+    void       (*ri_wake)();           /* wake up a sleeping thread */
+} Ri;
+    
+
+
+
+/*
+ * Information about one particular modification to make.  This data should
+ * be considered private to routines in re.c, and to routines in ri.c.
+ */
+typedef struct mi {
+    
+    /* Private data */
+    char       *mi_type;               /* attr or type */
+    char       *mi_val;                /* value */
+    int                mi_len;                 /* length of mi_val */
+
+} Mi;
+
+
+
+
+/* 
+ * Information about one particular replication entry.  Only routines in
+ * re.c  and rq.c should touch the private data.  Other routines should
+ * only use member functions.
+ */
+typedef struct re {
+
+    /* Private data */
+    pthread_mutex_t
+               re_mutex;               /* mutex for this Re */
+    int                re_refcnt;              /* ref count, 0 = done */
+    char       *re_timestamp;          /* timestamp of this re */
+    int                re_seq;                 /* sequence number */
+    Rh         *re_replicas;           /* array of replica info */
+    char       *re_dn;                 /* dn of entry being modified */
+    int                re_changetype;          /* type of modification */
+    Mi         *re_mods;               /* array of modifications to make */
+    struct re  *re_next;               /* pointer to next element */
+
+    /* Public functions */
+    int        (*re_free)();           /* free an re struct */
+    struct re  *(*re_getnext)();       /* return next Re in linked list */
+    int                (*re_parse)();          /* parse a replication log entry */
+    int                (*re_write)();          /* write a replication log entry */
+    void       (*re_dump)();           /* debugging  - print contents */
+    int                (*re_lock)();           /* lock this re */
+    int                (*re_unlock)();         /* unlock this re */
+    int                (*re_decrefcnt)();      /* decrement the refcnt */
+    int                (*re_getrefcnt)();      /* get the refcnt */
+} Re;
+
+
+
+
+/* 
+ * Definition for the queue of replica information.  Private data is
+ * private to rq.c.  Other routines should only touch public data or
+ * use member functions.  Note that although we have a member function
+ * for locking the queue's mutex, we need to expose the rq_mutex
+ * variable so routines in ri.c can use it as a mutex for the
+ * rq_more condition variable.
+ */
+typedef struct rq {
+
+    /* Private data */
+    Re         *rq_head;               /* pointer to head */
+    Re         *rq_tail;               /* pointer to tail */
+    int                rq_nre;                 /* total number of Re's in queue */
+    int                rq_ndel;                /* number of deleted Re's in queue */
+    time_t     rq_lasttrim;            /* Last time we trimmed file */
+    
+    /* Public data */
+    pthread_mutex_t
+               rq_mutex;               /* mutex for whole queue */
+    pthread_cond_t
+               rq_more;                /* condition var - more work added */
+
+    /* Member functions */
+    Re         *(*rq_gethead)();       /* get the element at head */
+    Re         *(*rq_getnext)();       /* get the next element */
+    int                (*rq_delhead)();        /* delete the element at head */
+    int                (*rq_add)();            /* add at tail */
+    void       (*rq_gc)();             /* garbage-collect queue */
+    int                (*rq_lock)();           /* lock the queue */
+    int                (*rq_unlock)();         /* unlock the queue */
+    int                (*rq_needtrim)();       /* see if queue needs trimming */
+    int                (*rq_write)();          /* write Rq contents to a file */
+    int                (*rq_getcount)();       /* return queue counts */
+    void       (*rq_dump)();           /* debugging  - print contents */
+} Rq;
+
+
+
+/*
+ * An Stel (status element) contains information about one replica.
+ * Stel structs are associated with the St (status) struct, defined 
+ * below.
+ */
+typedef struct stel {
+    char       *hostname;              /* host name of replica */
+    int                port;                   /* port number of replica */
+    char       last[ 64 ];             /* timestamp of last successful repl */
+    int                seq;                    /* Sequence number of last repl */
+} Stel;
+
+
+/*
+ * An St struct in an in-core structure which contains the current
+ * slurpd state.  Most importantly, it contains an array of Stel
+ * structs which contain the timestamp and sequence number of the last
+ * successful replication for each replica.  The st_write() member
+ * function is called periodically to flush status information to
+ * disk.  At startup time, slurpd checks for the status file, and
+ * if present, uses the timestamps to avoid "replaying" replications
+ * which have already been sent to a given replica.
+ */
+typedef struct st {
+
+    /* Private data */
+    pthread_mutex_t
+               st_mutex;               /* mutex to serialize access */
+    Stel       **st_data;              /* array of pointers to Stel structs */
+    int                st_nreplicas;           /* number of repl hosts */
+    int                st_err_logged;          /* 1 if fopen err logged */
+    FILE       *st_fp;                 /* st file kept open */
+    FILE       *st_lfp;                /* lockfile fp */
+
+    /* Public member functions */
+    int                (*st_update)();         /* update the entry for a host */
+    Stel       *(*st_add)();           /* add a new repl host */
+    int                (*st_write)();          /* write status to disk */
+    int                (*st_read)();           /* read status info from disk */
+    int                (*st_lock)();           /* read status info from disk */
+    int                (*st_unlock)();         /* read status info from disk */
+} St;
+
+#if defined( THREAD_SUNOS4_LWP )
+typedef struct tl {
+    thread_t   tl_tid;         /* thread being managed */
+    time_t     tl_wake;        /* time thread should be resumed */
+    struct tl  *tl_next;       /* next node in list */
+} tl_t;
+
+typedef struct tsl {
+    tl_t       *tsl_list;
+    mon_t      tsl_mon;
+} tsl_t;
+#endif /* THREAD_SUNOS4_LWP */
+
+    
+
+/* 
+ * Public functions used to instantiate and initialize queue objects.
+ */
+#ifdef NEEDPROTOS
+extern int Ri_init( Ri **ri );
+extern int Rq_init( Rq **rq );
+extern int Re_init( Re **re );
+#else /* NEEDPROTOS */
+extern int Ri_init();
+extern int Rq_init();
+extern int Re_init();
+#endif /* NEEDPROTOS */
+
+#endif /* _SLURPD_H_ */
+
diff --git a/servers/slurpd/st.c b/servers/slurpd/st.c
new file mode 100644 (file)
index 0000000..610b295
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 1996 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+
+/*
+ * st.c - routines for managing the status structure, and for reading and
+ * writing status information to disk.
+ */
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "slurp.h"
+#include "globals.h"
+
+#ifndef SYSERRLIST_IN_STDIO
+extern char *sys_errlist[];
+#endif /* SYSERRLIST_IN_STDIO */
+
+/*
+ * Add information about replica host specified by Ri to list
+ * of hosts.
+ */
+static Stel *
+St_add(
+    St *st,
+    Ri *ri
+)
+{
+    int        ind;
+
+    if ( st == NULL || ri == NULL ) {
+       return NULL;
+    }
+
+    /* Serialize access to the St struct */
+    pthread_mutex_lock( &(st->st_mutex ));
+
+    st->st_nreplicas++;
+    ind = st->st_nreplicas - 1;
+    st->st_data = ( Stel ** ) ch_realloc( st->st_data, 
+           ( st->st_nreplicas * sizeof( Stel * )));
+    if ( st->st_data == NULL ) {
+       pthread_mutex_unlock( &(st->st_mutex ));
+       return NULL;
+    }
+    st->st_data[ ind ]  = ( Stel * ) ch_malloc( st->st_data,
+           sizeof( Stel ));
+    if ( st->st_data[ ind ] == NULL ) {
+       pthread_mutex_unlock( &(st->st_mutex ));
+       return NULL;
+    }
+
+    st->st_data[ ind ]->hostname = strdup( ri->ri_hostname );
+    st->st_data[ ind ]->port = ri->ri_port;
+    memset( st->st_data[ ind ]->last, 0, sizeof( st->st_data[ ind ]->last )); 
+    st->st_data[ ind ]->seq = 0;
+
+    pthread_mutex_unlock( &(st->st_mutex ));
+    return st->st_data[ ind ];
+}
+
+
+
+/*
+ * Write the contents of an St to disk.
+ */
+static int
+St_write (
+    St *st
+)
+{
+    int                rc;
+    Stel       *stel;
+    int                i;
+
+    if ( st == NULL ) {
+       return -1;
+    }
+    pthread_mutex_lock( &(st->st_mutex ));
+    if ( st->st_fp == NULL ) {
+       /* Open file */
+       if (( rc = acquire_lock( sglob->slurpd_status_file, &(st->st_fp),
+               &(st->st_lfp))) < 0 ) {
+           if ( !st->st_err_logged ) {
+               Debug( LDAP_DEBUG_ANY,
+                       "Error: cannot open status file \"%s\": %s\n",
+                       sglob->slurpd_status_file, sys_errlist[ errno ], 0 );
+               st->st_err_logged = 1;
+               pthread_mutex_unlock( &(st->st_mutex ));
+               return -1;
+           }
+       } else {
+           st->st_err_logged = 0;
+       }
+    }
+
+    /* Write data to the file */
+    truncate( sglob->slurpd_status_file, 0L );
+    fseek( st->st_fp, 0L, 0 );
+    for ( i = 0; i < st->st_nreplicas; i++ ) {
+       stel = st->st_data[ i ];
+       fprintf( st->st_fp, "%s:%d:%s:%d\n", stel->hostname, stel->port,
+               stel->last, stel->seq );
+    }
+    fflush( st->st_fp );
+
+    pthread_mutex_unlock( &(st->st_mutex ));
+
+    return 0;
+}
+    
+
+
+
+/*
+ * Update the entry for a given host.
+ */
+static int
+St_update(
+    St         *st,
+    Stel       *stel,
+    Re         *re
+)
+{
+    if ( stel == NULL || re == NULL ) {
+       return -1;
+    }
+
+    pthread_mutex_lock( &(st->st_mutex ));
+    strcpy( stel->last, re->re_timestamp );
+    stel->seq = re->re_seq;
+    pthread_mutex_unlock( &(st->st_mutex ));
+    return 0;
+}
+
+
+
+
+/*
+ * Read status information from disk file.
+ */
+static int
+St_read(
+    St *st
+)
+{
+    FILE       *fp;
+    FILE       *lfp;
+    char       buf[ 255 ];
+    int                i;
+    int                rc;
+    char       *hostname, *port, *timestamp, *seq, *p, *t;
+    int                found;
+
+    if ( st == NULL ) {
+       return -1;
+    }
+    pthread_mutex_lock( &(st->st_mutex ));
+    if ( access( sglob->slurpd_status_file, F_OK ) < 0 ) {
+       /*
+        * File doesn't exist, so create it and return.
+        */
+       if (( fp = fopen( sglob->slurpd_status_file, "w" )) == NULL ) {
+           Debug( LDAP_DEBUG_ANY, "Error: cannot create status file \"%s\"\n",
+                   sglob->slurpd_status_file, 0, 0 );
+           pthread_mutex_unlock( &(st->st_mutex ));
+           return -1;
+       }
+       (void) fclose( fp );
+       pthread_mutex_unlock( &(st->st_mutex ));
+       Debug( LDAP_DEBUG_ARGS, "No status file found, defaulting values\n",
+               0, 0, 0 );
+       return 0;
+    }
+    if (( rc = acquire_lock( sglob->slurpd_status_file, &fp, &lfp)) < 0 ) {
+       return 0;
+    }
+    while ( fgets( buf, sizeof( buf ), fp ) != NULL ) {
+       p = buf;
+       hostname = p;
+       if (( t = strchr( p, ':' )) == NULL ) {
+           goto bad;
+       }
+       *t++ = '\0';
+       p = t;
+       port = p;
+       if (( t = strchr( p, ':' )) == NULL ) {
+           goto bad;
+       }
+       *t++ = '\0';
+       p = t;
+       timestamp = p;
+       if (( t = strchr( p, ':' )) == NULL ) {
+           goto bad;
+       }
+       *t++ = '\0';
+       seq = t;
+       if (( t = strchr( seq, '\n' )) != NULL ) {
+           *t = '\0';
+       }
+
+       found = 0;
+       for ( i = 0; i < sglob->st->st_nreplicas; i++ ) {
+           if ( !strcmp( hostname, sglob->st->st_data[ i ]->hostname ) &&
+                   atoi( port ) == sglob->st->st_data[ i ]->port ) {
+               found = 1;
+               strcpy( sglob->st->st_data[ i ]->last, timestamp );
+               sglob->st->st_data[ i ]->seq = atoi( seq );
+               break;
+           }
+       }
+       if ( found ) {
+           char tbuf[ 255 ];
+           sprintf( tbuf, "%s:%s (timestamp %s.%s)", hostname, port,
+                   timestamp, seq );
+           Debug( LDAP_DEBUG_ARGS,
+                   "Retrieved state information for %s\n", tbuf, 0, 0 );
+       } else {
+           Debug(  LDAP_DEBUG_ANY,
+                   "Warning: saved state for %s:%s, not a known replica\n",
+                   hostname, port, 0 );
+       }
+    }
+    (void) relinquish_lock( sglob->slurpd_status_file, fp, lfp);
+    pthread_mutex_unlock( &(st->st_mutex ));
+    return 0;
+
+bad:
+    (void) relinquish_lock( sglob->slurpd_status_file, fp, lfp);
+    pthread_mutex_unlock( &(st->st_mutex ));
+    return -1;
+}
+    
+
+
+
+/*
+ * Lock an St struct.
+ */
+static int
+St_lock(
+    St *st
+)
+{
+    return( pthread_mutex_lock( &st->st_mutex ));
+}
+
+
+
+
+/*
+ * Lock an St struct.
+ */
+static int
+St_unlock(
+    St *st
+)
+{
+    return( pthread_mutex_unlock( &st->st_mutex ));
+}
+
+
+
+
+/*
+ * Allocate and initialize an St struct.
+ */
+int
+St_init(
+    St **st
+)
+{
+    if ( st == NULL ) {
+       return -1;
+    }
+
+    (*st) = (St *) malloc( sizeof( St ));
+    if ( *st == NULL ) {
+       return -1;
+    }
+
+    pthread_mutex_init( &((*st)->st_mutex), pthread_mutexattr_default );
+    (*st)->st_data = NULL;
+    (*st)->st_fp = NULL;
+    (*st)->st_lfp = NULL;
+    (*st)->st_nreplicas = 0;
+    (*st)->st_err_logged = 0;
+    (*st)->st_update = St_update;
+    (*st)->st_add = St_add;
+    (*st)->st_write = St_write;
+    (*st)->st_read = St_read;
+    (*st)->st_lock = St_lock;
+    (*st)->st_unlock = St_unlock;
+    return 0;
+}
+
diff --git a/servers/slurpd/tsleep.c b/servers/slurpd/tsleep.c
new file mode 100644 (file)
index 0000000..5dc3ba3
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 1996 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+ */
+
+/*
+ * tsleep.c - allow a thread to sleep without putting the whole process
+ * (e.g. pod under lwp) to sleep.  Contains platform-specific code to
+ * allow this:
+ *
+ * Under non-preemptive threads packages like SunOS lwp, tsleep() adds
+ * the thread to a list of sleepers.  The lwp_scheduler process takes
+ * care of resuming suspended threads.
+ *
+ * Under a fully-preemptive threads package, like Solaris threads,
+ * tsleep just calls sleep(), and there is no scheduler thread.  Life
+ * is so much simpler...
+ */
+
+#include <stdio.h>
+
+#include "slurp.h"
+#include "globals.h"
+
+
+#if defined( THREAD_SUNOS4_LWP )
+
+extern stkalign_t *get_stack( int * );
+extern void free_stack( int );
+
+int
+tsleep(
+    int        interval
+)
+{
+    thread_t   mylwp;
+    tl_t       *t, *nt;
+    time_t     now;
+
+
+    if ( lwp_self( &mylwp ) < 0 ) {
+       return -1;
+    }
+    time( &now );
+
+    mon_enter( &sglob->tsl_mon );
+    if ( sglob->tsl_list != NULL ) {
+       for ( t = sglob->tsl_list; t != NULL; t = t->tl_next ) {
+           if ( SAMETHREAD( t->tl_tid, mylwp )) {
+               /* We're already sleeping? */
+               t->tl_wake = now + (time_t) interval;
+               mon_exit( &sglob->tsl_mon );
+               lwp_suspend( mylwp );
+               return 0;
+           }
+       }
+    }
+    nt = (tl_t *) malloc( sizeof( tl_t ));
+
+    nt->tl_next = sglob->tsl_list;
+    nt->tl_wake = now + (time_t) interval;
+    nt->tl_tid = mylwp;
+    sglob->tsl_list = nt;
+    mon_exit( &sglob->tsl_mon );
+    lwp_suspend( mylwp );
+    return 0;
+}
+
+/*
+ * The lwp_scheduler thread periodically checks to see if any threads
+ * are due to be resumed.  If there are, it resumes them.  Otherwise,
+ * it computes the lesser of ( 1 second ) or ( the minimum time until
+ * a thread need to be resumed ) and puts itself to sleep for that amount
+ * of time.
+ */
+void
+lwp_scheduler(
+    int        stackno
+)
+{
+    time_t             now, min;
+    struct timeval     interval;
+    tl_t               *t;
+
+    while ( !sglob->slurpd_shutdown ) {
+       mon_enter( &sglob->tsl_mon );
+       time( &now );
+       min = 0L;
+       if ( sglob->tsl_list != NULL ) {
+           for ( t = sglob->tsl_list; t != NULL; t = t->tl_next ) {
+               if (( t->tl_wake  > 0L ) && ( t->tl_wake < now )) {
+                   lwp_resume( t->tl_tid );
+                   t->tl_wake = 0L;
+               }
+               if (( t->tl_wake > now ) && ( t->tl_wake < min )) {
+                   min =  t->tl_wake;
+               }
+           }
+       }
+       mon_exit( &sglob->tsl_mon );
+       interval.tv_usec = 0L;
+       if ( min == 0L ) {
+           interval.tv_sec = 1L;
+       } else {
+           interval.tv_sec = min;
+       }
+       lwp_sleep( &interval );
+    }
+    mon_enter( &sglob->tsl_mon );
+    for ( t = sglob->tsl_list; t != NULL; t = t->tl_next ) {
+       lwp_resume( t->tl_tid );
+    }
+    mon_exit( &sglob->tsl_mon );
+    free_stack( stackno );
+}
+
+
+/*
+ * Create the lwp_scheduler thread.
+ */
+void
+start_lwp_scheduler()
+{
+    thread_t   tid;
+    stkalign_t *stack;
+    int                stackno;
+
+    if (( stack = get_stack( &stackno )) == NULL ) {
+       return;
+    }
+    lwp_create( &tid, lwp_scheduler, MINPRIO, 0, stack, 1, stackno );
+    return;
+}
+
+
+#else /* THREAD_SUNOS4_LWP */
+
+/*
+ * Here we assume we have fully preemptive threads, and that sleep()
+ * does the right thing.
+ */
+void
+tsleep(
+    time_t     interval
+)
+{
+    sleep( interval );
+}
+#endif /* THREAD_SUNOS4_LWP */
+
+
+
diff --git a/tests/Make-template b/tests/Make-template
new file mode 100644 (file)
index 0000000..f8cae98
--- /dev/null
@@ -0,0 +1,35 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 1996 Regents of the University of Michigan.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of Michigan at Ann Arbor. 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'' without express or implied warranty.
+#
+#       LDAP tests Make template file
+#
+#-----------------------------------------------------------------------------
+
+SCRIPTSDIR=./scripts
+
+all:   FORCE
+       @echo "Initiating LDAP tests..."; \
+       $(SCRIPTSDIR)/all $(SCRIPTSDIR)
+
+install:       FORCE
+
+depend:        FORCE
+
+clean: FORCE
+       $(RM) test-db/* test-repl/*
+
+veryclean:     clean
+
+links:
+       @echo "making links in `$(PWD)`"; \
+       $(LN) .src/scripts . ; \
+       $(LN) .src/data . ; \
+       $(MKDIR) test-db test-repl
diff --git a/tests/README b/tests/README
new file mode 100644 (file)
index 0000000..1e4633b
--- /dev/null
@@ -0,0 +1,3 @@
+This directory contains a series of test scripts which are used to
+verify basic functionality of the LDAP libraries, slapd, and slurpd.
+To run the tests, type "make" in the ./tests directory.
diff --git a/tests/data/acl.out.master b/tests/data/acl.out.master
new file mode 100644 (file)
index 0000000..4bef01e
--- /dev/null
@@ -0,0 +1,278 @@
+dn: cn=James A Jones 1, ou=Alumni Association, ou=People, o=University of Mich
+ igan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: James A Jones 1
+cn: James Jones
+cn: Jim Jones
+sn: Jones
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: jaj
+krbname: jaj@umich.edu
+nobatchupdates: TRUE
+onvacation: FALSE
+homepostaladdress: 3882 Beverly Rd. $ Ann Arbor, MI 48105
+homephone: +1 313 555 4772
+multilinedescription: Outstanding
+title: Mad Cow Researcher, UM Alumni Association
+pager: +1 313 555 3923
+mail: jaj@mail.alumni.umich.edu
+modifytimestamp: 960404171231Z
+modifiersname: cn=Manager,o=University of Michigan,c=US
+facsimiletelephonenumber: +1 313 555 4332
+telephonenumber: +1 313 555 0895
+dn: cn=All Staff,ou=Groups,o=University of Michigan,c=US
+member: cn=Manager, o=University of Michigan, c=US
+member: cn=Barbara Jensen, ou=Information Technology Division, ou=People, o=Un
+ iversity of Michigan, c=US
+member: cn=Jane Doe, ou=Alumni Association, ou=People, o=University of Michiga
+ n, c=US
+member: cn=John Doe, ou=Information Technology Division, ou=People, o=Universi
+ ty of Michigan, c=US
+member: cn=Mark Elliot, ou=Alumni Association, ou=People, o=University of Mich
+ igan, c=US
+member: cn=James A Jones 1, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=James A Jones 2, ou=Information Technology Division, ou=People, o=U
+ niversity of Michigan, c=US
+member: cn=Jennifer Smith, ou=Alumni Association, ou=People, o=University of M
+ ichigan, c=US
+member: cn=Dorothy Stevens, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=Ursula Hampster, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, o=Univ
+ ersity of Michigan, c=US
+associateddomain: umich.edu
+requeststo: cn=Manager, o=University of Michigan, c=US
+errorsto: cn=Manager, o=University of Michigan, c=US
+owner: cn=Manager, o=University of Michigan, c=US
+cn: All Staff
+joinable: FALSE
+multilinedescription: Everyone in the sample data
+objectclass: rfc822mailgroup
+
+dn: cn=Alumni Assoc Staff,ou=Groups,o=University of Michigan,c=US
+member: cn=Manager, o=University of Michigan, c=US
+member: cn=Dorothy Stevens, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=James A Jones 1, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=Jane Doe, ou=Alumni Association, ou=People, o=University of Michiga
+ n, c=US
+member: cn=Jennifer Smith, ou=Alumni Association, ou=People, o=University of M
+ ichigan, c=US
+member: cn=Mark Elliot, ou=Alumni Association, ou=People, o=University of Mich
+ igan, c=US
+member: cn=Ursula Hampster, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+associateddomain: umich.edu
+requeststo: cn=Manager, o=University of Michigan, c=US
+errorsto: cn=Manager, o=University of Michigan, c=US
+owner: cn=Manager, o=University of Michigan, c=US
+multilinedescription: All Alumni Assoc Staff
+cn: Alumni Assoc Staff
+joinable: FALSE
+objectclass: rfc822mailgroup
+
+dn: ou=Alumni Association, ou=People, o=University of Michigan, c=US
+objectclass: top
+objectclass: organizationalUnit
+objectclass: quipuObject
+objectclass: quipuNonLeafObject
+ou: Alumni Association
+
+dn: cn=Barbara Jensen, ou=Information Technology Division, ou=People, o=Univer
+ sity of Michigan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: Barbara Jensen
+cn: Babs Jensen
+sn: Jensen
+title: Mythical Manager, Research Systems
+postaladdress: ITD Prod Dev & Deployment $ 535 W. William St. Room 4212 $ Ann 
+ Arbor, MI 48103-4943
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: bjensen
+mail: bjensen@mailgw.umich.edu
+homepostaladdress: 123 Wesley $ Ann Arbor, MI 48103
+krbname: bjensen@umich.edu
+multilinedescription: Mythical manager of the rsdd unix project 
+nobatchupdates: TRUE
+notice: Off sailing this month.
+onvacation: FALSE
+labeledurl: http://www.umich.edu/ U-M Home Page
+drink: water
+lastmodifiedtime: 960404035839Z
+lastmodifiedby: cn=Barbara Jensen, ou=Information Technology Division, ou=Peop
+ le, o=University of Michigan, c=US
+homephone: +1 313 555 2333
+pager: +1 313 555 3233
+facsimiletelephonenumber: +1 313 555 2274
+telephonenumber: +1 313 555 9022
+
+dn: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, o=Universi
+ ty of Michigan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: Bjorn Jensen
+cn: Biiff Jensen
+sn: Jensen
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: bjorn
+krbname: jdoe@umich.edu
+nobatchupdates: TRUE
+onvacation: FALSE
+homepostaladdress: 19923 Seven Mile Rd. $ South Lyon, MI 49999
+drink: Iced Tea
+multilinedescription: Hiker, biker
+title: Director, Embedded Systems
+postaladdress: Info Tech Division $ 535 W. William St. $ Ann Arbor, MI 48103
+mail: bjorn@mailgw.umich.edu
+homephone: +1 313 555 5444
+pager: +1 313 555 4474
+facsimiletelephonenumber: +1 313 555 2177
+telephonenumber: +1 313 555 0355
+
+dn: ou=Groups, o=University of Michigan, c=US
+objectclass: top
+objectclass: organizationalUnit
+objectclass: quipuObject
+objectclass: quipuNonLeafObject
+ou: Groups
+lastmodifiedtime: 950120182331Z
+lastmodifiedby: cn=manager, o=university of michigan, c=US
+
+dn: ou=Information Technology Division, ou=People, o=University of Michigan, c
+ =US
+objectclass: top
+objectclass: organizationalUnit
+objectclass: quipuObject
+objectclass: quipuNonLeafObject
+ou: Information Technology Divisio
+
+dn: cn=ITD Staff,ou=Groups,o=University of Michigan,c=US
+associateddomain: umich.edu
+requeststo: cn=Manager, o=University of Michigan, c=US
+errorsto: cn=Manager, o=University of Michigan, c=US
+owner: cn=Manager, o=University of Michigan, c=US
+multilinedescription: All ITD Staff
+cn: ITD Staff
+joinable: FALSE
+objectclass: rfc822mailgroup
+member: cn=Manager, o=University of Michigan, c=US
+member: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, o=Univ
+ ersity of Michigan, c=US
+member: cn=James A Jones 2, ou=Information Technology Division, ou=People, o=U
+ niversity of Michigan, c=US
+member: cn=John Doe, ou=Information Technology Division, ou=People, o=Universi
+ ty of Michigan, c=US
+member: cn=James A Jones 1, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+labeledurl: http://www.itd.umich.edu ITD Home Page
+ University of Michigan,c=US
+telephonenumber: +1 810 555 1212
+
+dn: cn=James A Jones 2, ou=Information Technology Division, ou=People, o=Unive
+ rsity of Michigan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: James A Jones 2
+cn: James Jones
+cn: Jim Jones
+sn: Doe
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: jjones
+krbname: jdoe@umich.edu
+nobatchupdates: TRUE
+onvacation: FALSE
+homepostaladdress: 933 Brooks $ Ann Arbor, MI 48104
+homephone: +1 313 555 8838
+title: Senior Manager, Information Technology Division
+multilinedescription: Not around very much
+mail: jjones@mailgw.umich.edu
+postaladdress: Info Tech Division $ 535 W William $ Ann Arbor, MI 48103
+pager: +1 313 555 2833
+facsimiletelephonenumber: +1 313 555 8688
+telephonenumber: +1 313 555 7334
+
+dn: cn=John Doe, ou=Information Technology Division, ou=People, o=University o
+ f Michigan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: John Doe
+cn: Jonathon Doe
+sn: Doe
+postaladdress: ITD $ 535 W. William $ Ann Arbor, MI 48109
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: johnd
+krbname: johnd@umich.edu
+nobatchupdates: TRUE
+onvacation: FALSE
+homepostaladdress: 912 East Bllvd $ Ann Arbor, MI 48104
+title: System Administrator, Information Technology Division
+multilinedescription: overworked!
+mail: johnd@mailgw.umich.edu
+homephone: +1 313 555 3774
+pager: +1 313 555 6573
+facsimiletelephonenumber: +1 313 555 4544
+telephonenumber: +1 313 555 9394
+
+dn: cn=Manager, o=University of Michigan, c=US
+objectclass: top
+objectclass: person
+objectclass: quipuObject
+objectclass: kerberosSecurityObject
+cn: Manager
+cn: Directory Manager
+cn: Dir Man
+sn: Manager
+description: Manager of the directory
+lastmodifiedtime: 951212214144Z
+lastmodifiedby: cn=Manager, o=University of Michigan, c=US
+krbname: bjensen@umich.edu
+
+dn: ou=People, o=University of Michigan, c=US
+objectclass: top
+objectclass: organizationalUnit
+objectclass: quipuObject
+objectclass: quipuNonLeafObject
+ou: People
+
+dn: o=University of Michigan, c=US
+objectclass: top
+objectclass: organization
+objectclass: domainRelatedObject
+objectclass: quipuObject
+objectclass: quipuNonLeafObject
+l: Ann Arbor, Michigan
+st: Michigan
+streetaddress: 535 West William St.
+o: University of Michigan
+o: UMICH
+o: UM
+o: U-M
+o: U of M
+description: The University of Michigan at Ann Arbor
+postaladdress: University of Michigan $ 535 W. William St. $ Ann Arbor, MI 481
+ 09 $ USpostalcode: 48109
+telephonenumber: +1 313 764-1817
+lastmodifiedtime: 930106182800Z
+lastmodifiedby: cn=manager, o=university of michigan, c=US
+associateddomain: umich.edu
diff --git a/tests/data/modify.out.master b/tests/data/modify.out.master
new file mode 100644 (file)
index 0000000..7147534
--- /dev/null
@@ -0,0 +1,391 @@
+dn: cn=All Staff,ou=Groups,o=University of Michigan,c=US
+associateddomain: umich.edu
+requeststo: cn=Manager, o=University of Michigan, c=US
+errorsto: cn=Manager, o=University of Michigan, c=US
+owner: cn=Manager, o=University of Michigan, c=US
+cn: All Staff
+joinable: FALSE
+multilinedescription: Everyone in the sample data
+objectclass: rfc822mailgroup
+modifiersname: cn=Manager,o=University of Michigan,c=US
+
+dn: cn=Alumni Assoc Staff,ou=Groups,o=University of Michigan,c=US
+member: cn=Manager, o=University of Michigan, c=US
+member: cn=Dorothy Stevens, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=James A Jones 1, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=Jane Doe, ou=Alumni Association, ou=People, o=University of Michiga
+ n, c=US
+member: cn=Jennifer Smith, ou=Alumni Association, ou=People, o=University of M
+ ichigan, c=US
+member: cn=Mark Elliot, ou=Alumni Association, ou=People, o=University of Mich
+ igan, c=US
+member: cn=Ursula Hampster, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+associateddomain: umich.edu
+requeststo: cn=Manager, o=University of Michigan, c=US
+errorsto: cn=Manager, o=University of Michigan, c=US
+owner: cn=Manager, o=University of Michigan, c=US
+multilinedescription: All Alumni Assoc Staff
+cn: Alumni Assoc Staff
+joinable: FALSE
+objectclass: rfc822mailgroup
+
+dn: ou=Alumni Association, ou=People, o=University of Michigan, c=US
+objectclass: top
+objectclass: organizationalUnit
+objectclass: quipuObject
+objectclass: quipuNonLeafObject
+ou: Alumni Association
+
+dn: cn=Barbara Jensen, ou=Information Technology Division, ou=People, o=Univer
+ sity of Michigan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: Barbara Jensen
+cn: Babs Jensen
+sn: Jensen
+title: Mythical Manager, Research Systems
+postaladdress: ITD Prod Dev & Deployment $ 535 W. William St. Room 4212 $ Ann 
+ Arbor, MI 48103-4943
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: bjensen
+userpassword: bjensen
+mail: bjensen@mailgw.umich.edu
+homepostaladdress: 123 Wesley $ Ann Arbor, MI 48103
+krbname: bjensen@umich.edu
+multilinedescription: Mythical manager of the rsdd unix project 
+nobatchupdates: TRUE
+notice: Off sailing this month.
+onvacation: FALSE
+labeledurl: http://www.umich.edu/ U-M Home Page
+drink: water
+lastmodifiedtime: 960404035839Z
+lastmodifiedby: cn=Barbara Jensen, ou=Information Technology Division, ou=Peop
+ le, o=University of Michigan, c=US
+modifiersname: cn=Manager,o=University of Michigan,c=US
+homephone: +1 313 555 2333
+pager: +1 313 555 3233
+facsimiletelephonenumber: +1 313 555 2274
+telephonenumber: +1 313 555 9022
+
+dn: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, o=Universi
+ ty of Michigan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: Bjorn Jensen
+cn: Biiff Jensen
+sn: Jensen
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: bjorn
+userpassword: bjorn
+krbname: jdoe@umich.edu
+nobatchupdates: TRUE
+onvacation: FALSE
+homepostaladdress: 19923 Seven Mile Rd. $ South Lyon, MI 49999
+title: Director, Embedded Systems
+postaladdress: Info Tech Division $ 535 W. William St. $ Ann Arbor, MI 48103
+mail: bjorn@mailgw.umich.edu
+homephone: +1 313 555 5444
+pager: +1 313 555 4474
+facsimiletelephonenumber: +1 313 555 2177
+telephonenumber: +1 313 555 0355
+modifiersname: cn=Manager,o=University of Michigan,c=US
+multilinedescription: The replaced multiLineDescription $ Blah Woof.
+drink: Iced Tea
+drink: Mad Dog 20/20
+
+dn: cn=Dorothy Stevens, ou=Alumni Association, ou=People, o=University of Mich
+ igan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: Dorothy Stevens
+cn: Dot Stevens
+sn: Stevens
+title: Secretary, UM Alumni Association
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: dots
+krbname: jdoe@umich.edu
+nobatchupdates: TRUE
+onvacation: FALSE
+drink: Lemonade
+homepostaladdress: 377 White St. Apt. 3 $ Ann Arbor, MI 48104
+multilinedescription: Very tall
+facsimiletelephonenumber: +1 313 555 3223
+telephonenumber: +1 313 555 3664
+mail: dots@mail.alumni.umich.edu
+modifiersname: cn=Manager,o=University of Michigan,c=US
+homephone: +1 313 555 0454
+
+dn: cn=Gern Jensen, ou=Information Technology Division, ou=People, o=Universit
+ y of Michigan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: Gern Jensen
+title: Chief Investigator, ITD
+postaladdress: ITD $ 535 W. William St $ Ann Arbor, MI 48103
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: gjensen
+krbname: gjensen@umich.edu
+nobatchupdates: TRUE
+onvacation: FALSE
+drink: Coffee
+homepostaladdress: 844 Brown St. Apt. 4 $ Ann Arbor, MI 48104
+multilinedescription: Very odd
+facsimiletelephonenumber: +1 313 555 7557
+telephonenumber: +1 313 555 8343
+mail: gjensen@mailgw.umich.edu
+homephone: +1 313 555 8844
+creatorsname: cn=Manager,o=University of Michigan,c=US
+
+dn: ou=Groups, o=University of Michigan, c=US
+objectclass: top
+objectclass: organizationalUnit
+objectclass: quipuObject
+objectclass: quipuNonLeafObject
+ou: Groups
+lastmodifiedtime: 950120182331Z
+lastmodifiedby: cn=manager, o=university of michigan, c=US
+
+dn: ou=Information Technology Division, ou=People, o=University of Michigan, c
+ =US
+objectclass: top
+objectclass: organizationalUnit
+objectclass: quipuObject
+objectclass: quipuNonLeafObject
+ou: Information Technology Divisio
+
+dn: cn=ITD Staff,ou=Groups,o=University of Michigan,c=US
+associateddomain: umich.edu
+requeststo: cn=Manager, o=University of Michigan, c=US
+errorsto: cn=Manager, o=University of Michigan, c=US
+owner: cn=Manager, o=University of Michigan, c=US
+multilinedescription: All ITD Staff
+cn: ITD Staff
+joinable: FALSE
+objectclass: rfc822mailgroup
+member: cn=Manager, o=University of Michigan, c=US
+member: cn=John Doe, ou=Information Technology Division, ou=People, o=Universi
+ ty of Michigan, c=US
+member: cn=Dorothy Stevens, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=James A Jones 1, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+labeledurl: http://www.itd.umich.edu ITD Home Page
+modifiersname: cn=Manager,o=University of Michigan,c=US
+
+dn: cn=James A Jones 1, ou=Alumni Association, ou=People, o=University of Mich
+ igan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: James A Jones 1
+cn: James Jones
+cn: Jim Jones
+sn: Jones
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: jaj
+krbname: jaj@umich.edu
+userpassword: jaj
+nobatchupdates: TRUE
+onvacation: FALSE
+homepostaladdress: 3882 Beverly Rd. $ Ann Arbor, MI 48105
+homephone: +1 313 555 4772
+multilinedescription: Outstanding
+title: Mad Cow Researcher, UM Alumni Association
+pager: +1 313 555 3923
+mail: jaj@mail.alumni.umich.edu
+facsimiletelephonenumber: +1 313 555 4332
+telephonenumber: +1 313 555 0895
+modifiersname: cn=Manager,o=University of Michigan,c=US
+drink: Orange Juice
+
+dn: cn=Jane Doe, ou=Alumni Association, ou=People, o=University of Michigan, c
+ =US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: Jane Doe
+cn: Jane Alverson
+sn: Doe
+title: Programmer Analyst, UM Alumni Association
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: jdoe
+homepostaladdress: 123 Anystreet $ Ann Arbor, MI 48104
+krbname: jdoe@umich.edu
+nobatchupdates: TRUE
+onvacation: FALSE
+drink: diet coke
+multilinedescription: Enthusiastic
+mail: jdoe@woof.net
+modifiersname: cn=Manager,o=University of Michigan,c=US
+homephone: +1 313 555 5445
+pager: +1 313 555 1220
+facsimiletelephonenumber: +1 313 555 2311
+telephonenumber: +1 313 555 4774
+
+dn: cn=Jennifer Smith, ou=Alumni Association, ou=People, o=University of Michi
+ gan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: Jennifer Smith
+cn: Jen Smith
+sn: Smith
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: jen
+krbname: jdoe@umich.edu
+nobatchupdates: TRUE
+onvacation: FALSE
+drink: Sam Adams
+homepostaladdress: 1000 Maple #44 $ Ann Arbor, MI 48103
+title: Telemarketer, UM Alumni Association
+mail: jen@mail.alumni.umich.edu
+modifiersname: cn=Manager,o=University of Michigan,c=US
+homephone: +1 313 555 2333
+pager: +1 313 555 6442
+facsimiletelephonenumber: +1 313 555 2756
+telephonenumber: +1 313 555 8232
+
+dn: cn=John Doe, ou=Information Technology Division, ou=People, o=University o
+ f Michigan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: John Doe
+cn: Jonathon Doe
+sn: Doe
+postaladdress: ITD $ 535 W. William $ Ann Arbor, MI 48109
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: johnd
+krbname: johnd@umich.edu
+nobatchupdates: TRUE
+onvacation: FALSE
+homepostaladdress: 912 East Bllvd $ Ann Arbor, MI 48104
+title: System Administrator, Information Technology Division
+multilinedescription: overworked!
+mail: johnd@mailgw.umich.edu
+modifiersname: cn=Manager,o=University of Michigan,c=US
+homephone: +1 313 555 3774
+pager: +1 313 555 6573
+facsimiletelephonenumber: +1 313 555 4544
+telephonenumber: +1 313 555 9394
+
+dn: cn=Manager, o=University of Michigan, c=US
+objectclass: top
+objectclass: person
+objectclass: quipuObject
+objectclass: kerberosSecurityObject
+cn: Manager
+cn: Directory Manager
+cn: Dir Man
+sn: Manager
+description: Manager of the directory
+userpassword: secret
+lastmodifiedtime: 951212214144Z
+lastmodifiedby: cn=Manager, o=University of Michigan, c=US
+krbname: bjensen@umich.edu
+
+dn: cn=Mark Elliot, ou=Alumni Association, ou=People, o=University of Michigan
+ , c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: Mark Elliot
+cn: Mark A Elliot
+sn: Elliot
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: melliot
+krbname: jdoe@umich.edu
+nobatchupdates: TRUE
+onvacation: FALSE
+homepostaladdress: 199 Outer Drive $ Ypsilanti, MI 48198
+homephone: +1 313 555 0388
+drink: Gasoline
+title: Director, UM Alumni Association
+mail: melliot@mail.alumni.umich.edu
+modifiersname: cn=Manager,o=University of Michigan,c=US
+pager: +1 313 555 7671
+facsimiletelephonenumber: +1 313 555 7762
+telephonenumber: +1 313 555 4177
+
+dn: ou=People, o=University of Michigan, c=US
+objectclass: top
+objectclass: organizationalUnit
+objectclass: quipuObject
+objectclass: quipuNonLeafObject
+ou: People
+
+dn: o=University of Michigan, c=US
+objectclass: top
+objectclass: organization
+objectclass: domainRelatedObject
+objectclass: quipuObject
+objectclass: quipuNonLeafObject
+l: Ann Arbor, Michigan
+st: Michigan
+streetaddress: 535 West William St.
+o: University of Michigan
+o: UMICH
+o: UM
+o: U-M
+o: U of M
+description: The University of Michigan at Ann Arbor
+postaladdress: University of Michigan $ 535 W. William St. $ Ann Arbor, MI 481
+ 09 $ USpostalcode: 48109
+telephonenumber: +1 313 764-1817
+lastmodifiedtime: 930106182800Z
+lastmodifiedby: cn=manager, o=university of michigan, c=US
+associateddomain: umich.edu
+
+dn: cn=Ursula Hampster, ou=Alumni Association, ou=People, o=University of Mich
+ igan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: Ursula Hampster
+sn: Hampster
+title: Secretary, UM Alumni Association
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: uham
+homepostaladdress: 123 Anystreet $ Ann Arbor, MI 48104
+krbname: jdoe@umich.edu
+nobatchupdates: TRUE
+onvacation: FALSE
+mail: uham@mail.alumni.umich.edu
+modifiersname: cn=Manager,o=University of Michigan,c=US
+homephone: +1 313 555 8421
+pager: +1 313 555 2844
+facsimiletelephonenumber: +1 313 555 9700
+telephonenumber: +1 313 555 5331
diff --git a/tests/data/search.out.master b/tests/data/search.out.master
new file mode 100644 (file)
index 0000000..52619e9
--- /dev/null
@@ -0,0 +1,343 @@
+dn: cn=Barbara Jensen, ou=Information Technology Division, ou=People, o=Univer
+ sity of Michigan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: Barbara Jensen
+cn: Babs Jensen
+sn: Jensen
+title: Mythical Manager, Research Systems
+postaladdress: ITD Prod Dev & Deployment $ 535 W. William St. Room 4212 $ Ann 
+ Arbor, MI 48103-4943
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: bjensen
+userpassword: bjensen
+mail: bjensen@mailgw.umich.edu
+homepostaladdress: 123 Wesley $ Ann Arbor, MI 48103
+krbname: bjensen@umich.edu
+multilinedescription: Mythical manager of the rsdd unix project 
+nobatchupdates: TRUE
+notice: Off sailing this month.
+onvacation: FALSE
+labeledurl: http://www.umich.edu/ U-M Home Page
+drink: water
+lastmodifiedtime: 960404035839Z
+lastmodifiedby: cn=Barbara Jensen, ou=Information Technology Division, ou=Peop
+ le, o=University of Michigan, c=US
+modifytimestamp: 960404171405Z
+modifiersname: cn=Manager,o=University of Michigan,c=US
+homephone: +1 313 555 2333
+pager: +1 313 555 3233
+facsimiletelephonenumber: +1 313 555 2274
+telephonenumber: +1 313 555 9022
+
+dn: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, o=Universi
+ ty of Michigan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: Bjorn Jensen
+cn: Biiff Jensen
+sn: Jensen
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: bjorn
+userpassword: bjorn
+krbname: jdoe@umich.edu
+nobatchupdates: TRUE
+onvacation: FALSE
+homepostaladdress: 19923 Seven Mile Rd. $ South Lyon, MI 49999
+drink: Iced Tea
+multilinedescription: Hiker, biker
+title: Director, Embedded Systems
+postaladdress: Info Tech Division $ 535 W. William St. $ Ann Arbor, MI 48103
+mail: bjorn@mailgw.umich.edu
+modifytimestamp: 960404171424Z
+modifiersname: cn=Manager,o=University of Michigan,c=US
+homephone: +1 313 555 5444
+pager: +1 313 555 4474
+facsimiletelephonenumber: +1 313 555 2177
+telephonenumber: +1 313 555 0355
+dn: cn=All Staff,ou=Groups,o=University of Michigan,c=US
+member: cn=Manager, o=University of Michigan, c=US
+member: cn=Barbara Jensen, ou=Information Technology Division, ou=People, o=Un
+ iversity of Michigan, c=US
+member: cn=Jane Doe, ou=Alumni Association, ou=People, o=University of Michiga
+ n, c=US
+member: cn=John Doe, ou=Information Technology Division, ou=People, o=Universi
+ ty of Michigan, c=US
+member: cn=Mark Elliot, ou=Alumni Association, ou=People, o=University of Mich
+ igan, c=US
+member: cn=James A Jones 1, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=James A Jones 2, ou=Information Technology Division, ou=People, o=U
+ niversity of Michigan, c=US
+member: cn=Jennifer Smith, ou=Alumni Association, ou=People, o=University of M
+ ichigan, c=US
+member: cn=Dorothy Stevens, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=Ursula Hampster, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, o=Univ
+ ersity of Michigan, c=US
+associateddomain: umich.edu
+requeststo: cn=Manager, o=University of Michigan, c=US
+errorsto: cn=Manager, o=University of Michigan, c=US
+owner: cn=Manager, o=University of Michigan, c=US
+cn: All Staff
+joinable: FALSE
+multilinedescription: Everyone in the sample data
+objectclass: rfc822mailgroup
+
+dn: cn=Alumni Assoc Staff,ou=Groups,o=University of Michigan,c=US
+member: cn=Manager, o=University of Michigan, c=US
+member: cn=Dorothy Stevens, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=James A Jones 1, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=Jane Doe, ou=Alumni Association, ou=People, o=University of Michiga
+ n, c=US
+member: cn=Jennifer Smith, ou=Alumni Association, ou=People, o=University of M
+ ichigan, c=US
+member: cn=Mark Elliot, ou=Alumni Association, ou=People, o=University of Mich
+ igan, c=US
+member: cn=Ursula Hampster, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+associateddomain: umich.edu
+requeststo: cn=Manager, o=University of Michigan, c=US
+errorsto: cn=Manager, o=University of Michigan, c=US
+owner: cn=Manager, o=University of Michigan, c=US
+multilinedescription: All Alumni Assoc Staff
+cn: Alumni Assoc Staff
+joinable: FALSE
+objectclass: rfc822mailgroup
+
+dn: cn=ITD Staff,ou=Groups,o=University of Michigan,c=US
+associateddomain: umich.edu
+requeststo: cn=Manager, o=University of Michigan, c=US
+errorsto: cn=Manager, o=University of Michigan, c=US
+owner: cn=Manager, o=University of Michigan, c=US
+multilinedescription: All ITD Staff
+cn: ITD Staff
+joinable: FALSE
+objectclass: rfc822mailgroup
+member: cn=Manager, o=University of Michigan, c=US
+member: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, o=Univ
+ ersity of Michigan, c=US
+member: cn=James A Jones 2, ou=Information Technology Division, ou=People, o=U
+ niversity of Michigan, c=US
+member: cn=John Doe, ou=Information Technology Division, ou=People, o=Universi
+ ty of Michigan, c=US
+modifytimestamp: 960404171730Z
+modifiersname: cn=Manager,o=University of Michigan,c=US
+labeledurl: http://www.itd.umich.edu ITD Home Page
+
+dn: cn=James A Jones 1, ou=Alumni Association, ou=People, o=University of Mich
+ igan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: James A Jones 1
+cn: James Jones
+cn: Jim Jones
+sn: Jones
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: jaj
+krbname: jaj@umich.edu
+userpassword: jaj
+nobatchupdates: TRUE
+onvacation: FALSE
+homepostaladdress: 3882 Beverly Rd. $ Ann Arbor, MI 48105
+homephone: +1 313 555 4772
+multilinedescription: Outstanding
+title: Mad Cow Researcher, UM Alumni Association
+pager: +1 313 555 3923
+mail: jaj@mail.alumni.umich.edu
+modifytimestamp: 960404171231Z
+modifiersname: cn=Manager,o=University of Michigan,c=US
+facsimiletelephonenumber: +1 313 555 4332
+telephonenumber: +1 313 555 0895
+dn: cn=All Staff,ou=Groups,o=University of Michigan,c=US
+member: cn=Manager, o=University of Michigan, c=US
+member: cn=Barbara Jensen, ou=Information Technology Division, ou=People, o=Un
+ iversity of Michigan, c=US
+member: cn=Jane Doe, ou=Alumni Association, ou=People, o=University of Michiga
+ n, c=US
+member: cn=John Doe, ou=Information Technology Division, ou=People, o=Universi
+ ty of Michigan, c=US
+member: cn=Mark Elliot, ou=Alumni Association, ou=People, o=University of Mich
+ igan, c=US
+member: cn=James A Jones 1, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=James A Jones 2, ou=Information Technology Division, ou=People, o=U
+ niversity of Michigan, c=US
+member: cn=Jennifer Smith, ou=Alumni Association, ou=People, o=University of M
+ ichigan, c=US
+member: cn=Dorothy Stevens, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=Ursula Hampster, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, o=Univ
+ ersity of Michigan, c=US
+associateddomain: umich.edu
+requeststo: cn=Manager, o=University of Michigan, c=US
+errorsto: cn=Manager, o=University of Michigan, c=US
+owner: cn=Manager, o=University of Michigan, c=US
+cn: All Staff
+joinable: FALSE
+multilinedescription: Everyone in the sample data
+objectclass: rfc822mailgroup
+
+dn: cn=Alumni Assoc Staff,ou=Groups,o=University of Michigan,c=US
+member: cn=Manager, o=University of Michigan, c=US
+member: cn=Dorothy Stevens, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=James A Jones 1, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=Jane Doe, ou=Alumni Association, ou=People, o=University of Michiga
+ n, c=US
+member: cn=Jennifer Smith, ou=Alumni Association, ou=People, o=University of M
+ ichigan, c=US
+member: cn=Mark Elliot, ou=Alumni Association, ou=People, o=University of Mich
+ igan, c=US
+member: cn=Ursula Hampster, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+associateddomain: umich.edu
+requeststo: cn=Manager, o=University of Michigan, c=US
+errorsto: cn=Manager, o=University of Michigan, c=US
+owner: cn=Manager, o=University of Michigan, c=US
+multilinedescription: All Alumni Assoc Staff
+cn: Alumni Assoc Staff
+joinable: FALSE
+objectclass: rfc822mailgroup
+dn: cn=All Staff,ou=Groups,o=University of Michigan,c=US
+member: cn=Manager, o=University of Michigan, c=US
+member: cn=Barbara Jensen, ou=Information Technology Division, ou=People, o=Un
+ iversity of Michigan, c=US
+member: cn=Jane Doe, ou=Alumni Association, ou=People, o=University of Michiga
+ n, c=US
+member: cn=John Doe, ou=Information Technology Division, ou=People, o=Universi
+ ty of Michigan, c=US
+member: cn=Mark Elliot, ou=Alumni Association, ou=People, o=University of Mich
+ igan, c=US
+member: cn=James A Jones 1, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=James A Jones 2, ou=Information Technology Division, ou=People, o=U
+ niversity of Michigan, c=US
+member: cn=Jennifer Smith, ou=Alumni Association, ou=People, o=University of M
+ ichigan, c=US
+member: cn=Dorothy Stevens, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=Ursula Hampster, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, o=Univ
+ ersity of Michigan, c=US
+associateddomain: umich.edu
+requeststo: cn=Manager, o=University of Michigan, c=US
+errorsto: cn=Manager, o=University of Michigan, c=US
+owner: cn=Manager, o=University of Michigan, c=US
+cn: All Staff
+joinable: FALSE
+multilinedescription: Everyone in the sample data
+objectclass: rfc822mailgroup
+
+dn: cn=Alumni Assoc Staff,ou=Groups,o=University of Michigan,c=US
+member: cn=Manager, o=University of Michigan, c=US
+member: cn=Dorothy Stevens, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=James A Jones 1, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=Jane Doe, ou=Alumni Association, ou=People, o=University of Michiga
+ n, c=US
+member: cn=Jennifer Smith, ou=Alumni Association, ou=People, o=University of M
+ ichigan, c=US
+member: cn=Mark Elliot, ou=Alumni Association, ou=People, o=University of Mich
+ igan, c=US
+member: cn=Ursula Hampster, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+associateddomain: umich.edu
+requeststo: cn=Manager, o=University of Michigan, c=US
+errorsto: cn=Manager, o=University of Michigan, c=US
+owner: cn=Manager, o=University of Michigan, c=US
+multilinedescription: All Alumni Assoc Staff
+cn: Alumni Assoc Staff
+joinable: FALSE
+objectclass: rfc822mailgroup
+
+dn: ou=Alumni Association, ou=People, o=University of Michigan, c=US
+objectclass: top
+objectclass: organizationalUnit
+objectclass: quipuObject
+objectclass: quipuNonLeafObject
+ou: Alumni Association
+
+dn: ou=Groups, o=University of Michigan, c=US
+objectclass: top
+objectclass: organizationalUnit
+objectclass: quipuObject
+objectclass: quipuNonLeafObject
+ou: Groups
+lastmodifiedtime: 950120182331Z
+lastmodifiedby: cn=manager, o=university of michigan, c=US
+
+dn: ou=Information Technology Division, ou=People, o=University of Michigan, c
+ =US
+objectclass: top
+objectclass: organizationalUnit
+objectclass: quipuObject
+objectclass: quipuNonLeafObject
+ou: Information Technology Divisio
+
+dn: cn=ITD Staff,ou=Groups,o=University of Michigan,c=US
+associateddomain: umich.edu
+requeststo: cn=Manager, o=University of Michigan, c=US
+errorsto: cn=Manager, o=University of Michigan, c=US
+owner: cn=Manager, o=University of Michigan, c=US
+multilinedescription: All ITD Staff
+cn: ITD Staff
+joinable: FALSE
+objectclass: rfc822mailgroup
+member: cn=Manager, o=University of Michigan, c=US
+member: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, o=Univ
+ ersity of Michigan, c=US
+member: cn=James A Jones 2, ou=Information Technology Division, ou=People, o=U
+ niversity of Michigan, c=US
+member: cn=John Doe, ou=Information Technology Division, ou=People, o=Universi
+ ty of Michigan, c=US
+modifiersname: cn=Manager,o=University of Michigan,c=US
+labeledurl: http://www.itd.umich.edu ITD Home Page
+
+dn: ou=People, o=University of Michigan, c=US
+objectclass: top
+objectclass: organizationalUnit
+objectclass: quipuObject
+objectclass: quipuNonLeafObject
+ou: People
+
+dn: o=University of Michigan, c=US
+objectclass: top
+objectclass: organization
+objectclass: domainRelatedObject
+objectclass: quipuObject
+objectclass: quipuNonLeafObject
+l: Ann Arbor, Michigan
+st: Michigan
+streetaddress: 535 West William St.
+o: University of Michigan
+o: UMICH
+o: UM
+o: U-M
+o: U of M
+description: The University of Michigan at Ann Arbor
+postaladdress: University of Michigan $ 535 W. William St. $ Ann Arbor, MI 481
+ 09 $ USpostalcode: 48109
+telephonenumber: +1 313 764-1817
+lastmodifiedtime: 930106182800Z
+lastmodifiedby: cn=manager, o=university of michigan, c=US
+associateddomain: umich.edu
diff --git a/tests/data/slapd-acl.conf b/tests/data/slapd-acl.conf
new file mode 100644 (file)
index 0000000..5e56dea
--- /dev/null
@@ -0,0 +1,36 @@
+#
+# master slapd config -- for testing
+#
+include                ./data/slapd.at.conf
+include                ./data/slapd.oc.conf
+schemacheck    off
+
+#######################################################################
+# ldbm database definitions
+#######################################################################
+
+database       ldbm
+suffix         "o=University of Michigan, c=US"
+directory      ./test-db
+rootdn         "cn=Manager, o=University of Michigan, c=US"
+rootpw         secret
+index          cn,sn,uid       pres,eq,approx
+index          default         none
+lastmod                on
+defaultaccess  none
+access         to attr=objectclass
+               by * read
+access         to attr=userpassword
+               by self write
+               by * compare
+access         to dn=".*,ou=Alumni Association,ou=People,o=University of Michigan,c=US"
+               by dn=".*,o=University of Michigan,c=US"
+               read
+               by * none
+access         to attr=member
+               by dnattr=member selfwrite
+               by * read
+access         to filter="objectclass=rfc822mailgroup"
+               by dn="Bjorn Jensen,ou=Information Technology Division,ou=People,o=University of Michigan,c=US" write
+               by * read
+access         to * by * read
diff --git a/tests/data/slapd-master.conf b/tests/data/slapd-master.conf
new file mode 100644 (file)
index 0000000..2b936ab
--- /dev/null
@@ -0,0 +1,19 @@
+#
+# master slapd config -- for testing
+#
+include                ./data/slapd.at.conf
+include                ./data/slapd.oc.conf
+schemacheck    off
+
+#######################################################################
+# ldbm database definitions
+#######################################################################
+
+database       ldbm
+suffix         "o=University of Michigan, c=US"
+directory      ./test-db
+rootdn         "cn=Manager, o=University of Michigan, c=US"
+rootpw         secret
+index          cn,sn,uid       pres,eq,approx
+index          default         none
+lastmod                on
diff --git a/tests/data/slapd-repl-master.conf b/tests/data/slapd-repl-master.conf
new file mode 100644 (file)
index 0000000..bce1d68
--- /dev/null
@@ -0,0 +1,26 @@
+#
+# master slapd config -- for testing of replication
+#
+include                ./data/slapd.at.conf
+include                ./data/slapd.oc.conf
+schemacheck    off
+
+#######################################################################
+# ldbm database definitions
+#######################################################################
+
+database       ldbm
+suffix         "o=University of Michigan, c=US"
+directory      ./test-db
+rootdn         "cn=Manager, o=University of Michigan, c=US"
+rootpw         secret
+index          cn,sn,uid       pres,eq,approx
+index          default         none
+lastmod                on
+
+replogfile     ./test-db/slapd.replog
+
+replica                host=localhost:9010
+               binddn="cn=Manager, o=University of Michigan, c=US"
+               bindmethod=simple
+               credentials=secret
diff --git a/tests/data/slapd-repl-slave.conf b/tests/data/slapd-repl-slave.conf
new file mode 100644 (file)
index 0000000..ca81b76
--- /dev/null
@@ -0,0 +1,20 @@
+#
+# master slapd config -- for testing of replication
+#
+include                ./data/slapd.at.conf
+include                ./data/slapd.oc.conf
+schemacheck    off
+
+#######################################################################
+# ldbm database definitions
+#######################################################################
+
+database       ldbm
+suffix         "o=University of Michigan, c=US"
+directory      ./test-repl
+rootdn         "cn=Manager, o=University of Michigan, c=US"
+rootpw         secret
+updatedn       "cn=Manager, o=University of Michigan, c=US"
+index          cn,sn,uid       pres,eq,approx
+index          default         none
+lastmod                on
diff --git a/tests/data/slapd.at.conf b/tests/data/slapd.at.conf
new file mode 100644 (file)
index 0000000..c3c8b13
--- /dev/null
@@ -0,0 +1,23 @@
+attribute      photo                                   bin
+attribute      personalsignature                       bin
+attribute      jpegphoto                               bin
+attribute      audio                                   bin
+attribute      labeledurl                              ces
+attribute      userpassword                            ces
+attribute      telephonenumber                         tel
+attribute      facsimiletelephonenumber        fax     tel
+attribute      pagertelephonenumber            pager   tel
+attribute      homephone                               tel
+attribute      mobiletelephonenumber           mobile  tel
+attribute      aliasedObjectName                       dn
+attribute      member                                  dn
+attribute      owner                                   dn
+attribute      seealso                                 dn
+attribute      manager                                 dn
+attribute      documentauthor                          dn
+attribute      secretary                               dn
+attribute      lastmodifiedby                          dn
+attribute      associatedname                          dn
+attribute      naminglink                              dn
+attribute      reciprocalnaminglink                    dn
+attribute      dn                                      dn
diff --git a/tests/data/slapd.oc.conf b/tests/data/slapd.oc.conf
new file mode 100644 (file)
index 0000000..94f2349
--- /dev/null
@@ -0,0 +1,903 @@
+objectclass top
+       requires
+               objectClass
+
+objectclass alias
+       requires
+               aliasedObjectName,
+               objectClass
+
+objectclass country
+       requires
+               objectClass,
+               c
+       allows
+               searchGuide,
+               description
+
+objectclass locality
+       requires
+               objectClass
+       allows
+               description,
+               l,
+               searchGuide,
+               seeAlso,
+               st,
+               streetAddress
+
+objectclass organization
+       requires
+               objectClass,
+               o
+       allows
+               businessCategory,
+               description,
+               destinationIndicator,
+               facsimileTelephoneNumber,
+               internationaliSDNNumber,
+               l,
+               physicalDeliveryOfficeName,
+               postOfficeBox,
+               postalAddress,
+               postalCode,
+               preferredDeliveryMethod,
+               registeredAddress,
+               searchGuide,
+               seeAlso,
+               st,
+               streetAddress,
+               telephoneNumber,
+               teletexTerminalIdentifier,
+               telexNumber,
+               userPassword,
+               x121Address
+
+objectclass organizationalUnit
+       requires
+               objectClass,
+               ou
+       allows
+               businessCategory,
+               description,
+               destinationIndicator,
+               facsimileTelephoneNumber,
+               internationaliSDNNumber,
+               l,
+               physicalDeliveryOfficeName,
+               postOfficeBox,
+               postalAddress,
+               postalCode,
+               preferredDeliveryMethod,
+               registeredAddress,
+               searchGuide,
+               seeAlso,
+               st,
+               streetAddress,
+               telephoneNumber,
+               teletexTerminalIdentifier,
+               telexNumber,
+               userPassword,
+               x121Address
+
+objectclass person
+       requires
+               objectClass,
+               sn,
+               cn
+       allows
+               description,
+               seeAlso,
+               telephoneNumber,
+               userPassword
+
+objectclass organizationalPerson
+       requires
+               objectClass,
+               sn,
+               cn
+       allows
+               description,
+               destinationIndicator,
+               facsimileTelephoneNumber,
+               internationaliSDNNumber,
+               l,
+               ou,
+               physicalDeliveryOfficeName,
+               postOfficeBox,
+               postalAddress,
+               postalCode,
+               preferredDeliveryMethod,
+               registeredAddress,
+               seeAlso,
+               st,
+               streetAddress,
+               telephoneNumber,
+               teletexTerminalIdentifier,
+               telexNumber,
+               title,
+               userPassword,
+               x121Address
+
+objectclass organizationalRole
+       requires
+               objectClass,
+               cn
+       allows
+               description,
+               destinationIndicator,
+               facsimileTelephoneNumber,
+               internationaliSDNNumber,
+               l,
+               ou,
+               physicalDeliveryOfficeName,
+               postOfficeBox,
+               postalAddress,
+               postalCode,
+               preferredDeliveryMethod,
+               registeredAddress,
+               roleOccupant,
+               seeAlso,
+               st,
+               streetAddress,
+               telephoneNumber,
+               teletexTerminalIdentifier,
+               telexNumber,
+               x121Address
+
+objectclass groupOfNames
+       requires
+               objectClass,
+               member,
+               cn
+       allows
+               businessCategory,
+               description,
+               o,
+               ou,
+               owner,
+               seeAlso
+
+objectclass residentialPerson
+       requires
+               objectClass,
+               sn,
+               cn,
+               l
+       allows
+               businessCategory,
+               description,
+               destinationIndicator,
+               facsimileTelephoneNumber,
+               internationaliSDNNumber,
+               l,
+               physicalDeliveryOfficeName,
+               postOfficeBox,
+               postalAddress,
+               postalCode,
+               preferredDeliveryMethod,
+               registeredAddress,
+               seeAlso,
+               st,
+               streetAddress,
+               telephoneNumber,
+               teletexTerminalIdentifier,
+               telexNumber,
+               userPassword,
+               x121Address
+
+objectclass applicationProcess
+       requires
+               objectClass,
+               cn
+       allows
+               description,
+               l,
+               ou,
+               seeAlso
+
+objectclass applicationEntity
+       requires
+               objectClass,
+               presentationAddress,
+               cn
+       allows
+               description,
+               l,
+               o,
+               ou,
+               seeAlso,
+               supportedApplicationContext
+
+objectclass dSA
+       requires
+               objectClass,
+               presentationAddress,
+               cn
+       allows
+               knowledgeInformation
+
+objectclass device
+       requires
+               objectClass,
+               cn
+       allows
+               description,
+               l,
+               o,
+               ou,
+               owner,
+               seeAlso,
+               serialNumber
+
+objectclass strongAuthenticationUser
+       requires
+               objectClass,
+               userCertificate
+
+objectclass certificationAuthority
+       requires
+               objectClass,
+               authorityRevocationList,
+               certificateRevocationList,
+               cACertificate
+       allows
+               crossCertificatePair
+
+objectclass pilotObject
+       requires
+               objectClass
+       allows
+               audio,
+               dITRedirect,
+               info,
+               jpegPhoto,
+               lastModifiedBy,
+               lastModifiedTime,
+               manager,
+               photo,
+               uniqueIdentifier
+
+objectclass newPilotPerson
+       requires
+               objectClass,
+               sn,
+               cn
+       allows
+               businessCategory,
+               description,
+               drink,
+               homePhone,
+               homePostalAddress,
+               janetMailbox,
+               mail,
+               mailPreferenceOption,
+               mobile,
+               organizationalStatus,
+               otherMailbox,
+               pager,
+               personalSignature,
+               personalTitle,
+               preferredDeliveryMethod,
+               roomNumber,
+               secretary,
+               seeAlso,
+               telephoneNumber,
+               textEncodedORaddress,
+               uid,
+               userClass,
+               userPassword
+
+objectclass account
+       requires
+               objectClass,
+               uid
+       allows
+               description,
+               host,
+               l,
+               o,
+               ou,
+               seeAlso
+
+objectclass document
+       requires
+               objectClass,
+               documentIdentifier
+       allows
+               abstract,
+               audio,
+               authorCN,
+               authorSN,
+               cn,
+               dITRedirect,
+               description,
+               documentAuthor,
+               documentLocation,
+               documentPublisher,
+               documentStore,
+               documentTitle,
+               documentVersion,
+               info,
+               jpegPhoto,
+               keywords,
+               l,
+               lastModifiedBy,
+               lastModifiedTime,
+               manager,
+               o,
+               obsoletedByDocument,
+               obsoletesDocument,
+               ou,
+               photo,
+               seeAlso,
+               subject,
+               uniqueIdentifier,
+               updatedByDocument,
+               updatesDocument
+
+objectclass room
+       requires
+               objectClass,
+               cn
+       allows
+               description,
+               roomNumber,
+               seeAlso,
+               telephoneNumber
+
+objectclass documentSeries
+       requires
+               objectClass,
+               cn
+       allows
+               description,
+               l,
+               o,
+               ou,
+               seeAlso,
+               telephoneNumber
+
+objectclass domain
+       requires
+               objectClass,
+               dc
+       allows
+               associatedName,
+               businessCategory,
+               description,
+               destinationIndicator,
+               facsimileTelephoneNumber,
+               internationaliSDNNumber,
+               l,
+               o,
+               physicalDeliveryOfficeName,
+               postOfficeBox,
+               postalAddress,
+               postalCode,
+               preferredDeliveryMethod,
+               registeredAddress,
+               searchGuide,
+               seeAlso,
+               st,
+               streetAddress,
+               telephoneNumber,
+               teletexTerminalIdentifier,
+               telexNumber,
+               userPassword,
+               x121Address
+
+objectclass rFC822localPart
+       requires
+               objectClass,
+               dc
+       allows
+               associatedName,
+               businessCategory,
+               cn,
+               description,
+               destinationIndicator,
+               facsimileTelephoneNumber,
+               internationaliSDNNumber,
+               l,
+               o,
+               physicalDeliveryOfficeName,
+               postOfficeBox,
+               postalAddress,
+               postalCode,
+               preferredDeliveryMethod,
+               registeredAddress,
+               searchGuide,
+               seeAlso,
+               sn,
+               st,
+               streetAddress,
+               telephoneNumber,
+               teletexTerminalIdentifier,
+               telexNumber,
+               userPassword,
+               x121Address
+
+objectclass dNSDomain
+       requires
+               objectClass,
+               dc
+       allows
+               associatedName,
+               businessCategory,
+               dNSRecord,
+               description,
+               destinationIndicator,
+               facsimileTelephoneNumber,
+               internationaliSDNNumber,
+               l,
+               o,
+               physicalDeliveryOfficeName,
+               postOfficeBox,
+               postalAddress,
+               postalCode,
+               preferredDeliveryMethod,
+               registeredAddress,
+               searchGuide,
+               seeAlso,
+               st,
+               streetAddress,
+               telephoneNumber,
+               teletexTerminalIdentifier,
+               telexNumber,
+               userPassword,
+               x121Address
+
+objectclass domainRelatedObject
+       requires
+               objectClass,
+               associatedDomain
+
+objectclass friendlyCountry
+       requires
+               objectClass,
+               c,
+               co
+       allows
+               description,
+               searchGuide
+
+objectclass simpleSecurityObject
+       requires
+               objectClass,
+               userPassword
+
+objectclass pilotOrganization
+       requires
+               objectClass,
+               ou,
+               o
+       allows
+               buildingName,
+               businessCategory,
+               description,
+               destinationIndicator,
+               facsimileTelephoneNumber,
+               internationaliSDNNumber,
+               l,
+               physicalDeliveryOfficeName,
+               postOfficeBox,
+               postalAddress,
+               postalCode,
+               preferredDeliveryMethod,
+               registeredAddress,
+               searchGuide,
+               seeAlso,
+               st,
+               streetAddress,
+               telephoneNumber,
+               teletexTerminalIdentifier,
+               telexNumber,
+               userPassword,
+               x121Address
+
+objectclass nadfObject
+       requires
+               objectClass
+       allows
+               lastModifiedTime,
+               nadfSearchGuide,
+               supplementaryInformation
+
+objectclass usStateOrEquivalent
+       requires
+               objectClass,
+               st,
+               fipsStateAlphaCode,
+               fipsStateNumericCode,
+               l
+       allows
+               description,
+               lastModifiedTime,
+               nadfSearchGuide,
+               searchGuide,
+               seeAlso,
+               streetAddress,
+               supplementaryInformation
+
+objectclass usPlace
+       requires
+               objectClass,
+               fips55,
+               l
+       allows
+               description,
+               lastModifiedTime,
+               nadfSearchGuide,
+               searchGuide,
+               seeAlso,
+               st,
+               streetAddress,
+               supplementaryInformation
+
+objectclass usCountyOrEquivalent
+       requires
+               objectClass,
+               fipsCountyNumericCode,
+               fips55,
+               l
+       allows
+               description,
+               lastModifiedTime,
+               nadfSearchGuide,
+               searchGuide,
+               seeAlso,
+               st,
+               streetAddress,
+               supplementaryInformation
+
+objectclass ansiOrgObject
+       requires
+               objectClass,
+               ansiOrgNumericCode
+
+objectclass nadfApplicationEntity
+       requires
+               objectClass,
+               supportedApplicationContext,
+               presentationAddress,
+               cn
+       allows
+               description,
+               l,
+               o,
+               ou,
+               seeAlso,
+               supportedApplicationContext
+
+objectclass nadfADDMD
+       requires
+               objectClass,
+               ad
+       allows
+               businessCategory,
+               description,
+               destinationIndicator,
+               facsimileTelephoneNumber,
+               internationaliSDNNumber,
+               l,
+               lastModifiedTime,
+               nadfSearchGuide,
+               o,
+               physicalDeliveryOfficeName,
+               postOfficeBox,
+               postalAddress,
+               postalCode,
+               preferredDeliveryMethod,
+               registeredAddress,
+               searchGuide,
+               seeAlso,
+               st,
+               streetAddress,
+               supplementaryInformation,
+               telephoneNumber,
+               teletexTerminalIdentifier,
+               telexNumber,
+               userPassword,
+               x121Address
+
+objectclass publicObject
+       requires
+               objectClass,
+               namingLink
+
+objectclass providerObject
+       requires
+               objectClass,
+               reciprocalNamingLink
+
+objectclass nationalObject
+       requires
+               objectClass,
+               c
+
+objectclass fips55Object
+       requires
+               objectClass,
+               fips55
+       allows
+               st
+
+objectclass restaurant
+       requires
+               objectClass,
+               description,
+               telephoneNumber,
+               streetAddress
+       allows
+               Ambiance,
+               Appearance,
+               Average-price,
+               Closed,
+               CreditCardsAccepted,
+               Kosher,
+               Max-price,
+               MaximumInParty,
+               Min-price,
+               Music,
+               NotRecommended,
+               OutdoorSeating,
+               Parking,
+               QualityOfService,
+               QualityPriceRatio,
+               Recommended,
+               RecommendedBy,
+               Reservation,
+               ServiceSpeed,
+               Specialty,
+               Taux-de-frequentation,
+               TransportationMeans,
+               facsimileTelephoneNumber,
+               postalAddress
+
+objectclass kerberosSecurityObject
+       requires
+               objectClass,
+               krbName
+
+objectclass umichPerson
+       requires
+               objectClass,
+               sn,
+               cn,
+               universityID
+       allows
+               affiliationCode,
+               audio,
+               businessCategory,
+               classStanding,
+               description,
+               destinationIndicator,
+               doNotDelete,
+               doNotMove,
+               drink,
+               expire,
+               facsimileTelephoneNumber,
+               homePhone,
+               homePostalAddress,
+               internationaliSDNNumber,
+               janetMailbox,
+               jpegPhoto,
+               keepNames,
+               krbName,
+               l,
+               labeledURL,
+               mail,
+               mailPreferenceOption,
+               memberOfGroup,
+               mobile,
+               multiLineDescription,
+               noBatchUpdates,
+               notRegistered,
+               notice,
+               onVacation,
+               organizationalStatus,
+               otherMailbox,
+               ou,
+               pager,
+               personalSignature,
+               personalTitle,
+               photo,
+               physicalDeliveryOfficeName,
+               postOfficeBox,
+               postalAddress,
+               postalCode,
+               preferredDeliveryMethod,
+               proxy,
+               registeredAddress,
+               registrationStatus,
+               roomNumber,
+               secretary,
+               seeAlso,
+               st,
+               streetAddress,
+               telephoneNumber,
+               teletexTerminalIdentifier,
+               telexNumber,
+               textEncodedORaddress,
+               title,
+               uid,
+               updateSource,
+               userCertificate,
+               userClass,
+               userPassword,
+               vacationMessage,
+               x121Address,
+               xacl
+
+objectclass rfc822MailGroup
+       requires
+               objectClass,
+               owner,
+               cn
+       allows
+               associatedDomain,
+               autoMgt,
+               description,
+               destinationIndicator,
+               errorsTo,
+               facsimileTelephoneNumber,
+               internationaliSDNNumber,
+               joinable,
+               krbName,
+               labeledURL,
+               mail,
+               member,
+               memberOfGroup,
+               moderator,
+               multiLineDescription,
+               notice,
+               physicalDeliveryOfficeName,
+               postOfficeBox,
+               postalAddress,
+               postalCode,
+               preferredDeliveryMethod,
+               registeredAddress,
+               requestsTo,
+               rfc822ErrorsTo,
+               rfc822RequestsTo,
+               seeAlso,
+               streetAddress,
+               suppressNoEmailError,
+               telephoneNumber,
+               teletexTerminalIdentifier,
+               telexNumber,
+               userPassword,
+               x121Address,
+               xacl
+
+objectclass image
+       requires
+               objectClass,
+               cn
+       allows
+               citation,
+               copyright,
+               imageFiles,
+               jpegPhoto,
+               keywords,
+               multiLineDescription,
+               owner,
+               predominantColor
+
+objectclass imageFile
+       requires
+               objectClass,
+               cn
+       allows
+               colorDepth,
+               documentLocation,
+               fileFormat,
+               fileSize,
+               height,
+               resolution,
+               seeAlso,
+               width
+
+objectclass service
+       requires
+               objectClass,
+               cn
+       allows
+               category,
+               dependentUpon,
+               destinationIndicator,
+               facsimileTelephoneNumber,
+               hoursOfOperation,
+               internationaliSDNNumber,
+               jpegPhoto,
+               keywords,
+               labeledURL,
+               mail,
+               multiLineDescription,
+               owner,
+               physicalDeliveryOfficeName,
+               platform,
+               postOfficeBox,
+               postalAddress,
+               postalCode,
+               preferredDeliveryMethod,
+               product,
+               provider,
+               ratingDescription,
+               ratingTime,
+               registeredAddress,
+               seeAlso,
+               serviceArea,
+               serviceRating,
+               streetAddress,
+               telephoneNumber,
+               teletexTerminalIdentifier,
+               telexNumber,
+               x121Address
+
+objectclass umichDocument
+       requires
+               objectClass,
+               documentIdentifier
+       allows
+               abstract,
+               audio,
+               authorCN,
+               authorSN,
+               category,
+               cn,
+               dITRedirect,
+               description,
+               documentAuthor,
+               documentAvailable,
+               documentLocation,
+               documentPublisher,
+               documentSeriesTitle,
+               documentStore,
+               documentTitle,
+               documentVersion,
+               info,
+               jpegPhoto,
+               keywords,
+               l,
+               labeledURL,
+               lastModifiedBy,
+               lastModifiedTime,
+               manager,
+               multiLineAbstract,
+               o,
+               obsoletedByDocument,
+               obsoletesDocument,
+               ou,
+               owner,
+               photo,
+               platform,
+               product,
+               seeAlso,
+               serviceArea,
+               subject,
+               uniqueIdentifier,
+               updatedByDocument,
+               updatesDocument
+
+objectclass documentDescription
+       requires
+               objectClass,
+               cn
+       allows
+               labeledURL,
+               multiLineDescription,
+               owner
+
+objectclass labeledURLObject
+       requires
+               objectClass
+       allows
+               labeledURL
+
+objectclass cacheObject
+       requires
+               objectClass
+       allows
+               ttl
diff --git a/tests/data/test-ordered.ldif b/tests/data/test-ordered.ldif
new file mode 100644 (file)
index 0000000..c9f9325
--- /dev/null
@@ -0,0 +1,423 @@
+dn: o=University of Michigan, c=US
+objectclass: top
+objectclass: organization
+objectclass: domainRelatedObject
+objectclass: quipuObject
+objectclass: quipuNonLeafObject
+l: Ann Arbor, Michigan
+st: Michigan
+streetaddress: 535 West William St.
+o: University of Michigan
+o: UMICH
+o: UM
+o: U-M
+o: U of M
+description: The University of Michigan at Ann Arbor
+postaladdress: University of Michigan $ 535 W. William St. $ Ann Arbor, MI 481
+ 09 $ USpostalcode: 48109
+telephonenumber: +1 313 764-1817
+lastmodifiedtime: 930106182800Z
+lastmodifiedby: cn=manager, o=university of michigan, c=US
+associateddomain: umich.edu
+
+dn: ou=People, o=University of Michigan, c=US
+objectclass: top
+objectclass: organizationalUnit
+objectclass: quipuObject
+objectclass: quipuNonLeafObject
+ou: People
+
+dn: ou=Groups, o=University of Michigan, c=US
+objectclass: top
+objectclass: organizationalUnit
+objectclass: quipuObject
+objectclass: quipuNonLeafObject
+ou: Groups
+lastmodifiedtime: 950120182331Z
+lastmodifiedby: cn=manager, o=university of michigan, c=US
+
+dn: ou=Alumni Association, ou=People, o=University of Michigan, c=US
+objectclass: top
+objectclass: organizationalUnit
+objectclass: quipuObject
+objectclass: quipuNonLeafObject
+ou: Alumni Association
+
+dn: ou=Information Technology Division, ou=People, o=University of Michigan, c
+ =US
+objectclass: top
+objectclass: organizationalUnit
+objectclass: quipuObject
+objectclass: quipuNonLeafObject
+ou: Information Technology Divisio
+
+dn: cn=All Staff,ou=Groups,o=University of Michigan,c=US
+member: cn=Manager, o=University of Michigan, c=US
+member: cn=Barbara Jensen, ou=Information Technology Division, ou=People, o=Un
+ iversity of Michigan, c=US
+member: cn=Jane Doe, ou=Alumni Association, ou=People, o=University of Michiga
+ n, c=US
+member: cn=John Doe, ou=Information Technology Division, ou=People, o=Universi
+ ty of Michigan, c=US
+member: cn=Mark Elliot, ou=Alumni Association, ou=People, o=University of Mich
+ igan, c=US
+member: cn=James A Jones 1, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=James A Jones 2, ou=Information Technology Division, ou=People, o=U
+ niversity of Michigan, c=US
+member: cn=Jennifer Smith, ou=Alumni Association, ou=People, o=University of M
+ ichigan, c=US
+member: cn=Dorothy Stevens, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=Ursula Hampster, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, o=Univ
+ ersity of Michigan, c=US
+associateddomain: umich.edu
+requeststo: cn=Manager, o=University of Michigan, c=US
+errorsto: cn=Manager, o=University of Michigan, c=US
+owner: cn=Manager, o=University of Michigan, c=US
+cn: All Staff
+joinable: FALSE
+multilinedescription: Everyone in the sample data
+objectclass: rfc822mailgroup
+
+dn: cn=Alumni Assoc Staff,ou=Groups,o=University of Michigan,c=US
+member: cn=Manager, o=University of Michigan, c=US
+member: cn=Dorothy Stevens, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=James A Jones 1, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=Jane Doe, ou=Alumni Association, ou=People, o=University of Michiga
+ n, c=US
+member: cn=Jennifer Smith, ou=Alumni Association, ou=People, o=University of M
+ ichigan, c=US
+member: cn=Mark Elliot, ou=Alumni Association, ou=People, o=University of Mich
+ igan, c=US
+member: cn=Ursula Hampster, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+associateddomain: umich.edu
+requeststo: cn=Manager, o=University of Michigan, c=US
+errorsto: cn=Manager, o=University of Michigan, c=US
+owner: cn=Manager, o=University of Michigan, c=US
+multilinedescription: All Alumni Assoc Staff
+cn: Alumni Assoc Staff
+joinable: FALSE
+objectclass: rfc822mailgroup
+
+dn: cn=Barbara Jensen, ou=Information Technology Division, ou=People, o=Univer
+ sity of Michigan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: Barbara Jensen
+cn: Babs Jensen
+sn: Jensen
+title: Mythical Manager, Research Systems
+postaladdress: ITD Prod Dev & Deployment $ 535 W. William St. Room 4212 $ Ann 
+ Arbor, MI 48103-4943
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: bjensen
+userpassword: bjensen
+mail: bjensen@mailgw.umich.edu
+homepostaladdress: 123 Wesley $ Ann Arbor, MI 48103
+krbname: bjensen@umich.edu
+multilinedescription: Mythical manager of the rsdd unix project 
+nobatchupdates: TRUE
+notice: Off sailing this month.
+onvacation: FALSE
+labeledurl: http://www.umich.edu/ U-M Home Page
+drink: water
+lastmodifiedtime: 960404035839Z
+lastmodifiedby: cn=Barbara Jensen, ou=Information Technology Division, ou=Peop
+ le, o=University of Michigan, c=US
+modifytimestamp: 960404171405Z
+modifiersname: cn=Manager,o=University of Michigan,c=US
+homephone: +1 313 555 2333
+pager: +1 313 555 3233
+facsimiletelephonenumber: +1 313 555 2274
+telephonenumber: +1 313 555 9022
+
+dn: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, o=Universi
+ ty of Michigan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: Bjorn Jensen
+cn: Biiff Jensen
+sn: Jensen
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: bjorn
+userpassword: bjorn
+krbname: jdoe@umich.edu
+nobatchupdates: TRUE
+onvacation: FALSE
+homepostaladdress: 19923 Seven Mile Rd. $ South Lyon, MI 49999
+drink: Iced Tea
+multilinedescription: Hiker, biker
+title: Director, Embedded Systems
+postaladdress: Info Tech Division $ 535 W. William St. $ Ann Arbor, MI 48103
+mail: bjorn@mailgw.umich.edu
+modifytimestamp: 960404171424Z
+modifiersname: cn=Manager,o=University of Michigan,c=US
+homephone: +1 313 555 5444
+pager: +1 313 555 4474
+facsimiletelephonenumber: +1 313 555 2177
+telephonenumber: +1 313 555 0355
+
+dn: cn=Dorothy Stevens, ou=Alumni Association, ou=People, o=University of Mich
+ igan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: Dorothy Stevens
+cn: Dot Stevens
+sn: Stevens
+title: Secretary, UM Alumni Association
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: dots
+krbname: jdoe@umich.edu
+nobatchupdates: TRUE
+onvacation: FALSE
+drink: Lemonade
+homepostaladdress: 377 White St. Apt. 3 $ Ann Arbor, MI 48104
+multilinedescription: Very tall
+facsimiletelephonenumber: +1 313 555 3223
+telephonenumber: +1 313 555 3664
+mail: dots@mail.alumni.umich.edu
+modifytimestamp: 960404171218Z
+modifiersname: cn=Manager,o=University of Michigan,c=US
+homephone: +1 313 555 0454
+
+dn: cn=ITD Staff,ou=Groups,o=University of Michigan,c=US
+associateddomain: umich.edu
+requeststo: cn=Manager, o=University of Michigan, c=US
+errorsto: cn=Manager, o=University of Michigan, c=US
+owner: cn=Manager, o=University of Michigan, c=US
+multilinedescription: All ITD Staff
+cn: ITD Staff
+joinable: FALSE
+objectclass: rfc822mailgroup
+member: cn=Manager, o=University of Michigan, c=US
+member: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, o=Univ
+ ersity of Michigan, c=US
+member: cn=James A Jones 2, ou=Information Technology Division, ou=People, o=U
+ niversity of Michigan, c=US
+member: cn=John Doe, ou=Information Technology Division, ou=People, o=Universi
+ ty of Michigan, c=US
+modifytimestamp: 960404171730Z
+modifiersname: cn=Manager,o=University of Michigan,c=US
+labeledurl: http://www.itd.umich.edu ITD Home Page
+
+dn: cn=James A Jones 1, ou=Alumni Association, ou=People, o=University of Mich
+ igan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: James A Jones 1
+cn: James Jones
+cn: Jim Jones
+sn: Jones
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: jaj
+krbname: jaj@umich.edu
+userpassword: jaj
+nobatchupdates: TRUE
+onvacation: FALSE
+homepostaladdress: 3882 Beverly Rd. $ Ann Arbor, MI 48105
+homephone: +1 313 555 4772
+multilinedescription: Outstanding
+title: Mad Cow Researcher, UM Alumni Association
+pager: +1 313 555 3923
+mail: jaj@mail.alumni.umich.edu
+modifytimestamp: 960404171231Z
+modifiersname: cn=Manager,o=University of Michigan,c=US
+facsimiletelephonenumber: +1 313 555 4332
+telephonenumber: +1 313 555 0895
+
+dn: cn=James A Jones 2, ou=Information Technology Division, ou=People, o=Unive
+ rsity of Michigan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: James A Jones 2
+cn: James Jones
+cn: Jim Jones
+sn: Doe
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: jjones
+krbname: jdoe@umich.edu
+nobatchupdates: TRUE
+onvacation: FALSE
+homepostaladdress: 933 Brooks $ Ann Arbor, MI 48104
+homephone: +1 313 555 8838
+title: Senior Manager, Information Technology Division
+multilinedescription: Not around very much
+mail: jjones@mailgw.umich.edu
+postaladdress: Info Tech Division $ 535 W William $ Ann Arbor, MI 48103
+modifytimestamp: 960404171442Z
+modifiersname: cn=Manager,o=University of Michigan,c=US
+pager: +1 313 555 2833
+facsimiletelephonenumber: +1 313 555 8688
+telephonenumber: +1 313 555 7334
+
+dn: cn=Jane Doe, ou=Alumni Association, ou=People, o=University of Michigan, c
+ =US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: Jane Doe
+cn: Jane Alverson
+sn: Doe
+title: Programmer Analyst, UM Alumni Association
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: jdoe
+homepostaladdress: 123 Anystreet $ Ann Arbor, MI 48104
+krbname: jdoe@umich.edu
+nobatchupdates: TRUE
+onvacation: FALSE
+drink: diet coke
+multilinedescription: Enthusiastic
+mail: jdoe@woof.net
+modifytimestamp: 960404171249Z
+modifiersname: cn=Manager,o=University of Michigan,c=US
+homephone: +1 313 555 5445
+pager: +1 313 555 1220
+facsimiletelephonenumber: +1 313 555 2311
+telephonenumber: +1 313 555 4774
+
+dn: cn=Jennifer Smith, ou=Alumni Association, ou=People, o=University of Michi
+ gan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: Jennifer Smith
+cn: Jen Smith
+sn: Smith
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: jen
+krbname: jdoe@umich.edu
+nobatchupdates: TRUE
+onvacation: FALSE
+drink: Sam Adams
+homepostaladdress: 1000 Maple #44 $ Ann Arbor, MI 48103
+title: Telemarketer, UM Alumni Association
+mail: jen@mail.alumni.umich.edu
+modifytimestamp: 960404171309Z
+modifiersname: cn=Manager,o=University of Michigan,c=US
+homephone: +1 313 555 2333
+pager: +1 313 555 6442
+facsimiletelephonenumber: +1 313 555 2756
+telephonenumber: +1 313 555 8232
+
+dn: cn=John Doe, ou=Information Technology Division, ou=People, o=University o
+ f Michigan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: John Doe
+cn: Jonathon Doe
+sn: Doe
+postaladdress: ITD $ 535 W. William $ Ann Arbor, MI 48109
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: johnd
+krbname: johnd@umich.edu
+nobatchupdates: TRUE
+onvacation: FALSE
+homepostaladdress: 912 East Bllvd $ Ann Arbor, MI 48104
+title: System Administrator, Information Technology Division
+multilinedescription: overworked!
+mail: johnd@mailgw.umich.edu
+modifytimestamp: 960404171509Z
+modifiersname: cn=Manager,o=University of Michigan,c=US
+homephone: +1 313 555 3774
+pager: +1 313 555 6573
+facsimiletelephonenumber: +1 313 555 4544
+telephonenumber: +1 313 555 9394
+
+dn: cn=Manager, o=University of Michigan, c=US
+objectclass: top
+objectclass: person
+objectclass: quipuObject
+objectclass: kerberosSecurityObject
+cn: Manager
+cn: Directory Manager
+cn: Dir Man
+sn: Manager
+description: Manager of the directory
+userpassword: secret
+lastmodifiedtime: 951212214144Z
+lastmodifiedby: cn=Manager, o=University of Michigan, c=US
+krbname: bjensen@umich.edu
+
+dn: cn=Mark Elliot, ou=Alumni Association, ou=People, o=University of Michigan
+ , c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: Mark Elliot
+cn: Mark A Elliot
+sn: Elliot
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: melliot
+krbname: jdoe@umich.edu
+nobatchupdates: TRUE
+onvacation: FALSE
+homepostaladdress: 199 Outer Drive $ Ypsilanti, MI 48198
+homephone: +1 313 555 0388
+drink: Gasoline
+title: Director, UM Alumni Association
+mail: melliot@mail.alumni.umich.edu
+modifytimestamp: 960404171327Z
+modifiersname: cn=Manager,o=University of Michigan,c=US
+pager: +1 313 555 7671
+facsimiletelephonenumber: +1 313 555 7762
+telephonenumber: +1 313 555 4177
+
+dn: cn=Ursula Hampster, ou=Alumni Association, ou=People, o=University of Mich
+ igan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: Ursula Hampster
+sn: Hampster
+title: Secretary, UM Alumni Association
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: uham
+homepostaladdress: 123 Anystreet $ Ann Arbor, MI 48104
+krbname: jdoe@umich.edu
+nobatchupdates: TRUE
+onvacation: FALSE
+mail: uham@mail.alumni.umich.edu
+modifytimestamp: 960404171346Z
+modifiersname: cn=Manager,o=University of Michigan,c=US
+homephone: +1 313 555 8421
+pager: +1 313 555 2844
+facsimiletelephonenumber: +1 313 555 9700
+telephonenumber: +1 313 555 5331
diff --git a/tests/data/test.ldif b/tests/data/test.ldif
new file mode 100644 (file)
index 0000000..272412d
--- /dev/null
@@ -0,0 +1,423 @@
+dn: cn=All Staff,ou=Groups,o=University of Michigan,c=US
+member: cn=Manager, o=University of Michigan, c=US
+member: cn=Barbara Jensen, ou=Information Technology Division, ou=People, o=Un
+ iversity of Michigan, c=US
+member: cn=Jane Doe, ou=Alumni Association, ou=People, o=University of Michiga
+ n, c=US
+member: cn=John Doe, ou=Information Technology Division, ou=People, o=Universi
+ ty of Michigan, c=US
+member: cn=Mark Elliot, ou=Alumni Association, ou=People, o=University of Mich
+ igan, c=US
+member: cn=James A Jones 1, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=James A Jones 2, ou=Information Technology Division, ou=People, o=U
+ niversity of Michigan, c=US
+member: cn=Jennifer Smith, ou=Alumni Association, ou=People, o=University of M
+ ichigan, c=US
+member: cn=Dorothy Stevens, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=Ursula Hampster, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, o=Univ
+ ersity of Michigan, c=US
+associateddomain: umich.edu
+requeststo: cn=Manager, o=University of Michigan, c=US
+errorsto: cn=Manager, o=University of Michigan, c=US
+owner: cn=Manager, o=University of Michigan, c=US
+cn: All Staff
+joinable: FALSE
+multilinedescription: Everyone in the sample data
+objectclass: rfc822mailgroup
+
+dn: cn=Alumni Assoc Staff,ou=Groups,o=University of Michigan,c=US
+member: cn=Manager, o=University of Michigan, c=US
+member: cn=Dorothy Stevens, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=James A Jones 1, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+member: cn=Jane Doe, ou=Alumni Association, ou=People, o=University of Michiga
+ n, c=US
+member: cn=Jennifer Smith, ou=Alumni Association, ou=People, o=University of M
+ ichigan, c=US
+member: cn=Mark Elliot, ou=Alumni Association, ou=People, o=University of Mich
+ igan, c=US
+member: cn=Ursula Hampster, ou=Alumni Association, ou=People, o=University of 
+ Michigan, c=US
+associateddomain: umich.edu
+requeststo: cn=Manager, o=University of Michigan, c=US
+errorsto: cn=Manager, o=University of Michigan, c=US
+owner: cn=Manager, o=University of Michigan, c=US
+multilinedescription: All Alumni Assoc Staff
+cn: Alumni Assoc Staff
+joinable: FALSE
+objectclass: rfc822mailgroup
+
+dn: ou=Alumni Association, ou=People, o=University of Michigan, c=US
+objectclass: top
+objectclass: organizationalUnit
+objectclass: quipuObject
+objectclass: quipuNonLeafObject
+ou: Alumni Association
+
+dn: cn=Barbara Jensen, ou=Information Technology Division, ou=People, o=Univer
+ sity of Michigan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: Barbara Jensen
+cn: Babs Jensen
+sn: Jensen
+title: Mythical Manager, Research Systems
+postaladdress: ITD Prod Dev & Deployment $ 535 W. William St. Room 4212 $ Ann 
+ Arbor, MI 48103-4943
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: bjensen
+userpassword: bjensen
+mail: bjensen@mailgw.umich.edu
+homepostaladdress: 123 Wesley $ Ann Arbor, MI 48103
+krbname: bjensen@umich.edu
+multilinedescription: Mythical manager of the rsdd unix project 
+nobatchupdates: TRUE
+notice: Off sailing this month.
+onvacation: FALSE
+labeledurl: http://www.umich.edu/ U-M Home Page
+drink: water
+lastmodifiedtime: 960404035839Z
+lastmodifiedby: cn=Barbara Jensen, ou=Information Technology Division, ou=Peop
+ le, o=University of Michigan, c=US
+modifytimestamp: 960404171405Z
+modifiersname: cn=Manager,o=University of Michigan,c=US
+homephone: +1 313 555 2333
+pager: +1 313 555 3233
+facsimiletelephonenumber: +1 313 555 2274
+telephonenumber: +1 313 555 9022
+
+dn: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, o=Universi
+ ty of Michigan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: Bjorn Jensen
+cn: Biiff Jensen
+sn: Jensen
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: bjorn
+userpassword: bjorn
+krbname: jdoe@umich.edu
+nobatchupdates: TRUE
+onvacation: FALSE
+homepostaladdress: 19923 Seven Mile Rd. $ South Lyon, MI 49999
+drink: Iced Tea
+multilinedescription: Hiker, biker
+title: Director, Embedded Systems
+postaladdress: Info Tech Division $ 535 W. William St. $ Ann Arbor, MI 48103
+mail: bjorn@mailgw.umich.edu
+modifytimestamp: 960404171424Z
+modifiersname: cn=Manager,o=University of Michigan,c=US
+homephone: +1 313 555 5444
+pager: +1 313 555 4474
+facsimiletelephonenumber: +1 313 555 2177
+telephonenumber: +1 313 555 0355
+
+dn: cn=Dorothy Stevens, ou=Alumni Association, ou=People, o=University of Mich
+ igan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: Dorothy Stevens
+cn: Dot Stevens
+sn: Stevens
+title: Secretary, UM Alumni Association
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: dots
+krbname: jdoe@umich.edu
+nobatchupdates: TRUE
+onvacation: FALSE
+drink: Lemonade
+homepostaladdress: 377 White St. Apt. 3 $ Ann Arbor, MI 48104
+multilinedescription: Very tall
+facsimiletelephonenumber: +1 313 555 3223
+telephonenumber: +1 313 555 3664
+mail: dots@mail.alumni.umich.edu
+modifytimestamp: 960404171218Z
+modifiersname: cn=Manager,o=University of Michigan,c=US
+homephone: +1 313 555 0454
+
+dn: ou=Groups, o=University of Michigan, c=US
+objectclass: top
+objectclass: organizationalUnit
+objectclass: quipuObject
+objectclass: quipuNonLeafObject
+ou: Groups
+lastmodifiedtime: 950120182331Z
+lastmodifiedby: cn=manager, o=university of michigan, c=US
+
+dn: ou=Information Technology Division, ou=People, o=University of Michigan, c
+ =US
+objectclass: top
+objectclass: organizationalUnit
+objectclass: quipuObject
+objectclass: quipuNonLeafObject
+ou: Information Technology Divisio
+
+dn: cn=ITD Staff,ou=Groups,o=University of Michigan,c=US
+associateddomain: umich.edu
+requeststo: cn=Manager, o=University of Michigan, c=US
+errorsto: cn=Manager, o=University of Michigan, c=US
+owner: cn=Manager, o=University of Michigan, c=US
+multilinedescription: All ITD Staff
+cn: ITD Staff
+joinable: FALSE
+objectclass: rfc822mailgroup
+member: cn=Manager, o=University of Michigan, c=US
+member: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, o=Univ
+ ersity of Michigan, c=US
+member: cn=James A Jones 2, ou=Information Technology Division, ou=People, o=U
+ niversity of Michigan, c=US
+member: cn=John Doe, ou=Information Technology Division, ou=People, o=Universi
+ ty of Michigan, c=US
+modifytimestamp: 960404171730Z
+modifiersname: cn=Manager,o=University of Michigan,c=US
+labeledurl: http://www.itd.umich.edu ITD Home Page
+
+dn: cn=James A Jones 1, ou=Alumni Association, ou=People, o=University of Mich
+ igan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: James A Jones 1
+cn: James Jones
+cn: Jim Jones
+sn: Jones
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: jaj
+krbname: jaj@umich.edu
+userpassword: jaj
+nobatchupdates: TRUE
+onvacation: FALSE
+homepostaladdress: 3882 Beverly Rd. $ Ann Arbor, MI 48105
+homephone: +1 313 555 4772
+multilinedescription: Outstanding
+title: Mad Cow Researcher, UM Alumni Association
+pager: +1 313 555 3923
+mail: jaj@mail.alumni.umich.edu
+modifytimestamp: 960404171231Z
+modifiersname: cn=Manager,o=University of Michigan,c=US
+facsimiletelephonenumber: +1 313 555 4332
+telephonenumber: +1 313 555 0895
+
+dn: cn=James A Jones 2, ou=Information Technology Division, ou=People, o=Unive
+ rsity of Michigan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: James A Jones 2
+cn: James Jones
+cn: Jim Jones
+sn: Doe
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: jjones
+krbname: jdoe@umich.edu
+nobatchupdates: TRUE
+onvacation: FALSE
+homepostaladdress: 933 Brooks $ Ann Arbor, MI 48104
+homephone: +1 313 555 8838
+title: Senior Manager, Information Technology Division
+multilinedescription: Not around very much
+mail: jjones@mailgw.umich.edu
+postaladdress: Info Tech Division $ 535 W William $ Ann Arbor, MI 48103
+modifytimestamp: 960404171442Z
+modifiersname: cn=Manager,o=University of Michigan,c=US
+pager: +1 313 555 2833
+facsimiletelephonenumber: +1 313 555 8688
+telephonenumber: +1 313 555 7334
+
+dn: cn=Jane Doe, ou=Alumni Association, ou=People, o=University of Michigan, c
+ =US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: Jane Doe
+cn: Jane Alverson
+sn: Doe
+title: Programmer Analyst, UM Alumni Association
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: jdoe
+homepostaladdress: 123 Anystreet $ Ann Arbor, MI 48104
+krbname: jdoe@umich.edu
+nobatchupdates: TRUE
+onvacation: FALSE
+drink: diet coke
+multilinedescription: Enthusiastic
+mail: jdoe@woof.net
+modifytimestamp: 960404171249Z
+modifiersname: cn=Manager,o=University of Michigan,c=US
+homephone: +1 313 555 5445
+pager: +1 313 555 1220
+facsimiletelephonenumber: +1 313 555 2311
+telephonenumber: +1 313 555 4774
+
+dn: cn=Jennifer Smith, ou=Alumni Association, ou=People, o=University of Michi
+ gan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: Jennifer Smith
+cn: Jen Smith
+sn: Smith
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: jen
+krbname: jdoe@umich.edu
+nobatchupdates: TRUE
+onvacation: FALSE
+drink: Sam Adams
+homepostaladdress: 1000 Maple #44 $ Ann Arbor, MI 48103
+title: Telemarketer, UM Alumni Association
+mail: jen@mail.alumni.umich.edu
+modifytimestamp: 960404171309Z
+modifiersname: cn=Manager,o=University of Michigan,c=US
+homephone: +1 313 555 2333
+pager: +1 313 555 6442
+facsimiletelephonenumber: +1 313 555 2756
+telephonenumber: +1 313 555 8232
+
+dn: cn=John Doe, ou=Information Technology Division, ou=People, o=University o
+ f Michigan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: John Doe
+cn: Jonathon Doe
+sn: Doe
+postaladdress: ITD $ 535 W. William $ Ann Arbor, MI 48109
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: johnd
+krbname: johnd@umich.edu
+nobatchupdates: TRUE
+onvacation: FALSE
+homepostaladdress: 912 East Bllvd $ Ann Arbor, MI 48104
+title: System Administrator, Information Technology Division
+multilinedescription: overworked!
+mail: johnd@mailgw.umich.edu
+modifytimestamp: 960404171509Z
+modifiersname: cn=Manager,o=University of Michigan,c=US
+homephone: +1 313 555 3774
+pager: +1 313 555 6573
+facsimiletelephonenumber: +1 313 555 4544
+telephonenumber: +1 313 555 9394
+
+dn: cn=Manager, o=University of Michigan, c=US
+objectclass: top
+objectclass: person
+objectclass: quipuObject
+objectclass: kerberosSecurityObject
+cn: Manager
+cn: Directory Manager
+cn: Dir Man
+sn: Manager
+description: Manager of the directory
+userpassword: secret
+lastmodifiedtime: 951212214144Z
+lastmodifiedby: cn=Manager, o=University of Michigan, c=US
+krbname: bjensen@umich.edu
+
+dn: cn=Mark Elliot, ou=Alumni Association, ou=People, o=University of Michigan
+ , c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: Mark Elliot
+cn: Mark A Elliot
+sn: Elliot
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: melliot
+krbname: jdoe@umich.edu
+nobatchupdates: TRUE
+onvacation: FALSE
+homepostaladdress: 199 Outer Drive $ Ypsilanti, MI 48198
+homephone: +1 313 555 0388
+drink: Gasoline
+title: Director, UM Alumni Association
+mail: melliot@mail.alumni.umich.edu
+modifytimestamp: 960404171327Z
+modifiersname: cn=Manager,o=University of Michigan,c=US
+pager: +1 313 555 7671
+facsimiletelephonenumber: +1 313 555 7762
+telephonenumber: +1 313 555 4177
+
+dn: ou=People, o=University of Michigan, c=US
+objectclass: top
+objectclass: organizationalUnit
+objectclass: quipuObject
+objectclass: quipuNonLeafObject
+ou: People
+
+dn: o=University of Michigan, c=US
+objectclass: top
+objectclass: organization
+objectclass: domainRelatedObject
+objectclass: quipuObject
+objectclass: quipuNonLeafObject
+l: Ann Arbor, Michigan
+st: Michigan
+streetaddress: 535 West William St.
+o: University of Michigan
+o: UMICH
+o: UM
+o: U-M
+o: U of M
+description: The University of Michigan at Ann Arbor
+postaladdress: University of Michigan $ 535 W. William St. $ Ann Arbor, MI 481
+ 09 $ USpostalcode: 48109
+telephonenumber: +1 313 764-1817
+lastmodifiedtime: 930106182800Z
+lastmodifiedby: cn=manager, o=university of michigan, c=US
+associateddomain: umich.edu
+
+dn: cn=Ursula Hampster, ou=Alumni Association, ou=People, o=University of Mich
+ igan, c=US
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: Ursula Hampster
+sn: Hampster
+title: Secretary, UM Alumni Association
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: uham
+homepostaladdress: 123 Anystreet $ Ann Arbor, MI 48104
+krbname: jdoe@umich.edu
+nobatchupdates: TRUE
+onvacation: FALSE
+mail: uham@mail.alumni.umich.edu
+modifytimestamp: 960404171346Z
+modifiersname: cn=Manager,o=University of Michigan,c=US
+homephone: +1 313 555 8421
+pager: +1 313 555 2844
+facsimiletelephonenumber: +1 313 555 9700
+telephonenumber: +1 313 555 5331
diff --git a/tests/scripts/all b/tests/scripts/all
new file mode 100755 (executable)
index 0000000..451c739
--- /dev/null
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+echo ">>>>> Executing all LDAP tests..."
+
+if [ $# -eq 0 ]; then
+       SCRIPTDIR="."
+else
+       SCRIPTDIR=$1; shift
+fi
+
+for i in $SCRIPTDIR/test*; do
+       CMD=$i $*
+       echo ">>>>> Starting $CMD ..."
+       $CMD
+       RC=$?
+       if [ $RC -eq 0 ]; then
+               echo ">>>>> $CMD completed OK."
+       else
+               echo ">>>>> $CMD failed (exit $RC)"
+               exit $RC
+       fi
+       echo
+done
diff --git a/tests/scripts/defines.sh b/tests/scripts/defines.sh
new file mode 100755 (executable)
index 0000000..6d8bf2f
--- /dev/null
@@ -0,0 +1,33 @@
+LDIF2LDBM=../servers/slapd/tools/ldif2ldbm
+SLAPD=../servers/slapd/slapd
+SLURPD=../servers/slurpd/slurpd
+LDAPSEARCH=../clients/tools/ldapsearch
+LDAPMODIFY=../clients/tools/ldapmodify
+LDAPADD=../clients/tools/ldapadd
+PORT=9009
+SLAVEPORT=9010
+DBDIR=./test-db
+REPLDIR=./test-repl
+CONF=./data/slapd-master.conf
+ACLCONF=./data/slapd-acl.conf
+MASTERCONF=./data/slapd-repl-master.conf
+SLAVECONF=./data/slapd-repl-slave.conf
+LDIF=./data/test.ldif
+LDIFORDERED=./data/test-ordered.ldif
+BASEDN="o=University of Michigan, c=US"
+MANAGERDN="cn=Manager, o=University of Michigan, c=US"
+PASSWD=secret
+BABSDN="cn=Barbara Jensen, ou=Information Technology Division, ou=People, o=University of Michigan, c=US"
+BJORNSDN="cn=Bjorn Jensen, ou=Information Technology Division, ou=People, o=University of Michigan, c=US"
+JAJDN="cn=James A Jones 1, ou=Alumni Association, ou=People, o=University of Michigan, c=US"
+SEARCHOUT=$DBDIR/ldapsearch.out
+MASTEROUT=$DBDIR/master.out
+SLAVEOUT=$DBDIR/slave.out
+TESTOUT=$DBDIR/ldapsearch.out
+SEARCHOUTMASTER=./data/search.out.master
+MODIFYOUTMASTER=./data/modify.out.master
+ADDDELOUTMASTER=./data/adddel.out.master
+MODRDNOUTMASTER=./data/modrdn.out.master
+ACLOUTMASTER=./data/acl.out.master
+REPLOUTMASTER=./data/repl.out.master
+MODSRCHFILTERS=./data/modify.search.filters
diff --git a/tests/scripts/makeldbm.sh b/tests/scripts/makeldbm.sh
new file mode 100755 (executable)
index 0000000..bb2aac0
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+. scripts/defines.sh
+
+echo "Cleaning up in $DBDIR..."
+
+rm -f $DBDIR/*
+
+echo "Running ldif2ldbm to build slapd database..."
+$LDIF2LDBM -f $CONF -i $LDIF -e ../servers/slapd/tools
+RC=$?
+if [ $RC != 0 ]; then
+       echo "ldif2ldbm failed!"
+       exit $RC
+fi
diff --git a/tests/scripts/test001-ldif2ldbm b/tests/scripts/test001-ldif2ldbm
new file mode 100755 (executable)
index 0000000..d22e04c
--- /dev/null
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+. scripts/defines.sh
+
+
+echo "Cleaning up in $DBDIR..."
+
+rm -f $DBDIR/*
+
+echo "Running ldif2ldbm to build slapd database..."
+$LDIF2LDBM -f $CONF -i $LDIF -e ../servers/slapd/tools
+RC=$?
+if [ $RC != 0 ]; then
+       echo "ldif2ldbm failed!"
+       exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT..."
+$SLAPD -f $CONF -p $PORT -d 1 > /dev/null 2>&1 &
+PID=$!
+
+echo "Using ldapsearch to retrieve all the entries..."
+for i in 0 1 2 3 4 5; do
+       $LDAPSEARCH -L -S "" -b "$BASEDN" -h localhost -p $PORT \
+               'objectClass=*' > $SEARCHOUT 2>&1
+       RC=$?
+       if [ $RC = 1 ]; then
+               echo "Waiting 5 seconds for slapd to start..."
+               sleep 5
+       fi
+done
+
+kill -HUP $PID
+
+if [ $RC != 0 ]; then
+       echo "ldapsearch failed!"
+       exit $RC
+fi
+
+echo "Comparing retrieved entries to LDIF file used to create database"
+cmp $SEARCHOUT $LDIF
+if [ $? != 0 ]; then
+       echo "comparison failed - database was not created correctly"
+       exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+
+exit 0
diff --git a/tests/scripts/test001-slapadd b/tests/scripts/test001-slapadd
new file mode 100755 (executable)
index 0000000..d22e04c
--- /dev/null
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+. scripts/defines.sh
+
+
+echo "Cleaning up in $DBDIR..."
+
+rm -f $DBDIR/*
+
+echo "Running ldif2ldbm to build slapd database..."
+$LDIF2LDBM -f $CONF -i $LDIF -e ../servers/slapd/tools
+RC=$?
+if [ $RC != 0 ]; then
+       echo "ldif2ldbm failed!"
+       exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT..."
+$SLAPD -f $CONF -p $PORT -d 1 > /dev/null 2>&1 &
+PID=$!
+
+echo "Using ldapsearch to retrieve all the entries..."
+for i in 0 1 2 3 4 5; do
+       $LDAPSEARCH -L -S "" -b "$BASEDN" -h localhost -p $PORT \
+               'objectClass=*' > $SEARCHOUT 2>&1
+       RC=$?
+       if [ $RC = 1 ]; then
+               echo "Waiting 5 seconds for slapd to start..."
+               sleep 5
+       fi
+done
+
+kill -HUP $PID
+
+if [ $RC != 0 ]; then
+       echo "ldapsearch failed!"
+       exit $RC
+fi
+
+echo "Comparing retrieved entries to LDIF file used to create database"
+cmp $SEARCHOUT $LDIF
+if [ $? != 0 ]; then
+       echo "comparison failed - database was not created correctly"
+       exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+
+exit 0
diff --git a/tests/scripts/test002-populate b/tests/scripts/test002-populate
new file mode 100755 (executable)
index 0000000..c04d1f5
--- /dev/null
@@ -0,0 +1,57 @@
+#!/bin/sh
+
+. scripts/defines.sh
+
+
+echo "Cleaning up in $DBDIR..."
+
+rm -f $DBDIR/*
+
+echo "Starting slapd on TCP/IP port $PORT..."
+$SLAPD -f $CONF -p $PORT -d 1 > /dev/null 2>&1 &
+PID=$!
+
+echo "Using ldapsearch to check that slapd is running..."
+for i in 0 1 2 3 4 5; do
+       $LDAPSEARCH -L -b "$BASEDN" -h localhost -p $PORT \
+               'cn=Monitor' > /dev/null 2>&1
+       RC=$?
+       if [ $RC = 1 ]; then
+               echo "Waiting 5 seconds for slapd to start..."
+               sleep 5
+       fi
+done
+
+echo "Using ldapmodify to populate the database..."
+$LDAPMODIFY -a -D "$MANAGERDN" -h localhost -p $PORT -w $PASSWD < \
+       $LDIFORDERED > /dev/null 2>&1
+RC=$?
+if [ $RC != 0 ]; then
+       echo "ldapmodify failed!"
+       kill -HUP $PID
+       exit $RC
+fi
+
+echo "Using ldapsearch to read all the entries..."
+$LDAPSEARCH -L -S "" -b "$BASEDN" -h localhost -p $PORT \
+       'objectclass=*' | egrep -iv '^creatorsname:|^createtimestamp:' > \
+       $SEARCHOUT 2>&1
+
+kill -HUP $PID
+
+if [ $RC != 0 ]; then
+       echo "ldapsearch failed!"
+       exit $RC
+fi
+
+echo "Comparing retrieved entries to LDIF file used to create database"
+cmp $SEARCHOUT $LDIF
+if [ $? != 0 ]; then
+       echo "comparison failed - database was not created correctly"
+       exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+
+exit 0
diff --git a/tests/scripts/test003-search b/tests/scripts/test003-search
new file mode 100755 (executable)
index 0000000..0912550
--- /dev/null
@@ -0,0 +1,89 @@
+#!/bin/sh
+
+. scripts/defines.sh
+
+echo "Cleaning up in $DBDIR..."
+
+rm -f $DBDIR/*
+
+echo "Running ldif2ldbm to build slapd database..."
+$LDIF2LDBM -f $CONF -i $LDIF -e ../servers/slapd/tools
+RC=$?
+if [ $RC != 0 ]; then
+       echo "ldif2ldbm failed!"
+       exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT..."
+$SLAPD -f $CONF -p $PORT -d 1 > /dev/null 2>&1 &
+PID=$!
+
+echo "Testing slapd searching..."
+for i in 0 1 2 3 4 5; do
+       $LDAPSEARCH -L -S "" -b "$BASEDN" -h localhost -p $PORT \
+               'cn=Manager' > /dev/null 2>&1
+       RC=$?
+       if [ $RC = 1 ]; then
+               echo "Waiting 5 seconds for slapd to start..."
+               sleep 5
+       fi
+done
+
+if [ $RC != 0 ]; then
+       echo "ldapsearch failed!"
+       kill -HUP $PID
+       exit $RC
+fi
+
+cat /dev/null > $TESTOUT
+
+echo "Testing exact searching..."
+$LDAPSEARCH -L -S "" -b "$BASEDN" -h localhost -p $PORT \
+       'sn=jensen' >> $TESTOUT 2>&1
+if [ $RC != 0 ]; then
+       echo "ldapsearch failed!"
+       kill -HUP $PID
+       exit $RC
+fi
+
+echo "Testing OR searching..."
+$LDAPSEARCH -L -S "" -b "$BASEDN" -h localhost -p $PORT \
+       '(|(objectclass=rfc822mailgroup)(sn=jones))' >> $TESTOUT 2>&1
+if [ $RC != 0 ]; then
+       echo "ldapsearch failed!"
+       kill -HUP $PID
+       exit $RC
+fi
+
+echo "Testing AND matching and ends-with searching..."
+$LDAPSEARCH -L -S "" -b "$BASEDN" -h localhost -p $PORT \
+       '(&(objectclass=rfc822mailgroup)(cn=A*))' >> $TESTOUT 2>&1
+if [ $RC != 0 ]; then
+       echo "ldapsearch failed!"
+       kill -HUP $PID
+       exit $RC
+fi
+
+echo "Testing NOT searching..."
+$LDAPSEARCH -L -S "" -b "$BASEDN" -h localhost -p $PORT \
+       '(!(objectclass=person))' | grep -v "^modifytimestamp:" \
+       >> $TESTOUT 2>&1
+if [ $RC != 0 ]; then
+       echo "ldapsearch failed!"
+       kill -HUP $PID
+       exit $RC
+fi
+
+kill -HUP $PID
+
+echo "Comparing results"
+cmp $TESTOUT $SEARCHOUTMASTER
+if [ $? != 0 ]; then
+       echo "Comparison failed"
+       exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+
+exit 0
diff --git a/tests/scripts/test004-modify b/tests/scripts/test004-modify
new file mode 100755 (executable)
index 0000000..09a4fdf
--- /dev/null
@@ -0,0 +1,126 @@
+#!/bin/sh
+
+. scripts/defines.sh
+
+echo "Cleaning up in $DBDIR..."
+
+rm -f $DBDIR/*
+
+echo "Running ldif2ldbm to build slapd database..."
+$LDIF2LDBM -f $CONF -i $LDIF -e ../servers/slapd/tools
+RC=$?
+if [ $RC != 0 ]; then
+       echo "ldif2ldbm failed!"
+       exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT..."
+$SLAPD -f $CONF -p $PORT -d 1 > /dev/null 2>&1 &
+PID=$!
+
+echo "Testing slapd modify operations..."
+for i in 0 1 2 3 4 5; do
+       $LDAPSEARCH -L -S "" -b "$BASEDN" -h localhost -p $PORT \
+               'cn=Manager' > /dev/null 2>&1
+       RC=$?
+       if [ $RC = 1 ]; then
+               echo "Waiting 5 seconds for slapd to start..."
+               sleep 5
+       fi
+done
+
+if [ $RC != 0 ]; then
+       echo "ldapsearch failed!"
+       kill -HUP $PID
+       exit $RC
+fi
+
+cat /dev/null > $TESTOUT
+
+echo "Testing modify, add, and delete..."
+$LDAPMODIFY -v -D "$MANAGERDN" -h localhost -p $PORT -w $PASSWD > \
+       /dev/null 2>&1 << EOMODS
+dn: cn=James A Jones 1, ou=Alumni Association, ou=People, o=University of Michigan, c=US
+changetype: modify
+add: drink
+drink: Orange Juice
+
+dn: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, o=University of Michigan, c=US
+changetype: modify
+replace: multilinedescription
+multilinedescription: The replaced multiLineDescription $ Blah Woof.
+-
+replace: drink
+drink: Iced Tea
+drink: Mad Dog 20/20
+
+dn: cn=ITD Staff,ou=Groups,o=University of Michigan,c=US
+delete: member
+member: cn=James A Jones 2, ou=Information Technology Division, ou=People, o=University of Michigan, c=US
+member: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, o=University of Michigan, c=US
+-
+add: member
+member: cn=Dorothy Stevens, ou=Alumni Association, ou=People, o=University of Michigan, c=US
+member: cn=James A Jones 1, ou=Alumni Association, ou=People, o=University of Michigan, c=US
+
+dn: cn=All Staff,ou=Groups,o=University of Michigan,c=US
+changetype: modify
+delete: member
+
+dn: cn=Gern Jensen, ou=Information Technology Division, ou=People, o=University of Michigan, c=US
+changetype: add
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: Gern Jensen
+title: Chief Investigator, ITD
+postaladdress: ITD $ 535 W. William St $ Ann Arbor, MI 48103
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: gjensen
+krbname: gjensen@umich.edu
+nobatchupdates: TRUE
+onvacation: FALSE
+drink: Coffee
+homepostaladdress: 844 Brown St. Apt. 4 $ Ann Arbor, MI 48104
+multilinedescription: Very odd
+facsimiletelephonenumber: +1 313 555 7557
+telephonenumber: +1 313 555 8343
+mail: gjensen@mailgw.umich.edu
+homephone: +1 313 555 8844
+
+dn: cn=James A Jones 2, ou=Information Technology Division, ou=People, o=University of Michigan, c=US
+changetype: delete
+
+EOMODS
+
+RC=$?
+if [ $RC != 0 ]; then
+       echo "ldapmodify failed!"
+       kill -HUP $PID
+       exit $RC
+fi
+
+echo "Using ldapsearch to retrieve all the entries..."
+$LDAPSEARCH -L -S "" -b "$BASEDN" -h localhost -p $PORT \
+           'objectClass=*' | egrep -iv '^createtimestamp:|^modifytimestamp:' \
+           > $SEARCHOUT 2>&1
+RC=$?
+kill -HUP $PID
+if [ $RC != 0 ]; then
+       echo "ldapsearch failed!"
+       exit $RC
+fi
+
+echo "Comparing database to reference file"
+cmp $SEARCHOUT $MODIFYOUTMASTER
+if [ $? != 0 ]; then
+       echo "comparison failed - modify operations did not complete correctly"
+       exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+
+exit 0
diff --git a/tests/scripts/test005-modrdn b/tests/scripts/test005-modrdn
new file mode 100755 (executable)
index 0000000..0211ada
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+echo "modrdn test not yet written"
+
+exit 0
diff --git a/tests/scripts/test006-acls b/tests/scripts/test006-acls
new file mode 100755 (executable)
index 0000000..ec1c964
--- /dev/null
@@ -0,0 +1,118 @@
+#!/bin/sh
+
+. scripts/defines.sh
+
+echo "Cleaning up in $DBDIR..."
+
+rm -f $DBDIR/*
+
+echo "Running ldif2ldbm to build slapd database..."
+$LDIF2LDBM -f $CONF -i $LDIF -e ../servers/slapd/tools
+RC=$?
+if [ $RC != 0 ]; then
+       echo "ldif2ldbm failed!"
+       exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT..."
+$SLAPD -f $ACLCONF -p $PORT -d 1 > /dev/null 2>&1 &
+PID=$!
+
+echo "Testing slapd access control..."
+for i in 0 1 2 3 4 5; do
+       $LDAPSEARCH -L -S "" -b "$BASEDN" -h localhost -p $PORT \
+               'cn=Monitor' > /dev/null 2>&1
+       RC=$?
+       if [ $RC = 1 ]; then
+               echo "Waiting 5 seconds for slapd to start..."
+               sleep 5
+       fi
+done
+
+if [ $RC != 0 ]; then
+       echo "ldapsearch failed!"
+       kill -HUP $PID
+       exit $RC
+fi
+
+cat /dev/null > $SEARCHOUT
+
+#
+# Try to read an entry inside the Alumni Association container.  It should
+# give us nothing if we're not bound, and should return all attributes
+# if we're bound as anyone under UM.
+#
+$LDAPSEARCH -L -b "$JAJDN" -h localhost -p $PORT "objectclass=*" \
+       >> $SEARCHOUT 2>&1
+
+$LDAPSEARCH -L -b "$JAJDN" -h localhost -p $PORT \
+       -D "$BABSDN" -w bjensen "objectclass=*"  >> $SEARCHOUT 2>&1
+
+
+#
+# Try to add a "member" attribute to the "All Staff" group.  It should
+# fail when we add some DN other than our own, and should succeed when
+# we add our own DN.
+# bjensen
+$LDAPMODIFY -D "$JAJDN" -h localhost -p $PORT -w jaj > \
+       /dev/null 2>&1 << EOMODS1
+dn: cn=ITD Staff, ou=Groups, o=University of Michigan, c=US
+changetype: modify
+add: member
+member: cn=Barbara Jensen, ou=Information Technology Division, ou=People, o=University of Michigan, c=US
+
+EOMODS1
+
+$LDAPMODIFY -D "$JAJDN" -h localhost -p $PORT -w jaj > \
+       /dev/null 2>&1 << EOMODS2
+dn: cn=ITD Staff, ou=Groups, o=University of Michigan, c=US
+changetype: modify
+add: member
+member: cn=James A Jones 1, ou=Alumni Association, ou=People, o=University of Michigan, c=US
+
+EOMODS2
+
+#
+# Try to modify the "All Staff" group.  Two attempts are made:
+# 1) bound as "James A Jones 1" - should fail
+# 2) bound as "Barbara Jensen" - should succeed
+#
+$LDAPMODIFY -D "$JAJDN" -h localhost -p $PORT -w jaj > \
+       /dev/null 2>&1 << EOMODS3
+dn: cn=ITD Staff, ou=Groups, o=University of Michigan, c=US
+changetype: modify
+delete: member
+
+EOMODS3
+
+$LDAPMODIFY -D "$BJORNSDN" -h localhost -p $PORT -w bjorn > \
+       /dev/null 2>&1 << EOMODS4
+dn: cn=ITD Staff, ou=Groups, o=University of Michigan, c=US
+changetype: modify
+add: telephonenumber
+telephonenumber: +1 810 555 1212
+
+EOMODS4
+
+echo "Using ldapsearch to retrieve all the entries..."
+$LDAPSEARCH -L -S "" -b "$BASEDN" -h localhost -p $PORT \
+           'objectClass=*' | egrep -iv '^modifytimestamp|^modifiersname' \
+           >> $SEARCHOUT 2>&1
+RC=$?
+kill -HUP $PID
+if [ $RC != 0 ]; then
+       echo "ldapsearch failed!"
+       exit $RC
+fi
+
+echo "Comparing database to reference file"
+cmp $SEARCHOUT $ACLOUTMASTER
+if [ $? != 0 ]; then
+       echo "comparison failed - modify operations did not complete correctly"
+       exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+
+exit 0
diff --git a/tests/scripts/test007-replication b/tests/scripts/test007-replication
new file mode 100755 (executable)
index 0000000..c0f4913
--- /dev/null
@@ -0,0 +1,161 @@
+#!/bin/sh
+
+#
+# Test replication:
+# - start master
+# - start slave
+# - start slurpd
+# - populate over ldap
+# - perform some modifies and deleted
+# - retrieve database over ldap and compare against expected results
+#
+
+. scripts/defines.sh
+
+echo "Cleaning up in $DBDIR..."
+rm -f $DBDIR/*
+echo "Cleaning up in $REPLDIR..."
+rm -f $REPLDIR/*
+
+echo "Starting master slapd on TCP/IP port $PORT..."
+$SLAPD -f $MASTERCONF -p $PORT -d 1 > /dev/null 2>&1 &
+PID=$!
+
+echo "Starting slave slapd on TCP/IP port $SLAVEPORT..."
+$SLAPD -f $SLAVECONF -p $SLAVEPORT -d 1 > /dev/null 2>&1 &
+SLAVEPID=$!
+
+echo "Using ldapsearch to check that master slapd is running..."
+for i in 0 1 2 3 4 5; do
+       $LDAPSEARCH -L -b "$BASEDN" -h localhost -p $PORT \
+               'cn=Monitor' > /dev/null 2>&1
+       RC=$?
+       if [ $RC = 1 ]; then
+               echo "Waiting 5 seconds for slapd to start..."
+               sleep 5
+       fi
+done
+
+echo "Using ldapsearch to check that slave slapd is running..."
+for i in 0 1 2 3 4 5; do
+       $LDAPSEARCH -L -b "$BASEDN" -h localhost -p $SLAVEPORT \
+               'cn=Monitor' > /dev/null 2>&1
+       RC=$?
+       if [ $RC = 1 ]; then
+               echo "Waiting 5 seconds for slapd to start..."
+               sleep 5
+       fi
+done
+
+echo "Starting slurpd..."
+$SLURPD -f $MASTERCONF -d 4 -t $REPLDIR > /dev/null 2>&1 &
+SLURPPID=$!
+
+echo "Using ldapmodify to populate the database..."
+$LDAPMODIFY -a -D "$MANAGERDN" -h localhost -p $PORT -w $PASSWD < \
+       $LDIFORDERED > /dev/null 2>&1
+RC=$?
+if [ $RC != 0 ]; then
+       echo "ldapmodify failed!"
+       kill -HUP $PID $SLAVEPID $SLURPPID
+       exit $RC
+fi
+
+echo "Using ldapmodify to modify the database..."
+#
+# Do some modifications
+#
+
+$LDAPMODIFY -v -D "$MANAGERDN" -h localhost -p $PORT -w $PASSWD > \
+       /dev/null 2>&1 << EOMODS
+dn: cn=James A Jones 1, ou=Alumni Association, ou=People, o=University of Michigan, c=US
+changetype: modify
+add: drink
+drink: Orange Juice
+
+dn: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, o=University of Michigan, c=US
+changetype: modify
+replace: multilinedescription
+multilinedescription: The replaced multiLineDescription $ Blah Woof.
+-
+replace: drink
+drink: Iced Tea
+drink: Mad Dog 20/20
+
+dn: cn=ITD Staff,ou=Groups,o=University of Michigan,c=US
+delete: member
+member: cn=James A Jones 2, ou=Information Technology Division, ou=People, o=University of Michigan, c=US
+member: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, o=University of Michigan, c=US
+-
+add: member
+member: cn=Dorothy Stevens, ou=Alumni Association, ou=People, o=University of Michigan, c=US
+member: cn=James A Jones 1, ou=Alumni Association, ou=People, o=University of Michigan, c=US
+
+dn: cn=All Staff,ou=Groups,o=University of Michigan,c=US
+changetype: modify
+delete: member
+
+dn: cn=Gern Jensen, ou=Information Technology Division, ou=People, o=University of Michigan, c=US
+changetype: add
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: newPilotPerson
+objectclass: umichPerson
+cn: Gern Jensen
+title: Chief Investigator, ITD
+postaladdress: ITD $ 535 W. William St $ Ann Arbor, MI 48103
+seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US
+uid: gjensen
+krbname: gjensen@umich.edu
+nobatchupdates: TRUE
+onvacation: FALSE
+drink: Coffee
+homepostaladdress: 844 Brown St. Apt. 4 $ Ann Arbor, MI 48104
+multilinedescription: Very odd
+facsimiletelephonenumber: +1 313 555 7557
+telephonenumber: +1 313 555 8343
+mail: gjensen@mailgw.umich.edu
+homephone: +1 313 555 8844
+
+dn: cn=James A Jones 2, ou=Information Technology Division, ou=People, o=University of Michigan, c=US
+changetype: delete
+
+EOMODS
+
+echo "Waiting 10 seconds for slurpd to send changes..."
+sleep 10
+
+echo "Using ldapsearch to read all the entries from the master..."
+$LDAPSEARCH -L -S "" -b "$BASEDN" -h localhost -p $PORT \
+       'objectclass=*' > $MASTEROUT 2>&1
+
+if [ $RC != 0 ]; then
+       echo "ldapsearch failed!"
+       kill -HUP $PID $SLAVEPID $SLURPPID
+       exit $RC
+fi
+
+echo "Using ldapsearch to read all the entries from the slave..."
+$LDAPSEARCH -L -S "" -b "$BASEDN" -h localhost -p $SLAVEPORT \
+       'objectclass=*' > $SLAVEOUT 2>&1
+
+if [ $RC != 0 ]; then
+       echo "ldapsearch failed!"
+       kill -HUP $PID $SLAVEPID $SLURPPID
+       exit $RC
+fi
+
+kill -HUP $PID $SLAVEPID $SLURPPID
+
+echo "Comparing retrieved entries from master and slave..."
+cmp $MASTEROUT $SLAVEOUT
+if [ $? != 0 ]; then
+       echo "test failed - master and slave databases differ"
+       exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+
+exit 0