From 273b96373b6d27999940339ae4b0f0186dc0ffe3 Mon Sep 17 00:00:00 2001 From: eknauel Date: Wed, 31 Dec 2003 15:40:26 +0000 Subject: [PATCH] + make bindings fit to API described as in the LDAP C API draft + use automake for building an external module + tools for importing c constants + numerous changes --- INSTALL | 2 +- Makefile.am | 15 +- Makefile.in | 545 --- c/Makefile.am | 15 +- c/ldap.c | 535 ++- c/main.c | 12 +- c/scsh-ldap.h | 87 +- configure.in | 28 +- doc/TODO | 47 + doc/draft-ietf-ldapext-ldap-c-api-05.txt | 4647 ++++++++++++++++++++++ doc/rfc1823.txt | 1235 ++++++ etc/notes.txt | 14 + etc/slapd.conf | 68 + ffi-tools/ffi-tools-package.scm | 27 + ffi-tools/ffi-tools-rts.scm | 34 + ffi-tools/ffi-tools.c | 96 + ffi-tools/ffi-tools.h | 76 + ffi-tools/ffi-tools.scm | 128 + scheme/Makefile.am | 27 + scheme/configure.scm | 24 + scheme/ldap-constants.scm | 128 + scheme/ldap-interfaces.scm | 15 +- scheme/ldap-packages.scm | 7 +- scheme/ldap-records.scm | 47 + scheme/ldap.scm | 41 +- scheme/load-ldap.scm.in | 17 + 26 files changed, 7206 insertions(+), 711 deletions(-) delete mode 100644 Makefile.in create mode 100644 doc/TODO create mode 100644 doc/draft-ietf-ldapext-ldap-c-api-05.txt create mode 100644 doc/rfc1823.txt create mode 100644 etc/notes.txt create mode 100644 etc/slapd.conf create mode 100644 ffi-tools/ffi-tools-package.scm create mode 100644 ffi-tools/ffi-tools-rts.scm create mode 100644 ffi-tools/ffi-tools.c create mode 100644 ffi-tools/ffi-tools.h create mode 100644 ffi-tools/ffi-tools.scm create mode 100644 scheme/Makefile.am create mode 100644 scheme/configure.scm create mode 100644 scheme/ldap-constants.scm create mode 100644 scheme/ldap-records.scm create mode 100644 scheme/load-ldap.scm.in diff --git a/INSTALL b/INSTALL index 54caf7c..a4b3414 100644 --- a/INSTALL +++ b/INSTALL @@ -1,4 +1,4 @@ -Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software +Copyright 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is free documentation; the Free Software Foundation gives diff --git a/Makefile.am b/Makefile.am index b9329d6..15a8208 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,15 +1,2 @@ -SUBDIRS= c +SUBDIRS = c scheme -scheme/load-ldap.scm: - (echo '(user)'; \ - echo "(open 'dynamic-externals)"; \ - echo "(open 'external-calls)"; \ - echo '(run '; \ - echo " '(let ((initializer-name \"scsh_yp_main\")"; \ - echo ' (module-file "$(prefix)/lib/libldap.so"))'; \ - echo ' (dynamic-load module-file)'; \ - echo ' (call-external (get-external initializer-name))))'; \ - echo '(config)'; \ - echo '(load "ldap-interfaces.scm")'; \ - echo '(load "ldap-packages.scm")'; \ - ) > $@ diff --git a/Makefile.in b/Makefile.in deleted file mode 100644 index fd21d99..0000000 --- a/Makefile.in +++ /dev/null @@ -1,545 +0,0 @@ -# Makefile.in generated by automake 1.7.8 from Makefile.am. -# @configure_input@ - -# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 -# Free Software Foundation, Inc. -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - -srcdir = @srcdir@ -top_srcdir = @top_srcdir@ -VPATH = @srcdir@ -pkgdatadir = $(datadir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -top_builddir = . - -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -INSTALL = @INSTALL@ -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -host_triplet = @host@ -ACLOCAL = @ACLOCAL@ -AMDEP_FALSE = @AMDEP_FALSE@ -AMDEP_TRUE = @AMDEP_TRUE@ -AMTAR = @AMTAR@ -AR = @AR@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -CC = @CC@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CPP = @CPP@ -CPPFLAGS = @CPPFLAGS@ -CXX = @CXX@ -CXXCPP = @CXXCPP@ -CXXDEPMODE = @CXXDEPMODE@ -CXXFLAGS = @CXXFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -ECHO = @ECHO@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -EXEEXT = @EXEEXT@ -F77 = @F77@ -FFLAGS = @FFLAGS@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -LDFLAGS = @LDFLAGS@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LIBTOOL = @LIBTOOL@ -LN_S = @LN_S@ -LTLIBOBJS = @LTLIBOBJS@ -MAKEINFO = @MAKEINFO@ -OBJEXT = @OBJEXT@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -RANLIB = @RANLIB@ -SET_MAKE = @SET_MAKE@ -SHELL = @SHELL@ -STRIP = @STRIP@ -VERSION = @VERSION@ -ac_ct_AR = @ac_ct_AR@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_CXX = @ac_ct_CXX@ -ac_ct_F77 = @ac_ct_F77@ -ac_ct_RANLIB = @ac_ct_RANLIB@ -ac_ct_STRIP = @ac_ct_STRIP@ -am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ -am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ -am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ -am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -datadir = @datadir@ -exec_prefix = @exec_prefix@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localstatedir = @localstatedir@ -mandir = @mandir@ -oldincludedir = @oldincludedir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -sbindir = @sbindir@ -scsh_includes = @scsh_includes@ -scsh_libraries = @scsh_libraries@ -sharedstatedir = @sharedstatedir@ -sysconfdir = @sysconfdir@ -target_alias = @target_alias@ -SUBDIRS = c -subdir = . -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs -CONFIG_HEADER = $(top_builddir)/c/config.h -CONFIG_CLEAN_FILES = -DIST_SOURCES = - -RECURSIVE_TARGETS = info-recursive dvi-recursive pdf-recursive \ - ps-recursive install-info-recursive uninstall-info-recursive \ - all-recursive install-data-recursive install-exec-recursive \ - installdirs-recursive install-recursive uninstall-recursive \ - check-recursive installcheck-recursive -DIST_COMMON = README $(srcdir)/Makefile.in $(srcdir)/configure \ - ../config.guess ../config.sub ../install-sh ../ltmain.sh \ - ../missing ../mkinstalldirs AUTHORS COPYING ChangeLog INSTALL \ - Makefile.am NEWS aclocal.m4 configure configure.in -DIST_SUBDIRS = $(SUBDIRS) -all: all-recursive - -.SUFFIXES: - -am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ - configure.lineno -$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) - cd $(top_srcdir) && \ - $(AUTOMAKE) --gnu Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe) - -$(top_builddir)/config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - $(SHELL) ./config.status --recheck -$(srcdir)/configure: $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES) - cd $(srcdir) && $(AUTOCONF) - -$(ACLOCAL_M4): configure.in - cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs - -distclean-libtool: - -rm -f libtool -uninstall-info-am: - -# This directory's subdirectories are mostly independent; you can cd -# into them and run `make' without going through this Makefile. -# To change the values of `make' variables: instead of editing Makefiles, -# (1) if the variable is set in `config.status', edit `config.status' -# (which will cause the Makefiles to be regenerated when you run `make'); -# (2) otherwise, pass the desired values on the `make' command line. -$(RECURSIVE_TARGETS): - @set fnord $$MAKEFLAGS; amf=$$2; \ - dot_seen=no; \ - target=`echo $@ | sed s/-recursive//`; \ - list='$(SUBDIRS)'; for subdir in $$list; do \ - echo "Making $$target in $$subdir"; \ - if test "$$subdir" = "."; then \ - dot_seen=yes; \ - local_target="$$target-am"; \ - else \ - local_target="$$target"; \ - fi; \ - (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ - done; \ - if test "$$dot_seen" = "no"; then \ - $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ - fi; test -z "$$fail" - -mostlyclean-recursive clean-recursive distclean-recursive \ -maintainer-clean-recursive: - @set fnord $$MAKEFLAGS; amf=$$2; \ - dot_seen=no; \ - case "$@" in \ - distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ - *) list='$(SUBDIRS)' ;; \ - esac; \ - rev=''; for subdir in $$list; do \ - if test "$$subdir" = "."; then :; else \ - rev="$$subdir $$rev"; \ - fi; \ - done; \ - rev="$$rev ."; \ - target=`echo $@ | sed s/-recursive//`; \ - for subdir in $$rev; do \ - echo "Making $$target in $$subdir"; \ - if test "$$subdir" = "."; then \ - local_target="$$target-am"; \ - else \ - local_target="$$target"; \ - fi; \ - (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ - done && test -z "$$fail" -tags-recursive: - list='$(SUBDIRS)'; for subdir in $$list; do \ - test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ - done -ctags-recursive: - list='$(SUBDIRS)'; for subdir in $$list; do \ - test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ - done - -ETAGS = etags -ETAGSFLAGS = - -CTAGS = ctags -CTAGSFLAGS = - -tags: TAGS - -ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - mkid -fID $$unique - -TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - tags=; \ - here=`pwd`; \ - if (etags --etags-include --version) >/dev/null 2>&1; then \ - include_option=--etags-include; \ - else \ - include_option=--include; \ - fi; \ - list='$(SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - test -f $$subdir/TAGS && \ - tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ - fi; \ - done; \ - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - test -z "$(ETAGS_ARGS)$$tags$$unique" \ - || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$tags $$unique - -ctags: CTAGS -CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - tags=; \ - here=`pwd`; \ - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - test -z "$(CTAGS_ARGS)$$tags$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$tags $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && cd $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) $$here - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) - -top_distdir = . -distdir = $(PACKAGE)-$(VERSION) - -am__remove_distdir = \ - { test ! -d $(distdir) \ - || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ - && rm -fr $(distdir); }; } - -GZIP_ENV = --best -distuninstallcheck_listfiles = find . -type f -print -distcleancheck_listfiles = find . -type f -print - -distdir: $(DISTFILES) - $(am__remove_distdir) - mkdir $(distdir) - $(mkinstalldirs) $(distdir)/.. - @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ - list='$(DISTFILES)'; for file in $$list; do \ - case $$file in \ - $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ - $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ - esac; \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test "$$dir" != "$$file" && test "$$dir" != "."; then \ - dir="/$$dir"; \ - $(mkinstalldirs) "$(distdir)$$dir"; \ - else \ - dir=''; \ - fi; \ - if test -d $$d/$$file; then \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ - fi; \ - cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ - else \ - test -f $(distdir)/$$file \ - || cp -p $$d/$$file $(distdir)/$$file \ - || exit 1; \ - fi; \ - done - list='$(SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - test -d $(distdir)/$$subdir \ - || mkdir $(distdir)/$$subdir \ - || exit 1; \ - (cd $$subdir && \ - $(MAKE) $(AM_MAKEFLAGS) \ - top_distdir="$(top_distdir)" \ - distdir=../$(distdir)/$$subdir \ - distdir) \ - || exit 1; \ - fi; \ - done - -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ - ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ - ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ - ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \ - || chmod -R a+r $(distdir) -dist-gzip: distdir - $(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz - $(am__remove_distdir) - -dist dist-all: distdir - $(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz - $(am__remove_distdir) - -# This target untars the dist file and tries a VPATH configuration. Then -# it guarantees that the distribution is self-contained by making another -# tarfile. -distcheck: dist - $(am__remove_distdir) - GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(AMTAR) xf - - chmod -R a-w $(distdir); chmod a+w $(distdir) - mkdir $(distdir)/_build - mkdir $(distdir)/_inst - chmod a-w $(distdir) - dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ - && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ - && cd $(distdir)/_build \ - && ../configure --srcdir=.. --prefix="$$dc_install_base" \ - $(DISTCHECK_CONFIGURE_FLAGS) \ - && $(MAKE) $(AM_MAKEFLAGS) \ - && $(MAKE) $(AM_MAKEFLAGS) dvi \ - && $(MAKE) $(AM_MAKEFLAGS) check \ - && $(MAKE) $(AM_MAKEFLAGS) install \ - && $(MAKE) $(AM_MAKEFLAGS) installcheck \ - && $(MAKE) $(AM_MAKEFLAGS) uninstall \ - && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ - distuninstallcheck \ - && chmod -R a-w "$$dc_install_base" \ - && ({ \ - (cd ../.. && $(mkinstalldirs) "$$dc_destdir") \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ - distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ - } || { rm -rf "$$dc_destdir"; exit 1; }) \ - && rm -rf "$$dc_destdir" \ - && $(MAKE) $(AM_MAKEFLAGS) dist-gzip \ - && rm -f $(distdir).tar.gz \ - && $(MAKE) $(AM_MAKEFLAGS) distcleancheck - $(am__remove_distdir) - @echo "$(distdir).tar.gz is ready for distribution" | \ - sed 'h;s/./=/g;p;x;p;x' -distuninstallcheck: - @cd $(distuninstallcheck_dir) \ - && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ - || { echo "ERROR: files left after uninstall:" ; \ - if test -n "$(DESTDIR)"; then \ - echo " (check DESTDIR support)"; \ - fi ; \ - $(distuninstallcheck_listfiles) ; \ - exit 1; } >&2 -distcleancheck: distclean - @if test '$(srcdir)' = . ; then \ - echo "ERROR: distcleancheck can only run from a VPATH build" ; \ - exit 1 ; \ - fi - @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ - || { echo "ERROR: files left in build directory after distclean:" ; \ - $(distcleancheck_listfiles) ; \ - exit 1; } >&2 -check-am: all-am -check: check-recursive -all-am: Makefile -installdirs: installdirs-recursive -installdirs-am: - -install: install-recursive -install-exec: install-exec-recursive -install-data: install-data-recursive -uninstall: uninstall-recursive - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-recursive -install-strip: - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - INSTALL_STRIP_FLAG=-s \ - `test -z '$(STRIP)' || \ - echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -rm -f $(CONFIG_CLEAN_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-recursive - -clean-am: clean-generic clean-libtool mostlyclean-am - -distclean: distclean-recursive - -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -f Makefile -distclean-am: clean-am distclean-generic distclean-libtool \ - distclean-tags - -dvi: dvi-recursive - -dvi-am: - -info: info-recursive - -info-am: - -install-data-am: - -install-exec-am: - -install-info: install-info-recursive - -install-man: - -installcheck-am: - -maintainer-clean: maintainer-clean-recursive - -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -rf $(top_srcdir)/autom4te.cache - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-recursive - -mostlyclean-am: mostlyclean-generic mostlyclean-libtool - -pdf: pdf-recursive - -pdf-am: - -ps: ps-recursive - -ps-am: - -uninstall-am: uninstall-info-am - -uninstall-info: uninstall-info-recursive - -.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am clean \ - clean-generic clean-libtool clean-recursive ctags \ - ctags-recursive dist dist-all dist-gzip distcheck distclean \ - distclean-generic distclean-libtool distclean-recursive \ - distclean-tags distcleancheck distdir distuninstallcheck dvi \ - dvi-am dvi-recursive info info-am info-recursive install \ - install-am install-data install-data-am install-data-recursive \ - install-exec install-exec-am install-exec-recursive \ - install-info install-info-am install-info-recursive install-man \ - install-recursive install-strip installcheck installcheck-am \ - installdirs installdirs-am installdirs-recursive \ - maintainer-clean maintainer-clean-generic \ - maintainer-clean-recursive mostlyclean mostlyclean-generic \ - mostlyclean-libtool mostlyclean-recursive pdf pdf-am \ - pdf-recursive ps ps-am ps-recursive tags tags-recursive \ - uninstall uninstall-am uninstall-info-am \ - uninstall-info-recursive uninstall-recursive - - -scheme/load-ldap.scm: - (echo '(user)'; \ - echo "(open 'dynamic-externals)"; \ - echo "(open 'external-calls)"; \ - echo '(run '; \ - echo " '(let ((initializer-name \"scsh_yp_main\")"; \ - echo ' (module-file "$(prefix)/lib/libldap.so"))'; \ - echo ' (dynamic-load module-file)'; \ - echo ' (call-external (get-external initializer-name))))'; \ - echo '(config)'; \ - echo '(load "ldap-interfaces.scm")'; \ - echo '(load "ldap-packages.scm")'; \ - ) > $@ -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/c/Makefile.am b/c/Makefile.am index 6d7378c..7385c92 100644 --- a/c/Makefile.am +++ b/c/Makefile.am @@ -1,5 +1,18 @@ INCLUDES = -I@top_srcdir@/c -I@scsh_includes@ +SCSH= @SCSH@ -lib_LTLIBRARIES = libscshldap.la +GENERATED_CODE= ldap-consts.c const-decls-h +SCHEME_DIR= ../scheme +CLEANFILES= $(GENERATED_CODE) + +noinst_LTLIBRARIES = libscshldap.la libscshldap_la_SOURCES = ldap.c + +libscshldap_la_LDFLAGS= + +$(GENERATED_CODE): + $(SCSH) -lm $(SCHEME_DIR)/ffi-tools-packages.scm \ + -lm $(SCHEME_DIR)/ldap-constants.scm \ + -o ldap-constants -c '(make-c-files command-line-arguments)' \ + `pwd` diff --git a/c/ldap.c b/c/ldap.c index 27dfb48..78e0c24 100644 --- a/c/ldap.c +++ b/c/ldap.c @@ -1,43 +1,40 @@ #include "scsh-ldap.h" -/* prototypes */ -s48_value scsh_enter_string_list(char **list); -char** scsh_extract_string_vector(s48_value vector); +FFIT_MAKE_ENTER_RECORD(scsh_enter_ldap, scsh_ldap_record_type, + LDAP*); -s48_value scsh_enter_ldap(LDAP *ldap) -{ - s48_value rec = S48_FALSE; - S48_DECLARE_GC_PROTECT(1); +FFIT_MAKE_ENTER_RECORD(scsh_enter_ldapmessage, scsh_ldapmessage_record_type, + LDAPMessage*); - S48_GC_PROTECT_1(rec); - rec = s48_make_record(scsh_ldap_record_type); - S48_RECORD_SET(rec, 0, s48_enter_integer((long) ldap)); - S48_GC_UNPROTECT(); - return rec; -} +FFIT_MAKE_ENTER_RECORD(scsh_enter_ldapmod, scsh_ldapmod_record_type, + LDAPMod*); -s48_value scsh_enter_ldapmessage(LDAPMessage *lm) -{ - s48_value rec = S48_FALSE; - S48_DECLARE_GC_PROTECT(1); +FFIT_MAKE_ENTER_RECORD(scsh_enter_ldapiinfo, scsh_ldapapiinfo_record_type, + LDAPAPIInfo*); - S48_GC_PROTECT_1(rec); - rec = s48_make_record(scsh_ldapmessage_record_type); - S48_RECORD_SET(rec, 0, s48_enter_integer((long) lm)); - S48_GC_UNPROTECT(); - return rec; -} +FFIT_STRUCT_GET_INT(scsh_ldapapiinfo_get_info_version, + scsh_ldapapiinfo_record_type, LDAPAPIInfo*, + ldapai_info_version); -s48_value scsh_ldap_open(s48_value host, s48_value port) -{ - LDAP *ldap; - S48_DECLARE_GC_PROTECT(2); - - S48_GC_PROTECT_2(host, port); - ldap = ldap_open(s48_extract_string(host), s48_extract_integer(port)); - S48_GC_UNPROTECT(); - return ldap == NULL ? S48_FALSE : scsh_enter_ldap(ldap); -} +FFIT_STRUCT_GET_INT(scsh_ldapapiinfo_get_api_version, + scsh_ldapapiinfo_record_type, LDAPAPIInfo*, + ldapai_api_version); + +FFIT_STRUCT_GET_INT(scsh_ldapapiinfo_get_protocol_version, + scsh_ldapapiinfo_record_type, LDAPAPIInfo*, + ldapai_protocol_version); + +FFIT_STRUCT_GET_STRING(scsh_ldapapiinfo_get_vendor_name, + scsh_ldapapiinfo_record_type, LDAPAPIInfo*, + ldapai_vendor_name); + +FFIT_STRUCT_GET_INT(scsh_ldapapiinfo_get_vendor_version, + scsh_ldapapiinfo_record_type, LDAPAPIInfo*, + ldapai_vendor_version); + +FFIT_STRUCT_GET(scsh_ldapapiinfo_get_extensions, + scsh_ldapapiinfo_record_type, LDAPAPIInfo*, + ldapai_extensions, ffit_enter_string_array); s48_value scsh_ldap_init(s48_value host, s48_value port) { @@ -50,19 +47,6 @@ s48_value scsh_ldap_init(s48_value host, s48_value port) return ldap == NULL ? S48_FALSE : scsh_enter_ldap(ldap); } -s48_value scsh_ldap_bind_s(s48_value ldap, s48_value user, - s48_value cred, s48_value method) -{ - int r; - S48_DECLARE_GC_PROTECT(4); - - S48_GC_PROTECT_4(ldap, user, cred, method); - r = ldap_bind_s(scsh_extract_ldap(ldap), s48_extract_string(user), - s48_extract_string(cred), s48_extract_integer(method)); - S48_GC_UNPROTECT(); - return s48_enter_integer(r); -} - s48_value scsh_ldap_simple_bind_s(s48_value ldap, s48_value user, s48_value cred) { int r; @@ -75,28 +59,25 @@ s48_value scsh_ldap_simple_bind_s(s48_value ldap, s48_value user, s48_value cred return s48_enter_integer(r); } -s48_value scsh_ldap_kerberos_bind_s(s48_value ldap, s48_value dn) +s48_value scsh_ldap_sasl_bind_s(s48_value ldap, s48_value dn, + s48_value mechanism, s48_value cred, + s48_value server_controls, + s48_value client_controls, + s48_value server_cred_p) { -#if HAVE_LDAP_KERBEROS_BIND_S - int r; - S48_DECLARE_GC_PROTECT(2); - - S48_GC_PROTECT_2(ldap, dn); - r = ldap_kerberos_bind_s(scsh_extract_ldap(ldap), s48_extract_string(dn)); - S48_GC_UNPROTECT(); - return s48_enter_integer(r); -#else + /* need to implement bindings for berval stuff first */ return S48_FALSE; -#endif } s48_value scsh_ldap_unbind_s(s48_value ldap) { + FFIT_CHECK_RECORD_TYPE(ldap, scsh_ldap_record_type); return s48_enter_integer(ldap_unbind_s(scsh_extract_ldap(ldap))); } s48_value scsh_ldap_error_string(s48_value errcode) { + FFIT_CHECK_INTEGER(errcode); return s48_enter_string(ldap_err2string(s48_extract_integer(errcode))); } @@ -114,12 +95,14 @@ s48_value scsh_ldap_result_error(s48_value ldap, s48_value res) s48_value scsh_ldap_memfree(s48_value ldap) { + FFIT_CHECK_RECORD_TYPE(ldap, scsh_ldap_record_type); ldap_memfree(scsh_extract_ldap(ldap)); return S48_UNSPECIFIC; } s48_value scsh_ldap_msgfree(s48_value ldapmsg) { + FFIT_CHECK_RECORD_TYPE(ldapmsg, scsh_ldapmessage_record_type); ldap_msgfree(scsh_extract_ldapmessage(ldapmsg)); return S48_UNSPECIFIC; } @@ -135,7 +118,9 @@ s48_value scsh_ldap_search_s(s48_value ldap, s48_value base, S48_DECLARE_GC_PROTECT(7); S48_GC_PROTECT_7(ldap, base, scope, filter, attrs, attrsonly, res); - a = scsh_extract_string_vector(attrs); + FFIT_CHECK_RECORD_TYPE(ldap, scsh_ldap_record_type); + + a = ffit_extract_list_of_strings(attrs); r = ldap_search_s(scsh_extract_ldap(ldap), s48_extract_string(base), s48_extract_integer(scope), @@ -161,12 +146,14 @@ s48_value scsh_ldap_search_st(s48_value ldap, s48_value base, s48_value res = S48_FALSE; S48_DECLARE_GC_PROTECT(9); - S48_GC_PROTECT_4(ldap, base, scope, filter); - S48_GC_PROTECT_3(attrs, attrsonly, res); - S48_GC_PROTECT_2(timeout_sec, timeout_usec); + S48_GC_PROTECT_9(ldap, base, scope, filter, attrs, attrsonly, res, + timeout_sec, timeout_usec); + FFIT_CHECK_RECORD_TYPE(ldap, scsh_ldap_record_type); + timeout.tv_sec = s48_extract_integer(timeout_sec); timeout.tv_usec = s48_extract_integer(timeout_usec); - a = scsh_extract_string_vector(attrs); + a = ffit_extract_list_of_strings(attrs); + r = ldap_search_st(scsh_extract_ldap(ldap), s48_extract_string(base), s48_extract_integer(scope), s48_extract_string(filter), a, S48_TRUE_P(attrsonly), &timeout, msg); @@ -176,12 +163,34 @@ s48_value scsh_ldap_search_st(s48_value ldap, s48_value base, return res; } +s48_value scsh_ldap_compare_s(s48_value ldap, s48_value dn, + s48_value attr, s48_value value) +{ + s48_value res; + int r; + S48_DECLARE_GC_PROTECT(5); + + S48_GC_PROTECT_5(ldap, dn, attr, value, res); + FFIT_CHECK_RECORD_TYPE(ldap, scsh_ldap_record_type); + r = ldap_compare_s(scsh_extract_ldap(ldap), s48_extract_string(dn), + s48_extract_string(attr), s48_extract_string(value)); + S48_GC_UNPROTECT(); + switch (r) { + case LDAP_COMPARE_TRUE: return S48_TRUE; + case LDAP_COMPARE_FALSE: return S48_FALSE; + default: return s48_enter_integer(r); + } +} + s48_value scsh_ldap_count_entries(s48_value ldap, s48_value lm) { int r; S48_DECLARE_GC_PROTECT(2); S48_GC_PROTECT_2(ldap, lm); + FFIT_CHECK_RECORD_TYPE(ldap, scsh_ldap_record_type); + FFIT_CHECK_RECORD_TYPE(lm, scsh_ldapmessage_record_type); + r = ldap_count_entries(scsh_extract_ldap(ldap), scsh_extract_ldapmessage(lm)); S48_GC_UNPROTECT(); @@ -191,35 +200,122 @@ s48_value scsh_ldap_count_entries(s48_value ldap, s48_value lm) s48_value scsh_ldap_first_entry(s48_value ldap, s48_value lm) { LDAPMessage *lm_new; - s48_value res = S48_FALSE; - S48_DECLARE_GC_PROTECT(3); + S48_DECLARE_GC_PROTECT(2); - S48_GC_PROTECT_3(ldap, lm, res); + S48_GC_PROTECT_2(ldap, lm); + FFIT_CHECK_RECORD_TYPE(ldap, scsh_ldap_record_type); + FFIT_CHECK_RECORD_TYPE(lm, scsh_ldapmessage_record_type); + lm_new = ldap_first_entry(scsh_extract_ldap(ldap), scsh_extract_ldapmessage(lm)); - res = scsh_enter_ldapmessage(lm_new); S48_GC_UNPROTECT(); - return res; + return (lm_new == NULL) ? S48_FALSE : scsh_enter_ldapmessage(lm_new); } s48_value scsh_ldap_next_entry(s48_value ldap, s48_value lm) { LDAPMessage *lm_new; - s48_value res = S48_FALSE; - S48_DECLARE_GC_PROTECT(3); + S48_DECLARE_GC_PROTECT(2); + + S48_GC_PROTECT_2(ldap, lm); + FFIT_CHECK_RECORD_TYPE(ldap, scsh_ldap_record_type); + FFIT_CHECK_RECORD_TYPE(lm, scsh_ldapmessage_record_type); - S48_GC_PROTECT_3(ldap, lm, res); lm_new = ldap_next_entry(scsh_extract_ldap(ldap), scsh_extract_ldapmessage(lm)); - res = scsh_enter_ldapmessage(lm_new); S48_GC_UNPROTECT(); - return res; + return (lm_new == NULL) ? S48_FALSE : scsh_enter_ldapmessage(lm_new); +} + +s48_value scsh_ldap_first_message(s48_value ldap, s48_value lm) +{ + LDAPMessage *first; + S48_DECLARE_GC_PROTECT(2); + + S48_GC_PROTECT_2(ldap, lm); + FFIT_CHECK_RECORD_TYPE(ldap, scsh_ldap_record_type); + FFIT_CHECK_RECORD_TYPE(lm, scsh_ldapmessage_record_type); + first = ldap_first_message(scsh_extract_ldap(ldap), + scsh_extract_ldapmessage(lm)); + S48_GC_UNPROTECT(); + return (first == NULL) ? S48_FALSE : scsh_enter_ldapmessage(first); +} + +s48_value scsh_ldap_next_message(s48_value ldap, s48_value lm) +{ + LDAPMessage *next; + S48_DECLARE_GC_PROTECT(2); + + S48_GC_PROTECT_2(ldap, lm); + FFIT_CHECK_RECORD_TYPE(ldap, scsh_ldap_record_type); + FFIT_CHECK_RECORD_TYPE(lm, scsh_ldapmessage_record_type); + next = ldap_next_message(scsh_extract_ldap(ldap), + scsh_extract_ldapmessage(lm)); + S48_GC_UNPROTECT(); + return (next == NULL) ? S48_FALSE : scsh_enter_ldapmessage(next); +} + +s48_value scsh_ldap_count_messages(s48_value ldap, s48_value lm) +{ + int c; + S48_DECLARE_GC_PROTECT(2); + + S48_GC_PROTECT_2(ldap, lm); + FFIT_CHECK_RECORD_TYPE(ldap, scsh_ldap_record_type); + FFIT_CHECK_RECORD_TYPE(lm, scsh_ldapmessage_record_type); + c = ldap_count_messages(scsh_extract_ldap(ldap), + scsh_extract_ldapmessage(lm)); + S48_GC_UNPROTECT(); + return (c == -1) ? S48_FALSE : s48_enter_integer(c); +} + +s48_value scsh_ldap_first_reference(s48_value ldap, s48_value lm) +{ + LDAPMessage *new_lm; + S48_DECLARE_GC_PROTECT(2); + + S48_GC_PROTECT_2(ldap, lm); + FFIT_CHECK_RECORD_TYPE(ldap, scsh_ldap_record_type); + FFIT_CHECK_RECORD_TYPE(lm, scsh_ldapmessage_record_type); + new_lm = ldap_first_reference(scsh_extract_ldap(ldap), + scsh_extract_ldapmessage(lm)); + S48_GC_UNPROTECT(); + return (new_lm == NULL) ? S48_FALSE : scsh_enter_ldapmessage(new_lm); +} + +s48_value scsh_ldap_next_reference(s48_value ldap, s48_value lm) +{ + LDAPMessage *new_lm; + S48_DECLARE_GC_PROTECT(2); + + S48_GC_PROTECT_2(ldap, lm); + FFIT_CHECK_RECORD_TYPE(ldap, scsh_ldap_record_type); + FFIT_CHECK_RECORD_TYPE(lm, scsh_ldapmessage_record_type); + new_lm = ldap_next_reference(scsh_extract_ldap(ldap), + scsh_extract_ldapmessage(lm)); + S48_GC_UNPROTECT(); + return (new_lm == NULL) ? S48_FALSE : scsh_enter_ldapmessage(new_lm); +} + +s48_value scsh_ldap_count_references(s48_value ldap, s48_value lm) +{ + int c; + S48_DECLARE_GC_PROTECT(2); + + S48_GC_PROTECT_2(ldap, lm); + FFIT_CHECK_RECORD_TYPE(ldap, scsh_ldap_record_type); + FFIT_CHECK_RECORD_TYPE(lm, scsh_ldapmessage_record_type); + c = ldap_count_references(scsh_extract_ldap(ldap), + scsh_extract_ldapmessage(lm)); + S48_GC_UNPROTECT(); + return (c == -1) ? S48_FALSE : s48_enter_integer(c); } s48_value scsh_ldap_msgtype(s48_value lm) { int r; - + + FFIT_CHECK_RECORD_TYPE(lm, scsh_ldapmessage_record_type); r = ldap_msgtype(scsh_extract_ldapmessage(lm)); return s48_enter_integer(r); } @@ -228,10 +324,69 @@ s48_value scsh_ldap_msgid(s48_value lm) { int r; + FFIT_CHECK_RECORD_TYPE(lm, scsh_ldapmessage_record_type); r = ldap_msgid(scsh_extract_ldapmessage(lm)); return s48_enter_integer(r); } +/* may raise ldap error */ +s48_value scsh_ldap_get_dn(s48_value ldap, s48_value entry) +{ + char *s; + S48_DECLARE_GC_PROTECT(2); + + S48_GC_PROTECT_2(ldap, entry); + FFIT_CHECK_RECORD_TYPE(ldap, scsh_ldap_record_type); + FFIT_CHECK_RECORD_TYPE(entry, scsh_ldapmessage_record_type); + s = ldap_get_dn(scsh_extract_ldap(ldap), scsh_extract_ldapmessage(entry)); + S48_GC_UNPROTECT(); + return (s == NULL) ? S48_FALSE : s48_enter_string(s); +} + +s48_value scsh_ldap_explode_dn(s48_value dn, s48_value notypes) +{ + char **a; + s48_value res = S48_FALSE; + S48_DECLARE_GC_PROTECT(3); + + S48_GC_PROTECT_3(dn, notypes, res); + a = ldap_explode_dn(s48_extract_string(dn), + S48_TRUE_P(notypes) ? 0 : 1); + res = ffit_enter_string_array(a); + S48_GC_UNPROTECT(); + ldap_value_free(a); + return res; +} + +s48_value scsh_ldap_explode_rdn(s48_value rdn, s48_value notypes) +{ + char **a; + s48_value res = S48_FALSE; + S48_DECLARE_GC_PROTECT(3); + + S48_GC_PROTECT_3(rdn, notypes, res); + a = ldap_explode_rdn(s48_extract_string(rdn), + S48_TRUE_P(notypes) ? 0 : 1); + res = ffit_enter_string_array(a); + S48_GC_UNPROTECT(); + ldap_value_free(a); + return res; +} + +s48_value scsh_ldap_dn2ufn(s48_value dn) +{ + char *a; + s48_value res = S48_FALSE; + S48_DECLARE_GC_PROTECT(2); + + S48_GC_PROTECT_2(dn, res); + a = ldap_dn2ufn(s48_extract_string(dn)); + res = s48_enter_string(a); + S48_GC_UNPROTECT(); + ldap_memfree(a); + return res; +} + s48_value scsh_ldap_get_values(s48_value ldap, s48_value entry, s48_value attr) { @@ -240,61 +395,225 @@ s48_value scsh_ldap_get_values(s48_value ldap, s48_value entry, S48_DECLARE_GC_PROTECT(4); S48_GC_PROTECT_4(ldap, entry, attr, res); + FFIT_CHECK_RECORD_TYPE(ldap, scsh_ldap_record_type); + FFIT_CHECK_RECORD_TYPE(entry, scsh_ldapmessage_record_type); + val = ldap_get_values(scsh_extract_ldap(ldap), scsh_extract_ldapmessage(entry), s48_extract_string(attr)); - res = scsh_enter_string_list(val); + res = ffit_enter_string_array(val); ldap_value_free(val); S48_GC_UNPROTECT(); return res; } -/* TODO: ldap_get_values_len() -- for binary attribute values */ -s48_value scsh_enter_string_list(char **list) +s48_value scsh_ldap_modify(s48_value ldap, s48_value dn, s48_value mods) { - int i; - s48_value res = S48_NULL; - S48_DECLARE_GC_PROTECT(1); + int r; + S48_DECLARE_GC_PROTECT(3); - S48_GC_PROTECT_1(res); - for (i = 0; list[i] != NULL; i++) - res = s48_cons(s48_enter_string(list[i]), res); + S48_GC_PROTECT_3(ldap, dn, mods); + FFIT_CHECK_RECORD_TYPE(ldap, scsh_ldap_record_type); + r = ldap_modify_s(scsh_extract_ldap(ldap), s48_extract_string(dn), + scsh_extract_ldapmod_vector(mods)); S48_GC_UNPROTECT(); - return res; + return s48_enter_integer(r); } -char** scsh_extract_string_vector(s48_value vector) +s48_value scsh_ldap_add(s48_value ldap, s48_value dn, s48_value mods) { - char** a; + int r; + S48_DECLARE_GC_PROTECT(3); + + S48_GC_PROTECT_3(ldap, dn, mods); + FFIT_CHECK_RECORD_TYPE(ldap, scsh_ldap_record_type); + if (!S48_VECTOR_P(mods)) + s48_raise_argument_type_error(mods); + + r = ldap_add_s(scsh_extract_ldap(ldap), s48_extract_string(dn), + scsh_extract_ldapmod_vector(mods)); + S48_GC_UNPROTECT(); + return s48_enter_integer(r); +} + +s48_value scsh_ldap_delete(s48_value ldap, s48_value dn) +{ + int r; + S48_DECLARE_GC_PROTECT(2); + + S48_GC_PROTECT_2(ldap, dn); + FFIT_CHECK_RECORD_TYPE(ldap, scsh_ldap_record_type); + r = ldap_delete_s(scsh_extract_ldap(ldap), s48_extract_string(dn)); + S48_GC_UNPROTECT(); + return s48_enter_integer(r); +} + +s48_value scsh_ldap_abandon(s48_value ldap, s48_value msgid) +{ + int r; + S48_DECLARE_GC_PROTECT(2); + + S48_GC_PROTECT_2(ldap, msgid); + FFIT_CHECK_RECORD_TYPE(ldap, scsh_ldap_record_type); + r = ldap_abandon(scsh_extract_ldap(ldap), s48_extract_integer(msgid)); + S48_GC_UNPROTECT(); + return s48_enter_integer(r); +} + +s48_value scsh_ldap_get_set_option(s48_value ldap, s48_value option, + s48_value set, s48_value inval) +{ + int opt, r; + LDAP *ld; + void *outvalue; + s48_value res = S48_UNSPECIFIC; + + FFIT_CHECK_RECORD_TYPE(ldap, scsh_ldap_record_type); + FFIT_CHECK_BOOLEAN(set); + ld = scsh_extract_ldap(ldap); + + switch (opt) { + case LDAP_OPT_API_INFO: + { + if (S48_TRUE_P(set)) + raise_ldap_read_only_option(); + r = ldap_get_option(ld, opt, outvalue); + if (r == LDAP_SUCCESS) + res = scsh_enter_ldapiinfo((LDAPAPIInfo *) outvalue); + break; + } + case LDAP_OPT_DEREF: + { + } + case LDAP_OPT_SIZELIMIT: + case LDAP_OPT_TIMELIMIT: + { + int l; + if (S48_TRUE_P(set)) { + FFIT_CHECK_INTEGER(inval); + l = s48_extract_integer(inval); + r = ldap_set_option(ld, opt, &l); + } + else + if ((r = ldap_get_option(ld, opt, outvalue)) == LDAP_SUCCESS) + res = s48_enter_integer(*((int*)outvalue)); + break; + } + case LDAP_OPT_REFERRALS: + case LDAP_OPT_RESTART: + { + if (S48_TRUE_P(set)) { + FFIT_CHECK_BOOLEAN(inval); + r = ldap_set_option(ld, opt, S48_TRUE_P(inval) ? LDAP_OPT_ON : LDAP_OPT_OFF); + } + else + if ((r = ldap_get_option(ld, opt, outvalue)) == LDAP_SUCCESS) + res = outvalue == 0 ? S48_TRUE : S48_FALSE; + break; + } + case LDAP_OPT_PROTOCOL_VERSION: + { + int v; + if (S48_TRUE_P(set)) { + FFIT_CHECK_INTEGER(inval); + v = s48_extract_integer(inval); + r = ldap_set_option(ld, opt, &v); + } + else + if ((r = ldap_get_option(ld, opt, outvalue)) == LDAP_SUCCESS) + res = s48_enter_integer(*(int *)outvalue); + break; + } + case LDAP_OPT_SERVER_CONTROLS: + case LDAP_OPT_CLIENT_CONTROLS: + { + raise_ldap_read_only_option(); + } + } +} + +/* ************************************************************************ */ + +/* FIXME: support modv_bvals (binary values) */ +s48_value scsh_ldapmod_create(s48_value op, s48_value type, s48_value data_vector) +{ + LDAPMod *m; + S48_DECLARE_GC_PROTECT(3); + + S48_GC_PROTECT_3(op, type, data_vector); + if ((m = (LDAPMod*) calloc(1, sizeof(LDAPMod))) == NULL) + raise_ldap_memory_alloc_error(); + + m->mod_op = s48_extract_integer(op); + m->mod_type = s48_extract_string(type); + m->mod_vals.modv_strvals = ffit_extract_list_of_strings(data_vector); + + return scsh_enter_ldapmod(m); +} + +LDAPMod** scsh_extract_ldapmod_vector(s48_value vector) +{ + LDAPMod **a; int l, i; S48_DECLARE_GC_PROTECT(1); - + S48_GC_PROTECT_1(vector); l = S48_VECTOR_LENGTH(vector); - if ((a = calloc (l, sizeof(char *))) == NULL) - RAISE_MEMORY_ALLOC_ERROR("scsh_extract_string_vector"); + if ((*a = (LDAPMod *) calloc(l+1, sizeof(LDAPMod*))) == NULL) + raise_ldap_memory_alloc_error(); for (i = 0; i < l; i++) - a[i] = s48_extract_string(S48_VECTOR_REF(vector, i)); + a[i] = scsh_extract_ldapmod(S48_VECTOR_REF(vector, i)); + a[l] = NULL; S48_GC_UNPROTECT(); return a; } -void scsh_ldap_main(void) +void raise_ldap_memory_alloc_error(void) +{ + s48_raise_scheme_exception(condition_ldap_memory_alloc_error, 0); +} + +void raise_ldap_feature_not_supported(void) { - S48_GC_PROTECT_GLOBAL(scsh_ldap_record_type); - scsh_ldap_record_type = s48_get_imported_binding("ldap"); + s48_raise_scheme_exception(condition_ldap_feature_not_supported, 0); +} - S48_GC_PROTECT_GLOBAL(scsh_ldapmessage_record_type); - scsh_ldapmessage_record_type = s48_get_imported_binding("ldap-message"); +void raise_ldap_read_only_option(void) +{ + s48_raise_scheme_exception(condition_ldap_read_only_option, 0); +} - S48_GC_PROTECT_GLOBAL(raise_ldap_memory_alloc_error); - raise_ldap_memory_alloc_error = s48_get_imported_binding("raise-ldap-memory-alloc-error"); +void scsh_init_ldap_bindings(void) +{ + ffit_init_hook(); + + scsh_ldap_gc_protect_globals(); + S48_GC_PROTECT_GLOBAL(condition_ldap_memory_alloc_error); + S48_GC_PROTECT_GLOBAL(condition_ldap_feature_not_supported); + S48_GC_PROTECT_GLOBAL(condition_ldap_read_only_option); + + condition_ldap_memory_alloc_error = + s48_get_imported_binding("condition-ldap-memory-alloc-error"); + condition_ldap_feature_not_supported = + s48_get_imported_binding("condition-ldap-feature-not-supported"); + condition_ldap_read_only_option = + s48_get_imported_binding("condition-ldap-read-only-option"); + + scsh_ldap_enter_ldap_constants(); + FFIT_RECORD_TYPE_INIT(scsh_ldap_record_type, ldap); + FFIT_RECORD_TYPE_INIT(scsh_ldapmessage_record_type, ldap-message); + FFIT_RECORD_TYPE_INIT(scsh_ldapmod_record_type, ldap-modification); + + FFIT_RECORD_TYPE_INIT(scsh_ldapapiinfo_record_type, ldap-api-info); + S48_EXPORT_FUNCTION(scsh_ldapapiinfo_get_info_version); + S48_EXPORT_FUNCTION(scsh_ldapapiinfo_get_protocol_version); + S48_EXPORT_FUNCTION(scsh_ldapapiinfo_get_vendor_name); + S48_EXPORT_FUNCTION(scsh_ldapapiinfo_get_vendor_version); + S48_EXPORT_FUNCTION(scsh_ldapapiinfo_get_extensions); - S48_EXPORT_FUNCTION(scsh_ldap_open); S48_EXPORT_FUNCTION(scsh_ldap_init); - S48_EXPORT_FUNCTION(scsh_ldap_bind_s); S48_EXPORT_FUNCTION(scsh_ldap_simple_bind_s); - S48_EXPORT_FUNCTION(scsh_ldap_kerberos_bind_s); + S48_EXPORT_FUNCTION(scsh_ldap_sasl_bind_s); S48_EXPORT_FUNCTION(scsh_ldap_unbind_s); S48_EXPORT_FUNCTION(scsh_ldap_error_string); S48_EXPORT_FUNCTION(scsh_ldap_result_error); @@ -302,11 +621,27 @@ void scsh_ldap_main(void) S48_EXPORT_FUNCTION(scsh_ldap_msgfree); S48_EXPORT_FUNCTION(scsh_ldap_search_s); S48_EXPORT_FUNCTION(scsh_ldap_search_st); + S48_EXPORT_FUNCTION(scsh_ldap_compare_s); S48_EXPORT_FUNCTION(scsh_ldap_count_entries); S48_EXPORT_FUNCTION(scsh_ldap_first_entry); S48_EXPORT_FUNCTION(scsh_ldap_next_entry); + S48_EXPORT_FUNCTION(scsh_ldap_first_message); + S48_EXPORT_FUNCTION(scsh_ldap_next_message); + S48_EXPORT_FUNCTION(scsh_ldap_count_messages); + S48_EXPORT_FUNCTION(scsh_ldap_first_reference); + S48_EXPORT_FUNCTION(scsh_ldap_next_reference); + S48_EXPORT_FUNCTION(scsh_ldap_count_references); S48_EXPORT_FUNCTION(scsh_ldap_msgtype); S48_EXPORT_FUNCTION(scsh_ldap_msgid); + S48_EXPORT_FUNCTION(scsh_ldap_get_dn); + S48_EXPORT_FUNCTION(scsh_ldap_explode_dn); + S48_EXPORT_FUNCTION(scsh_ldap_explode_rdn); + S48_EXPORT_FUNCTION(scsh_ldap_dn2ufn); S48_EXPORT_FUNCTION(scsh_ldap_get_values); + S48_EXPORT_FUNCTION(scsh_ldap_modify); + S48_EXPORT_FUNCTION(scsh_ldap_add); + S48_EXPORT_FUNCTION(scsh_ldap_delete); + S48_EXPORT_FUNCTION(scsh_ldap_abandon); + S48_EXPORT_FUNCTION(scsh_ldap_get_set_option); + S48_EXPORT_FUNCTION(scsh_ldapmod_create); } - diff --git a/c/main.c b/c/main.c index 5c97f19..4a67975 100644 --- a/c/main.c +++ b/c/main.c @@ -1,13 +1,13 @@ #include "scheme48.h" -#include "c/config.h" +#include "config.h" -extern void scsh_ldap_main(); - -int main(int argc, char **argv) -{ - s48_add_external_init(scsh_ldap_main); +extern void scsh_init_ldap_bindings(void); +int main(int argc, char **argv) { + + s48_add_external_init(scsh_init_ldap_bindings); return s48_main(10000000, 64000, SCSHIMAGE, --argc, ++argv); } + diff --git a/c/scsh-ldap.h b/c/scsh-ldap.h index 31a44cc..5ee1177 100644 --- a/c/scsh-ldap.h +++ b/c/scsh-ldap.h @@ -1,32 +1,105 @@ -#include "scheme48.h" #include "config.h" #include -#include +/* time.h */ +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#include "scheme48.h" +#include "ffi-tools/ffi-tools.h" #include static s48_value scsh_ldap_record_type = S48_FALSE; static s48_value scsh_ldapmessage_record_type = S48_FALSE; +static s48_value scsh_ldapmod_record_type = S48_FALSE; +static s48_value scsh_ldapapiinfo_record_type = S48_FALSE; -s48_value scsh_enter_ldap(LDAP *ldap); +FFIT_MAKE_ENTER_RECORD_PROTOTYPE(scsh_enter_ldap, LDAP*); #define scsh_extract_ldap(x) \ ((LDAP *) \ s48_extract_integer(S48_RECORD_REF(x, 0))) -s48_value scsh_enter_ldapmessage(LDAPMessage *lm); +FFIT_MAKE_ENTER_RECORD_PROTOTYPE(scsh_enter_ldapmessage, LDAPMessage*); #define scsh_extract_ldapmessage(x) \ ((LDAPMessage *) \ s48_extract_integer(S48_RECORD_REF(x, 0))) +FFIT_MAKE_ENTER_RECORD_PROTOTYPE(scsh_enter_ldapmod, LDAPMod*); +#define scsh_extract_ldapmod(x) \ + ((LDAPMod *) \ + s48_extract_integer(S48_RECORD_REF(x, 0))) + +FFIT_MAKE_ENTER_RECORD_PROTOTYPE(scsh_enter_ldapapiinfo, LDAPAPIInfo*); +#define scsh_extract_ldapapiinfo(x) \ + ((LDAPAPIInfo *) \ + s48_extract_integer(S48_RECORD_REF(x, 0))) + /* conditions */ -static s48_value raise_ldap_memory_alloc_error = S48_FALSE; +static s48_value condition_ldap_memory_alloc_error = S48_FALSE; +static s48_value condition_ldap_feature_not_supported = S48_FALSE; +static s48_value condition_ldap_read_only_option = S48_FALSE; #define RAISE_MEMORY_ALLOC_ERROR(FUNNAME) \ s48_call_scheme(S48_SHARED_BINDING_REF(raise_ldap_memory_alloc_error), \ 1, s48_enter_string(FUNNAME)); -char** scsh_extract_string_vector(s48_value vector); +/* prototypes */ -void scsh_ldap_main(void); +/* function body generated by ffi-tools */ +void scsh_ldap_enter_ldap_constants(void); + +/* function body generated by ffi-tools */ +void scsh_ldap_gc_protect_globals(void); + +LDAPMod** scsh_extract_ldapmod_vector(s48_value); +void raise_ldap_memory_alloc_error(void); +void raise_ldap_feature_not_supported(void); +void raise_ldap_read_only_option(void); + +s48_value scsh_ldap_init(s48_value, s48_value); +s48_value scsh_ldap_simple_bind_s(s48_value, s48_value, s48_value); +s48_value scsh_ldap_sasl_bind_s(s48_value, s48_value, s48_value, s48_value, + s48_value, s48_value, s48_value); +s48_value scsh_ldap_unbind_s(s48_value); +s48_value scsh_ldap_error_string(s48_value); +s48_value scsh_ldap_result_error(s48_value, s48_value); +s48_value scsh_ldap_memfree(s48_value); +s48_value scsh_ldap_msgfree(s48_value); +s48_value scsh_ldap_search_s(s48_value, s48_value, s48_value, s48_value, + s48_value, s48_value); +s48_value scsh_ldap_search_st(s48_value, s48_value, s48_value, s48_value, + s48_value, s48_value, s48_value, s48_value); +s48_value scsh_ldap_compare_s(s48_value, s48_value, s48_value, s48_value); +s48_value scsh_ldap_count_entries(s48_value, s48_value); +s48_value scsh_ldap_first_entry(s48_value, s48_value); +s48_value scsh_ldap_next_entry(s48_value, s48_value); +s48_value scsh_ldap_first_message(s48_value, s48_value); +s48_value scsh_ldap_next_message(s48_value, s48_value); +s48_value scsh_ldap_count_messages(s48_value, s48_value); +s48_value scsh_ldap_first_reference(s48_value, s48_value); +s48_value scsh_ldap_next_reference(s48_value, s48_value); +s48_value scsh_ldap_count_references(s48_value, s48_value); +s48_value scsh_ldap_msgtype(s48_value); +s48_value scsh_ldap_msgid(s48_value); +s48_value scsh_ldap_get_dn(s48_value, s48_value); +s48_value scsh_ldap_explode_dn(s48_value, s48_value); +s48_value scsh_ldap_explode_rdn(s48_value, s48_value); +s48_value scsh_ldap_dn2ufn(s48_value); +s48_value scsh_ldap_get_values(s48_value, s48_value, s48_value); +s48_value scsh_ldap_modify(s48_value, s48_value, s48_value); +s48_value scsh_ldap_add(s48_value, s48_value, s48_value); +s48_value scsh_ldap_delete(s48_value, s48_value); +s48_value scsh_ldap_abandon(s48_value, s48_value); +s48_value scsh_ldap_get_set_option(s48_value, s48_value, s48_value, s48_value); +s48_value scsh_ldapmod_create(s48_value, s48_value, s48_value); +void scsh_init_ldap_bindings(void); diff --git a/configure.in b/configure.in index eb5919f..49854e8 100644 --- a/configure.in +++ b/configure.in @@ -4,11 +4,12 @@ AM_INIT_AUTOMAKE dnl AM_MAINTAINER_MODE -AC_CONFIG_HEADERS(c/config.h) +AM_CONFIG_HEADER(c/config.h) AC_PROG_LIBTOOL AC_PROG_CC -define([PREPEND], [[$2]="$[$2] [$1]"]) +AC_HEADER_STDC +AC_CHECK_HEADERS(sys/time.h) AC_ARG_WITH(scsh-includes, AC_HELP_STRING([--with-scsh-includes=DIR], @@ -16,13 +17,15 @@ AC_ARG_WITH(scsh-includes, scsh_includes=$withval, scsh_includes=/usr/local/include) AC_SUBST(scsh_includes) +dnl AC_SUBST(CFLAGS, "$CFLAGS -I${scsh_includes}") +dnl AC_CHECK_HEADER([scheme48.h], [], +dnl AC_MSG_FAILURE("Could not find scheme48.h")) -AC_ARG_WITH(scsh-libraries, - AC_HELP_STRING([--with-scsh-libraries=DIR], - [scsh libraries are in DIR [/usr/local/lib/scsh]]), - scsh_libraries=$withval, - scsh_libraries=/usr/local/lib/scsh) -AC_SUBST(scsh_libraries) +AC_PATH_PROG([SCSH], [scsh], [-not found-], [$PATH]) +if test "$SCSH" = "-not found-"; then + AC_MSG_FAILURE("No scsh binary in path") +fi +AC_SUBST(SCSH) AC_ARG_WITH(ldap-prefix, AC_HELP_STRING([--with-ldap-prefix=DIR], @@ -69,6 +72,13 @@ AC_CHECK_FUNC([ldap_get_values], [], AC_CHECK_FUNCS([ldap_kerberos_bind_s]) +schemedir='${prefix}'"/scheme" +libdir='${prefix}'"/lib" +libsysdir=${libdir}"/`scsh -lm ${srcdir}/scheme/configure.scm -o configure -c '(display (host))'`" + +AC_SUBST(libdir) +AC_SUBST(libsysdir) +AC_SUBST(schemedir) AC_SUBST(LIBS) AC_SUBST(CC) -AC_OUTPUT([Makefile c/Makefile]) +AC_OUTPUT([Makefile c/Makefile scheme/Makefile]) diff --git a/doc/TODO b/doc/TODO new file mode 100644 index 0000000..f5c0ed6 --- /dev/null +++ b/doc/TODO @@ -0,0 +1,47 @@ + -*- outline -*- + +* Missing functionality + +** Server/Client-controls + plus all _ext_s() functions: + ldap_unbind_ext() + ldap_search_ext_s() + ldap_compare_ext_s() + ldap_modify_ext_s() + ldap_rename_s() + ldap_add_ext_s() + ldap_delete_ext_s() + ldap_extended_operation_s() + ldap_abandon_ext() + ldap_parse_result() + ldap_parse_sasl_bind_result() + ldap_parse_extended_result() + +* Fixing needed + +* Need ber-stuff first + ldap_sasl_bind_s() + ldap_first_attribute() + ldap_next_attribute() + ldap_get_value_len() + +* Not implemented + +** Check for errors in ldap_{first, next}_{entries, references, messages} + + These functions may return S48_FALSE if the corresponding C + function returns NULL. This is ambigious: a) end of list b) error + solution: check for error in Scheme + + ldap_explode_dn() + ldap_explode_rdn() + ldap_dn2ufn() + + ldap_get_entry_controls() + + ldap_parse_reference() + +* structures and accessors + + struct berval + struct ldapmod diff --git a/doc/draft-ietf-ldapext-ldap-c-api-05.txt b/doc/draft-ietf-ldapext-ldap-c-api-05.txt new file mode 100644 index 0000000..02a3486 --- /dev/null +++ b/doc/draft-ietf-ldapext-ldap-c-api-05.txt @@ -0,0 +1,4647 @@ + + +Network Working Group M. Smith, Editor +INTERNET-DRAFT Netscape Communications Corp. +Intended Category: Standards Track T. Howes +Obsoletes: RFC 1823 Loudcloud, Inc. +Expires: May 2001 A. Herron + Microsoft Corp. + M. Wahl + Sun Microsystems, Inc. + A. Anantha + Microsoft Corp. + + + 17 November 2000 + + The C LDAP Application Program Interface + + + +1. Status of this Memo + +This document is an Internet-Draft and is in full conformance with all +provisions of Section 10 of RFC2026. Internet-Drafts are working docu- +ments of the Internet Engineering Task Force (IETF), its areas, and its +working groups. Note that other groups may also distribute working +documents as Internet-Drafts. + +Internet-Drafts are draft documents valid for a maximum of six months +and may be updated, replaced, or obsoleted by other documents at any +time. It is inappropriate to use Internet-Drafts as reference material +or to cite them other than as "work in progress." + +The list of current Internet-Drafts can be accessed at +http://www.ietf.org/ietf/1id-abstracts.txt. + +The list of Internet-Draft Shadow Directories can be accessed at +http://www.ietf.org/shadow.html. + +This draft document will be submitted to the RFC Editor as a Standards +Track document. Distribution of this memo is unlimited. Technical dis- +cussion of this document will take place on the IETF LDAP Extension +Working Group mailing list . Please send +editorial comments directly to the authors. + +Copyright (C) The Internet Society (1997-1999). All Rights Reserved. + +Please see the Copyright section near the end of this document for more +information. + + + + +Expires: May 2001 [Page 1] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +2. Introduction + +This document defines a C language application program interface (API) +to the Lightweight Directory Access Protocol (LDAP). This document +replaces the previous definition of this API, defined in RFC 1823, +updating it to include support for features found in version 3 of the +LDAP protocol. New extended operation functions were added to support +LDAPv3 features such as controls. In addition, other LDAP API changes +were made to support information hiding and thread safety. + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", +"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this +document are to be interpreted as described in RFC 2119[1]. + +The C 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 applica- +tion program to obtain LDAP information. The API calls are described in +detail, followed by appendices that provide example code demonstrating +use of the API, the namespace consumed by the API, a summary of require- +ments for API extensions, known incompatibilities with RFC 1823, and a +list of changes made since the last revision of this document. + + +3. Table of Contents + +1. Status of this Memo............................................1 +2. Introduction...................................................2 +3. Table of Contents..............................................2 +4. Overview of the LDAP Model.....................................4 +5. Overview of LDAP API Use and General Requirements..............4 +6. Header Requirements............................................6 +7. Common Data Structures and Types...............................7 +8. Memory Handling Overview.......................................9 +9. Retrieving Information About the API Implementation............9 +9.1. Retrieving Information at Compile Time......................10 +9.2. Retrieving Information During Execution.....................11 +10. Result Codes...................................................14 +11. Performing LDAP Operations.....................................16 +11.1. Initializing an LDAP Session................................16 +11.2. LDAP Session Handle Options.................................17 +11.3. Working With Controls.......................................23 +11.3.1. A Client Control That Governs Referral Processing........24 +11.4. Authenticating to the directory.............................25 +11.5. Closing the session.........................................27 +11.6. Searching...................................................28 +11.7. Reading an Entry............................................32 + + + +Expires: May 2001 [Page 2] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + +11.8. Listing the Children of an Entry............................32 +11.9. Comparing a Value Against an Entry..........................33 +11.10. Modifying an entry..........................................35 +11.11. Modifying the Name of an Entry..............................37 +11.12. Adding an entry.............................................39 +11.13. Deleting an entry...........................................41 +11.14. Extended Operations.........................................43 +12. Abandoning An Operation........................................44 +13. Obtaining Results and Peeking Inside LDAP Messages.............45 +14. Handling Errors and Parsing Results............................47 +15. Stepping Through a List of Results.............................51 +16. Parsing Search Results.........................................51 +16.1. Stepping Through a List of Entries or References............52 +16.2. Stepping Through the Attributes of an Entry.................53 +16.3. Retrieving the Values of an Attribute.......................54 +16.4. Retrieving the name of an entry.............................55 +16.5. Retrieving controls from an entry...........................56 +16.6. Parsing References..........................................57 +17. Encoded ASN.1 Value Manipulation...............................58 +17.1. BER Data Structures and Types...............................58 +17.2. Memory Disposal and Utility Functions.......................60 +17.3. Encoding....................................................60 +17.4. Encoding Example............................................63 +17.5. Decoding....................................................64 +17.6. Decoding Example............................................67 +18. Security Considerations........................................70 +19. Acknowledgements...............................................70 +20. Copyright......................................................70 +21. Bibliography...................................................71 +22. Authors' Addresses.............................................72 +23. Appendix A - Sample C LDAP API Code............................73 +24. Appendix B - Namespace Consumed By This Specification..........74 +25. Appendix C - Summary of Requirements for API Extensions........75 +25.1. Compatibility...............................................75 +25.2. Style.......................................................75 +25.3. Dependence on Externally Defined Types......................75 +25.4. Compile Time Information....................................76 +25.5. Runtime Information.........................................76 +25.6. Values Used for Session Handle Options......................76 +26. Appendix D - Known Incompatibilities with RFC 1823.............76 +26.1. Opaque LDAP Structure.......................................76 +26.2. Additional Result Codes.....................................77 +26.3. Freeing of String Data with ldap_memfree()..................77 +26.4. Changes to ldap_result()....................................77 +26.5. Changes to ldap_first_attribute() and ldap_next_attribute...77 +26.6. Changes to ldap_modrdn() and ldap_modrdn_s() Functions......78 +26.7. Changes to the berval structure.............................78 +26.8. API Specification Clarified.................................78 + + +Expires: May 2001 [Page 3] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +26.9. Deprecated Functions........................................78 +27. Appendix E - Data Types and Legacy Implementations.............79 +28. Appendix F - Changes Made Since Last Document Revision.........80 +28.1. API Changes.................................................80 +28.2. Editorial Changes and Clarifications........................81 + + +4. Overview of the LDAP Model + +LDAP is the lightweight directory access protocol, described in [2] and +[3]. It can provide a lightweight frontend to the X.500 directory [4], +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 infor- +mation 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 attri- +bute (e.g., ASCII characters, a jpeg photograph, etc.) and how those +values behave during directory operations (e.g., is case significant +during comparisons). + +Entries may be organized in a tree structure, usually based on politi- +cal, 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 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 entry up +to the root of the tree. 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 [5]. + +Operations are provided to authenticate, search for and retrieve infor- +mation, 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 func- +tions. + + +5. Overview of LDAP API Use and General Requirements + +An application generally uses the C LDAP API in four simple steps. + + + +Expires: May 2001 [Page 4] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + 1. Initialize an LDAP session with a primary LDAP server. The + ldap_init() function returns a handle to the session, allowing + multiple connections to be open at once. + + 2. Authenticate to the LDAP server. The ldap_sasl_bind() function + and friends support a variety of authentication methods. + + 3. Perform some LDAP operations and obtain some results. + ldap_search() and friends return results which can be parsed by + ldap_parse_result(), ldap_first_entry(), ldap_next_entry(), etc. + + 4. Close the session. The ldap_unbind() function closes the connec- + tion. + +Operations can be performed either synchronously or asynchronously. The +names of the synchronous functions 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 rou- +tines return an indication of the outcome of the operation (e.g, the +constant LDAP_SUCCESS or some other result code). The asynchronous rou- +tines make available to the caller the message id of the operation ini- +tiated. 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() or ldap_abandon_ext(). Note that +there is no requirement that an LDAP API implementation not block when +handling asynchronous API functions; the term "asynchronous" as used in +this document refers to the fact that the sending of LDAP requests can +be separated from the receiving of LDAP responses. + +Results and errors are returned in an opaque structure called LDAPMes- +sage. Routines are provided to parse this structure, step through +entries and attributes returned, etc. Routines are also provided to +interpret errors. Later sections of this document describe these rou- +tines in more detail. + +LDAP version 3 servers can return referrals and references to other +servers. By default, implementations of this API will attempt to follow +referrals automatically for the application. This behavior can be dis- +abled globally (using the ldap_set_option() call) or on a per-request +basis through the use of a client control. + +All DN and string attribute values passed into or produced by this C +LDAP API are represented using the character set of the underlying LDAP +protocol version in use. When this API is used with LDAPv3, DN and +string values are represented as UTF-8[6] characters. When this API is +used with LDAPv2, the US-ASCII[7] or T.61[7] character set are used. +Future documents MAY specify additional APIs supporting other character +sets. + + + +Expires: May 2001 [Page 5] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +For compatibility with existing applications, implementations of this +API will by default use version 2 of the LDAP protocol. Applications +that intend to take advantage of LDAP version 3 features will need to +use the ldap_set_option() call with a LDAP_OPT_PROTOCOL_VERSION to +switch to version 3. + +Unless otherwise indicated, conformant implementations of this specifi- +cation MUST implement all of the C LDAP API functions as described in +this document, and they MUST use the function prototypes, macro defini- +tions, and types defined in this document. + +Note that this API is designed for use in environments where the 'int' +type is at least 32 bits in size. + + +6. Header Requirements + +To promote portability of applications, the following requirements are +imposed on the headers used by applications to access the services of +this API: + +Name and Inclusion + Applications only need to include a single header named ldap.h + to access all of the API services described in this document. + Therefore, the following C source program MUST compile and exe- + cute without errors: + + #include + + int + main() + { + return 0; + } + + The ldap.h header MAY include other implementation-specific + headers. + +Implementations SHOULD also provide a header named lber.h to facilitate +development of applications desiring compatibility with older LDAP +implementations. The lber.h header MAY be empty. Old applications that +include lber.h in order to use BER facilities will need to include +ldap.h. + + +Idempotence + All headers SHOULD be idempotent; that is, if they are included + more than once the effect is as if they had only been included + + + +Expires: May 2001 [Page 6] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + once. + +Must Be Included Before API Is Used + An application MUST include the ldap.h header before referencing + any of the function or type definitions described in this API + specification. + +Mutual Independence + Headers SHOULD be mutually independent with minimal dependence + on system or any other headers. + +Use of the 'const' Keyword + This API specification is defined in terms of ISO C[8]. It + makes use of function prototypes and the 'const' keyword. The + use of 'const' in this specification is limited to simple, non- + array function parameters to avoid forcing applications to + declare parameters and variables that accept return values from + LDAP API functions as 'const.' Implementations specifically + designed to be used with non-ISO C translators SHOULD provide + function declarations without prototypes or function prototypes + without specification of 'const' arguments. + +Definition of 'struct timeval' + This API specification uses the 'struct timeval' type. Imple- + mentations of this API MUST ensure that the struct timeval type + is by default defined as a consequence of including the ldap.h + header. Because struct timeval is usually defined in one or + more system headers, it is possible for header conflicts to + occur if ldap.h also defines it or arranges for it to be defined + by including another header. Therefore, applications MAY want + to arrange for struct timeval to be defined before they include + ldap.h. To support this, the ldap.h header MUST NOT itself + define struct timeval if the preprocessor symbol + LDAP_TYPE_TIMEVAL_DEFINED is defined before ldap.h is included. + + +7. Common Data Structures and Types + +Data structures and types that are common to several LDAP API functions +are defined here: + + typedef struct ldap LDAP; + + typedef struct ldapmsg LDAPMessage; + + typedef struct berelement BerElement; + + typedef ber_len_t; + + + +Expires: May 2001 [Page 7] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + typedef struct berval { + ber_len_t bv_len; + char *bv_val; + } BerValue; + + struct timeval { + tv_sec; + tv_usec; + }; + +The LDAP structure is an opaque data type that represents an LDAP ses- +sion Typically this corresponds to a connection to a single server, but +it MAY encompass several server connections in the face of LDAPv3 refer- +rals. + +The LDAPMessage structure is an opaque data type that is used to return +entry, reference, result, and error information. An LDAPMessage struc- +ture can represent the beginning of a list, or chain of messages that +consists of a series of entries, references, and result messages as +returned by LDAP operations such as search. LDAP API functions such as +ldap_parse_result() that operate on message chains that can contain more +than one result message always operate on the first result message in +the chain. See the "Obtaining Results and Peeking Inside LDAP Messages" +section of this document for more information. + +The BerElement structure is an opaque data type that is used to hold +data and state information about encoded data. It is described in more +detail in the section "Encoded ASN.1 Value Manipulation" later in this +document. + +The `ber_len_t' type is an unsigned integral data type that is large +enough to contain the length of the largest piece of data supported by +the API implementation. The `' in the `ber_len_t' typedef +MUST be replaced with an appropriate type. The width (number of signi- +ficant bits) of `ber_len_t' MUST be at least 32 and no larger than that +of `unsigned long'. See the appendix "Data Types and Legacy Implementa- +tions" for additional considerations. + +The BerValue structure is used to represent arbitrary binary data and +its fields have the following meanings: + +bv_len Length of data in bytes. + +bv_val A pointer to the data itself. + + +The timeval structure is used to represent an interval of time and its +fields have the following meanings: + + + +Expires: May 2001 [Page 8] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +tv_sec Seconds component of time interval. + +tv_usec Microseconds component of time interval. + +Note that because the struct timeval definition typically is derived +from a system header, the types used for the tv_sec and tv_usec com- +ponents are implementation-specific integral types. Therefore, +`' and `' in the struct timeval definition MUST +be replaced with appropriate types. See the earlier section "Header +Requirements" for more information on struct timeval. + + +8. Memory Handling Overview + +All memory that is allocated by a function in this C LDAP API and +returned to the caller SHOULD be disposed of by calling the appropriate +"free" function provided by this API. The correct "free" function to +call is documented in each section of this document where a function +that allocates memory is described. + +Memory that is allocated through means outside of the C LDAP API MUST +NOT be disposed of using a function provided by this API. + +If a pointer value passed to one of the C LDAP API "free" functions is +NULL, graceful failure (i.e, ignoring of the NULL pointer) MUST occur. + +The complete list of "free" functions that are used to dispose of allo- +cated memory is: + + ber_bvecfree() + ber_bvfree() + ber_free() + ldap_control_free() + ldap_controls_free() + ldap_memfree() + ldap_msgfree() + ldap_value_free() + ldap_value_free_len() + + +9. Retrieving Information About the API Implementation + +Applications developed to this specification need to be able to deter- +mine information about the particular API implementation they are using +both at compile time and during execution. + + + + + + +Expires: May 2001 [Page 9] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +9.1. Retrieving Information at Compile Time + +All conformant implementations MUST include the following five defini- +tions in a header so compile time tests can be done by LDAP software +developers: + + #define LDAP_API_VERSION level + #define LDAP_VERSION_MIN min-version + #define LDAP_VERSION_MAX max-version + #define LDAP_VENDOR_NAME "vend-name" + #define LDAP_VENDOR_VERSION vend-version + +where: + + "level" is replaced with the RFC number given to this C LDAP API + specification when it is published as a standards track RFC. + + min-version is replaced with the lowest LDAP protocol version sup- + ported by the implementation. + + max-version is replaced with the highest LDAP protocol version sup- + ported by the implementation. This SHOULD be 3. + + "vend-name" is replaced with a text string that identifies the + party that supplies the API implementation. + + "vend-version" is a supplier-specific version number multiplied + times 100. + +Note that the LDAP_VENDOR_NAME macro SHOULD be defined as "" if no ven- +dor name is available and the LDAP_VENDOR_VERSION macro SHOULD be +defined as 0 if no vendor-specific version information is available. + +For example, if this specification is published as RFC 88888, Netscape +Communication's version 4.0 implementation that supports LDAPv2 and v3 +might include macro definitions like these: + + #define LDAP_API_VERSION 88888 /* RFC 88888 compliant */ + #define LDAP_VERSION_MIN 2 + #define LDAP_VERSION_MAX 3 + #define LDAP_VENDOR_NAME "Netscape Communications Corp." + #define LDAP_VENDOR_VERSION 400 /* version 4.0 */ + +and application code can test the C LDAP API version level using a +construct such as this one: + + #if (LDAP_API_VERSION >= 88888) + /* use features supported in RFC 88888 or later */ + + + +Expires: May 2001 [Page 10] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + #endif + +Until such time as this document is published as an RFC, implementations +SHOULD use the value 2000 plus the revision number of this draft for +LDAP_API_VERSION. For example, the correct value for LDAP_API_VERSION +for revision 05 of this draft is 2005. + +Documents that extend this specification SHOULD define a macro of the +form: + + #define LDAP_API_FEATURE_x level + +where "x" is replaced with a name (textual identifier) for the feature +and "level" is replaced with the number of the RFC that specifies the +API extension. The name SHOULD NOT begin with the string "X_". + +For example, if C LDAP API extensions for Transport Layer Security [9] +were published in RFC 99999, that RFC might require conformant implemen- +tations to define a macro like this: + + #define LDAP_API_FEATURE_TLS 99999 + + +Private or experimental API extensions SHOULD be indicated by defining a +macro of this same form where "x" (the extension's name) begins with the +string "X_" and "level" is replaced with a integer number that is +specific to the extension. + +It is RECOMMENDED that private or experimental API extensions use only +the following prefixes for macros, types, and function names: + LDAP_X_ + LBER_X_ + ldap_x_ + ber_x_ +and that these prefixes not be used by standard extensions. + + +9.2. Retrieving Information During Execution + +The ldap_get_option() call (described in greater detail later in this +document) can be used during execution in conjunction with an option +parameter value of LDAP_OPT_API_INFO (0x00) to retrieve some basic +information about the API and about the specific implementation being +used. The ld parameter to ldap_get_option() can be either NULL or a +valid LDAP session handle which was obtained by calling ldap_init(). +The optdata parameter to ldap_get_option() SHOULD be the address of an +LDAPAPIInfo structure which is defined as follows: + + + + +Expires: May 2001 [Page 11] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + typedef struct ldapapiinfo { + int ldapai_info_version; /* version of this struct (1) */ + int ldapai_api_version; /* revision of API supported */ + int ldapai_protocol_version; /* highest LDAP version supported */ + char **ldapai_extensions; /* names of API extensions */ + char *ldapai_vendor_name; /* name of supplier */ + int ldapai_vendor_version; /* supplier-specific version times 100 */ + } LDAPAPIInfo; + +In addition, API implementations MUST include the following macro defin- +ition: + + #define LDAP_API_INFO_VERSION 1 + +Note that the ldapai_info_version field of the LDAPAPIInfo structure +SHOULD be set to the value LDAP_API_INFO_VERSION (1) before calling +ldap_get_option() so that it can be checked for consistency. All other +fields are set by the ldap_get_option() function. + +The members of the LDAPAPIInfo structure are: + +ldapai_info_version + A number that identifies the version of the LDAPAPIInfo struc- + ture. This SHOULD be set to the value LDAP_API_INFO_VERSION + (1) before calling ldap_get_option(). If the value received + is not recognized by the API implementation, the + ldap_get_option() function sets ldapai_info_version to a valid + value that would be recognized, sets the ldapai_api_version to + the correct value, and returns an error without filling in any + of the other fields in the LDAPAPIInfo structure. + +ldapai_api_version + A number that matches that assigned to the C LDAP API RFC sup- + ported by the API implementation. This SHOULD match the value + of the LDAP_API_VERSION macro defined earlier. + +ldapai_protocol_version + The highest LDAP protocol version supported by the implementa- + tion. For example, if LDAPv3 is the highest version supported + then this field will be set to 3. + +ldapai_vendor_name + A zero-terminated string that contains the name of the party + that produced the LDAP API implementation. This field may be + set to NULL if no name is available. If non-NULL, the caller + is responsible for disposing of the memory occupied by passing + this pointer to ldap_memfree() which is described later in + this document. This value SHOULD match the value of the + + + +Expires: May 2001 [Page 12] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + LDAP_VENDOR_NAME macro described earlier in this document. + +ldapai_vendor_version + An implementation-specific version number multiplied by 100. + For example, if the implementation version is 4.0 then this + field will be set to 400. If no version information is avail- + able, this field will be set to 0. This value SHOULD match + the value of the LDAP_VENDOR_VERSION macro described earlier + in this document. + +ldapai_extensions + A NULL-terminated array of character strings that lists the + names of the API extensions supported by the LDAP API imple- + mentation. These names will typically match the textual iden- + tifiers that appear in the "x" portion of the + LDAP_API_FEATURE_x macros described above, although the pre- + cise value MUST be defined by documents that specify C LDAP + API extensions. If no API extensions are supported, this + field will be set to NULL. The caller is responsible for + disposing of the memory occupied by this array by passing it + to ldap_value_free() which is described later in this docu- + ment. To retrieve more information about a particular exten- + sion, the ldap_get_option() call can be used with an option + parameter value of LDAP_OPT_API_FEATURE_INFO (0x15). The opt- + data parameter to the ldap_get_option() SHOULD be the address + of an LDAPAPIFeatureInfo structure which is defined as fol- + lows: + + typedef struct ldap_apifeature_info { + int ldapaif_info_version; /* version of this struct (1) */ + char *ldapaif_name; /* name of supported feature */ + int ldapaif_version; /* revision of supported feature */ + } LDAPAPIFeatureInfo; + + In addition, API implementations MUST include the following + macro definition: + + #define LDAP_FEATURE_INFO_VERSION 1 + + Note that the ldapaif_info_version field of the LDAPAPI- + FeatureInfo structure SHOULD be set to the value + LDAP_FEATURE_INFO_VERSION (1) and the ldapaif_name field + SHOULD be set to the extension name string as described below + before ldap_get_option() is called. The call will fill in the + ldapaif_version field of the LDAPAPIFeatureInfo structure. + + The members of the LDAPAPIFeatureInfo structure are: + + + + +Expires: May 2001 [Page 13] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + ldapaif_info_version + A number that identifies the version of the LDAPAPI- + FeatureInfo structure. This SHOULD be set to the value + LDAP_FEATURE_INFO_VERSION (1) before calling + ldap_get_option(). If the value received is not recognized + by the API implementation, the ldap_get_option() function + sets ldapaif_info_version to a valid value that would be + recognized and returns an error without filling in the + ldapaif_version field in the LDAPAPIFeatureInfo structure. + + ldapaif_name + The name of an extension, as returned in the + ldapai_extensions array of the LDAPAPIInfo structure and as + specified in the document that describes the extension. + + ldapaif_version + This field will be set as a result of calling + ldap_get_option(). It is a number that matches that + assigned to the C LDAP API extension RFC supported for this + extension. For private or experimental API extensions, the + value is extension-specific. In either case, the value of + ldapaxi_ext_version SHOULD be identical to the value of the + LDAP_API_FEATURE_x macro defined for the extension + (described above). + + +10. Result Codes + +Many of the LDAP API routines return result codes, some of which indi- +cate local API errors and some of which are LDAP resultCodes that are +returned by servers. All of the result codes are non-negative integers. +Supported result codes are as follows (hexadecimal values are given in +parentheses after the constant): + + LDAP_SUCCESS (0x00) + LDAP_OPERATIONS_ERROR (0x01) + LDAP_PROTOCOL_ERROR (0x02) + LDAP_TIMELIMIT_EXCEEDED (0x03) + LDAP_SIZELIMIT_EXCEEDED (0x04) + LDAP_COMPARE_FALSE (0x05) + LDAP_COMPARE_TRUE (0x06) + LDAP_STRONG_AUTH_NOT_SUPPORTED (0x07) + LDAP_STRONG_AUTH_REQUIRED (0x08) + LDAP_REFERRAL (0x0a) -- new in LDAPv3 + LDAP_ADMINLIMIT_EXCEEDED (0x0b) -- new in LDAPv3 + LDAP_UNAVAILABLE_CRITICAL_EXTENSION (0x0c) -- new in LDAPv3 + LDAP_CONFIDENTIALITY_REQUIRED (0x0d) -- new in LDAPv3 + LDAP_SASL_BIND_IN_PROGRESS (0x0e) -- new in LDAPv3 + + + +Expires: May 2001 [Page 14] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + LDAP_NO_SUCH_ATTRIBUTE (0x10) + LDAP_UNDEFINED_TYPE (0x11) + LDAP_INAPPROPRIATE_MATCHING (0x12) + LDAP_CONSTRAINT_VIOLATION (0x13) + LDAP_TYPE_OR_VALUE_EXISTS (0x14) + LDAP_INVALID_SYNTAX (0x15) + LDAP_NO_SUCH_OBJECT (0x20) + LDAP_ALIAS_PROBLEM (0x21) + LDAP_INVALID_DN_SYNTAX (0x22) + LDAP_IS_LEAF (0x23) -- not used in LDAPv3 + LDAP_ALIAS_DEREF_PROBLEM (0x24) + LDAP_INAPPROPRIATE_AUTH (0x30) + LDAP_INVALID_CREDENTIALS (0x31) + LDAP_INSUFFICIENT_ACCESS (0x32) + LDAP_BUSY (0x33) + LDAP_UNAVAILABLE (0x34) + LDAP_UNWILLING_TO_PERFORM (0x35) + LDAP_LOOP_DETECT (0x36) + LDAP_NAMING_VIOLATION (0x40) + LDAP_OBJECT_CLASS_VIOLATION (0x41) + LDAP_NOT_ALLOWED_ON_NONLEAF (0x42) + LDAP_NOT_ALLOWED_ON_RDN (0x43) + LDAP_ALREADY_EXISTS (0x44) + LDAP_NO_OBJECT_CLASS_MODS (0x45) + LDAP_RESULTS_TOO_LARGE (0x46) -- reserved for CLDAP + LDAP_AFFECTS_MULTIPLE_DSAS (0x47) -- new in LDAPv3 + LDAP_OTHER (0x50) + LDAP_SERVER_DOWN (0x51) + LDAP_LOCAL_ERROR (0x52) + LDAP_ENCODING_ERROR (0x53) + LDAP_DECODING_ERROR (0x54) + LDAP_TIMEOUT (0x55) + LDAP_AUTH_UNKNOWN (0x56) + LDAP_FILTER_ERROR (0x57) + LDAP_USER_CANCELLED (0x58) + LDAP_PARAM_ERROR (0x59) + LDAP_NO_MEMORY (0x5a) + LDAP_CONNECT_ERROR (0x5b) + LDAP_NOT_SUPPORTED (0x5c) + LDAP_CONTROL_NOT_FOUND (0x5d) + LDAP_NO_RESULTS_RETURNED (0x5e) + LDAP_MORE_RESULTS_TO_RETURN (0x5f) + LDAP_CLIENT_LOOP (0x60) + LDAP_REFERRAL_LIMIT_EXCEEDED (0x61) + + + + + + + +Expires: May 2001 [Page 15] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +11. Performing LDAP Operations + +This section describes each LDAP operation API call in detail. Most +functions take a "session handle," a pointer to an LDAP structure con- +taining per-connection information. Many routines return results in an +LDAPMessage structure. These structures and others are described as +needed below. + + +11.1. Initializing an LDAP Session + +ldap_init() initializes a session with an LDAP server. The server is not +actually contacted until an operation is performed that requires it, +allowing various options to be set after initialization. + + LDAP *ldap_init( + const char *hostname, + int portno + ); + +Use of the following routine is deprecated: + + LDAP *ldap_open( + const char *hostname, + int portno + ); + +Unlike ldap_init(), ldap_open() attempts to make a server connection +before returning to the caller. A more complete description can be +found in RFC 1823. + +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. Each hostname in the list MAY include a port number + which is separated from the host itself with a colon (:) char- + acter. The hosts will be tried in the order listed, stopping + with the first one to which a successful connection is made. + + Note: A suitable representation for including a literal IPv6[10] + address in the hostname parameter is desired, but has not yet been + determined or implemented in practice. + +portno Contains the TCP port number to connect to. The default LDAP + port of 389 can be obtained by supplying the value zero (0) or + the macro LDAP_PORT (389). If a host includes a port number + then this parameter is ignored. + + + +Expires: May 2001 [Page 16] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +ldap_init() and ldap_open() both return a "session handle," a pointer to +an opaque structure that MUST be passed to subsequent calls pertaining +to the session. These routines return NULL if the session cannot be ini- +tialized in which case the operating system error reporting mechanism +can be checked to see why the call failed. + +Note that if you connect to an LDAPv2 server, one of the LDAP bind calls +described below SHOULD be completed before other operations can be per- +formed on the session. LDAPv3 does not require that a bind operation be +completed before other operations can be performed. + +The calling program can set various attributes of the session by calling +the routines described in the next section. + + +11.2. LDAP Session Handle Options + +The LDAP session handle returned by ldap_init() is a pointer to an +opaque data type representing an LDAP session. In RFC 1823 this data +type was a structure exposed to the caller, and various fields in the +structure could be set to control aspects of the session, such as size +and time limits on searches. + +In the interest of insulating callers from inevitable changes to this +structure, these aspects of the session are now accessed through a pair +of accessor functions, described below. + +ldap_get_option() is used to access the current value of various +session-wide parameters. ldap_set_option() is used to set the value of +these parameters. Note that some options are READ-ONLY and cannot be +set; it is an error to call ldap_set_option() and attempt to set a +READ-ONLY option. + +Note that if automatic referral following is enabled (the default), any +connections created during the course of following referrals will +inherit the options associated with the session that sent the original +request that caused the referrals to be returned. + + int ldap_get_option( + LDAP *ld, + int option, + void *outvalue + ); + + int ldap_set_option( + LDAP *ld, + int option, + const void *invalue + + + +Expires: May 2001 [Page 17] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + ); + + #define LDAP_OPT_ON () + #define LDAP_OPT_OFF ((void *)0) + + LDAP_OPT_ON MUST be defined as a non-null pointer to void; that is, + MUST be replaced with a non-null pointer to + void, e.g., one could use: + #define LDAP_OPT_ON ((void *)1) + if that value is safe to use on the architecture where the API is + implemented. + +Parameters are: + +ld The session handle. If this is NULL, a set of global defaults is + accessed. New LDAP session handles created with ldap_init() or + ldap_open() inherit their characteristics from these global + defaults. + +option The name of the option being accessed or set. This parameter + SHOULD be one of the following constants, which have the indi- + cated meanings. After the constant the actual hexadecimal value + of the constant is listed in parentheses. + + + LDAP_OPT_API_INFO (0x00) + Type for invalue parameter: not applicable (option is READ-ONLY) + + Type for outvalue parameter: LDAPAPIInfo * + + Description: + Used to retrieve some basic information about the LDAP API + implementation at execution time. See the section "Retriev- + ing Information About the API Implementation" above for more + information. This option is READ-ONLY and cannot be set. + + LDAP_OPT_DEREF (0x02) + Type for invalue parameter: int * + + Type for outvalue parameter: int * + + Description: + Determines how aliases are handled during search. It SHOULD + have one of the following values: LDAP_DEREF_NEVER (0x00), + LDAP_DEREF_SEARCHING (0x01), LDAP_DEREF_FINDING (0x02), or + LDAP_DEREF_ALWAYS (0x03). The LDAP_DEREF_SEARCHING value + means aliases are dereferenced during the search but not when + locating the base object of the search. The + + + +Expires: May 2001 [Page 18] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + LDAP_DEREF_FINDING value means aliases are dereferenced when + locating the base object but not during the search. The + default value for this option is LDAP_DEREF_NEVER. + + LDAP_OPT_SIZELIMIT (0x03) + Type for invalue parameter: int * + + Type for outvalue parameter: int * + + Description: + A limit on the number of entries to return from a search. A + value of LDAP_NO_LIMIT (0) means no limit. The default value + for this option is LDAP_NO_LIMIT. + + LDAP_OPT_TIMELIMIT (0x04) + Type for invalue parameter: int * + + Type for outvalue parameter: int * + + Description: + A limit on the number of seconds to spend on a search. A + value of LDAP_NO_LIMIT (0) means no limit. The default value + for this option is LDAP_NO_LIMIT. This value is passed to + the server in the search request only; it does not affect how + long the C LDAP API implementation itself will wait locally + for search results. Note that the timeout parameter passed + to the ldap_search_ext_s() or ldap_result() functions can be + used to specify a limit on how long the API implementation + will wait for results. + + LDAP_OPT_REFERRALS (0x08) + Type for invalue parameter: void * (LDAP_OPT_ON or LDAP_OPT_OFF) + + Type for outvalue parameter: int * + + Description: + Determines whether the LDAP library automatically follows + referrals returned by LDAP servers or not. It MAY be set to + one of the constants LDAP_OPT_ON or LDAP_OPT_OFF; any non- + NULL pointer value passed to ldap_set_option() enables this + option. When reading the current setting using + ldap_get_option(), a zero value means OFF and any non-zero + value means ON. By default, this option is ON. + + LDAP_OPT_RESTART (0x09) + Type for invalue parameter: void * (LDAP_OPT_ON or LDAP_OPT_OFF) + + Type for outvalue parameter: int * + + + +Expires: May 2001 [Page 19] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + Description: + Determines whether LDAP I/O operations are automatically res- + tarted if they abort prematurely. It MAY be set to one of the + constants LDAP_OPT_ON or LDAP_OPT_OFF; any non-NULL pointer + value passed to ldap_set_option() enables this option. When + reading the current setting using ldap_get_option(), a zero + value means OFF and any non-zero value means ON. This option + is useful if an LDAP I/O operation can be interrupted prema- + turely, for example by a timer going off, or other interrupt. + By default, this option is OFF. + + LDAP_OPT_PROTOCOL_VERSION (0x11) + Type for invalue parameter: int * + + Type for outvalue parameter: int * + + Description: + This option indicates the version of the LDAP protocol used + when communicating with the primary LDAP server. It SHOULD be + one of the constants LDAP_VERSION2 (2) or LDAP_VERSION3 (3). + If no version is set the default is LDAP_VERSION2 (2). + + LDAP_OPT_SERVER_CONTROLS (0x12) + Type for invalue parameter: LDAPControl ** + + Type for outvalue parameter: LDAPControl *** + + Description: + A default list of LDAP server controls to be sent with each + request. See the Working With Controls section below. + + LDAP_OPT_CLIENT_CONTROLS (0x13) + Type for invalue parameter: LDAPControl ** + + Type for outvalue parameter: LDAPControl *** + + Description: + A default list of client controls that affect the LDAP ses- + sion. See the Working With Controls section below. + + LDAP_OPT_API_FEATURE_INFO (0x15) + Type for invalue parameter: not applicable (option is READ-ONLY) + + Type for outvalue parameter: LDAPAPIFeatureInfo * + + Description: + Used to retrieve version information about LDAP API extended + features at execution time. See the section "Retrieving + + + +Expires: May 2001 [Page 20] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + Information About the API Implementation" above for more + information. This option is READ-ONLY and cannot be set. + + LDAP_OPT_HOST_NAME (0x30) + Type for invalue parameter: char * + + Type for outvalue parameter: char ** + + Description: + The host name (or list of hosts) for the primary LDAP server. + See the definition of the hostname parameter to ldap_init() + for the allowed syntax. Note that if the portno parameter + passed to ldap_init() is a value other than 0 or 389 + (LDAP_PORT), this value SHOULD include a string like + ":portno" after each hostname or IP address that did not have + one in the original hostname parameter that was passed to + ldap_init(). For example, if this hostname value was passed + to ldap_init(): + + "ldap.example.com:389 ldap2.example.com" + + and the portno parameter passed to ldap_init() was 6389, then + the value returned for the LDAP_OPT_HOST_NAME option SHOULD + be: + + "ldap.example.com:389 ldap2.example.com:6389" + + + LDAP_OPT_RESULT_CODE (0x31) + Type for invalue parameter: int * + + Type for outvalue parameter: int * + + Description: + The most recent local (API generated) or server returned LDAP + result code that occurred for this session. + + LDAP_OPT_ERROR_STRING (0x32) + Type for invalue parameter: char * + + Type for outvalue parameter: char ** + + Description: + The message returned with the most recent LDAP error that + occurred for this session. + + LDAP_OPT_MATCHED_DN (0x33) + Type for invalue parameter: char * + + + +Expires: May 2001 [Page 21] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + Type for outvalue parameter: char ** + + Description: + The matched DN value returned with the most recent LDAP error + that occurred for this session. + + +outvalue The address of a place to put the value of the option. The + actual type of this parameter depends on the setting of the + option parameter. For outvalues of type char ** and LDAPCon- + trol **, a copy of the data that is associated with the LDAP + session ld is returned; callers should dispose of the memory by + calling ldap_memfree() or ldap_controls_free(), depending on + the type of data returned. + +invalue A pointer to the value the option is to be given. The actual + type of this parameter depends on the setting of the option + parameter. The data associated with invalue is copied by the + API implementation to allow callers of the API to dispose of or + otherwise change their copy of the data after a successful call + to ldap_set_option(). If a value passed for invalue is invalid + or cannot be accepted by the implementation, ldap_set_option() + should return -1 to indicate an error. + +Both ldap_get_option() and ldap_set_option() return 0 if successful and +-1 if an error occurs. If -1 is returned by either function, a specific +result code MAY be retrieved by calling ldap_get_option() with an option +value of LDAP_OPT_RESULT_CODE. Note that there is no way to retrieve a +more specific result code if a call to ldap_get_option() with an option +value of LDAP_OPT_RESULT_CODE fails. + +When a call to ldap_get_option() succeeds, the API implementation MUST +NOT change the state of the LDAP session handle or the state of the +underlying implementation in a way that affects the behavior of future +LDAP API calls. When a call to ldap_get_option() fails, the only ses- +sion handle change permitted is setting the LDAP result code (as +returned by the LDAP_OPT_RESULT_CODE option). + +When a call to ldap_set_option() fails, it MUST NOT change the state of +the LDAP session handle or the state of the underlying implementation in +a way that affects the behavior of future LDAP API calls. + +Standards track documents that extend this specification and specify new +options SHOULD use values for option macros that are between 0x1000 and +0x3FFF inclusive. Private and experimental extensions SHOULD use values +for the option macros that are between 0x4000 and 0x7FFF inclusive. All +values below 0x1000 and above 0x7FFF that are not defined in this docu- +ment are reserved and SHOULD NOT be used. The following macro MUST be + + + +Expires: May 2001 [Page 22] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +defined by C LDAP API implementations to aid extension implementors: + #define LDAP_OPT_PRIVATE_EXTENSION_BASE 0x4000 /* to 0x7FFF inclusive */ + + + +11.3. Working With Controls + +LDAPv3 operations can be extended through the use of controls. Controls +can be sent to a server or returned to the client with any LDAP message. +These controls are referred to as server controls. + +The LDAP API also supports a client-side extension mechanism through the +use of client controls. These controls affect the behavior of the LDAP +API only and are never sent to a server. A common data structure is +used to represent both types of controls: + + typedef struct ldapcontrol { + char *ldctl_oid; + struct berval ldctl_value; + char ldctl_iscritical; + } LDAPControl; + +The fields in the ldapcontrol structure have the following meanings: + +ldctl_oid The control type, represented as a string. + +ldctl_value The data associated with the control (if any). To + specify a zero-length value, set ldctl_value.bv_len to + zero and ldctl_value.bv_val to a zero-length string. + To indicate that no data is associated with the con- + trol, set ldctl_value.bv_val to NULL. + +ldctl_iscritical Indicates whether the control is critical of not. If + this field is non-zero, the operation will only be car- + ried out if the control is recognized by the server + and/or client. Note that the LDAP unbind and abandon + operations have no server response, so clients SHOULD + NOT mark server controls critical when used with these + two operations. + +Some LDAP API calls allocate an ldapcontrol structure or a NULL- +terminated array of ldapcontrol structures. The following routines can +be used to dispose of a single control or an array of controls: + + void ldap_control_free( LDAPControl *ctrl ); + void ldap_controls_free( LDAPControl **ctrls ); +If the ctrl or ctrls parameter is NULL, these calls do nothing. + + + + +Expires: May 2001 [Page 23] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +A set of controls that affect the entire session can be set using the +ldap_set_option() function (see above). A list of controls can also be +passed directly to some LDAP API calls such as ldap_search_ext(), in +which case any controls set for the session through the use of +ldap_set_option() are ignored. Control lists are represented as a NULL- +terminated array of pointers to ldapcontrol structures. + +Server controls are defined by LDAPv3 protocol extension documents; for +example, a control has been proposed to support server-side sorting of +search results [11]. + +One client control is defined in this document (described in the follow- +ing section). Other client controls MAY be defined in future revisions +of this document or in documents that extend this API. + + +11.3.1. A Client Control That Governs Referral Processing + +As described previously in the section "LDAP Session Handle Options," +applications can enable and disable automatic chasing of referrals on a +session-wide basic by using the ldap_set_option() function with the +LDAP_OPT_REFERRALS option. It is also useful to govern automatic refer- +ral chasing on per-request basis. A client control with an OID of +1.2.840.113556.1.4.616 exists to provide this functionality. + + /* OID for referrals client control */ + #define LDAP_CONTROL_REFERRALS "1.2.840.113556.1.4.616" + + /* Flags for referrals client control value */ + #define LDAP_CHASE_SUBORDINATE_REFERRALS 0x00000020U + #define LDAP_CHASE_EXTERNAL_REFERRALS 0x00000040U + +To create a referrals client control, the ldctl_oid field of an LDAPCon- +trol structure MUST be set to LDAP_CONTROL_REFERRALS +("1.2.840.113556.1.4.616") and the ldctl_value field MUST be set to a +value that contains a set of flags. The ldctl_value.bv_len field MUST +be set to sizeof(ber_uint_t), and the ldctl_value.bv_val field MUST +point to a ber_uint_t which contains the flags value." The ber_uint_t +type is define in the section "BER Data Structures and Types" below. + +The flags value can be set to zero to disable automatic chasing of +referrals and LDAPv3 references altogether. Alternatively, the flags +value can be set to the value LDAP_CHASE_SUBORDINATE_REFERRALS +(0x00000020U) to indicate that only LDAPv3 search continuation refer- +ences are to be automatically chased by the API implementation, to the +value LDAP_CHASE_EXTERNAL_REFERRALS (0x00000040U) to indicate that only +LDAPv3 referrals are to be automatically chased, or the logical OR of +the two flag values (0x00000060U) to indicate that both referrals and + + + +Expires: May 2001 [Page 24] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +references are to be automatically chased. + + +11.4. Authenticating to the directory + +The following functions are used to authenticate an LDAP client to an +LDAP directory server. + +The ldap_sasl_bind() and ldap_sasl_bind_s() functions can be used to do +general and extensible authentication over LDAP through the use of the +Simple Authentication Security Layer [12]. The routines both take the +dn to bind as, the method to use, as a dotted-string representation of +an OID identifying the method, and a struct berval holding the creden- +tials. The special constant value LDAP_SASL_SIMPLE (NULL) can be passed +to request simple authentication, or the simplified routines +ldap_simple_bind() or ldap_simple_bind_s() can be used. + + int ldap_sasl_bind( + LDAP *ld, + const char *dn, + const char *mechanism, + const struct berval *cred, + LDAPControl **serverctrls, + LDAPControl **clientctrls, + int *msgidp + ); + + int ldap_sasl_bind_s( + LDAP *ld, + const char *dn, + const char *mechanism, + const struct berval *cred, + LDAPControl **serverctrls, + LDAPControl **clientctrls, + struct berval **servercredp + ); + + int ldap_simple_bind( + LDAP *ld, + const char *dn, + const char *passwd + ); + + int ldap_simple_bind_s( + LDAP *ld, + const char *dn, + const char *passwd + ); + + + +Expires: May 2001 [Page 25] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + The use of the following routines is deprecated and more complete + descriptions can be found in RFC 1823: + + int ldap_bind( LDAP *ld, const char *dn, const char *cred, + int method ); + + int ldap_bind_s( LDAP *ld, const char *dn, const char *cred, + int method ); + + int ldap_kerberos_bind( LDAP *ld, const char *dn ); + + int ldap_kerberos_bind_s( LDAP *ld, const char *dn ); + +Parameters are: + +ld The session handle. + +dn The name of the entry to bind as. If NULL, a zero length + DN is sent to the server. + +mechanism Either LDAP_SASL_SIMPLE (NULL) to get simple authentica- + tion, or a text string identifying the SASL method. + +cred The credentials with which to authenticate. Arbitrary + credentials can be passed using this parameter. The format + and content of the credentials depends on the setting of + the mechanism parameter. If the cred parameter is NULL and + the mechanism is LDAP_SASL_SIMPLE, a zero-length octet + string is sent to the server in the simple credentials + field of the bind request. If the cred parameter is NULL + and the mechanism is anything else, no credentials are sent + to the server in the bind request. + +passwd For ldap_simple_bind(), the password that is sent to the + server in the simple credentials field of the bind request. + If NULL, a zero length password is sent to the server. + +serverctrls List of LDAP server controls, or NULL if no server controls + are used. + +clientctrls List of client controls, or NULL if no client controls are + used. + +msgidp This result parameter will be set to the message id of the + request if the ldap_sasl_bind() call succeeds. The value + is undefined if a value other than LDAP_SUCCESS is + returned. + + + + +Expires: May 2001 [Page 26] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +servercredp This result parameter will be filled in with the creden- + tials passed back by the server for mutual authentication, + if given. An allocated berval structure is returned that + SHOULD be disposed of by calling ber_bvfree(). NULL SHOULD + be passed to ignore this field. If an API error occurs or + the server did not return any credentials, *servercredp is + set to NULL. + +Additional parameters for the deprecated routines are not described. +Interested readers are referred to RFC 1823. + +The ldap_sasl_bind() function initiates an asynchronous bind operation +and returns the constant LDAP_SUCCESS if the request was successfully +sent, or another LDAP result code if not. See the section below on +error handling for more information about possible errors and how to +interpret them. If successful, ldap_sasl_bind() places the message id +of the request in *msgidp. A subsequent call to ldap_result(), described +below, can be used to obtain the result of the bind. + +The ldap_simple_bind() function initiates a simple asynchronous bind +operation and returns the message id of the operation initiated. A sub- +sequent call to ldap_result(), described below, can be used to obtain +the result of the bind. In case of error, ldap_simple_bind() will return +-1, setting the session error parameters in the LDAP structure appropri- +ately. + +The synchronous ldap_sasl_bind_s() and ldap_simple_bind_s() functions +both return the result of the operation, either the constant +LDAP_SUCCESS if the operation was successful, or another LDAP result +code if it was not. See the section below on error handling for more +information about possible errors and how to interpret them. + +Note that if an LDAPv2 server is contacted, no other operations over the +connection can be attempted before a bind call has successfully com- +pleted. + +Subsequent bind calls can be used to re-authenticate over the same con- +nection, and multistep SASL sequences can be accomplished through a +sequence of calls to ldap_sasl_bind() or ldap_sasl_bind_s(). + + +11.5. Closing the session + +The following functions are used to unbind from the directory, close +open connections, and dispose of the session handle. + + int ldap_unbind_ext( LDAP *ld, LDAPControl **serverctrls, + LDAPControl **clientctrls ); + + + +Expires: May 2001 [Page 27] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + int ldap_unbind( LDAP *ld ); + + int ldap_unbind_s( LDAP *ld ); + +Parameters are: + +ld The session handle. + +serverctrls List of LDAP server controls, or NULL if no server controls + are to be used. + +clientctrls List of client controls, or NULL if no client controls are + to be used. + +The ldap_unbind_ext(), ldap_unbind() and ldap_unbind_s() all work syn- +chronously in the sense that they send an unbind request to the server, +close all open connections associated with the LDAP session handle, and +dispose of all resources associated with the session handle before +returning. Note, however, that there is no server response to an LDAP +unbind operation. All three of the unbind functions return LDAP_SUCCESS +(or another LDAP result code if the request cannot be sent to the LDAP +server). After a call to one of the unbind functions, the session han- +dle ld is invalid and it is illegal to make any further LDAP API calls +using ld. + +The ldap_unbind() and ldap_unbind_s() functions behave identically. The +ldap_unbind_ext() function allows server and client controls to be +included explicitly, but note that since there is no server response to +an unbind request there is no way to receive a response to a server con- +trol sent with an unbind request. + + + +11.6. Searching + +The following functions are used to search the LDAP directory, returning +a requested set of attributes for each entry matched. There are five +variations. + + int ldap_search_ext( + LDAP *ld, + const char *base, + int scope, + const char *filter, + char **attrs, + int attrsonly, + LDAPControl **serverctrls, + LDAPControl **clientctrls, + + + +Expires: May 2001 [Page 28] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + struct timeval *timeout, + int sizelimit, + int *msgidp + ); + + int ldap_search_ext_s( + LDAP *ld, + const char *base, + int scope, + const char *filter, + char **attrs, + int attrsonly, + LDAPControl **serverctrls, + LDAPControl **clientctrls, + struct timeval *timeout, + int sizelimit, + LDAPMessage **res + ); + + int ldap_search( + LDAP *ld, + const char *base, + int scope, + const char *filter, + char **attrs, + int attrsonly + ); + + int ldap_search_s( + LDAP *ld, + const char *base, + int scope, + const char *filter, + char **attrs, + int attrsonly, + LDAPMessage **res + ); + + int ldap_search_st( + LDAP *ld, + const char *base, + int scope, + const char *filter, + char **attrs, + int attrsonly, + struct timeval *timeout, + LDAPMessage **res + ); + + + +Expires: May 2001 [Page 29] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +Parameters are: + +ld The session handle. + +base The dn of the entry at which to start the search. If NULL, + a zero length DN is sent to the server. + +scope One of LDAP_SCOPE_BASE (0x00), LDAP_SCOPE_ONELEVEL (0x01), + or LDAP_SCOPE_SUBTREE (0x02), indicating the scope of the + search. + +filter A character string as described in [13], representing the + search filter. The value NULL can be passed to indicate + that the filter "(objectclass=*)" which matches all entries + is to be used. Note that if the caller of the API is using + LDAPv2, only a subset of the filter functionality described + in [13] can be successfully used. + +attrs A NULL-terminated array of strings indicating which attri- + butes to return for each matching entry. Passing NULL for + this parameter causes all available user attributes to be + retrieved. The special constant string LDAP_NO_ATTRS + ("1.1") MAY be used as the only string in the array to + indicate that no attribute types are to be returned by the + server. The special constant string LDAP_ALL_USER_ATTRS + ("*") can be used in the attrs array along with the names + of some operational attributes to indicate that all user + attributes plus the listed operational attributes are to be + returned. + +attrsonly A boolean value that MUST be zero if both attribute types + and values are to be returned, and non-zero if only types + are wanted. + +timeout For the ldap_search_st() function, this specifies the local + search timeout value (if it is NULL, the timeout is infin- + ite). If a zero timeout (where tv_sec and tv_usec are both + zero) is passed, API implementations SHOULD return + LDAP_PARAM_ERROR. + + For the ldap_search_ext() and ldap_search_ext_s() func- + tions, the timeout parameter specifies both the local + search timeout value and the operation time limit that is + sent to the server within the search request. Passing a + NULL value for timeout causes the default timeout stored in + the LDAP session handle (set by using ldap_set_option() + with the LDAP_OPT_TIMELIMIT parameter) to be sent to the + server with the request but an infinite local search + + + +Expires: May 2001 [Page 30] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + timeout to be used. If a zero timeout (where tv_sec and + tv_usec are both zero) is passed in, API implementations + SHOULD return LDAP_PARAM_ERROR. If a zero value for tv_sec + is used but tv_usec is non-zero, an operation time limit of + 1 SHOULD be passed to the LDAP server as the operation time + limit. For other values of tv_sec, the tv_sec value itself + SHOULD be passed to the LDAP server. + +sizelimit For the ldap_search_ext() and ldap_search_ext_s() calls, + this is a limit on the number of entries to return from the + search. A value of LDAP_NO_LIMIT (0) means no limit. A + value of LDAP_DEFAULT_SIZELIMIT (-1) means use the default + timeout from the LDAP session handle (which is set by cal- + ling ldap_set_option() with the LDAP_OPT_SIZELIMIT parame- + ter). + +res For the synchronous calls, this is a result parameter which + will contain the results of the search upon completion of + the call. If an API error occurs or no results are + returned, *res is set to NULL. + +serverctrls List of LDAP server controls, or NULL if no server controls + are to be used. + +clientctrls List of client controls, or NULL if no client controls are + to be used. + +msgidp This result parameter will be set to the message id of the + request if the ldap_search_ext() call succeeds. The value + is undefined if a value other than LDAP_SUCCESS is + returned. + +There are three options in the session handle ld which potentially +affect how the search is performed. They are: + + LDAP_OPT_SIZELIMIT + LDAP_OPT_TIMELIMIT + LDAP_OPT_DEREF + +These options are fully described in the earlier section "LDAP Session +Handle Options." + +The ldap_search_ext() function initiates an asynchronous search opera- +tion and returns the constant LDAP_SUCCESS if the request was success- +fully sent, or another LDAP result code if not. See the section below +on error handling for more information about possible errors and how to +interpret them. If successful, ldap_search_ext() places the message id +of the request in *msgidp. A subsequent call to ldap_result(), described + + + +Expires: May 2001 [Page 31] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +below, can be used to obtain the results from the search. These results +can be parsed using the result parsing routines described in detail +later. + +Similar to ldap_search_ext(), the ldap_search() function initiates an +asynchronous search operation and returns the message id of the opera- +tion initiated. As for ldap_search_ext(), a subsequent call to +ldap_result(), described below, can be used to obtain the result of the +bind. In case of error, ldap_search() will return -1, setting the ses- +sion error parameters in the LDAP structure appropriately. + +The synchronous ldap_search_ext_s(), ldap_search_s(), and +ldap_search_st() functions all return the result of the operation, +either the constant LDAP_SUCCESS if the operation was successful, or +another LDAP result code if it was not. See the section below on error +handling for more information about possible errors and how to interpret +them. Entries returned from the search (if any) are contained in the +res parameter. This parameter is opaque to the caller. Entries, attri- +butes, values, etc., can 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. + +The ldap_search_ext() and ldap_search_ext_s() functions support LDAPv3 +server controls, client controls, and allow varying size and time limits +to be easily specified for each search operation. The ldap_search_st() +function is identical to ldap_search_s() except that it takes an addi- +tional parameter specifying a local timeout for the search. The local +search timeout is used to limit the amount of time the API implementa- +tion will wait for a search to complete. After the local search timeout +expires, the API implementation will send an abandon operation to abort +the search operation. + +11.7. 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=*)" or +NULL. attrs contains the list of attributes to return. + + +11.8. 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=*)" or +NULL. attrs contains the list of attributes to return for each child +entry. + + + + +Expires: May 2001 [Page 32] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +11.9. Comparing a Value Against an Entry + +The following routines are used to compare a given attribute value +assertion against an LDAP entry. There are four variations: + + int ldap_compare_ext( + LDAP *ld, + const char *dn, + const char *attr, + const struct berval *bvalue, + LDAPControl **serverctrls, + LDAPControl **clientctrls, + int *msgidp + ); + + int ldap_compare_ext_s( + LDAP *ld, + const char *dn, + const char *attr, + const struct berval *bvalue, + LDAPControl **serverctrls, + LDAPControl **clientctrls + ); + + int ldap_compare( + LDAP *ld, + const char *dn, + const char *attr, + const char *value + ); + + int ldap_compare_s( + LDAP *ld, + const char *dn, + const char *attr, + const char *value + ); + +Parameters are: + +ld The session handle. + +dn The name of the entry to compare against. If NULL, a zero + length DN is sent to the server. + +attr The attribute to compare against. + +bvalue The attribute value to compare against those found in the + + + +Expires: May 2001 [Page 33] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + given entry. This parameter is used in the extended rou- + tines and is a pointer to a struct berval so it is possible + to compare binary values. + +value A string attribute value to compare against, used by the + ldap_compare() and ldap_compare_s() functions. Use + ldap_compare_ext() or ldap_compare_ext_s() if you need to + compare binary values. + +serverctrls List of LDAP server controls, or NULL if no server controls + are to be used. + +clientctrls List of client controls, or NULL if no client controls are + to be used. + +msgidp This result parameter will be set to the message id of the + request if the ldap_compare_ext() call succeeds. The value + is undefined if a value other than LDAP_SUCCESS is + returned. + +The ldap_compare_ext() function initiates an asynchronous compare opera- +tion and returns the constant LDAP_SUCCESS if the request was success- +fully sent, or another LDAP result code if not. See the section below +on error handling for more information about possible errors and how to +interpret them. If successful, ldap_compare_ext() places the message id +of the request in *msgidp. A subsequent call to ldap_result(), described +below, can be used to obtain the result of the compare. + +Similar to ldap_compare_ext(), the ldap_compare() function initiates an +asynchronous compare operation and returns the message id of the opera- +tion initiated. As for ldap_compare_ext(), a subsequent call to +ldap_result(), described below, can be used to obtain the result of the +bind. In case of error, ldap_compare() will return -1, setting the ses- +sion error parameters in the LDAP structure appropriately. + +The synchronous ldap_compare_ext_s() and ldap_compare_s() functions both +return the result of the operation: one of the constants +LDAP_COMPARE_TRUE or LDAP_COMPARE_FALSE if the operation was successful, +or another LDAP result code if it was not. See the section below on +error handling for more information about possible errors and how to +interpret them. + +The ldap_compare_ext() and ldap_compare_ext_s() functions support LDAPv3 +server controls and client controls. + + + + + + + +Expires: May 2001 [Page 34] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +11.10. Modifying an entry + +The following routines are used to modify an existing LDAP entry. There +are four variations: + + typedef union mod_vals_u { + char **modv_strvals; + struct berval **modv_bvals; + } mod_vals_u_t; + + typedef struct ldapmod { + int mod_op; + char *mod_type; + mod_vals_u_t mod_vals; + } LDAPMod; + #define mod_values mod_vals.modv_strvals + #define mod_bvalues mod_vals.modv_bvals + + int ldap_modify_ext( + LDAP *ld, + const char *dn, + LDAPMod **mods, + LDAPControl **serverctrls, + LDAPControl **clientctrls, + int *msgidp + ); + + int ldap_modify_ext_s( + LDAP *ld, + const char *dn, + LDAPMod **mods, + LDAPControl **serverctrls, + LDAPControl **clientctrls + ); + + int ldap_modify( + LDAP *ld, + const char *dn, + LDAPMod **mods + ); + + int ldap_modify_s( + LDAP *ld, + const char *dn, + LDAPMod **mods + ); + +Parameters are: + + + +Expires: May 2001 [Page 35] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +ld The session handle. + +dn The name of the entry to modify. If NULL, a zero length DN + is sent to the server. + +mods A NULL-terminated array of modifications to make to the + entry. + +serverctrls List of LDAP server controls, or NULL if no server controls + are to be used. + +clientctrls List of client controls, or NULL if no client controls are + to be used. + +msgidp This result parameter will be set to the message id of the + request if the ldap_modify_ext() call succeeds. The value + is undefined if a value other than LDAP_SUCCESS is + returned. + +The fields in the LDAPMod structure have the following meanings: + +mod_op The modification operation to perform. It MUST be one of + LDAP_MOD_ADD (0x00), LDAP_MOD_DELETE (0x01), or + LDAP_MOD_REPLACE (0x02). This field also indicates the + type of values included in the mod_vals union. It is logi- + cally ORed with LDAP_MOD_BVALUES (0x80) 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 can 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. + +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 attri- +bute is to be deleted, the mod_vals field can be set to NULL. + +For LDAP_MOD_REPLACE modifications, the attribute will have the listed +values after the modification, having been created if necessary, or +removed if the mod_vals field is NULL. All modifications are performed + + + +Expires: May 2001 [Page 36] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +in the order in which they are listed. + +The ldap_modify_ext() function initiates an asynchronous modify opera- +tion and returns the constant LDAP_SUCCESS if the request was success- +fully sent, or another LDAP result code if not. See the section below +on error handling for more information about possible errors and how to +interpret them. If successful, ldap_modify_ext() places the message id +of the request in *msgidp. A subsequent call to ldap_result(), described +below, can be used to obtain the result of the modify. + +Similar to ldap_modify_ext(), the ldap_modify() function initiates an +asynchronous modify operation and returns the message id of the opera- +tion initiated. As for ldap_modify_ext(), a subsequent call to +ldap_result(), described below, can be used to obtain the result of the +modify. In case of error, ldap_modify() will return -1, setting the ses- +sion error parameters in the LDAP structure appropriately. + +The synchronous ldap_modify_ext_s() and ldap_modify_s() functions both +return the result of the operation, either the constant LDAP_SUCCESS if +the operation was successful, or another LDAP result code if it was not. +See the section below on error handling for more information about pos- +sible errors and how to interpret them. + +The ldap_modify_ext() and ldap_modify_ext_s() functions support LDAPv3 +server controls and client controls. + + +11.11. Modifying the Name of an Entry + +In LDAPv2, the ldap_modrdn(), ldap_modrdn_s(), ldap_modrdn2(), and +ldap_modrdn2_s() routines were used to change the name of an LDAP entry. +They could only be used to change the least significant component of a +name (the RDN or relative distinguished name). LDAPv3 provides the +Modify DN protocol operation that allows more general name change +access. The ldap_rename() and ldap_rename_s() routines are used to +change the name of an entry, and the use of the ldap_modrdn(), +ldap_modrdn_s(), ldap_modrdn2(), and ldap_modrdn2_s() routines is depre- +cated. + + int ldap_rename( + LDAP *ld, + const char *dn, + const char *newrdn, + const char *newparent, + int deleteoldrdn, + LDAPControl **serverctrls, + LDAPControl **clientctrls, + int *msgidp + + + +Expires: May 2001 [Page 37] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + ); + int ldap_rename_s( + LDAP *ld, + const char *dn, + const char *newrdn, + const char *newparent, + int deleteoldrdn, + LDAPControl **serverctrls, + LDAPControl **clientctrls + ); + + The use of the following routines is deprecated and more complete + descriptions can be found in RFC 1823: + + int ldap_modrdn( + LDAP *ld, + const char *dn, + const char *newrdn + ); + int ldap_modrdn_s( + LDAP *ld, + const char *dn, + const char *newrdn + ); + int ldap_modrdn2( + LDAP *ld, + const char *dn, + const char *newrdn, + int deleteoldrdn + ); + int ldap_modrdn2_s( + LDAP *ld, + const char *dn, + const char *newrdn, + int deleteoldrdn + ); + +Parameters are: + +ld The session handle. + +dn The name of the entry whose DN is to be changed. If NULL, + a zero length DN is sent to the server. + +newrdn The new RDN to give the entry. + +newparent The new parent, or superior entry. If this parameter is + NULL, only the RDN of the entry is changed. The root DN + + + +Expires: May 2001 [Page 38] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + SHOULD be specified by passing a zero length string, "". + The newparent parameter SHOULD always be NULL when using + version 2 of the LDAP protocol; otherwise the server's + behavior is undefined. + +deleteoldrdn This parameter only has meaning on the rename routines if + newrdn is different than the old RDN. It is a boolean + value, if non-zero indicating that the old RDN value(s) is + to be removed, if zero indicating that the old RDN value(s) + is to be retained as non-distinguished values of the entry. + +serverctrls List of LDAP server controls, or NULL if no server controls + are to be used. + +clientctrls List of client controls, or NULL if no client controls are + to be used. + +msgidp This result parameter will be set to the message id of the + request if the ldap_rename() call succeeds. The value is + undefined if a value other than LDAP_SUCCESS is returned. + +The ldap_rename() function initiates an asynchronous modify DN operation +and returns the constant LDAP_SUCCESS if the request was successfully +sent, or another LDAP result code if not. See the section below on +error handling for more information about possible errors and how to +interpret them. If successful, ldap_rename() places the DN message id +of the request in *msgidp. A subsequent call to ldap_result(), described +below, can be used to obtain the result of the rename. + +The synchronous ldap_rename_s() returns the result of the operation, +either the constant LDAP_SUCCESS if the operation was successful, or +another LDAP result code if it was not. See the section below on error +handling for more information about possible errors and how to interpret +them. + +The ldap_rename() and ldap_rename_s() functions both support LDAPv3 +server controls and client controls. + + +11.12. Adding an entry + +The following functions are used to add entries to the LDAP directory. +There are four variations: + + int ldap_add_ext( + LDAP *ld, + const char *dn, + LDAPMod **attrs, + + + +Expires: May 2001 [Page 39] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + LDAPControl **serverctrls, + LDAPControl **clientctrls, + int *msgidp + ); + + int ldap_add_ext_s( + LDAP *ld, + const char *dn, + LDAPMod **attrs, + LDAPControl **serverctrls, + LDAPControl **clientctrls + ); + + int ldap_add( + LDAP *ld, + const char *dn, + LDAPMod **attrs + ); + + int ldap_add_s( + LDAP *ld, + const char *dn, + LDAPMod **attrs + ); + +Parameters are: + +ld The session handle. + +dn The name of the entry to add. If NULL, a zero length DN is + sent to the server. + +attrs The entry's attributes, specified using the LDAPMod struc- + ture defined for ldap_modify(). The mod_type and mod_vals + fields MUST 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. + +serverctrls List of LDAP server controls, or NULL if no server controls + are to be used. + +clientctrls List of client controls, or NULL if no client controls are + to be used. + +msgidp This result parameter will be set to the message id of the + request if the ldap_add_ext() call succeeds. The value is + undefined if a value other than LDAP_SUCCESS is returned. + + + + +Expires: May 2001 [Page 40] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +Note that the parent of the entry being added must already exist or the +parent must be empty (i.e., equal to the root DN) for an add to succeed. + +The ldap_add_ext() function initiates an asynchronous add operation and +returns the constant LDAP_SUCCESS if the request was successfully sent, +or another LDAP result code if not. See the section below on error han- +dling for more information about possible errors and how to interpret +them. If successful, ldap_add_ext() places the message id of the +request in *msgidp. A subsequent call to ldap_result(), described below, +can be used to obtain the result of the add. + +Similar to ldap_add_ext(), the ldap_add() function initiates an asyn- +chronous add operation and returns the message id of the operation ini- +tiated. As for ldap_add_ext(), a subsequent call to ldap_result(), +described below, can be used to obtain the result of the add. In case of +error, ldap_add() will return -1, setting the session error parameters +in the LDAP structure appropriately. + +The synchronous ldap_add_ext_s() and ldap_add_s() functions both return +the result of the operation, either the constant LDAP_SUCCESS if the +operation was successful, or another LDAP result code if it was not. +See the section below on error handling for more information about pos- +sible errors and how to interpret them. + +The ldap_add_ext() and ldap_add_ext_s() functions support LDAPv3 server +controls and client controls. + + + +11.13. Deleting an entry + +The following functions are used to delete a leaf entry from the LDAP +directory. There are four variations: + + int ldap_delete_ext( + LDAP *ld, + const char *dn, + LDAPControl **serverctrls, + LDAPControl **clientctrls, + int *msgidp + ); + + int ldap_delete_ext_s( + LDAP *ld, + const char *dn, + LDAPControl **serverctrls, + LDAPControl **clientctrls + ); + + + +Expires: May 2001 [Page 41] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + + int ldap_delete( + LDAP *ld, + const char *dn + ); + + int ldap_delete_s( + LDAP *ld, + const char *dn + ); + +Parameters are: + +ld The session handle. + +dn The name of the entry to delete. If NULL, a zero length DN + is sent to the server. + +serverctrls List of LDAP server controls, or NULL if no server controls + are to be used. + +clientctrls List of client controls, or NULL if no client controls are + to be used. + +msgidp This result parameter will be set to the message id of the + request if the ldap_delete_ext() call succeeds. The value + is undefined if a value other than LDAP_SUCCESS is + returned. + +Note that the entry to delete must be a leaf entry (i.e., it must have +no children). Deletion of entire subtrees in a single operation is not +supported by LDAP. + +The ldap_delete_ext() function initiates an asynchronous delete opera- +tion and returns the constant LDAP_SUCCESS if the request was success- +fully sent, or another LDAP result code if not. See the section below +on error handling for more information about possible errors and how to +interpret them. If successful, ldap_delete_ext() places the message id +of the request in *msgidp. A subsequent call to ldap_result(), described +below, can be used to obtain the result of the delete. + +Similar to ldap_delete_ext(), the ldap_delete() function initiates an +asynchronous delete operation and returns the message id of the opera- +tion initiated. As for ldap_delete_ext(), a subsequent call to +ldap_result(), described below, can be used to obtain the result of the +delete. In case of error, ldap_delete() will return -1, setting the ses- +sion error parameters in the LDAP structure appropriately. + + + + +Expires: May 2001 [Page 42] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +The synchronous ldap_delete_ext_s() and ldap_delete_s() functions both +return the result of the operation, either the constant LDAP_SUCCESS if +the operation was successful, or another LDAP result code if it was not. +See the section below on error handling for more information about pos- +sible errors and how to interpret them. + +The ldap_delete_ext() and ldap_delete_ext_s() functions support LDAPv3 +server controls and client controls. + + +11.14. Extended Operations + +The ldap_extended_operation() and ldap_extended_operation_s() routines +allow extended LDAP operations to be passed to the server, providing a +general protocol extensibility mechanism. + + int ldap_extended_operation( + LDAP *ld, + const char *requestoid, + const struct berval *requestdata, + LDAPControl **serverctrls, + LDAPControl **clientctrls, + int *msgidp + ); + + int ldap_extended_operation_s( + LDAP *ld, + const char *requestoid, + const struct berval *requestdata, + LDAPControl **serverctrls, + LDAPControl **clientctrls, + char **retoidp, + struct berval **retdatap + ); + +Parameters are: + +ld The session handle. + +requestoid The dotted-OID text string naming the request. + +requestdata The arbitrary data needed by the operation (if NULL, no + data is sent to the server). + +serverctrls List of LDAP server controls, or NULL if no server controls + are to be used. + +clientctrls List of client controls, or NULL if no client controls are + + + +Expires: May 2001 [Page 43] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + to be used. + +msgidp This result parameter will be set to the message id of the + request if the ldap_extended_operation() call succeeds. The + value is undefined if a value other than LDAP_SUCCESS is + returned. + +retoidp Pointer to a character string that will be set to an allo- + cated, dotted-OID text string returned by the server. This + string SHOULD be disposed of using the ldap_memfree() func- + tion. If an API error occurs or no OID is returned by the + server, *retoidp is set to NULL. + +retdatap Pointer to a berval structure pointer that will be set an + allocated copy of the data returned by the server. This + struct berval SHOULD be disposed of using ber_bvfree(). If + an API error occurs or no data is returned by the server, + *retdatap is set to NULL. + +The ldap_extended_operation() function initiates an asynchronous +extended operation and returns the constant LDAP_SUCCESS if the request +was successfully sent, or another LDAP result code if not. See the sec- +tion below on error handling for more information about possible errors +and how to interpret them. If successful, ldap_extended_operation() +places the message id of the request in *msgidp. A subsequent call to +ldap_result(), described below, can be used to obtain the result of the +extended operation which can be passed to ldap_parse_extended_result() +to obtain the OID and data contained in the response. + +The synchronous ldap_extended_operation_s() function returns the result +of the operation, either the constant LDAP_SUCCESS if the operation was +successful, or another LDAP result code if it was not. See the section +below on error handling for more information about possible errors and +how to interpret them. The retoid and retdata parameters are filled in +with the OID and data from the response. + +The ldap_extended_operation() and ldap_extended_operation_s() functions +both support LDAPv3 server controls and client controls. + + +12. Abandoning An Operation + +The following calls are used to abandon an operation in progress: + + int ldap_abandon_ext( + LDAP *ld, + int msgid, + LDAPControl **serverctrls, + + + +Expires: May 2001 [Page 44] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + LDAPControl **clientctrls + ); + + int ldap_abandon( + LDAP *ld, + int msgid + ); + + +ld The session handle. + +msgid The message id of the request to be abandoned. + +serverctrls List of LDAP server controls, or NULL if no server controls + are to be used. + +clientctrls List of client controls, or NULL if no client controls are + to be used. + +ldap_abandon_ext() abandons the operation with message id msgid and +returns the constant LDAP_SUCCESS if the abandon was successful or +another LDAP result code if not. See the section below on error han- +dling for more information about possible errors and how to interpret +them. + +ldap_abandon() is identical to ldap_abandon_ext() except that it does +not accept client or server controls and it returns zero if the abandon +was successful, -1 otherwise. + +After a successful call to ldap_abandon() or ldap_abandon_ext(), results +with the given message id are never returned from a subsequent call to +ldap_result(). There is no server response to LDAP abandon operations. + + +13. Obtaining Results and Peeking Inside LDAP Messages + +ldap_result() is used to obtain the result of a previous asynchronously +initiated operation. Note that depending on how it is called, +ldap_result() can actually return a list or "chain" of result messages. +The ldap_result() function only returns messages for a single request, +so for all LDAP operations other than search only one result message is +expected; that is, the only time the "result chain" can contain more +than one message is if results from a search operation are returned. +Once a chain of messages has been returned to the caller, it is no +longer tied in any caller-visible way to the LDAP request that produced +it. However, it MAY be tied to the session handle. Therefore, a chain +of messages returned by calling ldap_result() or by calling a synchro- +nous search routine will never be affected by subsequent LDAP API calls + + + +Expires: May 2001 [Page 45] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +except for ldap_msgfree() (which is used to dispose of a chain of mes- +sages) and the unbind calls (which dispose of a session handle): +ldap_unbind(), ldap_unbind_s(), or ldap_unbind_ext(), or functions +defined by extensions of this API. + +ldap_msgfree() frees the result messages (possibly an entire chain of +messages) obtained from a previous call to ldap_result() or from a call +to a synchronous search routine. + +ldap_msgtype() returns the type of an LDAP message. + +ldap_msgid() returns the message ID of an LDAP message. + + int ldap_result( + LDAP *ld, + int msgid, + int all, + struct timeval *timeout, + LDAPMessage **res + ); + + int ldap_msgfree( LDAPMessage *res ); + + int ldap_msgtype( LDAPMessage *res ); + + int ldap_msgid( LDAPMessage *res ); + +Parameters are: + +ld The session handle. + +msgid The message id of the operation whose results are to be + returned, the constant LDAP_RES_UNSOLICITED (0) if an unsoli- + cited result is desired, or or the constant LDAP_RES_ANY (-1) + if any result is desired. + +all Specifies how many messages will be retrieved in a single call + to ldap_result(). This parameter only has meaning for search + results. Pass the constant LDAP_MSG_ONE (0x00) to retrieve one + message at a time. Pass LDAP_MSG_ALL (0x01) to request that + all results of a search be received before returning all + results in a single chain. Pass LDAP_MSG_RECEIVED (0x02) to + indicate that all messages retrieved so far are to be returned + in the result chain. + +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 seconds + + + +Expires: May 2001 [Page 46] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + specifies a polling behavior. + +res For ldap_result(), a result parameter that will contain the + result(s) of the operation. If an API error occurs or no + results are returned, *res is set to NULL. For ldap_msgfree(), + the result chain to be freed, obtained from a previous call to + ldap_result(), ldap_search_s(), or ldap_search_st(). If res is + NULL, nothing is done and ldap_msgfree() returns zero. + +Upon successful completion, ldap_result() returns the type of the first +result returned in the res parameter. This will be one of the following +constants. + + LDAP_RES_BIND (0x61) + LDAP_RES_SEARCH_ENTRY (0x64) + LDAP_RES_SEARCH_REFERENCE (0x73) -- new in LDAPv3 + LDAP_RES_SEARCH_RESULT (0x65) + LDAP_RES_MODIFY (0x67) + LDAP_RES_ADD (0x69) + LDAP_RES_DELETE (0x6B) + LDAP_RES_MODDN (0x6D) + LDAP_RES_COMPARE (0x6F) + LDAP_RES_EXTENDED (0x78) -- new in LDAPv3 + +ldap_result() returns 0 if the timeout expired and -1 if an error +occurs, in which case the error parameters of the LDAP session handle +will be set accordingly. + +ldap_msgfree() frees each message in the result chain pointed to by res +and returns the type of the last message in the chain. If res is NULL, +nothing is done and the value zero is returned. + +ldap_msgtype() returns the type of the LDAP message it is passed as a +parameter. The type will be one of the types listed above, or -1 on +error. + +ldap_msgid() returns the message ID associated with the LDAP message +passed as a parameter, or -1 on error. + + +14. Handling Errors and Parsing Results + +The following calls are used to extract information from results and +handle errors returned by other LDAP API routines. Note that +ldap_parse_sasl_bind_result() and ldap_parse_extended_result() must typ- +ically be used in addition to ldap_parse_result() to retrieve all the +result information from SASL Bind and Extended Operations respectively. + + + + +Expires: May 2001 [Page 47] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + int ldap_parse_result( + LDAP *ld, + LDAPMessage *res, + int *errcodep, + char **matcheddnp, + char **errmsgp, + char ***referralsp, + LDAPControl ***serverctrlsp, + int freeit + ); + + int ldap_parse_sasl_bind_result( + LDAP *ld, + LDAPMessage *res, + struct berval **servercredp, + int freeit + ); + + int ldap_parse_extended_result( + LDAP *ld, + LDAPMessage *res, + char **retoidp, + struct berval **retdatap, + int freeit + ); + + #define LDAP_NOTICE_OF_DISCONNECTION "1.3.6.1.4.1.1466.20036" + + char *ldap_err2string( int err ); + + The use of the following routines is deprecated and more complete + descriptions can be found in RFC 1823: + + int ldap_result2error( + LDAP *ld, + LDAPMessage *res, + int freeit + ); + + void ldap_perror( LDAP *ld, const char *msg ); + +Parameters are: + +ld The session handle. + +res The result of an LDAP operation as returned by + ldap_result() or one of the synchronous API operation + calls. + + + +Expires: May 2001 [Page 48] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +errcodep This result parameter will be filled in with the LDAP + resultCode field from the LDAPMessage message. This is the + indication from the server of the outcome of the operation. + NULL SHOULD be passed to ignore this field. + +matcheddnp If the server returned a matchedDN string to indicate how + much of a name passed in a request was recognized, this + result parameter will be filled in with that matchedDN + string. Otherwise, this field will be set to NULL. NULL + SHOULD be passed to ignore this field. The matched DN + string SHOULD be freed by calling ldap_memfree() which is + described later in this document. Note that the server may + return a zero length matchedDN (in which case *matchednp is + set to an allocated copy of "") which is different than not + returning a value at all (in which case *matcheddnp is set + to NULL). + +errmsgp This result parameter will be filled in with the contents + of the error message field from the LDAPMessage message. + The error message string SHOULD be freed by calling + ldap_memfree() which is described later in this document. + NULL SHOULD be passed to ignore this field. + +referralsp This result parameter will be filled in with the contents + of the referrals field from the LDAPMessage message, indi- + cating zero or more alternate LDAP servers where the + request is to be retried. The referrals array SHOULD be + freed by calling ldap_value_free() which is described later + in this document. NULL SHOULD be passed to ignore this + field. If no referrals were returned, *referralsp is set + to NULL. + +serverctrlsp This result parameter will be filled in with an allocated + array of controls copied out of the LDAPMessage message. + If serverctrlsp is NULL, no controls are returned. The + control array SHOULD be freed by calling + ldap_controls_free() which was described earlier. If no + controls were returned, *serverctrlsp is set to NULL. + +freeit A boolean that determines whether the res parameter is + disposed of or not. Pass any non-zero value to have these + routines free res after extracting the requested informa- + tion. This is provided as a convenience; you can also use + ldap_msgfree() to free the result later. If freeit is + non-zero, the entire chain of messages represented by res + is disposed of. + +servercredp For SASL bind results, this result parameter will be filled + + + +Expires: May 2001 [Page 49] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + in with the credentials passed back by the server for + mutual authentication, if given. An allocated berval struc- + ture is returned that SHOULD be disposed of by calling + ber_bvfree(). NULL SHOULD be passed to ignore this field. + +retoidp For extended results, this result parameter will be filled + in with the dotted-OID text representation of the name of + the extended operation response. This string SHOULD be + disposed of by calling ldap_memfree(). NULL SHOULD be + passed to ignore this field. If no OID was returned, + *retoidp is set to NULL. The LDAP_NOTICE_OF_DISCONNECTION + macro is defined as a convenience for clients that wish to + check an OID to see if it matches the one used for the + unsolicited Notice of Disconnection (defined in RFC 2251[2] + section 4.4.1). + +retdatap For extended results, this result parameter will be filled + in with a pointer to a struct berval containing the data in + the extended operation response. It SHOULD be disposed of + by calling ber_bvfree(). NULL SHOULD be passed to ignore + this field. If no data is returned, *retdatap is set to + NULL. + +err For ldap_err2string(), an LDAP result code, as returned by + ldap_parse_result() or another LDAP API call. + +Additional parameters for the deprecated routines are not described. +Interested readers are referred to RFC 1823. + +The ldap_parse_result(), ldap_parse_sasl_bind_result(), and +ldap_parse_extended_result() functions all skip over messages of type +LDAP_RES_SEARCH_ENTRY and LDAP_RES_SEARCH_REFERENCE when looking for a +result message to parse. They return the constant LDAP_SUCCESS if the +result was successfully parsed and another LDAP API result code if not. +If a value other than LDAP_SUCCESS is returned, the values of all the +result parameters are undefined. Note that the LDAP result code that +indicates the outcome of the operation performed by the server is placed +in the errcodep ldap_parse_result() parameter. If a chain of messages +that contains more than one result message is passed to these routines +they always operate on the first result in the chain. + +ldap_err2string() is used to convert a numeric LDAP result code, as +returned by ldap_parse_result(), ldap_parse_sasl_bind_result(), +ldap_parse_extended_result() or one of the synchronous API operation +calls, into an informative zero-terminated character string message +describing the error. It returns a pointer to static data and it MUST +NOT return NULL; the value returned is always a valid null-terminated +"C" string. + + + +Expires: May 2001 [Page 50] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +15. Stepping Through a List of Results + +The ldap_first_message() and ldap_next_message() routines are used to +step through the list of messages in a result chain returned by +ldap_result(). For search operations, the result chain can actually +include referral messages, entry messages, and result messages. +ldap_count_messages() is used to count the number of messages returned. +The ldap_msgtype() function, described above, can be used to distinguish +between the different message types. + + LDAPMessage *ldap_first_message( LDAP *ld, LDAPMessage *res ); + + LDAPMessage *ldap_next_message( LDAP *ld, LDAPMessage *msg ); + + int ldap_count_messages( LDAP *ld, LDAPMessage *res ); + +Parameters are: + +ld The session handle. + +res The result chain, as obtained by a call to one of the synchronous + search routines or ldap_result(). + +msg The message returned by a previous call to ldap_first_message() + or ldap_next_message(). + +ldap_first_message() and ldap_next_message() will return NULL when no +more messages exist in the result set to be returned. NULL is also +returned if an error occurs while stepping through the entries, in which +case the error parameters in the session handle ld will be set to indi- +cate the error. + +If successful, ldap_count_messages() returns the number of messages con- +tained in a chain of results; if an error occurs such as the res parame- +ter being invalid, -1 is returned. The ldap_count_messages() call can +also be used to count the number of messages that remain in a chain if +called with a message, entry, or reference returned by +ldap_first_message(), ldap_next_message(), ldap_first_entry(), +ldap_next_entry(), ldap_first_reference(), ldap_next_reference(). + + +16. Parsing Search Results + +The following calls are used to parse the entries and references +returned by ldap_search() and friends. These results are returned in an +opaque structure that MAY be accessed by calling the routines described +below. Routines are provided to step through the entries and references +returned, step through the attributes of an entry, retrieve the name of + + + +Expires: May 2001 [Page 51] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +an entry, and retrieve the values associated with a given attribute in +an entry. + + +16.1. Stepping Through a List of Entries or References + +The ldap_first_entry() and ldap_next_entry() routines are used to step +through and retrieve the list of entries from a search result chain. +The ldap_first_reference() and ldap_next_reference() routines are used +to step through and retrieve the list of continuation references from a +search result chain. ldap_count_entries() is used to count the number +of entries returned. ldap_count_references() is used to count the number +of references returned. + + LDAPMessage *ldap_first_entry( LDAP *ld, LDAPMessage *res ); + + LDAPMessage *ldap_next_entry( LDAP *ld, LDAPMessage *entry ); + + LDAPMessage *ldap_first_reference( LDAP *ld, LDAPMessage *res ); + + LDAPMessage *ldap_next_reference( LDAP *ld, LDAPMessage *ref ); + + int ldap_count_entries( LDAP *ld, LDAPMessage *res ); + + int ldap_count_references( LDAP *ld, LDAPMessage *res ); + +Parameters are: + +ld The session handle. + +res The search result, as obtained by a call to one of the synchro- + nous search routines or ldap_result(). + +entry The entry returned by a previous call to ldap_first_entry() or + ldap_next_entry(). + +ref The reference returned by a previous call to + ldap_first_reference() or ldap_next_reference(). + +ldap_first_entry(), ldap_next_entry(), ldap_first_reference() and +ldap_next_reference() all return NULL when no more entries or references +exist in the result set to be returned. NULL is also returned if an +error occurs while stepping through the entries or references, in which +case the error parameters in the session handle ld will be set to indi- +cate the error. + +ldap_count_entries() returns the number of entries contained in a chain +of entries; if an error occurs such as the res parameter being invalid, + + + +Expires: May 2001 [Page 52] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +-1 is returned. The ldap_count_entries() call can also be used to count +the number of entries that remain in a chain if called with a message, +entry or reference returned by ldap_first_message(), +ldap_next_message(), ldap_first_entry(), ldap_next_entry(), +ldap_first_reference(), ldap_next_reference(). + +ldap_count_references() returns the number of references contained in a +chain of search results; if an error occurs such as the res parameter +being invalid, -1 is returned. The ldap_count_references() call can +also be used to count the number of references that remain in a chain. + + +16.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, + BerElement **ptr + ); + + char *ldap_next_attribute( + LDAP *ld, + LDAPMessage *entry, + BerElement *ptr + ); + + void ldap_memfree( char *mem ); + +Parameters are: + +ld The session 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 inter- + nally 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(). The BerElement type itself is an opaque + structure that is described in more detail later in this document + in the section "Encoded ASN.1 Value Manipulation". + +mem A pointer to memory allocated by the LDAP library, such as the + attribute type names returned by ldap_first_attribute() and + ldap_next_attribute, or the DN returned by ldap_get_dn(). If mem + + + +Expires: May 2001 [Page 53] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + is NULL, the ldap_memfree() call does nothing. + +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 error parameters in the session handle ld will be set to indi- +cate the error. + +Both routines return a pointer to an allocated buffer containing the +current attribute name. This SHOULD be freed when no longer in use by +calling ldap_memfree(). + +ldap_first_attribute() will allocate and return in ptr a pointer to a +BerElement used to keep track of the current position. This pointer MAY +be passed in subsequent calls to ldap_next_attribute() to step through +the entry's attributes. After a set of calls to ldap_first_attribute() +and ldap_next_attribute(), if ptr is non-NULL, it SHOULD be freed by +calling ber_free( ptr, 0 ). Note that it is very important to pass the +second parameter as 0 (zero) in this call, since the buffer associated +with the BerElement does not point to separately allocated memory. + +The attribute type names returned are suitable for passing in a call to +ldap_get_values() and friends to retrieve the associated values. + + +16.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. + + char **ldap_get_values( + LDAP *ld, + LDAPMessage *entry, + const char *attr + ); + + struct berval **ldap_get_values_len( + LDAP *ld, + LDAPMessage *entry, + const char *attr + ); + + int ldap_count_values( char **vals ); + + int ldap_count_values_len( struct berval **vals ); + + void ldap_value_free( char **vals ); + + + +Expires: May 2001 [Page 54] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + void ldap_value_free_len( struct berval **vals ); + +Parameters are: + +ld The session 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(). + +Two forms of the various calls are provided. The first form is only +suitable for use with non-binary character string data. The second _len +form is used with any kind of data. + +ldap_get_values() and ldap_get_values_len() return NULL if no values are +found for attr or if an error occurs. + +ldap_count_values() and ldap_count_values_len() return -1 if an error +occurs such as the vals parameter being invalid. + +If a NULL vals parameter is passed to ldap_value_free() or +ldap_value_free_len(), nothing is done. + +Note that the values returned are dynamically allocated and SHOULD be +freed by calling either ldap_value_free() or ldap_value_free_len() when +no longer in use. + + +16.4. Retrieving the name of an entry + +ldap_get_dn() is used to retrieve the name of an entry. +ldap_explode_dn() and ldap_explode_rdn() are used to break up a 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( const char *dn, int notypes ); + + char **ldap_explode_rdn( const char *rdn, int notypes ); + + char *ldap_dn2ufn( const char *dn ); + + + +Expires: May 2001 [Page 55] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +Parameters are: + +ld The session 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, such as returned by ldap_get_dn(). If NULL, + a zero length DN is used. + +rdn The rdn to explode, such as returned in the components of the + array returned by ldap_explode_dn(). If NULL, a zero length DN + is used. + +notypes A boolean parameter, if non-zero indicating that the dn or rdn + components are to 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 error parameters in the session handle ld to indicate the error. +It returns a pointer to newly allocated space that the caller SHOULD +free by calling ldap_memfree() when it is no longer in use. Note the +format of the DNs returned is given by [5]. The root DN is returned as +a zero length string (""). + +ldap_explode_dn() returns a NULL-terminated char * array containing the +RDN components of the DN supplied, with or without types as indicated by +the notypes parameter. The components are returned in the order they +appear in the dn. The array returned SHOULD be freed when it is no +longer in use by calling ldap_value_free(). + +ldap_explode_rdn() returns a NULL-terminated char * array containing the +components of the RDN supplied, with or without types as indicated by +the notypes parameter. The components are returned in the order they +appear in the rdn. 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 +[14]. The UFN returned is newly allocated space that SHOULD be freed by +a call to ldap_memfree() when no longer in use. + + +16.5. Retrieving controls from an entry + +ldap_get_entry_controls() is used to extract LDAP controls from an +entry. + + + + + +Expires: May 2001 [Page 56] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + int ldap_get_entry_controls( + LDAP *ld, + LDAPMessage *entry, + LDAPControl ***serverctrlsp + ); + +Parameters are: + +ld The session handle. + +entry The entry to extract controls from, as returned by + ldap_first_entry() or ldap_next_entry(). + +serverctrlsp This result parameter will be filled in with an allocated + array of controls copied out of entry. The control array + SHOULD be freed by calling ldap_controls_free(). If ser- + verctrlsp is NULL, no controls are returned. If no con- + trols were returned, *serverctrlsp is set to NULL. + +ldap_get_entry_controls() returns an LDAP result code that indicates +whether the reference could be successfully parsed (LDAP_SUCCESS if all +goes well). If ldap_get_entry_controls() returns a value other than +LDAP_SUCCESS, the value of the serverctrlsp output parameter is unde- +fined. + + + +16.6. Parsing References + +ldap_parse_reference() is used to extract referrals and controls from a +SearchResultReference message. + + + int ldap_parse_reference( + LDAP *ld, + LDAPMessage *ref, + char ***referralsp, + LDAPControl ***serverctrlsp, + int freeit + ); + +Parameters are: + +ld The session handle. + +ref The reference to parse, as returned by ldap_result(), + ldap_first_reference(), or ldap_next_reference(). + + + + +Expires: May 2001 [Page 57] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +referralsp This result parameter will be filled in with an allocated + array of character strings. The elements of the array are + the referrals (typically LDAP URLs) contained in ref. The + array SHOULD be freed when no longer in used by calling + ldap_value_free(). If referralsp is NULL, the referral + URLs are not returned. If no referrals were returned, + *referralsp is set to NULL. + +serverctrlsp This result parameter will be filled in with an allocated + array of controls copied out of ref. The control array + SHOULD be freed by calling ldap_controls_free(). If ser- + verctrlsp is NULL, no controls are returned. If no con- + trols were returned, *serverctrlsp is set to NULL. + +freeit A boolean that determines whether the ref parameter is + disposed of or not. Pass any non-zero value to have this + routine free ref after extracting the requested informa- + tion. This is provided as a convenience; you can also use + ldap_msgfree() to free the result later. + +ldap_parse_reference() returns an LDAP result code that indicates +whether the reference could be successfully parsed (LDAP_SUCCESS if all +goes well). If a value other than LDAP_SUCCESS is returned, the value +of the referralsp and serverctrlsp result parameters are undefined. + + + +17. Encoded ASN.1 Value Manipulation + +This section describes routines which MAY be used to encode and decode +BER-encoded ASN.1 values, which are often used inside of control and +extension values. + +With the exceptions of two new functions ber_flatten() and ber_init(), +these functions are compatible with the University of Michigan LDAP 3.3 +implementation of BER. + +Note that the functions defined in this section all provide a method for +determining success or failure but generally do not provide access to +specific error codes. Therefore, applications that require precise +error information when encoding or decoding ASN.1 values SHOULD NOT use +these functions. + + +17.1. BER Data Structures and Types + +The following additional integral types are defined for use in manipula- +tion of BER encoded ASN.1 values: + + + +Expires: May 2001 [Page 58] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + typedef ber_tag_t; /* for BER tags */ + + typedef ber_int_t; /* for BER ints, enums, and Booleans */ + + typedef ber_uint_t; /* unsigned equivalent of ber_uint_t */ + + typedef ber_slen_t; /* signed equivalent of ber_len_t */ + +Note that the actual definition for these four integral types is imple- +mentation specific; that is, `', `', +`', and `' MUST each be replaced with an +appropriate implementation-specific type. + +The `ber_tag_t' type is an unsigned integral data type that is large +enough to hold the largest BER tag supported by the API implementation. +The width (number of significant bits) of `ber_tag_t' MUST be at least +32, greater than or equal to that of `unsigned int' (so that integer +promotions won't promote it to `int'), and no wider than that of +`unsigned long'. + +The `ber_int_t' and `ber_uint_t' types are the signed and unsigned vari- +ants of an integral type that is large enough to hold integers for pur- +poses of BER encoding and decoding. The width of `ber_int_t' MUST be at +least 32 and no larger than that of `long'. + +The `ber_slen_t' type is the signed variant of the `ber_len_t' integral +type, i.e. if `ber_len_t' is unsigned long, then `ber_slen_t' is signed +long. The `' in the `ber_len_t' typedef MUST be replaced +with an appropriate type. Note that `ber_slen_t' is not used directly +in the C LDAP API but is provided for the convenience of application +developers and for use by extensions to the API. + + typedef struct berval { + ber_len_t bv_len; + char *bv_val; + } BerValue; + +As defined earlier in the section "Common Data Structures", a berval +structure contains an arbitrary sequence of bytes and an indication of +its length. The bv_len element is an unsigned integer. The bv_val is +not necessarily zero-terminated. Applications MAY allocate their own +berval structures. + +As defined earlier in the section "Common Data Structures", the BerEle- +ment structure is an opaque structure: + + typedef struct berelement BerElement; + + + + +Expires: May 2001 [Page 59] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +It contains not only a copy of the encoded value, but also state infor- +mation used in encoding or decoding. Applications cannot allocate their +own BerElement structures. The internal state is neither thread- +specific nor locked, so two threads SHOULD NOT manipulate the same +BerElement value simultaneously. + +A single BerElement value cannot be used for both encoding and decoding. + +17.2. Memory Disposal and Utility Functions + + void ber_bvfree( struct berval *bv ); + +ber_bvfree() frees a berval structure returned from this API. Both the +bv->bv_val string and the berval structure itself are freed. If bv is +NULL, this call does nothing. + + void ber_bvecfree( struct berval **bv ); + +ber_bvecfree() frees an array of berval structures returned from this +API. Each of the berval structures in the array are freed using +ber_bvfree(), then the array itself is freed. If bv is NULL, this call +does nothing. + + struct berval *ber_bvdup( const struct berval *bv ); + +ber_bvdup() returns a copy of a berval structure. The bv_val field in +the returned berval structure points to a different area of memory than +the bv_val field in the bv argument. The NULL pointer is returned on +error (e.g. out of memory). + + void ber_free( BerElement *ber, int fbuf ); + +ber_free() frees a BerElement which is returned from the API calls +ber_alloc_t() or ber_init(). Each BerElement SHOULD be freed by the +caller. The second argument fbuf SHOULD always be set to 1 to ensure +that the internal buffer used by the BER functions is freed as well as +the BerElement container itself. If ber is NULL, this call does noth- +ing. + + +17.3. Encoding + + BerElement *ber_alloc_t( int options ); + +ber_alloc_t() constructs and returns BerElement. The NULL pointer is +returned on error. The options field contains a bitwise-or of options +which are to be used when generating the encoding of this BerElement. +One option is defined and SHOULD always be supplied: + + + +Expires: May 2001 [Page 60] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + #define LBER_USE_DER 0x01 + +When this option is present, lengths will always be encoded in the +minimum number of octets. Note that this option does not cause values +of sets to be rearranged in tag and byte order or default values to be +removed, so these functions are not sufficient for generating DER output +as defined in X.509 and X.680. If the caller takes responsibility for +ordering values of sets correctly and removing default values, DER out- +put as defined in X.509 and X.680 can be produced. + +Unrecognized option bits are ignored. + +The BerElement returned by ber_alloc_t() is initially empty. Calls to +ber_printf() will append bytes to the end of the ber_alloc_t(). + + int ber_printf( BerElement *ber, const char *fmt, ... ); + +The ber_printf() routine is used to encode a BER element in much the +same way that sprintf() works. One important difference, though, is +that state information is kept in the ber argument so that multiple +calls can be made to ber_printf() to append to the end of the BER ele- +ment. ber MUST be a pointer to a BerElement returned by ber_alloc_t(). +ber_printf() interprets and formats its arguments according to the for- +mat string fmt. ber_printf() returns -1 if there is an error during +encoding and a non-negative number if successful. As with sprintf(), +each character in fmt refers to an argument to ber_printf(). + +The format string can contain the following format characters: + +'t' Tag. The next argument is a ber_tag_t specifying the tag to + override the next element to be written to the ber. This works + across calls. The integer tag value SHOULD contain the tag + class, constructed bit, and tag value. For example, a tag of + "[3]" for a constructed type is 0xA3U. All implementations MUST + support tags that fit in a single octet (i.e., where the tag + value is less than 32) and they MAY support larger tags. + +'b' Boolean. The next argument is an ber_int_t, containing either 0 + for FALSE or 0xff for TRUE. A boolean element is output. If + this format character is not preceded by the 't' format modif- + ier, the tag 0x01U is used for the element. + +'e' Enumerated. The next argument is a ber_int_t, containing the + enumerated value in the host's byte order. An enumerated ele- + ment is output. If this format character is not preceded by the + 't' format modifier, the tag 0x0AU is used for the element. + +'i' Integer. The next argument is a ber_int_t, containing the + + + +Expires: May 2001 [Page 61] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + integer in the host's byte order. An integer element is output. + If this format character is not preceded by the 't' format + modifier, the tag 0x02U is used for the element. + +'B' Bitstring. The next two arguments are a char * pointer to the + start of the bitstring, followed by a ber_len_t containing the + number of bits in the bitstring. A bitstring element is output, + in primitive form. If this format character is not preceded by + the 't' format modifier, the tag 0x03U is used for the element. + +'X' Reserved and not to be used. In older revisions of this specif- + ication, + +'n' Null. No argument is needed. An ASN.1 NULL element is output. + If this format character is not preceded by the 't' format + modifier, the tag 0x05U is used for the element. + +'o' Octet string. The next two arguments are a char *, followed by + a ber_len_t with the length of the string. The string MAY con- + tain null bytes and are do not have to be zero-terminated. An + octet string element is output, in primitive form. If this for- + mat character is not preceded by the 't' format modifier, the + tag 0x04U is used for the element. + +'s' Octet string. The next argument is a char * pointing to a + zero-terminated string. An octet string element in primitive + form is output, which does not include the trailing '\0' (null) + byte. If this format character is not preceded by the 't' format + modifier, the tag 0x04U is used for the element. + +'v' Several octet strings. The next argument is a char **, an array + of char * pointers to zero-terminated strings. The last element + in the array MUST be a NULL pointer. The octet strings do not + include the trailing '\0' (null) byte. Note that a construct + like '{v}' is used to get an actual SEQUENCE OF octet strings. + The 't' format modifier cannot be used with this format charac- + ter. + +'V' Several octet strings. A NULL-terminated array of struct berval + *'s is supplied. Note that a construct like '{V}' is used to + get an actual SEQUENCE OF octet strings. The 't' format modifier + cannot be used with this format character. + +'{' Begin sequence. No argument is needed. If this format charac- + ter is not preceded by the 't' format modifier, the tag 0x30U is + used. + +'}' End sequence. No argument is needed. The 't' format modifier + + + +Expires: May 2001 [Page 62] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + cannot be used with this format character. + +'[' Begin set. No argument is needed. If this format character is + not preceded by the 't' format modifier, the tag 0x31U is used. + +']' End set. No argument is needed. The 't' format modifier cannot + be used with this format character. + +Each use of a '{' format character SHOULD be matched by a '}' character, +either later in the format string, or in the format string of a subse- +quent call to ber_printf() for that BerElement. The same applies to the +'[' and ']' format characters. + +Sequences and sets nest, and implementations of this API MUST maintain +internal state to be able to properly calculate the lengths. + + int ber_flatten( BerElement *ber, struct berval **bvPtr ); + +The ber_flatten routine allocates a struct berval whose contents are a +BER encoding taken from the ber argument. The bvPtr pointer points to +the returned berval structure, which SHOULD be freed using ber_bvfree(). +This routine returns 0 on success and -1 on error. + +The ber_flatten API call is not present in U-M LDAP 3.3. + +The use of ber_flatten on a BerElement in which all '{' and '}' format +modifiers have not been properly matched is an error (i.e., -1 will be +returned by ber_flatten() if this situation is exists). + + +17.4. Encoding Example + +The following is an example of encoding the following ASN.1 data type: + + Example1Request ::= SEQUENCE { + s OCTET STRING, -- must be printable + val1 INTEGER, + val2 [0] INTEGER DEFAULT 0 + } + + + int encode_example1(const char *s, ber_int_t val1, ber_int_t val2, + struct berval **bvPtr) + { + BerElement *ber; + int rc = -1; + + *bvPtr = NULL; /* in case of error */ + + + +Expires: May 2001 [Page 63] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + ber = ber_alloc_t(LBER_USE_DER); + + if (ber == NULL) return -1; + + if (ber_printf(ber,"{si",s,val1) == -1) { + goto done; + } + + if (val2 != 0) { + if (ber_printf(ber,"ti",(ber_tag_t)0x80,val2) == -1) { + goto done; + } + } + + if (ber_printf(ber,"}") == -1) { + goto done; + } + + rc = ber_flatten(ber,bvPtr); + + done: + ber_free(ber,1); + return rc; + } + + +17.5. Decoding + +The following two macros are available to applications: LBER_ERROR and +LBER_DEFAULT. Both of these macros MUST be #define'd as ber_tag_t +integral values that are treated as invalid tags by the API implementa- +tion. It is RECOMMENDED that the values of LBER_ERROR and LBER_DEFAULT +be the same and that they be defined as values where all octets have the +value 0xFF. ISO C guarantees that these definitions will work: + + #define LBER_ERROR ((ber_tag_t)-1) + #define LBER_DEFAULT ((ber_tag_t)-1) + +The intent is that LBER_ERROR and LBER_DEFAULT are both defined as the +integer value that has all octets set to 0xFF, as such a value is not a +valid BER tag. + + BerElement *ber_init( const struct berval *bv ); + +The ber_init function constructs a BerElement and returns a new BerEle- +ment containing a copy of the data in the bv argument. ber_init returns +the NULL pointer on error. + + + + +Expires: May 2001 [Page 64] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + ber_tag_t ber_scanf( BerElement *ber, const char *fmt, ... ); + +The ber_scanf() routine is used to decode a BER element in much the same +way that sscanf() works. One important difference, though, is that some +state information is kept with the ber argument so that multiple calls +can be made to ber_scanf() to sequentially read from the BER element. +The ber argument SHOULD be a pointer to a BerElement returned by +ber_init(). ber_scanf interprets the bytes according to the format +string fmt, and stores the results in its additional arguments. +ber_scanf() returns LBER_ERROR on error, and a different value on suc- +cess. If an error occurred, the values of all the result parameters are +undefined. + +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: + +'a' Octet string. A char ** argument MUST be supplied. Memory is + allocated, filled with the contents of the octet string, zero- + terminated, and the pointer to the string is stored in the argu- + ment. The returned value SHOULD be freed using ldap_memfree. + The tag of the element MUST indicate the primitive form (con- + structed strings are not supported) but is otherwise ignored and + discarded during the decoding. This format cannot be used with + octet strings which could contain null bytes. + +'O' Octet string. A struct berval ** argument MUST be supplied, + which upon return points to an allocated struct berval contain- + ing the octet string and its length. ber_bvfree() SHOULD be + called to free the allocated memory. The tag of the element + MUST indicate the primitive form (constructed strings are not + supported) but is otherwise ignored during the decoding. + +'b' Boolean. A pointer to a ber_int_t MUST be supplied. The + ber_int_t value stored will be 0 for FALSE or nonzero for TRUE. + The tag of the element MUST indicate the primitive form but is + otherwise ignored during the decoding. + +'e' Enumerated. A pointer to a ber_int_t MUST be supplied. The + enumerated value stored will be in host byte order. The tag of + the element MUST indicate the primitive form but is otherwise + ignored during the decoding. ber_scanf() will return an error + if the value of the enumerated value cannot be stored in a + ber_int_t. + +'i' Integer. A pointer to a ber_int_t MUST be supplied. The + ber_int_t value stored will be in host byte order. The tag of + the element MUST indicate the primitive form but is otherwise + + + +Expires: May 2001 [Page 65] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + ignored during the decoding. ber_scanf() will return an error + if the integer cannot be stored in a ber_int_t. + +'B' Bitstring. A char ** argument MUST be supplied which will point + to the allocated bits, followed by a ber_len_t * argument, which + will point to the length (in bits) of the bitstring returned. + ldap_memfree SHOULD be called to free the bitstring. The tag of + the element MUST indicate the primitive form (constructed bit- + strings are not supported) but is otherwise ignored during the + decoding. + +'n' Null. No argument is needed. The element is verified to have a + zero-length value and is skipped. The tag is ignored. + +'t' Tag. A pointer to a ber_tag_t MUST be supplied. The ber_tag_t + value stored will be the tag of the next element in the BerEle- + ment ber, represented so it can be written using the 't' format + of ber_printf(). The decoding position within the ber argument + is unchanged by this; that is, the fact that the tag has been + retrieved does not affect future use of ber. + +'v' Several octet strings. A char *** argument MUST be supplied, + which upon return points to an allocated NULL-terminated array + of char *'s containing the octet strings. NULL is stored if the + sequence is empty. ldap_memfree SHOULD be called to free each + element of the array and the array itself. The tag of the + sequence and of the octet strings are ignored. + +'V' Several octet strings (which could contain null bytes). A + struct berval *** MUST be supplied, which upon return points to + a allocated NULL-terminated array of struct berval *'s contain- + ing the octet strings and their lengths. NULL is stored if the + sequence is empty. ber_bvecfree() can be called to free the + allocated memory. The tag of the sequence and of the octet + strings are ignored. + +'x' Skip element. The next element is skipped. No argument is + needed. + +'{' Begin sequence. No argument is needed. The initial sequence + tag and length are skipped. + +'}' End sequence. No argument is needed. + +'[' Begin set. No argument is needed. The initial set tag and + length are skipped. + +']' End set. No argument is needed. + + + +Expires: May 2001 [Page 66] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + ber_tag_t ber_peek_tag( BerElement *ber, + ber_len_t *lenPtr ); + +ber_peek_tag() returns the tag of the next element to be parsed in the +BerElement argument. The length of this element is stored in the +*lenPtr argument. LBER_DEFAULT is returned if there is no further data +to be read. The decoding position within the ber argument is unchanged +by this call; that is, the fact that ber_peek_tag() has been called does +not affect future use of ber. + + ber_tag_t ber_skip_tag( BerElement *ber, ber_len_t *lenPtr ); + +ber_skip_tag() is similar to ber_peek_tag(), except that the state +pointer in the BerElement argument is advanced past the first tag and +length, and is pointed to the value part of the next element. This rou- +tine SHOULD only be used with constructed types and situations when a +BER encoding is used as the value of an OCTET STRING. The length of the +value is stored in *lenPtr. + + ber_tag_t ber_first_element( BerElement *ber, + ber_len_t *lenPtr, char **opaquePtr ); + + ber_tag_t ber_next_element( BerElement *ber, + ber_len_t *lenPtr, char *opaque ); + +ber_first_element() and ber_next_element() are used to traverse a SET, +SET OF, SEQUENCE or SEQUENCE OF data value. ber_first_element() calls +ber_skip_tag(), stores internal information in *lenPtr and *opaquePtr, +and calls ber_peek_tag() for the first element inside the constructed +value. LBER_DEFAULT is returned if the constructed value is empty. +ber_next_element() positions the state at the start of the next element +in the constructed type. LBER_DEFAULT is returned if there are no +further values. + +The len and opaque values SHOULD NOT be used by applications other than +as arguments to ber_next_element(), as shown in the example below. + + +17.6. Decoding Example + +The following is an example of decoding an ASN.1 data type: + + Example2Request ::= SEQUENCE { + dn OCTET STRING, -- must be printable + scope ENUMERATED { b (0), s (1), w (2) }, + ali ENUMERATED { n (0), s (1), f (2), a (3) }, + size INTEGER, + time INTEGER, + + + +Expires: May 2001 [Page 67] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + tonly BOOLEAN, + attrs SEQUENCE OF OCTET STRING, -- must be printable + [0] SEQUENCE OF SEQUENCE { + type OCTET STRING -- must be printable, + crit BOOLEAN DEFAULT FALSE, + value OCTET STRING + } OPTIONAL } + + #define TAG_CONTROL_LIST 0xA0U /* context specific cons 0 */ + + int decode_example2(struct berval *bv) + { + BerElement *ber; + ber_len_t len; + ber_tag_t res; + ber_int_t scope, ali, size, time, tonly; + char *dn = NULL, **attrs = NULL; + int i,rc = 0; + + ber = ber_init(bv); + if (ber == NULL) { + fputs("ERROR ber_init failed\n", stderr); + return -1; + } + + res = ber_scanf(ber,"{aiiiib{v}",&dn,&scope,&ali, + &size,&time,&tonly,&attrs); + + if (res == LBER_ERROR) { + fputs("ERROR ber_scanf failed\n", stderr); + ber_free(ber,1); + return -1; + } + + /* *** use dn */ + ldap_memfree(dn); + + for (i = 0; attrs != NULL && attrs[i] != NULL; i++) { + /* *** use attrs[i] */ + ldap_memfree(attrs[i]); + } + ldap_memfree((char *)attrs); + + if (ber_peek_tag(ber,&len) == TAG_CONTROL_LIST) { + char *opaque; + ber_tag_t tag; + + for (tag = ber_first_element(ber,&len,&opaque); + + + +Expires: May 2001 [Page 68] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + tag != LBER_DEFAULT; + tag = ber_next_element (ber,&len,opaque)) { + + ber_len_t tlen; + ber_tag_t ttag; + char *type; + ber_int_t crit; + struct berval *value; + + if (ber_scanf(ber,"{a",&type) == LBER_ERROR) { + fputs("ERROR cannot parse type\n", stderr); + break; + } + /* *** use type */ + ldap_memfree(type); + + ttag = ber_peek_tag(ber,&tlen); + if (ttag == 0x01U) { /* boolean */ + if (ber_scanf(ber,"b", + &crit) == LBER_ERROR) { + fputs("ERROR cannot parse crit\n", + stderr); + rc = -1; + break; + } + } else if (ttag == 0x04U) { /* octet string */ + crit = 0; + } else { + fputs("ERROR extra field in controls\n", + stderr ); + break; + } + + if (ber_scanf(ber,"O}",&value) == LBER_ERROR) { + fputs("ERROR cannot parse value\n", stderr); + rc = -1; + break; + } + /* *** use value */ + ber_bvfree(value); + } + } + + if ( rc == 0 ) { /* no errors so far */ + if (ber_scanf(ber,"}") == LBER_ERROR) { + rc = -1; + } + } + + + +Expires: May 2001 [Page 69] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + ber_free(ber,1); + + return rc; + } + + + +18. Security Considerations + +LDAPv2 supports security through protocol-level authentication using +clear-text passwords. LDAPv3 adds support for SASL [12] (Simple Authen- +tication Security Layer) methods. LDAPv3 also supports operation over a +secure transport layer using Transport Layer Security TLS [9]. Readers +are referred to the protocol documents for discussion of related secu- +rity considerations. + +Implementations of this API SHOULD be cautious when handling authentica- +tion credentials. In particular, keeping long-lived copies of creden- +tials without the application's knowledge is discouraged. + + +19. Acknowledgements + +Many members of the IETF ASID and LDAPEXT working groups as well as +members of the Internet at large have provided useful comments and +suggestions that have been incorporated into this document. Chris +Weider deserves special mention for his contributions as co-author of +earlier revisions of this document. + +The original material upon which this specification is based was sup- +ported by the National Science Foundation under Grant No. NCR-9416667. + + +20. Copyright + +Copyright (C) The Internet Society (1997-2000). All Rights Reserved. + +This document and translations of it may be copied and furnished to oth- +ers, and derivative works that comment on or otherwise explain it or +assist in its implementation may be prepared, copied, published and dis- +tributed, in whole or in part, without restriction of any kind, provided +that the above copyright notice and this paragraph are included on all +such copies and derivative works. However, this document itself may not +be modified in any way, such as by removing the copyright notice or +references to the Internet Society or other Internet organizations, +except as needed for the purpose of developing Internet standards in +which case the procedures for copyrights defined in the Internet Stan- +dards process must be followed, or as required to translate it into + + + +Expires: May 2001 [Page 70] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +languages other than English. + +The limited permissions granted above are perpetual and will not be +revoked by the Internet Society or its successors or assigns. + +This document and the information contained herein is provided on an "AS +IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK +FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT +INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FIT- +NESS FOR A PARTICULAR PURPOSE. + + +21. Bibliography + +[1] Bradner, S., "Key words for use in RFCs to Indicate Requirement + Levels", RFC 2119, March 1997. + +[2] M. Wahl, T. Howes, S. Kille, "Lightweight Directory Access Protocol + (v3)", RFC 2251, December 1997. + +[3] M. Wahl, A. Coulbeck, T. Howes, S. Kille, W. Yeong, C. Robbins, + "Lightweight Directory Access Protocol (v3): Attribute Syntax + Definitions", RFC 2252, December 1997. + +[4] The Directory: Selected Attribute Syntaxes. CCITT, Recommendation + X.520. + +[5] M. Wahl, S. Kille, T. Howes, "Lightweight Directory Access Protocol + (v3): A UTF-8 String Representation of Distinguished Names", RFC + 2253, December 1997. + +[6] F. Yergeau, "UTF-8, a transformation format of Unicode and ISO + 10646", RFC 2044, October 1996. + +[7] K. Simonsen, "Character Mnemonics and Character Sets," RFC 1345, + June 1992. + +[8] "Programming Languages - C", ANSI/ISO Standard 9899, revised 1997. + +[9] J. Hodges, R. Morgan, M. Wahl, "Lightweight Directory Access Proto- + col (v3): Extension for Transport Layer Security", INTERNET-DRAFT + (work in progress) , June + 1999. + +[10] R. Hinden, S. Deering, "IP Version 6 Addressing Architecture," RFC + 1884, December 1995. + + + + +Expires: May 2001 [Page 71] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +[11] A. Herron, T. Howes, M. Wahl, A. Anantha, "LDAP Control Extension + for Server Side Sorting of Search Results", INTERNET-DRAFT (work in + progress) , 5 April 1999. + +[12] J. Meyers, "Simple Authentication and Security Layer (SASL)", RFC + 2222, October 1997. + +[13] T. Howes, "The String Representation of LDAP Search Filters," RFC + 2254, December 1997. + +[14] S. Kille, "Using the OSI Directory to Achieve User Friendly Nam- + ing," RFC 1781, March 1995. + + +22. Authors' Addresses + + Mark Smith (document editor) + Netscape Communications Corp. + 901 San Antonio Rd. + Palo Alto, CA 94303-4900 + Mail Stop SCA17 - 201 + USA + +1 650 937-3477 + mcs@netscape.com + + Tim Howes + Loudcloud, Inc. + 599 N. Mathilda Avenue + Sunnyvale, CA 94085 + USA + +1 408 744-7300 + howes@loudcloud.com + + Andy Herron + Microsoft Corp. + 1 Microsoft Way + Redmond, WA 98052 + USA + +1 425 882-8080 + andyhe@microsoft.com + + Mark Wahl + Sun Microsystems, Inc. + 8911 Capital of Texas Hwy, Suite 4140 + Austin, TX 78759 + USA + +1 626 919 3600 + Mark.Wahl@sun.com + + + +Expires: May 2001 [Page 72] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + Anoop Anantha + Microsoft Corp. + 1 Microsoft Way + Redmond, WA 98052 + USA + +1 425 882-8080 + anoopa@microsoft.com + + +23. Appendix A - Sample C LDAP API Code + + #include + #include + + main() + { + LDAP *ld; + LDAPMessage *res, *e; + int i, rc; + char *a, *dn; + BerElement *ptr; + char **vals; + + /* open an LDAP session */ + if ( (ld = ldap_init( "dotted.host.name", LDAP_PORT )) == NULL ) + return 1; + + /* authenticate as nobody */ + if (( rc = ldap_simple_bind_s( ld, NULL, NULL )) != LDAP_SUCCESS ) { + fprintf( stderr, "ldap_simple_bind_s: %s\n", + ldap_err2string( rc )); + ldap_unbind( ld ); + return 1; + } + + /* search for entries with cn of "Babs Jensen", return all attrs */ + if (( rc = ldap_search_s( ld, "o=University of Michigan, c=US", + LDAP_SCOPE_SUBTREE, "(cn=Babs Jensen)", NULL, 0, &res )) + != LDAP_SUCCESS ) { + fprintf( stderr, "ldap_search_s: %s\n", + ldap_err2string( rc )); + if ( res == NULL ) { + ldap_unbind( ld ); + return 1; + } + } + + /* step through each entry returned */ + + + +Expires: May 2001 [Page 73] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + 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: %s\n", dn ); + ldap_memfree( dn ); + + /* print each attribute */ + for ( a = ldap_first_attribute( ld, e, &ptr ); a != NULL; + a = ldap_next_attribute( ld, e, ptr ) ) { + printf( "\tattribute: %s\n", a ); + + /* print each value */ + vals = ldap_get_values( ld, e, a ); + for ( i = 0; vals[i] != NULL; i++ ) { + printf( "\t\tvalue: %s\n", vals[i] ); + } + ldap_value_free( vals ); + ldap_memfree( a ); + } + if ( ptr != NULL ) { + ber_free( ptr, 0 ); + } + } + /* free the search results */ + ldap_msgfree( res ); + + /* close and free connection resources */ + ldap_unbind( ld ); + + return 0; + } + + +24. Appendix B - Namespace Consumed By This Specification + +The following 2 prefixes are used in this specification to name func- +tions: + ldap_ + ber_ + +The following 6 prefixes are used in this specification to name struc- +tures, unions, and typedefs: + ldap + LDAP + mod_vals_u + ber + Ber + + + +Expires: May 2001 [Page 74] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + timeval + +The following 3 prefixes are used in this specification to name #defined +macros: + LDAP + LBER_ + mod_ + + +25. Appendix C - Summary of Requirements for API Extensions + +As the LDAP protocol is extended, this C LDAP API will need to be +extended as well. For example, an LDAPv3 control extension has already +been defined for server-side sorting of search results [7]. This appen- +dix summarizes the requirements for extending this API. + +25.1. Compatibility + +Extensions to this document SHOULD NOT, by default, alter the behavior +of any of the APIs specified in this document. If an extension option- +ally changes the behavior of any existing C LDAP API function calls, the +behavior change MUST be well documented. If an extension that operates +on an LDAP session affects a chain of messages that was previously +obtained by a call to ldap_result() or by calling a synchronous search +routine, this MUST be well documented. + +25.2. Style + +Extensions to this API SHOULD follow the general style and naming con- +ventions used in this document. For example, function names SHOULD +start with "ldap_" or "ber_" and consist entirely of lowercase letters, +digits, and underscore ('_') characters. It is RECOMMENDED that private +and experimental extensions use only the following prefixes for macros, +types, and function names: + LDAP_X_ + LBER_X_ + ldap_x_ + ber_x_ +and that these prefixes not be used by standard extensions. + +25.3. Dependence on Externally Defined Types + +Extensions to this API SHOULD minimize dependencies on types and macros +that are defined in system headers and generally use only intrinsic +types that are part of the C language, types defined in this specifica- +tion, or types defined in the extension document itself. + + + + + +Expires: May 2001 [Page 75] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +25.4. Compile Time Information + +Extensions to this API SHOULD conform to the requirements contained in +the "Retrieving Information at Compile Time" section of this document. +That is, extensions SHOULD define a macro of the form: + + #define LDAP_API_FEATURE_x level + +so that applications can detect the presence or absence of the extension +at compile time and also test the version or level of the extension pro- +vided by an API implementation. + +25.5. Runtime Information + +Extensions to this API SHOULD conform to the requirements contained in +the "Retrieving Information During Execution" section of this document. +That is, each extension SHOULD be given a character string name and that +name SHOULD appear in the ldapai_extensions array field of the LDAPAPI- +Info structure following a successful call to ldap_get_option() with an +option parameter value of LDAP_OPT_API_INFO. In addition, information +about the extension SHOULD be available via a call to ldap_get_option() +with an option parameter value of LDAP_OPT_API_FEATURE_INFO. + +25.6. Values Used for Session Handle Options + +Extensions to this API that add new session options (for use with the +ldap_get_option() and ldap_set_option() functions) SHOULD meet the +requirements contained in the last paragraph of the "LDAP Session Handle +Options" section of this document. Specifically, standards track docu- +ments MUST use values for option macros that are between 0x1000 and +0x3FFF inclusive and private and experimental extensions MUST use values +for the option macros that are between 0x4000 and 0x7FFF inclusive. + + +26. Appendix D - Known Incompatibilities with RFC 1823 + +This appendix lists known incompatibilities between this API specifica- +tion and the one contained in RFC 1823, beyond the additional API func- +tions added in support of LDAPv3. + + +26.1. Opaque LDAP Structure + +In RFC 1823, some fields in the LDAP structure were exposed to applica- +tion programmers. To provide a cleaner interface and to make it easier +for implementations to evolve over time without sacrificing binary com- +patibility with older applications, the LDAP structure is now entirely +opaque. The new ldap_set_option() and ldap_get_option() calls can be + + + +Expires: May 2001 [Page 76] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +used to manipulate per-session and global options. + + +26.2. Additional Result Codes + +The following new result code macros were introduced to support LDAPv3: + LDAP_REFERRAL + LDAP_ADMINLIMIT_EXCEEDED + LDAP_UNAVAILABLE_CRITICAL_EXTENSION + LDAP_CONFIDENTIALITY_REQUIRED + LDAP_SASL_BIND_IN_PROGRESS + LDAP_AFFECTS_MULTIPLE_DSAS + LDAP_CONNECT_ERROR + LDAP_NOT_SUPPORTED + LDAP_CONTROL_NOT_FOUND + LDAP_NO_RESULTS_RETURNED + LDAP_MORE_RESULTS_TO_RETURN + LDAP_CLIENT_LOOP + LDAP_REFERRAL_LIMIT_EXCEEDED + + +26.3. Freeing of String Data with ldap_memfree() + +All strings received from the API (e.g., those returned by the +ldap_get_dn() or ldap_dn2ufn() functions) SHOULD be freed by calling +ldap_memfree() not free(). RFC 1823 did not define an ldap_memfree() +function. + + +26.4. Changes to ldap_result() + +The meaning of the all parameter to ldap_result has changed slightly. +Nonzero values from RFC 1823 correspond to LDAP_MSG_ALL (0x01). There +is also a new possible value, LDAP_MSG_RECEIVED (0x02). + +The result type LDAP_RES_MODDN is now returned where RFC 1823 returned +LDAP_RES_MODRDN. The actual value for these two macros is the same +(0x6D). + + +26.5. Changes to ldap_first_attribute() and ldap_next_attribute + +Each non-NULL return value SHOULD be freed by calling ldap_memfree() +after use. In RFC 1823, these two functions returned a pointer to a +per-session buffer, which was not very thread-friendly. + +After the last call to ldap_first_attribute() or ldap_next_attribute(), +the value set in the ptr parameter SHOULD be freed by calling ber_free( + + + +Expires: May 2001 [Page 77] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +ptr, 0 ). RFC 1823 did not mention that the ptr value SHOULD be freed. + +The type of the ptr parameter was changed from void * to BerElement *. + + +26.6. Changes to ldap_modrdn() and ldap_modrdn_s() Functions + +In RFC 1823, the ldap_modrdn() and ldap_modrdn_s() functions include a +parameter called deleteoldrdn. This does not match the great majority +of implementations, so in this specification the deleteoldrdn parameter +was removed from ldap_modrdn() and ldap_modrdn_s(). Two additional +functions that support deleteoldrdn and are widely implemented as well +were added to this specification: ldap_modrdn2() and ldap_modrdn2_s(). + + +26.7. Changes to the berval structure + +In RFC 1823, the bv_len element of the berval structure was defined as +an `unsigned long'. In this specification, the type is implementation- +specific, although it MUST be an unsigned integral type that is at least +32 bits in size. See the appendix "Data Types and Legacy Implementa- +tions" for additional considerations. + + +26.8. API Specification Clarified + +RFC 1823 left many things unspecified, including behavior of various +memory disposal functions when a NULL pointer is presented, requirements +for headers, values of many macros, and so on. This specification is +more complete and generally tighter than the one in RFC 1823. + + +26.9. Deprecated Functions + +A number of functions that are in RFC 1823 are labeled as "deprecated" +in this specification. In most cases, a replacement that provides +equivalent functionality has been defined. The deprecated functions +are: + + ldap_bind() + Use ldap_simple_bind() or ldap_sasl_bind() instead. + + ldap_bind_s() + Use ldap_simple_bind_s() or ldap_sasl_bind_s() instead. + + ldap_kerberos_bind() and ldap_kerberos_bind_s() + No equivalent functions are provided. + + + + +Expires: May 2001 [Page 78] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + ldap_modrdn() and ldap_modrdn2() + Use ldap_rename() instead. + + ldap_modrdn_s() and ldap_modrdn2_s() + Use ldap_rename_s() instead. + + ldap_open() + Use ldap_init() instead. + + ldap_perror() + Use ldap_get_option( ld, LDAP_OPT_RESULT_CODE, &rc ) followed + by fprintf( stderr, "%s: %s", msg, ldap_err2string( rc )) + instead. + + ldap_result2error() + Use ldap_parse_result() instead. + + +27. Appendix E - Data Types and Legacy Implementations + +The data types associated with the length of a ber value (ber_len_t), +and the tag (ber_tag_t) have been defined in this specification as +unsigned integral types of implementation-specific size. The data type +used for encoding and decoding ber integer, enumerated, and boolean +values has been defined in this specification as a signed integral type +of implementation-specific size. This was done so that source and +binary compatibility of the C LDAP API can be maintained across ILP32 +environments (where int, long, and pointers are all 32 bits in size) and +LP64 environments (where ints remain 32 bits but longs and pointers grow +to 64 bits). + +In older implementations of the C LDAP API, such as those based on RFC +1823, implementors may have chosen to use an `unsigned long' for length +and tag values. If a long data type was used for either of these items, +a port of an application to a 64-bit operating system using the LP64 +data model would find the size of the types used by the C LDAP API to +increase. Also, if the legacy implementation had chosen to implement +the tag and types as an unsigned int, adoption of a specification that +mandated use of unsigned longs would cause a source incompatibility in +an LP64 application. By using implementation-specific data types, the C +LDAP API implementation is free to choose the correct data type and the +ability to maintain source compatibility. + +For example, suppose a legacy implementation chose to define the return +value of ber_skip_tag() as an unsigned long but wishes to have the +library return a 32-bit quantity in both ILP32 and LP64 data models. +The following typedefs for ber_tag_t will provide a fixed sized data +structure while preserving existing ILP32 source -- all without + + + +Expires: May 2001 [Page 79] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +generating compiler warnings: + #include /* provides UINT_MAX in ISO C */ + #if UINT_MAX >= 0xffffffffU + typedef unsigned int ber_tag_t; + #else + typedef unsigned long ber_tag_t; + #endif + +Similar code can be used to define appropriate ber_len_t, ber_int_t, +ber_slen_t and ber_uint_t types. + + +28. Appendix F - Changes Made Since Last Document Revision + +The previous version of this document was draft-ietf-ldapext-ldap-c- +api-04.txt, dated 8 October 1999. This appendix lists all of the +changes made to that document to produce this one. + +28.1. API Changes + + "Header Requirements" section: added requirement that the simple pro- + gram provided must execute as well as compile without errors. + + "LDAP Session Handle Options" section: changed the name of the + LDAP_OPT_ERROR_NUMBER option to LDAP_OPT_RESULT_CODE. Allow + LDAP_OPT_ON to be defined as an implementation specific value (to + avoid problems on architectures where the value ((void *)1) is not + usable). + + "Initializing an LDAP Session" section: allow use of the value zero + for the `portno' parameter to mean "use port 389." + + "Searching" section: added LDAP_DEFAULT_SIZELIMIT (-1) to allow + application programmers to use the sizelimit from the LDAP session + handle with ldap_search_ext() and ldap_search_ext_s(). + + "Modifying an entry" section: moved mod_vals union out of LDAPMod and + added mod_vals_u_t typedef so users of the API can declare variables + using the union type. "Handling Errors and Parsing Results" section: + added text to require that ldap_err2string() MUST NOT return NULL. + + "A Client Control That Governs Referral Processing" section: modified + the text to specify that a ber_uint_t value should be used to hold + the flags. + + + + + + + +Expires: May 2001 [Page 80] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + +28.2. Editorial Changes and Clarifications + + "Overview of LDAP API Use and General Requirements" section: added + text to clarify our use of the term "asynchronous." + + "Retrieving Information During Execution" section: added text + describing the `ldapai_vendor_name' and `ldapai_vendor_version' + fields (text was accidently deleted during a previous round of + edits). + + "LDAP Session Handle Options" section: improved the text that + describes the LDAP_OPT_TIMELIMIT, LDAP_OPT_SIZELIMIT, and + LDAP_OPT_RESULT_CODE options. Provided details and an example of the + correct LDAP_OPT_HOST_NAME string to return when the `portno' passed + to ldap_init() is not zero or 389. + + "Result Codes" section: renamed section (was "LDAP Error Codes"). + + "Authenticating to the directory" section: clarified that the `dn', + `cred', and `passwd' parameters can be NULL. Added text indicate + that the `servercredp' is set to NULL if an API error occurs. + + "Performing LDAP Operations" section: replaced "All functions take a + session handle" with "Most functions...." + + "Search" section: removed the detailed discussion of the session han- + dle options (already covered in the "Retrieving Information During + Execution" section). Also removed the word "global" when discussing + the session default value for the `timeout' parameter. Also clari- + fied that a NULL `base' parameter means use a zero-length string for + the base DN. + + "Comparing a Value Against an Entry" section: corrected the "success- + ful" return codes for ldap_compare_ext_s() and ldap_compare_s() (was + LDAP_SUCCESS; changed to LDAP_COMPARE_TRUE or LDAP_COMPARE_FALSE). + + "Extended Operations" section: added text to indicate that the + `retoidp' and `retdatap' result parameters are set to NULL if an API + error occurs in ldap_extended_operation_s(). + + "Handling Errors and Parsing Results" section: added text to say that + the `matcheddnp' result parameter will be set to NULL if the server + does not return a matched DN string. Added text to indicate that + serverctrlsp can be NULL. Added text to indicate that *retoidpp, + *retdatap, *referralsp, and *serverctrlsp will be set to NULL if no + items of that type are returned. Removed specific reference to + LDAP_NO_SUCH_OBJECT result code when discussing the `matcheddnp' + result parameter and added clarifying note about "" vs. NULL. + + + +Expires: May 2001 [Page 81] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + "Parsing References" section: added text to indicate that *refer- + ralsp, and *serverctrlsp will be set to NULL if no items of that type + are returned. + + "Obtaining Results and Peeking Inside LDAP Messages" section: added + text to say that LDAPMessage chains MAY be tied to a session handle. + + "BER Data Structures and Types" section: removed note about + ber_uint_t not being used in this document (it is now). Changed text + to simplify the description of ber_slen_t. Removed misleading sen- + tence about the width of ber_uint_t. + + "Encoded ASN.1 Value Manipulation / Encoding" section: added note + that 'X' is reserved. Also fixed a few small bugs in the example + code. + + "Encoded ASN.1 Value Manipulation / Decoding" section: clarified the + requirements for LBER_ERROR and LBER_DEFAULT (expressed using octets + instead of bits). Also fixed a few small bugs in the example code. + + Added the following text to all descriptions of the `serverctrls' and + `clientctrls' parameters: ", or NULL if no controls + are to be used." + + Added the following text to the description of all `dn' and `rdn' + parameters: "If NULL, a zero length DN is sent to the server." + + Replaced many occurrences of the phrase "error code" with "result + code" throughout the document. + + Added text to indicate that the value of the `msgidp' result parame- + ter is undefined if an error occurs in the following functions: + ldap_sasl_bind(), ldap_search_ext(), ldap_compare_ext(), + ldap_modify_ext(), ldap_add_ext(), ldap_delete_ext(), + ldap_extended_operation(). + + Added text to indicate that the `res' result parameter is set to NULL + if an API error occurs in the following functions: ldap_result(), + ldap_search_s(), ldap_search_st(). + + Added text to indicate that all result parameters have undefined + values if an API error is returned by the following functions: + ldap_parse_result(), ldap_parse_sasl_bind_result(), + ldap_parse_extended_result(), ldap_parse_reference(), ber_scanf(). + + Added angle brackets around ficticious impl_XXX_t types to make it + more obvious that these are not real "C" types, e.g., typedef + ber_len_t'. + + + +Expires: May 2001 [Page 82] + +C LDAP API C LDAP Application Program Interface 17 November 2000 + + + Appendix B: Added mod_vals_u and removed PLDAP from the struct, + unions, and typedefs prefix list. + + Appendix C: Added note in "Compatibility" section about extensions + possible affecting chains of messages and the fact that that must be + well documented. Appendix D: Improved text for ldap_perror() (what + to use instead). + + "Authors" section: updated contact information for Mark Smith, Tim + Howes, and Mark Wahl. + + Fixed a few obvious typos, improved indentation, added missing blank + lines, and so on. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Expires: May 2001 [Page 83] + diff --git a/doc/rfc1823.txt b/doc/rfc1823.txt new file mode 100644 index 0000000..a09d780 --- /dev/null +++ b/doc/rfc1823.txt @@ -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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +RFC 1823 LDAP API August 1995 + + +13. Appendix A - Sample LDAP API Code + + #include + + 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] + +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] + diff --git a/etc/notes.txt b/etc/notes.txt new file mode 100644 index 0000000..b5c04ab --- /dev/null +++ b/etc/notes.txt @@ -0,0 +1,14 @@ + -*- outline -*- + +* LDAP server + +** Starting slapd + su -m + /afs/wsi/ppc_macx66/openldap-2.1.23/libexec/slapd -d 9 -f slapd.conf + +** Adding entries of a ldif file + ldapadd -v -W -x -h localhost -p 389 -D + cn=Manager,dc=informatik,dc=uni-tuebingen,dc=de -f file.ldif + +** Querying an LDAP server + ldapsearch -b "dc=informatik,dc=uni-tuebingen,dc=de" \ No newline at end of file diff --git a/etc/slapd.conf b/etc/slapd.conf new file mode 100644 index 0000000..ff14778 --- /dev/null +++ b/etc/slapd.conf @@ -0,0 +1,68 @@ +# $OpenLDAP: pkg/ldap/servers/slapd/slapd.conf,v 1.23.2.8 2003/05/24 23:19:14 kurt Exp $ +# +# See slapd.conf(5) for details on configuration options. +# This file should NOT be world readable. +# +include /afs/informatik.uni-tuebingen.de/ppc_macx66/openldap-2.1.23/etc/openldap/schema/core.schema + +# Define global ACLs to disable default read access. + +# Do not enable referrals until AFTER you have a working directory +# service AND an understanding of referrals. +#referral ldap://root.openldap.org + +pidfile /tmp/knauel/slapd.pid +argsfile /tmp/knauel/slapd.args + +# Load dynamic backend modules: +# modulepath /Users/Shared/sw/openldap-2.1.23/libexec/openldap +# moduleload back_bdb.la +# moduleload back_ldap.la +# moduleload back_ldbm.la +# moduleload back_passwd.la +# moduleload back_shell.la + +# Sample security restrictions +# Require integrity protection (prevent hijacking) +# Require 112-bit (3DES or better) encryption for updates +# Require 63-bit encryption for simple bind +# security ssf=1 update_ssf=112 simple_bind=64 + +# Sample access control policy: +# Root DSE: allow anyone to read it +# Subschema (sub)entry DSE: allow anyone to read it +# Other DSEs: +# Allow self write access +# Allow authenticated users read access +# Allow anonymous users to authenticate +# Directives needed to implement policy: +# access to dn.base="" by * read +# access to dn.base="cn=Subschema" by * read +# access to * +# by self write +# by users read +# by anonymous auth +# +# if no access controls are present, the default policy is: +# Allow read by all +# +# rootdn can always write! + +####################################################################### +# ldbm database definitions +####################################################################### + +database bdb +suffix "dc=informatik,dc=uni-tuebingen,dc=de" +rootdn "cn=Manager,dc=informatik,dc=uni-tuebingen,dc=de" +# Cleartext passwords, especially for the rootdn, should +# be avoid. See slappasswd(8) and slapd.conf(5) for details. +# Use of strong authentication encouraged. +rootpw secret +# The database directory MUST exist prior to running slapd AND +# should only be accessible by the slapd and slap tools. +# Mode 700 recommended. +directory /Users/knauel/cool-stuff/scsh-ldap/etc/data +# Indices to maintain + +index objectClass eq diff --git a/ffi-tools/ffi-tools-package.scm b/ffi-tools/ffi-tools-package.scm new file mode 100644 index 0000000..bbcdd9f --- /dev/null +++ b/ffi-tools/ffi-tools-package.scm @@ -0,0 +1,27 @@ +(define-interface ffi-import-constants-interface + (export + make-constant + constant? + constant-type-int? + constant-type-char? + constant-type-string? + constant-c-name + constant-scheme-name + constant-c-value-name + constant-type + + make-constant-from-c-name + make-constant-from-c-name-integer + + generate-c-declarations + generate-c-enter-values-function + generate-c-gc-protect-globals-function + + generate-finite-type-definition + make-drop-common-prefix-name-converter)) + +(define-structure ffi-import-constants ffi-import-constants-interface + (open + scheme signals + srfi-1 srfi-9 srfi-13 srfi-28) + (files ffi-tools)) diff --git a/ffi-tools/ffi-tools-rts.scm b/ffi-tools/ffi-tools-rts.scm new file mode 100644 index 0000000..839f71c --- /dev/null +++ b/ffi-tools/ffi-tools-rts.scm @@ -0,0 +1,34 @@ +(define-interface ffi-tools-rts-interface + (export + (lookup-shared-value :syntax) + make-finite-type-import-function)) + +(define-structure ffi-tools-rts ffi-tools-rts-interface + (open scheme) + (begin + + (define-syntax lookup-shared-value + (syntax-rules () + ((lookup-shared-value %s) + (shared-binding-ref + (lookup-imported-binding %s))))) + + (define (make-finite-type-alist elements id-proc) + (map + (lambda (e) (cons (id-proc e) e)) + (vector->list elements))) + + (define (make-finite-type-import-function finite-type-name elements id-proc) + (let ((alist (make-finite-type-alist elements id-proc))) + (lambda (id) + (cond + ((assoc id alis) => cdr) + (else + (error "Could not map value to finite type " + finite-type-name id)))))) + + )) + + + + diff --git a/ffi-tools/ffi-tools.c b/ffi-tools/ffi-tools.c new file mode 100644 index 0000000..6b5396e --- /dev/null +++ b/ffi-tools/ffi-tools.c @@ -0,0 +1,96 @@ +#include "ffi-tools.h" + +/* convert null-terminated array of strings to a list of Scheme strings */ +s48_value ffit_enter_string_array(char **array) +{ + int i; + s48_value res = S48_NULL; + S48_DECLARE_GC_PROTECT(1); + + S48_GC_PROTECT_1(res); + for (i = 0; array[i] != NULL; i++) + res = s48_cons(s48_enter_string(array[i]), res); + S48_GC_UNPROTECT(); + return res; +} + +int length_scheme_list(s48_value list) +{ + s48_value res; + S48_DECLARE_GC_PROTECT(2); + + S48_GC_PROTECT_2(list, res); + FFIT_CHECK_LIST(list); + res = s48_call_scheme(scheme_list_length_function, 1, list); + S48_GC_UNPROTECT(); + return s48_extract_integer(res); +} + +int call_scheme_boolean_p(s48_value v) +{ + s48_value res; + S48_DECLARE_GC_PROTECT(2); + + S48_GC_PROTECT_2(v, res); + res = s48_call_scheme(scheme_boolean_p_function, 1, v); + S48_GC_UNPROTECT(); + return S48_TRUE_P(res); +} + +int call_scheme_integer_p(s48_value v) +{ + s48_value res; + S48_DECLARE_GC_PROTECT(2); + + S48_GC_PROTECT_2(v, res); + res = s48_call_scheme(scheme_integer_p_function, 1, v); + S48_GC_UNPROTECT(); + return S48_TRUE_P(res); +} + +/* convert a Scheme list of strings into an null-terminated array of strings */ +char** ffit_extract_list_of_strings(s48_value list) +{ + char **a; + int l, i; + s48_value res, e; + S48_DECLARE_GC_PROTECT(3); + + S48_GC_PROTECT_3(list, res, e); + l = length_scheme_list(list); + + if ((*a = (char *) calloc(l + 1, sizeof(char *))) == NULL) + s48_raise_out_of_memory_error(); + a[l] = NULL; + + e = list; + i = 0; + while (e != S48_NULL) { + if (S48_PAIR_P(e)) + if (S48_STRING_P(e)) { + a[i] = s48_extract_string(e); + e = S48_CDR(e); + i++; + } + else { + free(a); + s48_raise_argument_type_error(e); + } + else { + free(a); + s48_raise_argument_type_error(e); + } + } + return a; +} + +void ffit_init_hook(void) +{ + S48_GC_PROTECT_GLOBAL(scheme_list_length_function); + S48_GC_PROTECT_GLOBAL(scheme_integer_p_function); + S48_GC_PROTECT_GLOBAL(scheme_boolean_p_function); + + scheme_list_length_function = s48_get_imported_binding("length"); + scheme_integer_p_function = s48_get_imported_binding("integer?"); + scheme_boolean_p_function = s48_get_imported_binding("boolean?"); +} diff --git a/ffi-tools/ffi-tools.h b/ffi-tools/ffi-tools.h new file mode 100644 index 0000000..9842d4f --- /dev/null +++ b/ffi-tools/ffi-tools.h @@ -0,0 +1,76 @@ +#include +#include "scheme48.h" + +/* variables */ +static s48_value scheme_list_length_function = S48_FALSE; +static s48_value scheme_boolean_p_function = S48_FALSE; +static s48_value scheme_integer_p_function = S48_FALSE; + +/* prototypes */ +s48_value ffit_enter_string_array(char**); +int length_scheme_list(s48_value); +int call_scheme_boolean_p(s48_value); +int call_scheme_integer_p(s48_value); +char** ffit_extract_list_of_strings(s48_value); +void ffit_init_hook(void); + +/* macros */ +#define FFIT_MAKE_ENTER_RECORD(FUNNAME, SCM_RECTYPE, C_RECTYPE) \ + s48_value FUNNAME(C_RECTYPE c_rec) { \ + s48_value scm_rec = S48_FALSE; \ + S48_DECLARE_GC_PROTECT(1); \ + \ + S48_GC_PROTECT_1(scm_rec); \ + scm_rec = s48_make_record(SCM_RECTYPE); \ + S48_RECORD_SET(scm_rec, 0, s48_enter_integer((long) c_rec)); \ + S48_GC_UNPROTECT(); \ + return scm_rec; \ + } + +#define FFIT_MAKE_ENTER_RECORD_PROTOTYPE(FUNNAME, C_RECTYPE) \ + s48_value FUNNAME(C_RECTYPE c_rec); + +#define FFIT_RECORD_TYPE_INIT(C_RECTYPE, SCM_NAME) \ + S48_GC_PROTECT_GLOBAL(C_RECTYPE); \ + C_RECTYPE = s48_get_imported_binding("SCM_NAME"); + +#if 0 +#define FFIT_CHECK_RECORD_TYPE(SCM_VAL, SCM_RECTYPE) \ + if (!(S48_RECORD_P(SCM_VAL) && (S48_RECORD_TYPE(SCM_VAL) == SCM_RECTYPE))) \ + s48_raise_argument_type_error(SCM_VAL) +#endif + +#define FFIT_CHECK_RECORD_TYPE(SCM_VAL, SCM_RECTYPE) ; + +#define FFIT_STRUCT_GET(FUNNAME, SCM_RECTYPE, C_RECTYPE, C_FIELD, FIELD_SCM_ENTER_FUN) \ +s48_value FUNNAME(s48_value scm_rec) { \ + s48_value res = S48_FALSE; \ + C_RECTYPE c_rec; \ + S48_DECLARE_GC_PROTECT(2); \ + \ + S48_GC_PROTECT_2(res, scm_rec); \ + FFIT_CHECK_RECORD_TYPE(scm_rec, SCM_RECTYPE); \ + c_rec = (C_RECTYPE) s48_extract_integer(S48_RECORD_REF(scm_rec, 0)); \ + res = FIELD_SCM_ENTER_FUN(c_rec->C_FIELD); \ + S48_GC_UNPROTECT(); \ + return res; \ +} + +#define FFIT_STRUCT_GET_INT(FUNNAME, SCM_RECTYPE, C_RECTYPE, C_FIELD) \ + FFIT_STRUCT_GET(FUNNAME, SCM_RECTYPE, C_RECTYPE, C_FIELD, s48_enter_integer); + +#define FFIT_STRUCT_GET_CHAR(FUNNAME, SCM_RECTYPE, C_RECTYPE, C_FIELD) \ + FFIT_STRUCT_GET(FUNNAMEm SCM_RECTYPE, C_RECTYPE, C_FIELD, s48_enter_char); + +#define FFIT_STRUCT_GET_STRING(FUNNAME, SCM_RECTYPE, C_RECTYPE, C_FIELD) \ + FFIT_STRUCT_GET(FUNNAME, SCM_RECTYPE, C_RECTYPE, C_FIELD, s48_enter_string); + +/* predicates */ +#define FFIT_LIST_P(x) (S48_PAIR_P(x) || (x == S48_NULL)) + +#define FFIT_CHECK_LIST(v) \ + do { if (!FFIT_LIST_P(v)) s48_raise_argument_type_error(v); } while (0) +#define FFIT_CHECK_INTEGER(v) \ + do { if (!call_scheme_integer_p(v)) s48_raise_argument_type_error(v); } while (0) +#define FFIT_CHECK_BOOLEAN(v) \ + do { if (!call_scheme_boolean_p(v)) s48_raise_argument_type_error(v); } while (0) diff --git a/ffi-tools/ffi-tools.scm b/ffi-tools/ffi-tools.scm new file mode 100644 index 0000000..19f7e0a --- /dev/null +++ b/ffi-tools/ffi-tools.scm @@ -0,0 +1,128 @@ +(define-record-type constant + (make-constant c-name scheme-name c-value-name type) + constant? + (c-name constant-c-name) + (scheme-name constant-scheme-name) + (c-value-name constant-c-value-name) + (type constant-type)) + +(define constant-type-int 'constant-type-int) +(define (constant-type-int? thing) + (equal? (constant-type thing) constant-type-int)) + +(define constant-type-char 'constant-type-char) +(define (constant-type-char? thing) + (equal? (constant-type thing) constant-type-char)) + +(define constant-type-string 'constant-type-string) +(define (constant-type-string? thing) + (equal? (constant-type thing) constant-type-string)) + +(define (constant-name->scheme-name constant-name) + (let ((replace-underscore + (lambda (c) (if (char=? c #\_) #\- c)))) + (string-map replace-underscore (string-downcase constant-name)))) + +(define c-value-name-prefix "scheme_") + +(define (constant-name->value-name constant-name) + (string-append c-value-name-prefix constant-name)) + +(define (make-constant-from-c-name c-name type) + (let ((scheme-name (constant-name->scheme-name c-name))) + (make-constant c-name scheme-name + (constant-name->value-name c-name) + type))) + +(define (make-constant-from-c-name-integer c-name) + (make-constant-from-c-name c-name constant-type-int)) + +(define (generate-c-declarations constant-list) + (string-join + (map + (lambda (c) + (format "static s48_value ~a = S48_FALSE;~%" + (constant-c-value-name c))) + constant-list))) + +(define (generate-c-gc-protect-globals constant-list) + (string-join + (map + (lambda (c) + (format "S48_GC_PROTECT_GLOBAL(~a);~%" + (constant-c-value-name c))) + constant-list))) + +(define (generate-c-enter-value c) + (cond + ((constant-type-int? c) + (format "~a = s48_enter_integer(~a);~%" + (constant-c-value-name c) (constant-c-name c))) + ((constant-type-string? c) + (format "~a = s48_enter_integer(~a);~%" + (constant-c-value-name c) (constant-c-name c))) + (else + (error "Don't know how to handle this constant type: " + (constant-type c))))) + +(define (generate-c-enter-values constant-list) + (string-join + (map generate-c-enter-value constant-list))) + +(define (wrap-in-c-function fun-name body) + (format + (string-append + "void ~a(void) {~%" + "~a~%" + "}~%~%") + fun-name body)) + +(define (generate-c-enter-values-function c-fun-name constant-list) + (wrap-in-c-function c-fun-name + (generate-c-enter-values constant-list))) + +(define (generate-c-gc-protect-globals-function c-fun-name constant-list) + (wrap-in-c-function c-fun-name + (generate-c-gc-protect-globals constant-list))) + +;;; generating scheme code + +(define (generate-finite-type-definition ft-name name-converter constants) + (let ((predicate-name (string-append ft-name "-object?")) + (elements-name (string-append ft-name "-elments")) + (name-name (string-append ft-name "-name")) + (index-name (string-append ft-name "-index")) + (id-name (string-append ft-name "-id"))) + (format + (string-append + "(define-finite-type ~a :~a~%" + " (id)~%" + " ~a~% ~a~% ~a~% ~a~%" + " (~a)~%" + " ~a)~%~%") + ft-name ft-name + predicate-name elements-name name-name index-name + (string-append "id " id-name) + (generate-finite-type-items name-converter constants)))) + +(define (generate-finite-type-items name-converter constants) + (string-join + (map (lambda (c) (generate-finite-type-item name-converter c)) + constants))) + +(define (generate-finite-type-item name-converter constant) + (format " (~a\t(lookup-shared-binding \"~a\"))~%" + (name-converter constant) + (constant-c-value-name constant))) + +(define (make-drop-common-prefix-name-converter prefix) + (let ((len (string-length prefix))) + (lambda (constant) + (let ((name (constant-c-name constant))) + (constant-name->scheme-name + (if (string-prefix? prefix name) + (string-drop name len) + name)))))) + + + diff --git a/scheme/Makefile.am b/scheme/Makefile.am new file mode 100644 index 0000000..95ec1e2 --- /dev/null +++ b/scheme/Makefile.am @@ -0,0 +1,27 @@ +SCSH= @SCSH@ +scheme_SCRIPTS=load-ldap.scm + +nobase_scheme_SCRIPTS= \ + ldap.scm + +EXTRA_DIST= load-ldap.scm.in $(nobase_scheme_SCRIPTS) +GENERATED_CODE= const-gen.scm +CLEANFILES= load-ldap.scm $(GENERATED_CODE) + +$(GENERATED_CODE): + $(SCSH) -lm ffi-tools-packages.scm -lm ldap-constants.scm \ + -o ldap-constants -c '(make-c-files command-line-arguments)' \ + `pwd` + +load-ldap.scm: $(srcdir)/load-ldap.scm.in + sed -e "s|@scshldapschemedir@|`pwd`/$(srcdir)|g" \ + -e "s|@scshldaphost@||g" \ + -e "s|@scshldaplibdir@|`pwd`/../c/.libs|g" \ + $< > $@ + +install-data-hook: + sed -e "s|@scshldapschemedir@|$(schemedir)|g" \ + -e "s|@scshldaphost@|(host)|g" \ + -e "s|@scshldaplibdir@|$(libdir)|g" \ + $(srcdir)/load-ldap.scm.in \ + > $(DESTDIR)/$(schemedir)/load-ldap.scm \ No newline at end of file diff --git a/scheme/configure.scm b/scheme/configure.scm new file mode 100644 index 0000000..ccbf1a6 --- /dev/null +++ b/scheme/configure.scm @@ -0,0 +1,24 @@ +(define-structure configure (export host) + (open scheme-with-scsh + srfi-13) + (begin + (define (canonical-machine uname-record) + (let* ((machine (uname:machine uname-record)) + (os (uname:os-name uname-record))) + (cond + ((member machine '("i386" "i486" "i586" "i686")) "i386") + ((or (string=? machine "Power Macintosh") + (and (string=? os "AIX") + (regexp-search? (rx (: "00" (= 6 digit) any any "00")) + machine))) + "powerpc") + (else machine)))) + + (define (canonical-os-name uname-record) + (string-downcase (uname:os-name uname-record))) + + (define (host) + (let ((uname-record (uname))) + (string-append (canonical-machine uname-record) + "-" + (canonical-os-name uname-record)))))) diff --git a/scheme/ldap-constants.scm b/scheme/ldap-constants.scm new file mode 100644 index 0000000..1dba403 --- /dev/null +++ b/scheme/ldap-constants.scm @@ -0,0 +1,128 @@ +(define-interface ldap-constants-interface + (export + make-c-files + make-scm-files)) + +(define-structure ldap-constants ldap-constants-interface + (open + scheme signals + ffi-import-constants) + (begin + + (define ldap-return-codes + (map make-constant-from-c-name-integer + '("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_REFERRAL" + "LDAP_ADMINLIMIT_EXCEEDED" + "LDAP_UNAVAILABLE_CRITICAL_EXTENSION" + "LDAP_CONFIDENTIALITY_REQUIRED" + "LDAP_SASL_BIND_IN_PROGRESS" + "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_AFFECTS_MULTIPLE_DSAS" + "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" + "LDAP_CONNECT_ERROR" + "LDAP_NOT_SUPPORTED" + "LDAP_CONTROL_NOT_FOUND" + "LDAP_NO_RESULTS_RETURNED" + "LDAP_MORE_RESULTS_TO_RETURN" + "LDAP_CLIENT_LOOP" + "LDAP_REFERRAL_LIMIT_EXCEEDED"))) + + (define ldap-opt-protocol-version + (map make-constant-from-c-name-integer + '("LDAP_VERSION" "LDAP_VERSION3"))) + + (define ldap-all-constants + (append ldap-return-codes + ldap-opt-protocol-version)) + + (define (write-source-file name string) + (call-with-output-file name + (lambda (port) + (display string port)))) + + (define (generate-ldap-consts-c path) + (write-source-file + (string-append path "/ldap-consts.c") + (string-append + + "#include \"scheme48.h\"\n" + "#include \n" + + (generate-c-declarations ldap-all-constants) + + (generate-c-enter-values-function + "scsh_ldap_enter_ldap_constants" + ldap-all-constants) + + (generate-c-gc-protect-globals-function + "scsh_ldap_gc_protect_globals" + ldap-all-constants)))) + + (define (generate-const-gen-scm path) + (write-source-file + (string-append path "/const-gen.scm") + (string-append + (generate-finite-type-definition + "ldap-return" (make-drop-common-prefix-name-converter "LDAP_") + ldap-return-codes) + (generate-finite-type-definition + "ldap-option-version" (make-drop-common-prefix-name-converter "LDAP_") + ldap-opt-protocol-version)))) + + (define (make-c-files args) + (if (null? args) + (error "missing parameter") + (let ((path (car args))) + (generate-ldap-consts-c path)))) + + (define (make-scm-files args) + (if (null? args) + (error "missing parameter") + (let ((path (car args))) + (generate-const-gen-scm path)))) + +)) + diff --git a/scheme/ldap-interfaces.scm b/scheme/ldap-interfaces.scm index 16ea56a..f333714 100644 --- a/scheme/ldap-interfaces.scm +++ b/scheme/ldap-interfaces.scm @@ -8,4 +8,17 @@ ldap-bind-sync ldap-unbind-sync ldap-error-string - ldap-result-error)) \ No newline at end of file + ldap-result-error)) + +(define-interface ldap-types-interface + (export + ldap? + ldap-message? + ldap-modification? + + ldap-api-info? + ldap-api-info-info-version + ldap-api-info-api-version + ldap-api-info-protocol-version + ldap-api-info-vendor-name + ldap-api-info-vendor-version)) diff --git a/scheme/ldap-packages.scm b/scheme/ldap-packages.scm index 376ad00..85bc54d 100644 --- a/scheme/ldap-packages.scm +++ b/scheme/ldap-packages.scm @@ -1,6 +1,7 @@ (define-structure ldap-low ldap-low-interface (open scheme - primitives define-record-types - external-calls) - (files ldap)) + primitives + external-calls + ffi-tools-rts) + (files ldap const-gen)) diff --git a/scheme/ldap-records.scm b/scheme/ldap-records.scm new file mode 100644 index 0000000..8b0b6d7 --- /dev/null +++ b/scheme/ldap-records.scm @@ -0,0 +1,47 @@ +(define-record-type ldap :ldap + (make-ldap c-pointer) + ldap? + (c-pointer ldap-c-pointer)) + +(define-exported-binding "ldap" :ldap) + +(define-record-type ldap-message :ldap-message + (make-ldap-message c-pointer) + ldap-message? + (c-pointer ldap-message-c-pointer)) + +(define-exported-binding "ldap-message" :ldap-message) + +(define-record-type ldap-modification :ldap-modification + (make-ldap-modification c-pointer) + ldap-modification? + (c-pointer ldap-modification-c-pointer)) + +(define-exported-binding "ldap-modification" :ldap-modification) + +(define-record-type ldap-api-info :ldap-api-info + (make-ldap-api-info c-pointer) + ldap-api-info? + (c-pointer ldap-api-info-c-pointer)) + +(define-exported-binding "ldap-api-info" :ldap-api-info) + +(import-lambda-definition ldap-api-info-info-version + (ldap-ai) + "scsh_ldapapiinfo_get_info_version") + +(import-lambda-definition ldap-api-info-api-version + (ldap-ai) + "scsh_ldapapiinfo_get_api_version") + +(import-lambda-definition ldap-api-info-protocol-version + (ldap-ai) + "scsh_ldapapiinfo_get_protocol_version") + +(import-lambda-definition ldap-api-info-vendor-name + (ldap-ai) + "scsh_ldapapiinfo_get_vendor_name") + +(import-lambda-definition ldap-api-info-vendor-version + (ldap-ai) + "scsh_ldapapiinfo_get_vendor_version") diff --git a/scheme/ldap.scm b/scheme/ldap.scm index 568c57d..385c9b4 100644 --- a/scheme/ldap.scm +++ b/scheme/ldap.scm @@ -1,26 +1,4 @@ -(define-record-type ldap :ldap - (make-ldap c-pointer) - ldap? - (c-pointer ldap-c-pointer)) - -(define-exported-binding "ldap" :ldap) - -(define-record-type ldap-message :ldap-message - (make-ldap-message c-pointer) - ldap-message? - (c-pointer ldap-message-c-pointer)) - -(define-exported-binding "ldap-message" :ldap-message) - -(define (ldap-open host port) - (let ((ldap (ldap-open-internal host port))) - (if ldap (add-finalizer! ldap ldap-memfree)) - ldap)) - -(define (ldap-init host port) - (let ((ldap (ldap-init-internal host port))) - (if ldap (add-finalizer! ldap ldap-memfree)) - ldap)) +; ,open define-record-types external-calls (import-lambda-definition ldap-open-internal (host port) @@ -95,4 +73,19 @@ (ldap message attribute) "scsh_ldap_get_values") - +(define (ldap-open host port) + (let ((ldap (ldap-open-internal host port))) + (if ldap (add-finalizer! ldap ldap-memfree)) + ldap)) + +(define (ldap-init host port) + (let ((ldap (ldap-init-internal host port))) + (if ldap (add-finalizer! ldap ldap-memfree)) + ldap)) + +;;; import functions from C +(define c-value->ldap-success + (make-finite-type-import-function + 'ldap-success ldap-success-elements ldap-success-id)) + + diff --git a/scheme/load-ldap.scm.in b/scheme/load-ldap.scm.in new file mode 100644 index 0000000..8656758 --- /dev/null +++ b/scheme/load-ldap.scm.in @@ -0,0 +1,17 @@ +(config) +(load "@scshldapschemedir@/configure.scm") +(user) +(load-package 'dynamic-externals) +(open 'dynamic-externals) +(open 'external-calls) +(load-package 'configure) +(open 'configure) +(run '(let ((initializer-name "scx_init_xlib") + (module-file (string-append "@scshldaplibdir@/" @scshldaphost@ "/libscshldap.so"))) + (dynamic-load module-file) + (call-external (get-external initializer-name)))) +(config) +(load "@scshldapschemedir@/ldap-interfaces.scm") +(load "@schhldapschemedir@/ldap-packages.scm") + +