summaryrefslogtreecommitdiffstats
path: root/ldapaddressbook
diff options
context:
space:
mode:
authorSam Varshavchik2013-08-19 16:39:41 -0400
committerSam Varshavchik2013-08-25 14:43:51 -0400
commit9c45d9ad13fdf439d44d7443ae75da15ea0223ed (patch)
tree7a81a04cb51efb078ee350859a64be2ebc6b8813 /ldapaddressbook
parenta9520698b770168d1f33d6301463bb70a19655ec (diff)
downloadcourier-libs-9c45d9ad13fdf439d44d7443ae75da15ea0223ed.tar.bz2
Initial checkin
Imported from subversion report, converted to git. Updated all paths in scripts and makefiles, reflecting the new directory hierarchy.
Diffstat (limited to 'ldapaddressbook')
-rw-r--r--ldapaddressbook/.gitignore1
-rw-r--r--ldapaddressbook/Makefile.am25
-rw-r--r--ldapaddressbook/abookadd.c28
-rw-r--r--ldapaddressbook/abookdel.c53
-rw-r--r--ldapaddressbook/abookfind.c24
-rw-r--r--ldapaddressbook/abookread.c244
-rw-r--r--ldapaddressbook/abooksearch.c142
-rw-r--r--ldapaddressbook/configure.in87
-rw-r--r--ldapaddressbook/ldapaddressbook.dist16
-rw-r--r--ldapaddressbook/ldapaddressbook.h108
-rw-r--r--ldapaddressbook/ldapsearch.c62
-rw-r--r--ldapaddressbook/libldapsearch.c449
-rw-r--r--ldapaddressbook/libldapsearch.h73
-rw-r--r--ldapaddressbook/noldapsearch.c16
14 files changed, 1328 insertions, 0 deletions
diff --git a/ldapaddressbook/.gitignore b/ldapaddressbook/.gitignore
new file mode 100644
index 0000000..66ba562
--- /dev/null
+++ b/ldapaddressbook/.gitignore
@@ -0,0 +1 @@
+/ldapsearch
diff --git a/ldapaddressbook/Makefile.am b/ldapaddressbook/Makefile.am
new file mode 100644
index 0000000..450375a
--- /dev/null
+++ b/ldapaddressbook/Makefile.am
@@ -0,0 +1,25 @@
+#
+# Copyright 2000-2005 Double Precision, Inc. See COPYING for
+# distribution information.
+
+
+EXTRA_DIST=ldapaddressbook.dist
+noinst_LTLIBRARIES=libaddressbook.la
+noinst_PROGRAMS=ldapsearch
+
+libaddressbook_la_SOURCES=abookadd.c abookdel.c abookfind.c abookread.c \
+ abooksearch.c ldapaddressbook.h
+
+if HAVE_OPENLDAP
+ldapsearch_SOURCES=ldapsearch.c
+ldapsearch_LDADD=libldapsearch.la
+noinst_LTLIBRARIES += libldapsearch.la
+
+libldapsearch_la_SOURCES=libldapsearch.h libldapsearch.c
+libldapsearch_la_LIBADD=@OPENLDAP_LIBS@
+
+else
+
+ldapsearch_SOURCES=noldapsearch.c
+
+endif
diff --git a/ldapaddressbook/abookadd.c b/ldapaddressbook/abookadd.c
new file mode 100644
index 0000000..11c6136
--- /dev/null
+++ b/ldapaddressbook/abookadd.c
@@ -0,0 +1,28 @@
+/*
+** Copyright 2006, Double Precision Inc.
+**
+** See COPYING for distribution information.
+*/
+
+#include "config.h"
+#include "ldapaddressbook.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+int ldapabook_add(const char *f, const struct ldapabook *a)
+{
+FILE *fp=fopen(f, "a");
+
+ if (!fp) return (-1);
+
+ ldapabook_writerec(a, fp);
+
+ if (fflush(fp) || fclose(fp))
+ {
+ fclose(fp);
+ return (-1);
+ }
+ return (0);
+}
diff --git a/ldapaddressbook/abookdel.c b/ldapaddressbook/abookdel.c
new file mode 100644
index 0000000..a5da9d0
--- /dev/null
+++ b/ldapaddressbook/abookdel.c
@@ -0,0 +1,53 @@
+/*
+** Copyright 2006, Double Precision Inc.
+**
+** See COPYING for distribution information.
+*/
+
+#include "config.h"
+#include "ldapaddressbook.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int ldapabook_del(const char *filename, const char *tempname,
+ const char *delname)
+{
+/* This is cheating, but we won't really have many abooks, come on... */
+struct ldapabook *a=ldapabook_read(filename), *b;
+
+FILE *fp;
+
+ if (!a) return (0);
+
+ if ((fp=fopen(tempname, "w")) == 0)
+ {
+ ldapabook_free(a);
+ return (-1);
+ }
+
+ for (b=a; b; b=b->next)
+ {
+ if (strcmp(b->name, delname) == 0) continue;
+
+ ldapabook_writerec(b, fp);
+ }
+ ldapabook_free(a);
+
+ if (fflush(fp) || fclose(fp))
+ {
+ fclose(fp);
+ unlink(tempname);
+ return (-1);
+ }
+
+ if (rename(tempname, filename))
+ {
+ unlink(tempname);
+ return (-1);
+ }
+
+ return (0);
+}
diff --git a/ldapaddressbook/abookfind.c b/ldapaddressbook/abookfind.c
new file mode 100644
index 0000000..48c1007
--- /dev/null
+++ b/ldapaddressbook/abookfind.c
@@ -0,0 +1,24 @@
+/*
+** Copyright 2006, Double Precision Inc.
+**
+** See COPYING for distribution information.
+*/
+
+#include "config.h"
+#include "ldapaddressbook.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+const struct ldapabook *ldapabook_find(const struct ldapabook *l,
+ const char *n)
+{
+ while (l)
+ {
+ if (strcmp(l->name, n) == 0) return (l);
+
+ l=l->next;
+ }
+ return (0);
+}
diff --git a/ldapaddressbook/abookread.c b/ldapaddressbook/abookread.c
new file mode 100644
index 0000000..63e75e9
--- /dev/null
+++ b/ldapaddressbook/abookread.c
@@ -0,0 +1,244 @@
+/*
+**
+** Copyright 2003-2006, Double Precision Inc.
+**
+** See COPYING for distribution information.
+*/
+
+#include "config.h"
+#include "ldapaddressbook.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+static void dequote(char *);
+
+struct ldapabook *ldapabook_read(const char *filename)
+{
+char buf[BUFSIZ];
+FILE *fp;
+struct ldapabook *list, *last;
+char *s;
+char *name;
+char *host;
+char *port;
+char *suffix;
+char *binddn;
+char *bindpw;
+
+ if ((fp=fopen(filename, "r")) == 0) return (0);
+
+ list=last=0;
+ while (fgets(buf, sizeof(buf), fp))
+ {
+ struct ldapabook *p;
+
+ struct ldapabook_opts *opts=NULL, *lastopt=NULL;
+ struct ldapabook_opts *nextopt;
+
+ s=strchr(buf, '\n');
+ if (s) *s=0;
+ if ((s=strchr(buf, '#')) != 0) *s=0;
+ name=buf;
+ s=strchr(buf, '\t');
+ if (!s) continue;
+ *s++=0;
+ host=s;
+ s=strchr(s, '\t');
+ if (s) *s++=0;
+ port=s;
+ if (s) s=strchr(s, '\t');
+ if (s) *s++=0;
+ suffix=s;
+ if (s) s=strchr(s, '\t');
+ if (s) *s++=0;
+ binddn=s;
+ if (s) s=strchr(s, '\t');
+ if (s) *s++=0;
+ bindpw=s;
+ if (!port || !*port) port="389";
+ if (!suffix) suffix="";
+ if (!binddn) binddn="";
+ if (!bindpw) bindpw="";
+
+ if (s) s=strchr(s, '\t');
+ if (s) *s++=0;
+
+ while (s && *s)
+ {
+ char *t;
+
+ t=strchr(s, ',');
+ if (t)
+ *t++=0;
+
+ if ((nextopt=(struct ldapabook_opts *)
+ malloc(sizeof(struct ldapabook_opts))) == NULL
+ || (nextopt->options=strdup(s)) == NULL)
+ {
+ if (nextopt)
+ free(nextopt);
+ ldapabook_free(list);
+ fclose(fp);
+ return (NULL);
+ }
+
+ dequote(nextopt->options);
+ if (!lastopt)
+ opts=nextopt;
+ else
+ lastopt->next=nextopt;
+ nextopt->next=NULL;
+ lastopt=nextopt;
+ s=t;
+ }
+
+ if ((p=malloc(sizeof(struct ldapabook))) == 0)
+ {
+ struct ldapabook_opts *nextopt;
+
+ while ((nextopt=opts) != NULL)
+ {
+ opts=nextopt->next;
+ free(nextopt->options);
+ free(nextopt);
+ }
+
+ ldapabook_free(list);
+ fclose(fp);
+ return (0);
+ }
+
+ memset(p, 0, sizeof(*p));
+ p->opts=opts;
+
+ if ( (p->name=strdup(name)) != 0)
+ {
+ if ((p->host=strdup(host)) != 0)
+ {
+ if ((p->port=strdup(port)) != 0)
+ {
+ if ((p->suffix=strdup(suffix)) != 0)
+ {
+ if ((p->binddn=strdup(binddn))
+ != 0)
+ {
+ if ((p->bindpw=strdup
+ (bindpw)) != 0)
+ {
+ if (!list)
+ list=last=p;
+ else
+ last->next=p;
+ last=p;
+ p->next=0;
+ continue;
+ }
+ free(p->binddn);
+ }
+ free(p->suffix);
+ }
+ free(p->port);
+ }
+ free(p->host);
+ }
+ free(p->name);
+ }
+ free(p);
+ while ((nextopt=opts) != NULL)
+ {
+ opts=nextopt->next;
+ free(nextopt->options);
+ free(nextopt);
+ }
+ ldapabook_free(list);
+ fclose(fp);
+ return (0);
+ }
+ fclose(fp);
+ return (list);
+}
+
+void ldapabook_free(struct ldapabook *p)
+{
+ while (p)
+ {
+ struct ldapabook *n=p->next;
+ struct ldapabook_opts *opts;
+
+ while ((opts=p->opts) != NULL)
+ {
+ p->opts=opts->next;
+ free(opts->options);
+ free(opts);
+ }
+
+ free(p->bindpw);
+ free(p->binddn);
+ free(p->suffix);
+ free(p->port);
+ free(p->host);
+ free(p->name);
+ free(p);
+ p=n;
+ }
+}
+
+static const char hex[]="0123456789ABCDEF";
+
+static int nybble(char c)
+{
+ char *p=strchr(hex, c);
+
+ if (p) return (p-hex);
+ return (0);
+}
+
+static void dequote(char *p)
+{
+ char *q;
+
+ for (q=p; *q; q++)
+ {
+ if (*q == '+' && q[1] && q[2])
+ {
+ *p++=nybble(q[1])*16 + nybble(q[2]);
+ q += 2;
+ continue;
+ }
+ *p++=*q;
+ }
+ *p=0;
+}
+
+void ldapabook_writerec(const struct ldapabook *b, FILE *fp)
+{
+ struct ldapabook_opts *opts;
+ char *sep="\t";
+
+ fprintf(fp, "%s\t%s\t%s\t%s\t%s\t%s", b->name, b->host,
+ b->port ? b->port:"", b->suffix,
+ b->binddn ? b->binddn:"",
+ b->bindpw ? b->bindpw:"");
+
+ for (opts=b->opts; opts; opts=opts->next)
+ {
+ char *p;
+
+ fprintf(fp, "%s", sep);
+ sep=",";
+
+ for (p=opts->options; *p; p++)
+ {
+ if (*p <= ' ' || *p >= 127 ||
+ *p == ',' || *p == '+')
+ {
+ fprintf(fp, "+%02X", (int)(unsigned char)*p);
+ continue;
+ }
+ putc(*p, fp);
+ }
+ }
+ fprintf(fp, "\n");
+}
diff --git a/ldapaddressbook/abooksearch.c b/ldapaddressbook/abooksearch.c
new file mode 100644
index 0000000..7751445
--- /dev/null
+++ b/ldapaddressbook/abooksearch.c
@@ -0,0 +1,142 @@
+/*
+**
+** Copyright 2003-2006, Double Precision Inc.
+**
+** See COPYING for distribution information.
+*/
+
+#include "config.h"
+#include "ldapaddressbook.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#if HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+
+#define exit(_a_) _exit(_a_)
+
+int ldapabook_search(const struct ldapabook *b, /* Search this address book */
+ const char *script,
+ const char *search,
+ int (*callback_func)(const char *utf8_name,
+ const char *address,
+ void *callback_arg),
+ void (*callback_err)(const char *errmsg,
+ void *callback_arg),
+ void *callback_arg)
+{
+ int pipefd[2];
+ pid_t p;
+ const char *argv[40];
+ char buf1[BUFSIZ];
+ char buf2[BUFSIZ];
+ FILE *t, *fp;
+ int rc_code=0;
+ pid_t p2;
+ int waitstat;
+
+ signal(SIGCHLD, SIG_DFL);
+
+ if (pipe(pipefd) < 0) return (-1);
+
+ if ((t=tmpfile()) == NULL)
+ {
+ close(pipefd[0]);
+ close(pipefd[1]);
+ return (-1);
+ }
+
+ if ((p=fork()) == -1)
+ {
+ fclose(t);
+ close(pipefd[0]);
+ close(pipefd[1]);
+ return (-1);
+ }
+
+ if (p == 0)
+ {
+ dup2(pipefd[1], 1);
+ close(pipefd[0]);
+ close(pipefd[1]);
+
+ dup2(fileno(t), 2);
+ fclose(t);
+
+ argv[0]=script;
+ argv[1]=b->host;
+ argv[2]=b->port;
+ argv[3]=b->suffix;
+ argv[4]=search;
+ argv[5]=NULL;
+
+ execvp(script, (char **)argv);
+ perror(script);
+ exit(1);
+ }
+
+ fp=fdopen(pipefd[0], "r");
+ close(pipefd[1]);
+
+ if (!fp)
+ {
+ sprintf(buf1, "%1.256s", strerror(errno));
+
+ close(pipefd[0]);
+
+ while ((p2=wait(NULL)) != p)
+ ;
+ fclose(t);
+
+ (*callback_err)(buf1, callback_arg);
+ return -1;
+ }
+
+ while (fgets(buf1, sizeof(buf1), fp) != NULL &&
+ fgets(buf2, sizeof(buf2), fp) != NULL)
+ {
+ char *p=strchr(buf1, '\n');
+
+ if (p) *p=0;
+
+ p=strchr(buf2, '\n');
+ if (p) *p=0;
+
+ if (rc_code == 0)
+ rc_code=(*callback_func)(buf1, buf2, callback_arg);
+ }
+
+ fclose(fp);
+ close(pipefd[0]);
+
+ while ((p2=wait(&waitstat)) != p)
+ ;
+
+ if (waitstat && rc_code == 0)
+ {
+ rc_code= -1;
+ fseek(t, 0L, SEEK_SET);
+
+ if (fgets(buf1, sizeof(buf1), t))
+ {
+ char *p=strchr(buf1, '\n');
+ if (p) *p=0;
+
+ (*callback_err)(buf1, callback_arg);
+ }
+ }
+ fclose(t);
+ return rc_code;
+}
diff --git a/ldapaddressbook/configure.in b/ldapaddressbook/configure.in
new file mode 100644
index 0000000..f5cb1b1
--- /dev/null
+++ b/ldapaddressbook/configure.in
@@ -0,0 +1,87 @@
+dnl Process this file with autoconf to produce a configure script.
+dnl
+dnl Copyright 2000 - 2006 Double Precision, Inc. See COPYING for
+dnl distribution information.
+
+AC_INIT(ldapaddressbook, 0.10, [courier-users@lists.sourceforge.net])
+
+>confdefs.h # Kill PACKAGE_ macros
+
+AC_CONFIG_SRCDIR(Makefile.am)
+AC_CONFIG_AUX_DIR(../..)
+AM_INIT_AUTOMAKE([foreign no-define])
+LPATH="$PATH:/usr/local/bin"
+AM_CONFIG_HEADER(config.h)
+
+dnl Checks for programs.
+AC_USE_SYSTEM_EXTENSIONS
+AC_PROG_CC
+AC_PROG_LIBTOOL
+
+dnl Checks for libraries.
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(stdio.h sys/wait.h sys/time.h)
+AC_HEADER_TIME
+
+AC_ARG_WITH(ldapaddressbook,
+[ --without-ldapaddressbook Disable LDAP address book code ],
+ HAVE_OPENLDAP="$withval",
+ HAVE_OPENLDAP=1)
+
+OPENLDAP_LIBS=""
+
+if test "$HAVE_OPENLDAP" = 1
+then
+ HAVE_OPENLDAP=0
+
+AC_CHECK_HEADERS([lber.h])
+AC_CHECK_HEADERS([ldap.h],
+ [ HAVE_OPENLDAP=1 ],,[
+#if HAVE_LBER_H
+#include <lber.h>
+#endif
+])
+
+if test "$HAVE_OPENLDAP" = 1
+then
+ save_LIBS="$LIBS"
+ LIBS="$LIBS -lldap"
+ AC_TRY_LINK([
+#include <stdio.h>
+#if HAVE_LBER_H
+#include <lber.h>
+#endif
+#include <ldap.h>
+],
+[
+ LDAP *p=NULL;
+
+ ldap_search(p, "", 0, NULL, NULL, 0);
+],
+[
+ :
+],
+[
+ AC_MSG_ERROR([ldap.h header found, but a test compile failed -- check ldapaddressbook/config.log for more details])
+])
+ LIBS="$save_LIBS"
+ OPENLDAP_LIBS="-lldap"
+fi
+fi
+
+AC_DEFINE_UNQUOTED(HAVE_OPENLDAP, $HAVE_OPENLDAP,
+ [ Whether openldap support has been detected ])
+
+AM_CONDITIONAL(HAVE_OPENLDAP, [test $HAVE_OPENLDAP = 1])
+AC_SUBST(OPENLDAP_LIBS)
+
+AC_HEADER_SYS_WAIT
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_SYS_LARGEFILE
+
+dnl Checks for library functions.
+
+AC_OUTPUT(Makefile)
diff --git a/ldapaddressbook/ldapaddressbook.dist b/ldapaddressbook/ldapaddressbook.dist
new file mode 100644
index 0000000..7d176a0
--- /dev/null
+++ b/ldapaddressbook/ldapaddressbook.dist
@@ -0,0 +1,16 @@
+##VERSION: $Id:$
+#
+# ldapaddressbook created from ldapaddressbook.dist by sysconftool
+#
+# Do not alter lines that begin with ##, they are used when upgrading
+# this configuration.
+#
+# This is a list of some public LDAP address books. This is a global
+# list -- all clients will have this list by default.
+#
+##NAME: ldapaddressbook:0
+
+Bigfoot ldap.bigfoot.com 389 c=US
+Infospace ldap.infospace.com 389 c=US
+Netscape Netcenter memberdir.netscape.com 389 ou=member_directory,o=netcenter.com ou=people,o=netcenter.com
+WhoWhere ldap.whowhere.com 389 c=US
diff --git a/ldapaddressbook/ldapaddressbook.h b/ldapaddressbook/ldapaddressbook.h
new file mode 100644
index 0000000..bbef9c0
--- /dev/null
+++ b/ldapaddressbook/ldapaddressbook.h
@@ -0,0 +1,108 @@
+#ifndef ldapaddressbook_h
+#define ldapaddressbook_h
+
+
+#include <stdio.h>
+
+/*
+** Copyright 2000-2002 Double Precision, Inc. See COPYING for
+** distribution information.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** This module implements an abstraction of an interface to an LDAP address
+** book. There's no reason to reinvent the wheel, so we simply run ldapsearch
+** as a child process, and read its output. ldapsearch is run indirectly, via
+** a stub shell script that can be customized on a given system. The template
+** for the stub shell script is provided.
+**
+** There's a small library here that can be used to maintain a configuration
+** file listing available address books that can be contacted. The format
+** of each line in this library is simply:
+**
+** name<tab>host<tab>port<tab>suffix<tab>binddn<tab>bindpw
+**
+** Functions are provided to add and remove names from this configuration
+** file easily. The above is parsed into the following structure:
+*/
+
+struct ldapabook {
+ struct ldapabook *next;
+
+ char *name;
+ char *host;
+ char *port;
+ char *suffix;
+ char *binddn;
+ char *bindpw;
+
+ struct ldapabook_opts *opts;
+
+ } ;
+
+struct ldapabook_opts {
+ struct ldapabook_opts *next;
+ char *options; /* First char - name, rest - value */
+} ;
+
+ /* Potential first chars: */
+
+#define SASL_SECURITY_PROPERTIES 'O'
+#define SASL_AUTHENTICATION_ID 'U'
+#define SASL_AUTHENTICATION_RID 'X' /* u:username, or dn:dn */
+#define SASL_AUTHENTICATION_MECHANISM 'Y'
+#define SASL_STARTTLS 'Z'
+
+/* Read a configuration file, and create a link list of ldapabook structs */
+
+struct ldapabook *ldapabook_read(const char *); /* filename */
+
+/* Free memory allocated by ldapabook_init */
+
+void ldapabook_free(struct ldapabook *);
+
+/* Find a certain address book */
+
+const struct ldapabook *ldapabook_find(const struct ldapabook *,
+ const char *);
+
+/* Add a new entry to the address book */
+
+int ldapabook_add(const char *, /* filename */
+ const struct ldapabook *); /* new entry */
+
+/* Delete an entry from the address book */
+
+int ldapabook_del(const char *, /* filename */
+ const char *, /* temporary filename on same filesys */
+ const char *); /* name to delete */
+
+/* Run ldapsearch in the background, return a file descriptor containing
+** ldapsearch's output.
+*/
+
+int ldapabook_search(const struct ldapabook *b, /* Search this address book */
+ const char *script,
+ const char *search,
+ int (*callback_func)(const char *utf8_name,
+ const char *address,
+ void *callback_arg),
+ void (*callback_err)(const char *errmsg,
+ void *callback_arg),
+ void *callback_arg);
+
+/*
+** Internal function:
+*/
+
+void ldapabook_writerec(const struct ldapabook *, FILE *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/ldapaddressbook/ldapsearch.c b/ldapaddressbook/ldapsearch.c
new file mode 100644
index 0000000..d0deec6
--- /dev/null
+++ b/ldapaddressbook/ldapsearch.c
@@ -0,0 +1,62 @@
+/*
+** Copyright 2006, Double Precision Inc.
+**
+** See COPYING for distribution information.
+*/
+
+#include "libldapsearch.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+static int cb(const char *utf8_name,
+ const char *address,
+ void *callback_arg)
+{
+ if (strchr(utf8_name, '\n') == NULL &&
+ strchr(address, '\n') == NULL)
+ /* filter out if it looks funny */
+
+ printf("%s\n%s\n", utf8_name, address);
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ const char *host, *port, *suffix, *search;
+ int port_n;
+ struct ldapsearch *s;
+
+ if (argc < 5)
+ {
+ fprintf(stderr, "INTERNAL ERROR: Invalid # of parameters to ldapsearch\n");
+ exit(1);
+ }
+
+ host=argv[1];
+ port=argv[2];
+ suffix=argv[3];
+ search=argv[4];
+
+ port_n=atoi(port);
+
+ if (port_n <= 0)
+ port_n=LDAP_PORT;
+
+ s=l_search_alloc(host, port_n, argc > 5 ? argv[5]:NULL,
+ argc > 6 ?argv[6]:NULL, suffix);
+
+ if (!s)
+ {
+ perror("l_search_alloc");
+ exit(1);
+ }
+
+ if (l_search_do(s, search, cb, NULL))
+ {
+ perror("l_search_do");
+ exit(1);
+ }
+ l_search_free(s);
+ exit(0);
+}
diff --git a/ldapaddressbook/libldapsearch.c b/ldapaddressbook/libldapsearch.c
new file mode 100644
index 0000000..71ef2ed
--- /dev/null
+++ b/ldapaddressbook/libldapsearch.c
@@ -0,0 +1,449 @@
+/*
+** Copyright 2006, Double Precision Inc.
+**
+** See COPYING for distribution information.
+*/
+
+#include "libldapsearch.h"
+#include <stdlib.h>
+#include <errno.h>
+#include <time.h>
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+/*
+** Allocate and deallocate the ldapsearch struct.
+*/
+
+struct ldapsearch *l_search_alloc(const char *host,
+ int port,
+ const char *userid,
+ const char *password,
+ const char *base)
+{
+ char *buf;
+
+ struct ldapsearch *p=(struct ldapsearch *)
+ malloc(sizeof(struct ldapsearch));
+
+ if (!p)
+ return NULL;
+
+ if ((p->base=strdup(base)) == NULL)
+ {
+ free(p);
+ return NULL;
+ }
+
+ if ((buf=malloc(strlen(host)+100)) == NULL)
+ {
+ free(p->base);
+ free(p);
+ return NULL;
+ }
+
+ sprintf(buf, "ldap://%s:%d", host, port);
+
+ if (ldap_initialize(&p->handle, buf) != LDAP_SUCCESS)
+ {
+ free(buf);
+ free(p->base);
+ free(p);
+ return NULL;
+ }
+ free(buf);
+
+ if (userid && *userid)
+ {
+ struct berval cred;
+
+ cred.bv_len=password && *password ? strlen(password):0;
+ cred.bv_val=password && *password ? (char *)password:NULL;
+
+ if (ldap_sasl_bind_s(p->handle, userid, NULL, &cred, NULL,
+ NULL, NULL))
+ {
+ l_search_free(p);
+ errno=EPERM;
+ return NULL;
+ }
+ }
+
+ return p;
+}
+
+void l_search_free(struct ldapsearch *s)
+{
+ if (s->handle)
+ ldap_unbind_ext(s->handle, NULL, NULL);
+ free(s->base);
+ free(s);
+}
+
+/*
+** See RFC 2254 section 4.
+*/
+
+static char *encode_key(const char *lookupkey)
+{
+ const char *cp;
+
+ char *p=NULL, *q;
+ int pass;
+ size_t l=0;
+
+ for (pass=0; pass<2; pass++)
+ {
+ if (pass)
+ {
+ p=malloc(l);
+ if (!p)
+ return NULL;
+ }
+ l=1;
+ q=p;
+ for (cp=lookupkey; *cp; cp++)
+ {
+ const char *h;
+
+ switch (*cp) {
+ case '*':
+ h="\\2a";
+ break;
+ case '(':
+ h="\\28";
+ break;
+ case ')':
+ h="\\29";
+ break;
+ case '\\':
+ h="\\5c";
+ break;
+ default:
+ if (pass)
+ *q++= *cp;
+ ++l;
+ continue;
+ }
+
+ if (pass)
+ while ((*q++ = *h++) != 0)
+ ;
+ l += 3;
+ }
+ if (pass)
+ *q=0;
+ }
+ return p;
+}
+
+/*
+** Insert lookup key into the search filter.
+*/
+
+static char *make_search_key(const char *filter, const char *lookupkey)
+{
+ size_t l=strlen(filter)+1;
+ char *p, *q;
+ const char *cp;
+
+ for (cp=filter; *cp; cp++)
+ if (*cp == '@')
+ l += strlen(lookupkey);
+
+ p=malloc(l);
+ if (!p)
+ return NULL;
+
+ for (q=p, cp=filter; *cp; cp++)
+ {
+ if (*cp == '@')
+ {
+ const char *k=lookupkey;
+
+ while ( (*q++ = *k++ ) != 0)
+ ;
+ --q;
+ continue;
+ }
+ *q++ = *cp;
+ }
+ *q=0;
+ return p;
+}
+
+static int l_search_do_filter(struct ldapsearch *s,
+
+ int (*callback_func)(const char *utf8_name,
+ const char *address,
+ void *callback_arg),
+ void *callback_arg,
+
+ const char *filter,
+ const char *lookup_key,
+ int *found);
+
+
+int l_search_do(struct ldapsearch *s,
+ const char *lookupkey,
+
+ int (*callback_func)(const char *utf8_name,
+ const char *address,
+ void *callback_arg),
+ void *callback_arg)
+{
+ char *k;
+ const char *filter;
+ int rc_code;
+ int found;
+
+ k=encode_key(lookupkey);
+ if (!k)
+ return -1;
+
+ filter=getenv("LDAP_SEARCH_FILTER_EXACT");
+ if (!filter)
+ filter="(|(uid=@)(sn=@)(cn=@))";
+
+ rc_code=l_search_do_filter(s, callback_func, callback_arg,
+ filter, k, &found);
+
+ if (rc_code == 0 && !found)
+ {
+ filter=getenv("LDAP_SEARCH_FILTER_APPROX");
+ if (!filter)
+ filter="(|(uid=@*)(sn=@*)(mail=@*)(cn=@*))";
+
+ rc_code=l_search_do_filter(s, callback_func, callback_arg,
+ filter, k, &found);
+ }
+ free(k);
+ return rc_code;
+}
+
+static int l_search_do_filter(struct ldapsearch *s,
+ int (*callback_func)(const char *utf8_name,
+ const char *address,
+ void *callback_arg),
+ void *callback_arg,
+ const char *filter,
+ const char *lookup_key,
+ int *found)
+{
+ char *kk;
+ struct timeval tv;
+ LDAPMessage *result;
+ char *attrs[3];
+ int rc_code=0;
+ int msgidp;
+
+ *found=0;
+
+ kk=make_search_key(filter, lookup_key);
+
+ if (!kk)
+ return -1;
+
+ if (s->handle == NULL)
+ {
+ errno=ETIMEDOUT; /* Timeout previously */
+ return -1;
+ }
+
+
+ attrs[0]="cn";
+ attrs[1]="mail";
+ attrs[2]=NULL;
+
+ tv.tv_sec=60*60;
+ tv.tv_usec=0;
+
+ if (ldap_search_ext(s->handle, s->base, LDAP_SCOPE_SUBTREE,
+ kk, attrs, 0, NULL, NULL, &tv, 1000000, &msgidp)
+ != LDAP_SUCCESS)
+ return -1;
+
+ do
+ {
+ int rc;
+ LDAPMessage *msg;
+
+ const char *timeout=getenv("LDAP_SEARCH_TIMEOUT");
+
+ tv.tv_sec=atoi(timeout ? timeout:"30");
+ tv.tv_usec=0;
+
+ rc=ldap_result(s->handle, msgidp, 0, &tv, &result);
+
+ if (rc <= 0)
+ {
+ if (rc == 0)
+ errno=ETIMEDOUT;
+
+ ldap_unbind_ext(s->handle, NULL, NULL);
+ s->handle=NULL;
+ rc_code= -1;
+ break;
+ }
+
+ if (rc == LDAP_RES_SEARCH_RESULT)
+ {
+ ldap_msgfree(result);
+ break; /* End of search */
+ }
+
+ if (rc != LDAP_RES_SEARCH_ENTRY)
+ {
+ ldap_msgfree(result);
+ continue;
+ }
+
+ for (msg=ldap_first_message(s->handle, result); msg;
+ msg=ldap_next_message(s->handle, msg))
+ {
+ struct berval **n_val=
+ ldap_get_values_len(s->handle, msg, "cn");
+ struct berval **a_val=
+ ldap_get_values_len(s->handle, msg, "mail");
+
+ if (n_val && a_val)
+ {
+ size_t i, j;
+
+ for (i=0; n_val[i]; i++)
+ for (j=0; a_val[j]; j++)
+ {
+ char *p=malloc(n_val[i]->bv_len
+ +1);
+ char *q=malloc(a_val[j]->bv_len
+ +1);
+
+ if (!p || !q)
+ {
+ if (p) free(p);
+ if (q) free(q);
+ rc_code= -1;
+ break;
+ }
+
+ memcpy(p, n_val[i]->bv_val,
+ n_val[i]->bv_len);
+ p[n_val[i]->bv_len]=0;
+
+ memcpy(q, a_val[j]->bv_val,
+ a_val[j]->bv_len);
+ q[a_val[j]->bv_len]=0;
+
+ rc_code=(*callback_func)
+ (p, q, callback_arg);
+ free(p);
+ free(q);
+ if (rc_code)
+ break;
+ *found=1;
+ }
+ }
+ if (n_val)
+ ldap_value_free_len(n_val);
+ if (a_val)
+ ldap_value_free_len(a_val);
+ }
+
+ ldap_msgfree(result);
+ } while (rc_code == 0);
+ return rc_code;
+}
+
+int l_search_ping(struct ldapsearch *s)
+{
+ char *attrs[2];
+ struct timeval tv;
+ LDAPMessage *result;
+ int rc;
+ int msgid;
+
+ if (s->handle == NULL)
+ {
+ errno=ETIMEDOUT; /* Timeout previously */
+ return -1;
+ }
+
+ attrs[0]="objectClass";
+ attrs[1]=NULL;
+
+ tv.tv_sec=60*60;
+ tv.tv_usec=0;
+
+ if (ldap_search_ext(s->handle, s->base, LDAP_SCOPE_BASE,
+ "objectClass=*", attrs, 0, NULL, NULL, &tv,
+ 1000000, &msgid) < 0)
+ return -1;
+
+ do
+ {
+ const char *timeout=getenv("LDAP_SEARCH_TIMEOUT");
+
+ tv.tv_sec=atoi(timeout ? timeout:"30");
+ tv.tv_usec=0;
+
+ rc=ldap_result(s->handle, msgid, 0, &tv, &result);
+
+ if (rc <= 0)
+ {
+ if (rc == 0)
+ errno=ETIMEDOUT;
+
+ ldap_unbind_ext(s->handle, NULL, NULL);
+ s->handle=NULL;
+
+ return -1;
+ }
+
+ ldap_msgfree(result);
+ } while (rc != LDAP_RES_SEARCH_RESULT);
+ return 0;
+}
+
+#if 0
+
+#include <stdio.h>
+
+static int cb(const char *utf8_name,
+ const char *address,
+ void *callback_arg)
+{
+ printf("\"%s\" <%s>\n", utf8_name, address);
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ struct ldapsearch *s=l_search_alloc("localhost", 389,
+ "dc=courier-mta,dc=com");
+ int n;
+
+ if (!s)
+ {
+ perror("l_search_alloc");
+ exit(1);
+ }
+
+ for (n=1; n<argc; n++)
+ {
+ if (l_search_do(s, argv[n], cb, NULL) != 0)
+ {
+ printf("l_search_do: error\n");
+ }
+ }
+ l_search_free(s);
+ return 0;
+}
+#endif
diff --git a/ldapaddressbook/libldapsearch.h b/ldapaddressbook/libldapsearch.h
new file mode 100644
index 0000000..58241a7
--- /dev/null
+++ b/ldapaddressbook/libldapsearch.h
@@ -0,0 +1,73 @@
+/*
+** Copyright 2006, Double Precision Inc.
+**
+*/
+
+#ifndef ldapsearch_h
+#define ldapsearch_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** Encapsulate interface for search address book in LDAP
+*/
+
+#include "config.h"
+#if HAVE_LBER_H
+#include <lber.h>
+#endif
+#include <ldap.h>
+#include <stdio.h>
+
+struct ldapsearch {
+
+ LDAP *handle;
+
+ char *base; /* Saved base of the search */
+};
+
+/*
+** Allocate and deallocate the ldapsearch struct.
+*/
+
+struct ldapsearch *l_search_alloc(const char *host,
+ int port,
+ const char *userid,
+ const char *password,
+ const char *base);
+/* base - the starting point of the search in the LDAP tree */
+
+void l_search_free(struct ldapsearch *s);
+
+/*
+** Search the address book, and invoke the callback function for each
+** match found. The callback function receives the name & address of the
+** found entry. 'exact_match' is nonzero if the lookupkey matched on of the
+** LDAP attributes.
+**
+** The callback function must return zero. A non-zero return stops the
+** search.
+*/
+
+int l_search_do(struct ldapsearch *s,
+ const char *lookupkey,
+
+ int (*callback_func)(const char *utf8_name,
+ const char *address,
+ void *callback_arg),
+ void *callback_arg);
+
+/*
+** Ping the LDAP server (makes sure that host/port were valid, because
+** any connection attempt is deferred).
+*/
+
+int l_search_ping(struct ldapsearch *s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/ldapaddressbook/noldapsearch.c b/ldapaddressbook/noldapsearch.c
new file mode 100644
index 0000000..fa93b7e
--- /dev/null
+++ b/ldapaddressbook/noldapsearch.c
@@ -0,0 +1,16 @@
+/*
+** Copyright 2006, Double Precision Inc.
+**
+** See COPYING for distribution information.
+*/
+
+#include <stdio.h>
+
+/*
+** Stub ldapsearch binary when openldap is not available.
+*/
+
+int main()
+{
+ return (0);
+}