aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile4
-rw-r--r--lib/eldap/AUTHORS7
-rw-r--r--lib/eldap/Makefile39
-rw-r--r--lib/eldap/info2
-rw-r--r--lib/eldap/src/Makefile114
-rw-r--r--lib/eldap/src/eldap.appup.src6
-rw-r--r--lib/eldap/src/eldap.erl9
-rw-r--r--lib/eldap/test/Makefile83
-rw-r--r--lib/eldap/test/eldap.spec1
-rw-r--r--lib/eldap/test/eldap_basic_SUITE.erl224
-rw-r--r--lib/eldap/test/ldap_server/slapd.conf14
-rw-r--r--lib/eldap/vsn.mk1
12 files changed, 500 insertions, 4 deletions
diff --git a/lib/Makefile b/lib/Makefile
index aa4e074830..3753bd165b 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2011. All Rights Reserved.
+# Copyright Ericsson AB 1996-2012. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -31,7 +31,7 @@ ifdef BUILD_ALL
cosTransactions cosEvent cosTime cosNotification \
cosProperty cosFileTransfer cosEventDomain et megaco webtool \
xmerl edoc eunit ssh inviso typer erl_docgen \
- percept dialyzer hipe
+ percept eldap dialyzer hipe
EXTRA_FILE := $(wildcard EXTRA-APPLICATIONS)
EXTRA_APPLICATIONS := $(if $(EXTRA_FILE),$(shell cat $(EXTRA_FILE)))
endif
diff --git a/lib/eldap/AUTHORS b/lib/eldap/AUTHORS
new file mode 100644
index 0000000000..8f1e399306
--- /dev/null
+++ b/lib/eldap/AUTHORS
@@ -0,0 +1,7 @@
+Original author:
+ Torbjorn Tornkvist
+
+With patches from:
+ Simon MacMullen
+ Manuel DurĂ¡n Aguete
+ voluntas \ No newline at end of file
diff --git a/lib/eldap/Makefile b/lib/eldap/Makefile
new file mode 100644
index 0000000000..3635ec759d
--- /dev/null
+++ b/lib/eldap/Makefile
@@ -0,0 +1,39 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2012. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+
+#
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Macros
+# ----------------------------------------------------
+
+SUB_DIRECTORIES = src doc/src
+
+include vsn.mk
+VSN = $(ELDAP_VSN)
+
+SPECIAL_TARGETS =
+
+# ----------------------------------------------------
+# Default Subdir Targets
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_subdir.mk
+
diff --git a/lib/eldap/info b/lib/eldap/info
new file mode 100644
index 0000000000..463f9af6ea
--- /dev/null
+++ b/lib/eldap/info
@@ -0,0 +1,2 @@
+group: comm
+short: eldap - Erlang LDAP library
diff --git a/lib/eldap/src/Makefile b/lib/eldap/src/Makefile
new file mode 100644
index 0000000000..a3a818f09e
--- /dev/null
+++ b/lib/eldap/src/Makefile
@@ -0,0 +1,114 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2012. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+#
+include $(ERL_TOP)/make/target.mk
+
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../vsn.mk
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/eldap-$(ELDAP_VSN)
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+
+MODULES= \
+ eldap_app \
+ eldap \
+ eldap_fsm \
+ eldap_sup
+
+ASN1_FILES = ELDAPv3.asn1
+ASN1_HRL = $(EBIN)/$(ASN1_FILES:%.asn1=%.hrl)
+
+ERL_FILES= $(MODULES:%=%.erl)
+
+TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR)) $(ASN1_FILES:%.asn1=$(EBIN)/%.$(EMULATOR))
+
+EXTERNAL_HRL_FILES = ../include/eldap.hrl
+
+HRL_FILES = $(EXTERNAL_HRL_FILES) $(ASN1_HRL)
+
+APPUP_FILE = eldap.appup
+APPUP_SRC = $(APPUP_FILE).src
+APPUP_TARGET = $(EBIN)/$(APPUP_FILE)
+
+APP_FILE = eldap.app
+APP_SRC = $(APP_FILE).src
+APP_TARGET = $(EBIN)/$(APP_FILE)
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+ERL_COMPILE_FLAGS += -I../include -I../ebin
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET)
+
+debug:
+ @${MAKE} TYPE=debug opt
+
+clean:
+ rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET)
+ rm -f $(ASN1_FILES:%.asn1=$(EBIN)/%.*)
+ rm -f errs core *~
+
+$(APP_TARGET): $(APP_SRC) ../vsn.mk
+ sed -e 's;%VSN%;$(ELDAP_VSN);' $< > $@
+
+$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
+ sed -e 's;%VSN%;$(ELDAP_VSN);' $< > $@
+
+docs:
+
+$(TARGET_FILES): $(HRL_FILES)
+
+# ----------------------------------------------------
+# Special Build Targets
+# ----------------------------------------------------
+$(ASN1_HRL): ../asn1/$(ASN1_FILES)
+ $(ERLC) -o $(EBIN) $(ERL_COMPILE_FLAGS) ../asn1/ELDAPv3.asn1
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) $(RELSYSDIR)/src
+ $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR)/src
+ $(INSTALL_DIR) $(RELSYSDIR)/asn1
+ $(INSTALL_DATA) ../asn1/$(ASN1_FILES) $(RELSYSDIR)/asn1
+ $(INSTALL_DIR) $(RELSYSDIR)/include
+ $(INSTALL_DATA) $(EXTERNAL_HRL_FILES) $(RELSYSDIR)/include
+
+release_docs_spec:
+
+
diff --git a/lib/eldap/src/eldap.appup.src b/lib/eldap/src/eldap.appup.src
new file mode 100644
index 0000000000..8d33482f11
--- /dev/null
+++ b/lib/eldap/src/eldap.appup.src
@@ -0,0 +1,6 @@
+%% -*- erlang -*-
+{"%VSN%",
+ [
+ ],
+ [
+ ]}.
diff --git a/lib/eldap/src/eldap.erl b/lib/eldap/src/eldap.erl
index 7c9c02d681..d144aac872 100644
--- a/lib/eldap/src/eldap.erl
+++ b/lib/eldap/src/eldap.erl
@@ -352,9 +352,14 @@ parse_args([], _, Data) ->
try_connect([Host|Hosts], Data) ->
TcpOpts = [{packet, asn1}, {active,false}],
- case do_connect(Host, Data, TcpOpts) of
+ try do_connect(Host, Data, TcpOpts) of
{ok,Fd} -> {ok,Data#eldap{host = Host, fd = Fd}};
- _ -> try_connect(Hosts, Data)
+ Err ->
+ log2(Data, "Connect: ~p failed ~p~n",[Host, Err]),
+ try_connect(Hosts, Data)
+ catch _:Err ->
+ log2(Data, "Connect: ~p failed ~p~n",[Host, Err]),
+ try_connect(Hosts, Data)
end;
try_connect([],_) ->
{error,"connect failed"}.
diff --git a/lib/eldap/test/Makefile b/lib/eldap/test/Makefile
new file mode 100644
index 0000000000..a17d4f56b2
--- /dev/null
+++ b/lib/eldap/test/Makefile
@@ -0,0 +1,83 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2012. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+
+INCLUDES= -I. -I ../include
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+
+MODULES= \
+ eldap_basic_SUITE
+
+ERL_FILES= $(MODULES:%=%.erl)
+
+HRL_FILES=
+
+TARGET_FILES= \
+ $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+
+SPEC_FILES = eldap.spec
+
+# COVER_FILE = eldap.cover
+
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/eldap_test
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+ERL_COMPILE_FLAGS += $(INCLUDES)
+
+EBIN = .
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+
+tests debug opt: $(TARGET_FILES)
+
+
+clean:
+ rm -f $(TARGET_FILES)
+ rm -f core
+
+docs:
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_spec: opt
+
+release_tests_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)
+ $(INSTALL_DATA) $(SPEC_FILES) $(ERL_FILES) $(COVER_FILE) $(HRL_FILES) $(RELSYSDIR)
+ $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)
+# @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
+release_docs_spec:
diff --git a/lib/eldap/test/eldap.spec b/lib/eldap/test/eldap.spec
new file mode 100644
index 0000000000..b14e9a655a
--- /dev/null
+++ b/lib/eldap/test/eldap.spec
@@ -0,0 +1 @@
+{suites,"../eldap_test",all}.
diff --git a/lib/eldap/test/eldap_basic_SUITE.erl b/lib/eldap/test/eldap_basic_SUITE.erl
new file mode 100644
index 0000000000..deb0776f74
--- /dev/null
+++ b/lib/eldap/test/eldap_basic_SUITE.erl
@@ -0,0 +1,224 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(eldap_basic_SUITE).
+
+-compile(export_all).
+
+%%-include_lib("common_test/include/ct.hrl").
+-include_lib("test_server/include/test_server.hrl").
+-include_lib("eldap/include/eldap.hrl").
+
+-define(TIMEOUT, 120000). % 2 min
+
+init_per_suite(Config0) ->
+ {{EldapHost,Port}, Config1} =
+ case catch ct:get_config(eldap_server, undefined) of
+ undefined -> %% Dev test only
+ Server = {"localhost", 9876},
+ {Server, [{eldap_server, {"localhost", 9876}}|Config0]};
+ {'EXIT', _} -> %% Dev test only
+ Server = {"localhost", 9876},
+ {Server, [{eldap_server, {"localhost", 9876}}|Config0]};
+ Server ->
+ {Server, [{eldap_server, Server}|Config0]}
+ end,
+ %% Add path for this test run
+ try
+ {ok, Handle} = eldap:open([EldapHost], [{port, Port}]),
+ ok = eldap:simple_bind(Handle, "cn=Manager,dc=ericsson,dc=se", "hejsan"),
+ {ok, MyHost} = inet:gethostname(),
+ Path = "dc="++MyHost++",dc=ericsson,dc=se",
+ Config = [{eldap_path,Path}|Config1],
+ eldap:add(Handle,"dc=ericsson,dc=se",
+ [{"objectclass", ["dcObject", "organization"]},
+ {"dc", ["ericsson"]}, {"o", ["Testing"]}]),
+ eldap:add(Handle,Path,
+ [{"objectclass", ["dcObject", "organization"]},
+ {"dc", [MyHost]}, {"o", ["Test machine"]}]),
+ Config
+ catch error:{badmatch,Error} ->
+ io:format("Eldap init error ~p~n ~p~n",[Error, erlang:get_stacktrace()]),
+ {skip, lists:flatten(io_lib:format("Ldap init failed with host ~p", [EldapHost]))}
+ end.
+end_per_suite(Config) ->
+ %% Cleanup everything
+ {EHost, Port} = proplists:get_value(eldap_server, Config),
+ Path = proplists:get_value(eldap_path, Config),
+ {ok, H} = eldap:open([EHost], [{port, Port}]),
+ ok = eldap:simple_bind(H, "cn=Manager,dc=ericsson,dc=se", "hejsan"),
+ case eldap:search(H, [{base, Path},
+ {filter, eldap:present("objectclass")},
+ {scope, eldap:wholeSubtree()}])
+ of
+ {ok, {eldap_search_result, Entries, _}} ->
+ [ok = eldap:delete(H, Entry) || {eldap_entry, Entry, _} <- Entries];
+ _ -> ignore
+ end,
+ ok.
+
+init_per_testcase(_TestCase, Config) -> Config.
+end_per_testcase(_TestCase, _Config) -> ok.
+
+%% suite() ->
+
+all() ->
+ [app,
+ api].
+
+app(doc) -> "Test that the eldap app file is ok";
+app(suite) -> [];
+app(Config) when is_list(Config) ->
+ ok = test_server:app_test(public_key).
+
+api(doc) -> "Basic test that all api functions works as expected";
+api(suite) -> [];
+api(Config) ->
+ {Host,Port} = proplists:get_value(eldap_server, Config),
+ {ok, H} = eldap:open([Host], [{port,Port}]),
+ %% {ok, H} = eldap:open([Host], [{port,Port+1}, {ssl, true}]),
+ BasePath = proplists:get_value(eldap_path, Config),
+ All = fun(Where) ->
+ eldap:search(H, #eldap_search{base=Where,
+ filter=eldap:present("objectclass"),
+ scope= eldap:wholeSubtree()})
+ end,
+ Search = fun(Filter) ->
+ eldap:search(H, #eldap_search{base=BasePath,
+ filter=Filter,
+ scope=eldap:singleLevel()})
+ end,
+ {ok, #eldap_search_result{entries=[_]}} = All(BasePath),
+ {error, {searchResDone, _}} = All("cn=Bar,"++BasePath),
+
+ {error, strongerAuthRequired}
+ = eldap:add(H, "cn=Jonas Jonsson," ++ BasePath,
+ [{"objectclass", ["person"]},
+ {"cn", ["Jonas Jonsson"]}, {"sn", ["Jonsson"]}]),
+ eldap:simple_bind(H, "cn=Manager,dc=ericsson,dc=se", "hejsan"),
+
+ %% Add
+ ok = eldap:add(H, "cn=Jonas Jonsson," ++ BasePath,
+ [{"objectclass", ["person"]},
+ {"cn", ["Jonas Jonsson"]}, {"sn", ["Jonsson"]}]),
+ ok = eldap:add(H, "cn=Foo Bar," ++ BasePath,
+ [{"objectclass", ["person"]},
+ {"cn", ["Foo Bar"]}, {"sn", ["Bar"]}, {"telephoneNumber", ["555-1232", "555-5432"]}]),
+ ok = eldap:add(H, "ou=Team," ++ BasePath,
+ [{"objectclass", ["organizationalUnit"]},
+ {"ou", ["Team"]}]),
+
+ %% Search
+ JJSR = {ok, #eldap_search_result{entries=[#eldap_entry{}]}} = Search(eldap:equalityMatch("sn", "Jonsson")),
+ JJSR = Search(eldap:substrings("sn", [{any, "ss"}])),
+ FBSR = {ok, #eldap_search_result{entries=[#eldap_entry{object_name=FB}]}} =
+ Search(eldap:substrings("sn", [{any, "a"}])),
+ FBSR = Search(eldap:substrings("sn", [{initial, "B"}])),
+ FBSR = Search(eldap:substrings("sn", [{final, "r"}])),
+
+ F_AND = eldap:'and'([eldap:present("objectclass"), eldap:present("ou")]),
+ {ok, #eldap_search_result{entries=[#eldap_entry{}]}} = Search(F_AND),
+ F_NOT = eldap:'and'([eldap:present("objectclass"), eldap:'not'(eldap:present("ou"))]),
+ {ok, #eldap_search_result{entries=[#eldap_entry{}, #eldap_entry{}]}} = Search(F_NOT),
+
+
+ %% MODIFY
+ Mod = [eldap:mod_replace("telephoneNumber", ["555-12345"]),
+ eldap:mod_add("description", ["Nice guy"])],
+ %% io:format("MOD ~p ~p ~n",[FB, Mod]),
+ ok = eldap:modify(H, FB, Mod),
+ %% DELETE ATTR
+ ok = eldap:modify(H, FB, [eldap:mod_delete("telephoneNumber", [])]),
+
+ %% DELETE
+ {error, entryAlreadyExists} = eldap:add(H, "cn=Jonas Jonsson," ++ BasePath,
+ [{"objectclass", ["person"]},
+ {"cn", ["Jonas Jonsson"]}, {"sn", ["Jonsson"]}]),
+ ok = eldap:delete(H, "cn=Jonas Jonsson," ++ BasePath),
+ {error, noSuchObject} = eldap:delete(H, "cn=Jonas Jonsson," ++ BasePath),
+
+ %% MODIFY_DN
+ ok = eldap:modify_dn(H, FB, "cn=Niclas Andre", true, ""),
+ %%io:format("Res ~p~n ~p~n",[R, All(BasePath)]),
+
+ eldap:close(H),
+ ok.
+
+add(H, Attr, Value, Path0, Attrs, Class) ->
+ Path = case Path0 of
+ [] -> Attr ++ "=" ++ Value;
+ _ -> Attr ++ "=" ++ Value ++ "," ++ Path0
+ end,
+ case eldap:add(H, Path, [{"objectclass", Class}, {Attr, [Value]}] ++ Attrs)
+ of
+ ok -> {ok, Path};
+ {error, E = entryAlreadyExists} -> {E, Path};
+ R = {error, Reason} ->
+ io:format("~p:~p: ~s,~s =>~n ~p~n",
+ [?MODULE,?LINE, Attr, Value, R]),
+ exit({ldap, add, Reason})
+ end.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Develop
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+test() ->
+ run().
+
+run() ->
+ Cases = all(),
+ run(Cases).
+
+run(Case) when is_atom(Case) ->
+ run([Case]);
+run(Cases) when is_list(Cases) ->
+ Run = fun(Test, Config0) ->
+ Config = init_per_testcase(Test, Config0),
+ try
+ io:format("~nTest ~p ... ",[Test]),
+ ?MODULE:Test(Config),
+ end_per_testcase(Test, Config),
+ io:format("ok~n",[])
+ catch _:Reason ->
+ io:format("~n FAIL (~p): ~p~n ~p~n",
+ [Test, Reason, erlang:get_stacktrace()])
+ end
+ end,
+ process_flag(trap_exit, true),
+ Pid = spawn_link(fun() ->
+ case init_per_suite([]) of
+ {skip, Reason} -> io:format("Skip ~s~n",[Reason]);
+ Config ->
+ try
+ [Run(Test, Config) || Test <- Cases]
+ catch _:Err ->
+ io:format("Error ~p in ~p~n",[Err, erlang:get_stacktrace()])
+ end,
+ end_per_suite(Config)
+ end
+ end),
+ receive
+ {'EXIT', Pid, normal} -> ok;
+ Msg -> io:format("Received ~p (~p)~n",[Msg, Pid])
+ after 100 -> ok end,
+ process_flag(trap_exit, false),
+ ok.
diff --git a/lib/eldap/test/ldap_server/slapd.conf b/lib/eldap/test/ldap_server/slapd.conf
new file mode 100644
index 0000000000..87be676d9f
--- /dev/null
+++ b/lib/eldap/test/ldap_server/slapd.conf
@@ -0,0 +1,14 @@
+include /etc/ldap/schema/core.schema
+pidfile /tmp/openldap-data/slapd.pid
+argsfile /tmp/openldap-data/slapd.args
+
+database bdb
+suffix "dc=ericsson,dc=se"
+rootdn "cn=Manager,dc=ericsson,dc=se"
+rootpw hejsan
+# The database must exist before running slapd
+directory /tmp/openldap-data
+# Indices to maintain
+index objectClass eq
+# URI "ldap://0.0.0.0:9876 ldaps://0.0.0.0:9870"
+# servers/slapd/slapd -d 255 -h "ldap://0.0.0.0:9876 ldaps://0.0.0.0:9870" -f /ldisk/dgud/src/otp/lib/eldap/test/ldap_server/slapd.conf \ No newline at end of file
diff --git a/lib/eldap/vsn.mk b/lib/eldap/vsn.mk
new file mode 100644
index 0000000000..c9d6e4e324
--- /dev/null
+++ b/lib/eldap/vsn.mk
@@ -0,0 +1 @@
+ELDAP_VSN = 1.0