aboutsummaryrefslogtreecommitdiff
path: root/src/eldap
diff options
context:
space:
mode:
authorEvgeniy Khramtsov <ekhramtsov@process-one.net>2013-04-08 11:12:54 +0200
committerChristophe Romain <christophe.romain@process-one.net>2013-06-13 11:11:02 +0200
commit4d8f7706240a1603468968f47fc7b150b788d62f (patch)
tree92d55d789cc7ac979b3c9e161ffb7f908eba043a /src/eldap
parentFix Guide: ejabberd_service expects a shaper_rule, not a shaper (diff)
Switch to rebar build tool
Use dynamic Rebar configuration Make iconv dependency optional Disable transient_supervisors compile option Add hipe compilation support Only compile ibrowse and lhttpc when needed Make it possible to generate an OTP application release Add --enable-debug compile option Add --enable-all compiler option Add --enable-tools configure option Add --with-erlang configure option. Add --enable-erlang-version-check configure option. Add lager support Improve the test suite
Diffstat (limited to 'src/eldap')
-rw-r--r--src/eldap/ELDAPv3.asn301
-rw-r--r--src/eldap/Makefile.in58
-rw-r--r--src/eldap/Makefile.win3244
-rw-r--r--src/eldap/eldap.erl1199
-rw-r--r--src/eldap/eldap.hrl64
-rw-r--r--src/eldap/eldap_filter.erl191
-rw-r--r--src/eldap/eldap_filter_yecc.yrl71
-rw-r--r--src/eldap/eldap_pool.erl86
-rw-r--r--src/eldap/eldap_utils.erl354
9 files changed, 0 insertions, 2368 deletions
diff --git a/src/eldap/ELDAPv3.asn b/src/eldap/ELDAPv3.asn
deleted file mode 100644
index 1fec35cd8..000000000
--- a/src/eldap/ELDAPv3.asn
+++ /dev/null
@@ -1,301 +0,0 @@
--- LDAPv3 ASN.1 specification, taken from RFC 2251
-
--- Lightweight-Directory-Access-Protocol-V3 DEFINITIONS
-ELDAPv3 DEFINITIONS
-IMPLICIT TAGS ::=
-
-BEGIN
-
-LDAPMessage ::= SEQUENCE {
- messageID MessageID,
- protocolOp CHOICE {
- bindRequest BindRequest,
- bindResponse BindResponse,
- unbindRequest UnbindRequest,
- searchRequest SearchRequest,
- searchResEntry SearchResultEntry,
- searchResDone SearchResultDone,
- searchResRef SearchResultReference,
- modifyRequest ModifyRequest,
- modifyResponse ModifyResponse,
- addRequest AddRequest,
- addResponse AddResponse,
- delRequest DelRequest,
- delResponse DelResponse,
- modDNRequest ModifyDNRequest,
- modDNResponse ModifyDNResponse,
- compareRequest CompareRequest,
- compareResponse CompareResponse,
- abandonRequest AbandonRequest,
- extendedReq ExtendedRequest,
- extendedResp ExtendedResponse },
- controls [0] Controls OPTIONAL }
-
-MessageID ::= INTEGER (0 .. maxInt)
-
-maxInt INTEGER ::= 2147483647 -- (2^^31 - 1) --
-
-LDAPString ::= OCTET STRING
-
-LDAPOID ::= OCTET STRING
-
-LDAPDN ::= LDAPString
-
-RelativeLDAPDN ::= LDAPString
-
-AttributeType ::= LDAPString
-
-AttributeDescription ::= LDAPString
-
-
-
-
--- Wahl, et. al. Standards Track [Page 44]
---
--- RFC 2251 LDAPv3 December 1997
-
-
-AttributeDescriptionList ::= SEQUENCE OF
- AttributeDescription
-
-AttributeValue ::= OCTET STRING
-
-AttributeValueAssertion ::= SEQUENCE {
- attributeDesc AttributeDescription,
- assertionValue AssertionValue }
-
-AssertionValue ::= OCTET STRING
-
-Attribute ::= SEQUENCE {
- type AttributeDescription,
- vals SET OF AttributeValue }
-
-MatchingRuleId ::= LDAPString
-
-LDAPResult ::= SEQUENCE {
- resultCode ENUMERATED {
- success (0),
- operationsError (1),
- protocolError (2),
- timeLimitExceeded (3),
- sizeLimitExceeded (4),
- compareFalse (5),
- compareTrue (6),
- authMethodNotSupported (7),
- strongAuthRequired (8),
- -- 9 reserved --
- referral (10), -- new
- adminLimitExceeded (11), -- new
- unavailableCriticalExtension (12), -- new
- confidentialityRequired (13), -- new
- saslBindInProgress (14), -- new
- noSuchAttribute (16),
- undefinedAttributeType (17),
- inappropriateMatching (18),
- constraintViolation (19),
- attributeOrValueExists (20),
- invalidAttributeSyntax (21),
- -- 22-31 unused --
- noSuchObject (32),
- aliasProblem (33),
- invalidDNSyntax (34),
- -- 35 reserved for undefined isLeaf --
- aliasDereferencingProblem (36),
- -- 37-47 unused --
- inappropriateAuthentication (48),
-
--- Wahl, et. al. Standards Track [Page 45]
---
--- RFC 2251 LDAPv3 December 1997
-
-
- invalidCredentials (49),
- insufficientAccessRights (50),
- busy (51),
- unavailable (52),
- unwillingToPerform (53),
- loopDetect (54),
- -- 55-63 unused --
- namingViolation (64),
- objectClassViolation (65),
- notAllowedOnNonLeaf (66),
- notAllowedOnRDN (67),
- entryAlreadyExists (68),
- objectClassModsProhibited (69),
- -- 70 reserved for CLDAP --
- affectsMultipleDSAs (71), -- new
- -- 72-79 unused --
- other (80) },
- -- 81-90 reserved for APIs --
- matchedDN LDAPDN,
- errorMessage LDAPString,
- referral [3] Referral OPTIONAL }
-
-Referral ::= SEQUENCE OF LDAPURL
-
-LDAPURL ::= LDAPString -- limited to characters permitted in URLs
-
-Controls ::= SEQUENCE OF Control
-
-Control ::= SEQUENCE {
- controlType LDAPOID,
- criticality BOOLEAN DEFAULT FALSE,
- controlValue OCTET STRING OPTIONAL }
-
-BindRequest ::= [APPLICATION 0] SEQUENCE {
- version INTEGER (1 .. 127),
- name LDAPDN,
- authentication AuthenticationChoice }
-
-AuthenticationChoice ::= CHOICE {
- simple [0] OCTET STRING,
- -- 1 and 2 reserved
- sasl [3] SaslCredentials }
-
-SaslCredentials ::= SEQUENCE {
- mechanism LDAPString,
- credentials OCTET STRING OPTIONAL }
-
-BindResponse ::= [APPLICATION 1] SEQUENCE {
-
--- Wahl, et. al. Standards Track [Page 46]
---
--- RFC 2251 LDAPv3 December 1997
-
-
- COMPONENTS OF LDAPResult,
- serverSaslCreds [7] OCTET STRING OPTIONAL }
-
-UnbindRequest ::= [APPLICATION 2] NULL
-
-SearchRequest ::= [APPLICATION 3] SEQUENCE {
- baseObject LDAPDN,
- scope ENUMERATED {
- baseObject (0),
- singleLevel (1),
- wholeSubtree (2) },
- derefAliases ENUMERATED {
- neverDerefAliases (0),
- derefInSearching (1),
- derefFindingBaseObj (2),
- derefAlways (3) },
- sizeLimit INTEGER (0 .. maxInt),
- timeLimit INTEGER (0 .. maxInt),
- typesOnly BOOLEAN,
- filter Filter,
- attributes AttributeDescriptionList }
-
-Filter ::= CHOICE {
- and [0] SET OF Filter,
- or [1] SET OF Filter,
- not [2] Filter,
- equalityMatch [3] AttributeValueAssertion,
- substrings [4] SubstringFilter,
- greaterOrEqual [5] AttributeValueAssertion,
- lessOrEqual [6] AttributeValueAssertion,
- present [7] AttributeDescription,
- approxMatch [8] AttributeValueAssertion,
- extensibleMatch [9] MatchingRuleAssertion }
-
-SubstringFilter ::= SEQUENCE {
- type AttributeDescription,
- -- at least one must be present
- substrings SEQUENCE OF CHOICE {
- initial [0] LDAPString,
- any [1] LDAPString,
- final [2] LDAPString } }
-
-MatchingRuleAssertion ::= SEQUENCE {
- matchingRule [1] MatchingRuleId OPTIONAL,
- type [2] AttributeDescription OPTIONAL,
- matchValue [3] AssertionValue,
- dnAttributes [4] BOOLEAN DEFAULT FALSE }
-
--- Wahl, et. al. Standards Track [Page 47]
---
--- RFC 2251 LDAPv3 December 1997
-
-SearchResultEntry ::= [APPLICATION 4] SEQUENCE {
- objectName LDAPDN,
- attributes PartialAttributeList }
-
-PartialAttributeList ::= SEQUENCE OF SEQUENCE {
- type AttributeDescription,
- vals SET OF AttributeValue }
-
-SearchResultReference ::= [APPLICATION 19] SEQUENCE OF LDAPURL
-
-SearchResultDone ::= [APPLICATION 5] LDAPResult
-
-ModifyRequest ::= [APPLICATION 6] SEQUENCE {
- object LDAPDN,
- modification SEQUENCE OF SEQUENCE {
- operation ENUMERATED {
- add (0),
- delete (1),
- replace (2) },
- modification AttributeTypeAndValues } }
-
-AttributeTypeAndValues ::= SEQUENCE {
- type AttributeDescription,
- vals SET OF AttributeValue }
-
-ModifyResponse ::= [APPLICATION 7] LDAPResult
-
-AddRequest ::= [APPLICATION 8] SEQUENCE {
- entry LDAPDN,
- attributes AttributeList }
-
-AttributeList ::= SEQUENCE OF SEQUENCE {
- type AttributeDescription,
- vals SET OF AttributeValue }
-
-AddResponse ::= [APPLICATION 9] LDAPResult
-
-DelRequest ::= [APPLICATION 10] LDAPDN
-
-DelResponse ::= [APPLICATION 11] LDAPResult
-
-ModifyDNRequest ::= [APPLICATION 12] SEQUENCE {
- entry LDAPDN,
- newrdn RelativeLDAPDN,
- deleteoldrdn BOOLEAN,
- newSuperior [0] LDAPDN OPTIONAL }
-
-ModifyDNResponse ::= [APPLICATION 13] LDAPResult
-
--- Wahl, et. al. Standards Track [Page 48]
---
--- RFC 2251 LDAPv3 December 1997
-
-
-CompareRequest ::= [APPLICATION 14] SEQUENCE {
- entry LDAPDN,
- ava AttributeValueAssertion }
-
-CompareResponse ::= [APPLICATION 15] LDAPResult
-
-AbandonRequest ::= [APPLICATION 16] MessageID
-
-ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
- requestName [0] LDAPOID,
- requestValue [1] OCTET STRING OPTIONAL }
-
-ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
- COMPONENTS OF LDAPResult,
- responseName [10] LDAPOID OPTIONAL,
- response [11] OCTET STRING OPTIONAL }
-
-passwdModifyOID LDAPOID ::= "1.3.6.1.4.1.4203.1.11.1"
-
-PasswdModifyRequestValue ::= SEQUENCE {
- userIdentity [0] OCTET STRING OPTIONAL,
- oldPasswd [1] OCTET STRING OPTIONAL,
- newPasswd [2] OCTET STRING OPTIONAL }
-
-PasswdModifyResponseValue ::= SEQUENCE {
- genPasswd [0] OCTET STRING OPTIONAL }
-
-END
-
-
diff --git a/src/eldap/Makefile.in b/src/eldap/Makefile.in
deleted file mode 100644
index 6d895eecd..000000000
--- a/src/eldap/Makefile.in
+++ /dev/null
@@ -1,58 +0,0 @@
-# $Id: Makefile.in 2842 2009-12-29 19:10:52Z badlop $
-
-CC = @CC@
-CFLAGS = @CFLAGS@
-CPPFLAGS = @CPPFLAGS@
-LDFLAGS = @LDFLAGS@
-LIBS = @LIBS@
-
-ASN_FLAGS = -bber_bin +optimize +binary_strings
-
-ERLANG_CFLAGS = @ERLANG_CFLAGS@
-ERLANG_LIBS = @ERLANG_LIBS@
-
-EFLAGS += -I ..
-EFLAGS += -pz ..
-
-# make debug=true to compile Erlang module with debug informations.
-ifdef debug
- EFLAGS+=+debug_info
-endif
-
-OUTDIR = ..
-SOURCES = $(wildcard *.erl) ELDAPv3.erl eldap_filter_yecc.erl
-BEAMS = $(addprefix $(OUTDIR)/,$(SOURCES:.erl=.beam))
-
-
-all: $(BEAMS) ELDAPv3.beam eldap_filter_yecc.beam
-
-ELDAPv3.beam: ELDAPv3.erl
-
-ELDAPv3.erl: ELDAPv3.asn
- @ERLC@ $(ASN_FLAGS) -W $(EFLAGS) $<
- @ERL@ -noinput +B -eval \
- 'case file:read_file("ELDAPv3.erl") of {ok, Data} -> NewData = re:replace(Data, "\\?RT_BER:decode_octet_string", "eldap_utils:decode_octet_string", [global]), file:write_file("ELDAPv3.erl", NewData), halt(0); _Err -> halt(1) end'
-
-eldap_filter_yecc.beam: eldap_filter_yecc.erl
-
-eldap_filter_yecc.erl: eldap_filter_yecc.yrl
- @ERLC@ -W $<
-
-$(OUTDIR)/%.beam: %.erl ELDAPv3.erl eldap_filter_yecc.erl
- @ERLC@ -W $(EFLAGS) -o $(OUTDIR) $<
-
-clean:
- rm -f ELDAPv3.asn1db
- rm -f ELDAPv3.erl
- rm -f ELDAPv3.hrl
- rm -f ELDAPv3.beam
- rm -f eldap_filter_yecc.erl
- rm -f eldap_filter_yecc.beam
- rm -f $(BEAMS)
-
-distclean: clean
- rm -f Makefile
-
-TAGS:
- etags *.erl
-
diff --git a/src/eldap/Makefile.win32 b/src/eldap/Makefile.win32
deleted file mode 100644
index 394055d41..000000000
--- a/src/eldap/Makefile.win32
+++ /dev/null
@@ -1,44 +0,0 @@
-
-include ..\Makefile.inc
-
-EFLAGS = -I .. -pz ..
-
-OUTDIR = ..
-BEAMS = ..\eldap.beam ..\eldap_filter.beam ..\eldap_pool.beam ..\eldap_utils.beam ..\eldap_filter_yecc.beam
-
-ASN_FLAGS = -bber_bin +optimize
-
-ALL : $(BEAMS)
-
-Clean :
- -@erase ELDAPv3.asn1db
- -@erase ELDAPv3.erl
- -@erase ELDAPv3.hrl
- -@erase ELDAPv3.beam
- -@erase eldap_filter_yecc.erl
- -@erase eldap_filter_yecc.beam
- -@erase $(BEAMS)
-
-ELDAPv3.erl : ELDAPv3.asn
- erlc $(ASN_FLAGS) -W $(EFLAGS) ELDAPv3.asn
-
-eldap_filter_yecc.erl: eldap_filter_yecc.yrl
- erlc -W eldap_filter_yecc.yrl
-
-$(OUTDIR)\eldap.beam : eldap.erl ELDAPv3.erl
- erlc -W $(EFLAGS) -o $(OUTDIR) eldap.erl
-
-$(OUTDIR)\ELDAPv3.beam : ELDAPv3.erl
- erlc -W $(EFLAGS) -o $(OUTDIR) ELDAPv3.erl
-
-$(OUTDIR)\eldap_filter.beam : eldap_filter.erl
- erlc -W $(EFLAGS) -o $(OUTDIR) eldap_filter.erl
-
-$(OUTDIR)\eldap_utils.beam : eldap_utils.erl
- erlc -W $(EFLAGS) -o $(OUTDIR) eldap_utils.erl
-
-$(OUTDIR)\eldap_pool.beam : eldap_pool.erl
- erlc -W $(EFLAGS) -o $(OUTDIR) eldap_pool.erl
-
-$(OUTDIR)\eldap_filter_yecc.beam : eldap_filter_yecc.erl
- erlc -W $(EFLAGS) -o $(OUTDIR) eldap_filter_yecc.erl
diff --git a/src/eldap/eldap.erl b/src/eldap/eldap.erl
deleted file mode 100644
index 4df7d00eb..000000000
--- a/src/eldap/eldap.erl
+++ /dev/null
@@ -1,1199 +0,0 @@
--module(eldap).
-%%% --------------------------------------------------------------------
-%%% Created: 12 Oct 2000 by Tobbe <tnt@home.se>
-%%% Function: Erlang client LDAP implementation according RFC 2251.
-%%% The interface is based on RFC 1823, and
-%%% draft-ietf-asid-ldap-c-api-00.txt
-%%%
-%%% Copyright (C) 2000 Torbjorn Tornkvist, tnt@home.se
-%%%
-%%%
-%%% This program is free software; you can redistribute it and/or modify
-%%% it under the terms of the GNU General Public License as published by
-%%% the Free Software Foundation; either version 2 of the License, or
-%%% (at your option) any later version.
-%%%
-%%% This program is distributed in the hope that it will be useful,
-%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
-%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-%%% GNU General Public License for more details.
-%%%
-%%% You should have received a copy of the GNU General Public License
-%%% along with this program; if not, write to the Free Software
-%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-%%% Modified by Sean Hinde <shinde@iee.org> 7th Dec 2000
-%%% Turned into gen_fsm, made non-blocking, added timers etc to support this.
-%%% Now has the concept of a name (string() or atom()) per instance which allows
-%%% multiple users to call by name if so desired.
-%%%
-%%% Can be configured with start_link parameters or use a config file to get
-%%% host to connect to, dn, password, log function etc.
-
-%%% Modified by Alexey Shchepin <alexey@sevcom.net>
-
-%%% Modified by Evgeniy Khramtsov <ekhramtsov@process-one.net>
-%%% Implemented queue for bind() requests to prevent pending binds.
-%%% Implemented extensibleMatch/2 function.
-%%% Implemented LDAP Extended Operations (currently only Password Modify
-%%% is supported - RFC 3062).
-
-%%% Modified by Christophe Romain <christophe.romain@process-one.net>
-%%% Improve error case handling
-
-%%% Modified by Mickael Remond <mremond@process-one.net>
-%%% Now use ejabberd log mechanism
-
-%%% Modified by:
-%%% Thomas Baden <roo@ham9.net> 2008 April 6th
-%%% Andy Harb <Ahmad.N.Abou-Harb@jpl.nasa.gov> 2008 April 28th
-%%% Anton Podavalov <a.podavalov@gmail.com> 2009 February 22th
-%%% Added LDAPS support, modeled off jungerl eldap.erl version.
-%%% NOTICE: STARTTLS is not supported.
-
-%%% --------------------------------------------------------------------
--vc('$Id$ ').
-
-%%%----------------------------------------------------------------------
-%%% LDAP Client state machine.
-%%% Possible states are:
-%%% connecting - actually disconnected, but retrying periodically
-%%% wait_bind_response - connected and sent bind request
-%%% active - bound to LDAP Server and ready to handle commands
-%%% active_bind - sent bind() request and waiting for response
-%%%----------------------------------------------------------------------
-
--behaviour(gen_fsm).
-
--include("ejabberd.hrl").
-
-%% External exports
--export([start_link/1, start_link/6]).
-
--export([baseObject/0, singleLevel/0, wholeSubtree/0,
- close/1, equalityMatch/2, greaterOrEqual/2,
- lessOrEqual/2, approxMatch/2, search/2, substrings/2,
- present/1, extensibleMatch/2, 'and'/1, 'or'/1, 'not'/1,
- modify/3, mod_add/2, mod_delete/2, mod_replace/2, add/3,
- delete/2, modify_dn/5, modify_passwd/3, bind/3]).
-
--export([get_status/1]).
-
-%% gen_fsm callbacks
--export([init/1, connecting/2, connecting/3,
- wait_bind_response/3, active/3, active_bind/3,
- handle_event/3, handle_sync_event/4, handle_info/3,
- terminate/3, code_change/4]).
-
--export_type([filter/0]).
-
--include("ELDAPv3.hrl").
-
--include("eldap.hrl").
-
--define(LDAP_VERSION, 3).
-
--define(RETRY_TIMEOUT, 500).
-
--define(BIND_TIMEOUT, 10000).
-
--define(CMD_TIMEOUT, 100000).
-%% Used in gen_fsm sync calls.
-%% Used as a timeout for gen_tcp:send/2
-
--define(CALL_TIMEOUT,
- (?CMD_TIMEOUT) + (?BIND_TIMEOUT) + (?RETRY_TIMEOUT)).
-
--define(SEND_TIMEOUT, 30000).
-
--define(MAX_TRANSACTION_ID, 65535).
-
--define(MIN_TRANSACTION_ID, 0).
-%% Grace period after "soft" LDAP bind errors:
-
--define(GRACEFUL_RETRY_TIMEOUT, 5000).
-
--define(SUPPORTEDEXTENSION,
- <<"1.3.6.1.4.1.1466.101.120.7">>).
-
--define(SUPPORTEDEXTENSIONSYNTAX,
- <<"1.3.6.1.4.1.1466.115.121.1.38">>).
-
--define(STARTTLS, <<"1.3.6.1.4.1.1466.20037">>).
-
--type handle() :: pid() | atom() | binary().
-
--record(eldap,
- {version = ?LDAP_VERSION :: non_neg_integer(),
- hosts = [] :: [binary()],
- host :: binary(),
- port = 389 :: inet:port_number(),
- sockmod = gen_tcp :: ssl | gen_tcp,
- tls = none :: none | tls,
- tls_options = [] :: [{cacertfile, string()} |
- {depth, non_neg_integer()} |
- {verify, non_neg_integer()}],
- fd,
- rootdn = <<"">> :: binary(),
- passwd = <<"">> :: binary(),
- id = 0 :: non_neg_integer(),
- bind_timer = make_ref() :: reference(),
- dict = dict:new() :: dict(),
- req_q = queue:new() :: queue()}).
-
-%%%----------------------------------------------------------------------
-%%% API
-%%%----------------------------------------------------------------------
-start_link(Name) ->
- Reg_name = jlib:binary_to_atom(<<"eldap_",
- Name/binary>>),
- gen_fsm:start_link({local, Reg_name}, ?MODULE, [], []).
-
--spec start_link(binary(), [binary()], inet:port_number(), binary(),
- binary(), tlsopts()) -> any().
-
-start_link(Name, Hosts, Port, Rootdn, Passwd, Opts) ->
- Reg_name = jlib:binary_to_atom(<<"eldap_",
- Name/binary>>),
- gen_fsm:start_link({local, Reg_name}, ?MODULE,
- [Hosts, Port, Rootdn, Passwd, Opts], []).
-
--spec get_status(handle()) -> any().
-
-%%% --------------------------------------------------------------------
-%%% Get status of connection.
-%%% --------------------------------------------------------------------
-get_status(Handle) ->
- Handle1 = get_handle(Handle),
- gen_fsm:sync_send_all_state_event(Handle1, get_status).
-
-%%% --------------------------------------------------------------------
-%%% Shutdown connection (and process) asynchronous.
-%%% --------------------------------------------------------------------
--spec close(handle()) -> any().
-
-close(Handle) ->
- Handle1 = get_handle(Handle),
- gen_fsm:send_all_state_event(Handle1, close).
-
-%%% --------------------------------------------------------------------
-%%% Add an entry. The entry field MUST NOT exist for the AddRequest
-%%% to succeed. The parent of the entry MUST exist.
-%%% Example:
-%%%
-%%% add(Handle,
-%%% "cn=Bill Valentine, ou=people, o=Bluetail AB, dc=bluetail, dc=com",
-%%% [{"objectclass", ["person"]},
-%%% {"cn", ["Bill Valentine"]},
-%%% {"sn", ["Valentine"]},
-%%% {"telephoneNumber", ["545 555 00"]}]
-%%% )
-%%% --------------------------------------------------------------------
-add(Handle, Entry, Attributes) ->
- Handle1 = get_handle(Handle),
- gen_fsm:sync_send_event(Handle1,
- {add, Entry, add_attrs(Attributes)}, ?CALL_TIMEOUT).
-
-%%% Do sanity check !
-add_attrs(Attrs) ->
- F = fun ({Type, Vals}) ->
- {'AddRequest_attributes', Type, Vals}
- end,
- case catch lists:map(F, Attrs) of
- {'EXIT', _} -> throw({error, attribute_values});
- Else -> Else
- end.
-
-%%% --------------------------------------------------------------------
-%%% Delete an entry. The entry consists of the DN of
-%%% the entry to be deleted.
-%%% Example:
-%%%
-%%% delete(Handle,
-%%% "cn=Bill Valentine, ou=people, o=Bluetail AB, dc=bluetail, dc=com"
-%%% )
-%%% --------------------------------------------------------------------
-delete(Handle, Entry) ->
- Handle1 = get_handle(Handle),
- gen_fsm:sync_send_event(Handle1, {delete, Entry},
- ?CALL_TIMEOUT).
-
-%%% --------------------------------------------------------------------
-%%% Modify an entry. Given an entry a number of modification
-%%% operations can be performed as one atomic operation.
-%%% Example:
-%%%
-%%% modify(Handle,
-%%% "cn=Torbjorn Tornkvist, ou=people, o=Bluetail AB, dc=bluetail, dc=com",
-%%% [replace("telephoneNumber", ["555 555 00"]),
-%%% add("description", ["LDAP hacker"])]
-%%% )
-%%% --------------------------------------------------------------------
--spec modify(handle(), any(), [add | delete | replace]) -> any().
-
-modify(Handle, Object, Mods) ->
- Handle1 = get_handle(Handle),
- gen_fsm:sync_send_event(Handle1, {modify, Object, Mods},
- ?CALL_TIMEOUT).
-
-%%%
-%%% Modification operations.
-%%% Example:
-%%% replace("telephoneNumber", ["555 555 00"])
-%%%
-mod_add(Type, Values) ->
- m(add, Type, Values).
-
-mod_delete(Type, Values) ->
- m(delete, Type, Values).
-
-%%% --------------------------------------------------------------------
-%%% Modify an entry. Given an entry a number of modification
-%%% operations can be performed as one atomic operation.
-%%% Example:
-%%%
-%%% modify_dn(Handle,
-%%% "cn=Bill Valentine, ou=people, o=Bluetail AB, dc=bluetail, dc=com",
-%%% "cn=Ben Emerson",
-%%% true,
-%%% ""
-%%% )
-%%% --------------------------------------------------------------------
-mod_replace(Type, Values) ->
- m(replace, Type, Values).
-
-m(Operation, Type, Values) ->
- #'ModifyRequest_modification_SEQOF'{operation =
- Operation,
- modification =
- #'AttributeTypeAndValues'{type =
- Type,
- vals =
- Values}}.
-
-modify_dn(Handle, Entry, NewRDN, DelOldRDN, NewSup) ->
- Handle1 = get_handle(Handle),
- gen_fsm:sync_send_event(Handle1,
- {modify_dn, Entry, NewRDN, bool_p(DelOldRDN),
- optional(NewSup)},
- ?CALL_TIMEOUT).
-
--spec modify_passwd(handle(), binary(), binary()) -> any().
-
-modify_passwd(Handle, DN, Passwd) ->
- Handle1 = get_handle(Handle),
- gen_fsm:sync_send_event(Handle1,
- {modify_passwd, DN, Passwd}, ?CALL_TIMEOUT).
-
-%%% --------------------------------------------------------------------
-%%% Bind.
-%%% Example:
-%%%
-%%% bind(Handle,
-%%% "cn=Bill Valentine, ou=people, o=Bluetail AB, dc=bluetail, dc=com",
-%%% "secret")
-%%% --------------------------------------------------------------------
--spec bind(handle(), binary(), binary()) -> any().
-
-bind(Handle, RootDN, Passwd) ->
- Handle1 = get_handle(Handle),
- gen_fsm:sync_send_event(Handle1, {bind, RootDN, Passwd},
- ?CALL_TIMEOUT).
-
-%%% Sanity checks !
-
-bool_p(Bool) when Bool == true; Bool == false -> Bool.
-
-optional([]) -> asn1_NOVALUE;
-optional(Value) -> Value.
-
-%%% --------------------------------------------------------------------
-%%% Synchronous search of the Directory returning a
-%%% requested set of attributes.
-%%%
-%%% Example:
-%%%
-%%% Filter = eldap:substrings("sn", [{any,"o"}]),
-%%% eldap:search(S, [{base, "dc=bluetail, dc=com"},
-%%% {filter, Filter},
-%%% {attributes,["cn"]}])),
-%%%
-%%% Returned result: {ok, #eldap_search_result{}}
-%%%
-%%% Example:
-%%%
-%%% {ok,{eldap_search_result,
-%%% [{eldap_entry,
-%%% "cn=Magnus Froberg, dc=bluetail, dc=com",
-%%% [{"cn",["Magnus Froberg"]}]},
-%%% {eldap_entry,
-%%% "cn=Torbjorn Tornkvist, dc=bluetail, dc=com",
-%%% [{"cn",["Torbjorn Tornkvist"]}]}],
-%%% []}}
-%%%
-%%% --------------------------------------------------------------------
--type search_args() :: [{base, binary()} |
- {filter, filter()} |
- {scope, scope()} |
- {attributes, [binary()]} |
- {types_only, boolean()} |
- {timeout, non_neg_integer()} |
- {limit, non_neg_integer()} |
- {deref_aliases, never | searching | finding | always}].
-
--spec search(handle(), eldap_search() | search_args()) -> any().
-
-search(Handle, A) when is_record(A, eldap_search) ->
- call_search(Handle, A);
-search(Handle, L) when is_list(L) ->
- case catch parse_search_args(L) of
- {error, Emsg} -> {error, Emsg};
- {'EXIT', Emsg} -> {error, Emsg};
- A when is_record(A, eldap_search) ->
- call_search(Handle, A)
- end.
-
-call_search(Handle, A) ->
- Handle1 = get_handle(Handle),
- gen_fsm:sync_send_event(Handle1, {search, A},
- ?CALL_TIMEOUT).
-
--spec parse_search_args(search_args()) -> eldap_search().
-
-parse_search_args(Args) ->
- parse_search_args(Args,
- #eldap_search{scope = wholeSubtree}).
-
-parse_search_args([{base, Base} | T], A) ->
- parse_search_args(T, A#eldap_search{base = Base});
-parse_search_args([{filter, Filter} | T], A) ->
- parse_search_args(T, A#eldap_search{filter = Filter});
-parse_search_args([{scope, Scope} | T], A) ->
- parse_search_args(T, A#eldap_search{scope = Scope});
-parse_search_args([{attributes, Attrs} | T], A) ->
- parse_search_args(T,
- A#eldap_search{attributes = Attrs});
-parse_search_args([{types_only, TypesOnly} | T], A) ->
- parse_search_args(T,
- A#eldap_search{types_only = TypesOnly});
-parse_search_args([{timeout, Timeout} | T], A)
- when is_integer(Timeout) ->
- parse_search_args(T, A#eldap_search{timeout = Timeout});
-parse_search_args([{limit, Limit} | T], A)
- when is_integer(Limit) ->
- parse_search_args(T, A#eldap_search{limit = Limit});
-parse_search_args([{deref_aliases, never} | T], A) ->
- parse_search_args(T,
- A#eldap_search{deref_aliases = neverDerefAliases});
-parse_search_args([{deref_aliases, searching} | T],
- A) ->
- parse_search_args(T,
- A#eldap_search{deref_aliases = derefInSearching});
-parse_search_args([{deref_aliases, finding} | T], A) ->
- parse_search_args(T,
- A#eldap_search{deref_aliases = derefFindingBaseObj});
-parse_search_args([{deref_aliases, always} | T], A) ->
- parse_search_args(T,
- A#eldap_search{deref_aliases = derefAlways});
-parse_search_args([H | _], _) ->
- throw({error, {unknown_arg, H}});
-parse_search_args([], A) -> A.
-
-baseObject() -> baseObject.
-
-singleLevel() -> singleLevel.
-
-%%%
-%%% The Scope parameter
-%%%
-wholeSubtree() -> wholeSubtree.
-
-%%%
-%%% Boolean filter operations
-%%%
--type filter() :: 'and'() | 'or'() | 'not'() | equalityMatch() |
- greaterOrEqual() | lessOrEqual() | approxMatch() |
- present() | substrings() | extensibleMatch().
-
-%%%
-%%% The following Filter parameters consist of an attribute
-%%% and an attribute value. Example: F("uid","tobbe")
-%%%
--type 'and'() :: {'and', [filter()]}.
--spec 'and'([filter()]) -> 'and'().
-
-'and'(ListOfFilters) when is_list(ListOfFilters) ->
- {'and', ListOfFilters}.
-
--type 'or'() :: {'or', [filter()]}.
--spec 'or'([filter()]) -> 'or'().
-
-'or'(ListOfFilters) when is_list(ListOfFilters) ->
- {'or', ListOfFilters}.
-
--type 'not'() :: {'not', filter()}.
--spec 'not'(filter()) -> 'not'().
-
-'not'(Filter) when is_tuple(Filter) -> {'not', Filter}.
-
--type equalityMatch() :: {equalityMatch, 'AttributeValueAssertion'()}.
--spec equalityMatch(binary(), binary()) -> equalityMatch().
-
-equalityMatch(Desc, Value) ->
- {equalityMatch, av_assert(Desc, Value)}.
-
--type greaterOrEqual() :: {greaterOrEqual, 'AttributeValueAssertion'()}.
--spec greaterOrEqual(binary(), binary()) -> greaterOrEqual().
-
-greaterOrEqual(Desc, Value) ->
- {greaterOrEqual, av_assert(Desc, Value)}.
-
--type lessOrEqual() :: {lessOrEqual, 'AttributeValueAssertion'()}.
--spec lessOrEqual(binary(), binary()) -> lessOrEqual().
-
-lessOrEqual(Desc, Value) ->
- {lessOrEqual, av_assert(Desc, Value)}.
-
--type approxMatch() :: {approxMatch, 'AttributeValueAssertion'()}.
--spec approxMatch(binary(), binary()) -> approxMatch().
-
-approxMatch(Desc, Value) ->
- {approxMatch, av_assert(Desc, Value)}.
-
--type 'AttributeValueAssertion'() ::
- #'AttributeValueAssertion'{attributeDesc :: binary(),
- assertionValue :: binary()}.
-
--spec av_assert(binary(), binary()) -> 'AttributeValueAssertion'().
-
-av_assert(Desc, Value) ->
- #'AttributeValueAssertion'{attributeDesc = Desc,
- assertionValue = Value}.
-
-%%%
-%%% Filter to check for the presence of an attribute
-%%%
--type present() :: {present, binary()}.
--spec present(binary()) -> present().
-
-%%%
-%%% A substring filter seem to be based on a pattern:
-%%%
-%%% InitValue*AnyValue*FinalValue
-%%%
-%%% where all three parts seem to be optional (at least when
-%%% talking with an OpenLDAP server). Thus, the arguments
-%%% to substrings/2 looks like this:
-%%%
-%%% Type ::= string( <attribute> )
-%%% SubStr ::= listof( {initial,Value} | {any,Value}, {final,Value})
-%%%
-%%% Example: substrings("sn",[{initial,"To"},{any,"kv"},{final,"st"}])
-%%% will match entries containing: 'sn: Tornkvist'
-%%%
-present(Attribute) ->
- {present, Attribute}.
-
-%%%
-%%% extensibleMatch filter.
-%%% FIXME: Describe the purpose of this filter.
-%%%
-%%% Value ::= string( <attribute> )
-%%% Opts ::= listof( {matchingRule, Str} | {type, Str} | {dnAttributes, true} )
-%%%
-%%% Example: extensibleMatch("Fred", [{matchingRule, "1.2.3.4.5"}, {type, "cn"}]).
-%%%
--type substr() :: [{initial | any | final, binary()}].
--type 'SubstringFilter'() ::
- #'SubstringFilter'{type :: binary(),
- substrings :: {'SubstringFilter_substrings',
- substr()}}.
-
--type substrings() :: {substrings, 'SubstringFilter'()}.
--spec substrings(binary(), substr()) -> substrings().
-
-substrings(Type, SubStr) ->
- Ss = {'SubstringFilter_substrings', SubStr},
- {substrings,
- #'SubstringFilter'{type = Type, substrings = Ss}}.
-
--type match_opts() :: [{matchingRule | type, binary()} |
- {dnAttributes, boolean()}].
-
--type 'MatchingRuleAssertion'() ::
- #'MatchingRuleAssertion'{matchValue :: binary(),
- type :: asn1_NOVALUE | binary(),
- matchingRule :: asn1_NOVALUE | binary(),
- dnAttributes :: asn1_DEFAULT | true}.
-
--type extensibleMatch() :: {extensibleMatch, 'MatchingRuleAssertion'()}.
--spec extensibleMatch(binary(), match_opts()) -> extensibleMatch().
-
-extensibleMatch(Value, Opts) ->
- MRA = #'MatchingRuleAssertion'{matchValue = Value},
- {extensibleMatch, extensibleMatch_opts(Opts, MRA)}.
-
-extensibleMatch_opts([{matchingRule, Rule} | Opts], MRA) ->
- extensibleMatch_opts(Opts,
- MRA#'MatchingRuleAssertion'{matchingRule = Rule});
-extensibleMatch_opts([{type, Desc} | Opts], MRA) ->
- extensibleMatch_opts(Opts,
- MRA#'MatchingRuleAssertion'{type = Desc});
-extensibleMatch_opts([{dnAttributes, true} | Opts],
- MRA) ->
- extensibleMatch_opts(Opts,
- MRA#'MatchingRuleAssertion'{dnAttributes = true});
-extensibleMatch_opts([_ | Opts], MRA) ->
- extensibleMatch_opts(Opts, MRA);
-extensibleMatch_opts([], MRA) -> MRA.
-
-get_handle(Pid) when is_pid(Pid) -> Pid;
-get_handle(Atom) when is_atom(Atom) -> Atom;
-get_handle(Name) when is_binary(Name) ->
- jlib:binary_to_atom(<<"eldap_",
- Name/binary>>).
-
-%%%----------------------------------------------------------------------
-%%% Callback functions from gen_fsm
-%%%----------------------------------------------------------------------
-
-%%----------------------------------------------------------------------
-%% Func: init/1
-%% Returns: {ok, StateName, StateData} |
-%% {ok, StateName, StateData, Timeout} |
-%% ignore |
-%% {stop, StopReason}
-%% I use the trick of setting a timeout of 0 to pass control into the
-%% process.
-%%----------------------------------------------------------------------
-init([Hosts, Port, Rootdn, Passwd, Opts]) ->
- catch ssl:start(),
- Encrypt = case gen_mod:get_opt(encrypt, Opts,
- fun(tls) -> tls;
- (starttls) -> starttls;
- (none) -> none
- end) of
- tls -> tls;
- _ -> none
- end,
- PortTemp = case Port of
- undefined ->
- case Encrypt of
- tls -> ?LDAPS_PORT;
- _ -> ?LDAP_PORT
- end;
- PT -> PT
- end,
- CacertOpts = case gen_mod:get_opt(
- tls_cacertfile, Opts,
- fun(S) when is_binary(S) ->
- binary_to_list(S);
- (undefined) ->
- undefined
- end) of
- undefined ->
- [];
- Path ->
- [{cacertfile, Path}]
- end,
- DepthOpts = case gen_mod:get_opt(
- tls_depth, Opts,
- fun(I) when is_integer(I), I>=0 ->
- I;
- (undefined) ->
- undefined
- end) of
- undefined ->
- [];
- Depth ->
- [{depth, Depth}]
- end,
- Verify = gen_mod:get_opt(tls_verify, Opts,
- fun(hard) -> hard;
- (soft) -> soft;
- (false) -> false
- end, false),
- TLSOpts = if (Verify == hard orelse Verify == soft)
- andalso CacertOpts == [] ->
- ?WARNING_MSG("TLS verification is enabled but no CA "
- "certfiles configured, so verification "
- "is disabled.",
- []),
- [];
- Verify == soft ->
- [{verify, 1}] ++ CacertOpts ++ DepthOpts;
- Verify == hard ->
- [{verify, 2}] ++ CacertOpts ++ DepthOpts;
- true -> []
- end,
- {ok, connecting,
- #eldap{hosts = Hosts, port = PortTemp, rootdn = Rootdn,
- passwd = Passwd, tls = Encrypt, tls_options = TLSOpts,
- id = 0, dict = dict:new(), req_q = queue:new()},
- 0}.
-
-%%----------------------------------------------------------------------
-%% Func: StateName/2
-%% Called when gen_fsm:send_event/2,3 is invoked (async)
-%% Returns: {next_state, NextStateName, NextStateData} |
-%% {next_state, NextStateName, NextStateData, Timeout} |
-%% {stop, Reason, NewStateData}
-%%----------------------------------------------------------------------
-connecting(timeout, S) ->
- {ok, NextState, NewS} = connect_bind(S),
- {next_state, NextState, NewS}.
-
-%%----------------------------------------------------------------------
-%% Func: StateName/3
-%% Called when gen_fsm:sync_send_event/2,3 is invoked.
-%% Returns: {next_state, NextStateName, NextStateData} |
-%% {next_state, NextStateName, NextStateData, Timeout} |
-%% {reply, Reply, NextStateName, NextStateData} |
-%% {reply, Reply, NextStateName, NextStateData, Timeout} |
-%% {stop, Reason, NewStateData} |
-%% {stop, Reason, Reply, NewStateData}
-%%----------------------------------------------------------------------
-connecting(Event, From, S) ->
- Q = queue:in({Event, From}, S#eldap.req_q),
- {next_state, connecting, S#eldap{req_q = Q}}.
-
-wait_bind_response(Event, From, S) ->
- Q = queue:in({Event, From}, S#eldap.req_q),
- {next_state, wait_bind_response, S#eldap{req_q = Q}}.
-
-active_bind(Event, From, S) ->
- Q = queue:in({Event, From}, S#eldap.req_q),
- {next_state, active_bind, S#eldap{req_q = Q}}.
-
-active(Event, From, S) ->
- process_command(S, Event, From).
-
-%%----------------------------------------------------------------------
-%% Func: handle_event/3
-%% Called when gen_fsm:send_all_state_event/2 is invoked.
-%% Returns: {next_state, NextStateName, NextStateData} |
-%% {next_state, NextStateName, NextStateData, Timeout} |
-%% {stop, Reason, NewStateData}
-%%----------------------------------------------------------------------
-handle_event(close, _StateName, S) ->
- catch (S#eldap.sockmod):close(S#eldap.fd),
- {stop, normal, S};
-handle_event(_Event, StateName, S) ->
- {next_state, StateName, S}.
-
-%%----------------------------------------------------------------------
-%% Func: handle_sync_event/4
-%% Called when gen_fsm:sync_send_all_state_event/2,3 is invoked
-%% Returns: {next_state, NextStateName, NextStateData} |
-%% {next_state, NextStateName, NextStateData, Timeout} |
-%% {reply, Reply, NextStateName, NextStateData} |
-%% {reply, Reply, NextStateName, NextStateData, Timeout} |
-%% {stop, Reason, NewStateData} |
-%% {stop, Reason, Reply, NewStateData}
-%%----------------------------------------------------------------------
-handle_sync_event(_Event, _From, StateName, S) ->
- {reply, {StateName, S}, StateName, S}.
-
-%%----------------------------------------------------------------------
-%% Func: handle_info/3
-%% Returns: {next_state, NextStateName, NextStateData} |
-%% {next_state, NextStateName, NextStateData, Timeout} |
-%% {stop, Reason, NewStateData}
-%% {stop, Reason, NewStateData}
-%%----------------------------------------------------------------------
-
-%%
-%% Packets arriving in various states
-%%
-handle_info({Tag, _Socket, Data}, connecting, S)
- when Tag == tcp; Tag == ssl ->
- ?DEBUG("tcp packet received when disconnected!~n~p",
- [Data]),
- {next_state, connecting, S};
-handle_info({Tag, _Socket, Data}, wait_bind_response, S)
- when Tag == tcp; Tag == ssl ->
- cancel_timer(S#eldap.bind_timer),
- case catch recvd_wait_bind_response(Data, S) of
- bound -> dequeue_commands(S);
- {fail_bind, Reason} ->
- report_bind_failure(S#eldap.host, S#eldap.port, Reason),
- {next_state, connecting,
- close_and_retry(S, ?GRACEFUL_RETRY_TIMEOUT)};
- {'EXIT', Reason} ->
- report_bind_failure(S#eldap.host, S#eldap.port, Reason),
- {next_state, connecting, close_and_retry(S)};
- {error, Reason} ->
- report_bind_failure(S#eldap.host, S#eldap.port, Reason),
- {next_state, connecting, close_and_retry(S)}
- end;
-handle_info({Tag, _Socket, Data}, StateName, S)
- when (StateName == active orelse
- StateName == active_bind)
- andalso (Tag == tcp orelse Tag == ssl) ->
- case catch recvd_packet(Data, S) of
- {response, Response, RequestType} ->
- NewS = case Response of
- {reply, Reply, To, S1} -> gen_fsm:reply(To, Reply), S1;
- {ok, S1} -> S1
- end,
- if StateName == active_bind andalso
- RequestType == bindRequest
- orelse StateName == active ->
- dequeue_commands(NewS);
- true -> {next_state, StateName, NewS}
- end;
- _ -> {next_state, StateName, S}
- end;
-handle_info({Tag, _Socket}, Fsm_state, S)
- when Tag == tcp_closed; Tag == ssl_closed ->
- ?WARNING_MSG("LDAP server closed the connection: ~s:~p~nIn "
- "State: ~p",
- [S#eldap.host, S#eldap.port, Fsm_state]),
- {next_state, connecting, close_and_retry(S)};
-handle_info({Tag, _Socket, Reason}, Fsm_state, S)
- when Tag == tcp_error; Tag == ssl_error ->
- ?DEBUG("eldap received tcp_error: ~p~nIn State: ~p",
- [Reason, Fsm_state]),
- {next_state, connecting, close_and_retry(S)};
-%%
-%% Timers
-%%
-handle_info({timeout, Timer, {cmd_timeout, Id}},
- StateName, S) ->
- case cmd_timeout(Timer, Id, S) of
- {reply, To, Reason, NewS} ->
- gen_fsm:reply(To, Reason),
- {next_state, StateName, NewS};
- {error, _Reason} -> {next_state, StateName, S}
- end;
-handle_info({timeout, retry_connect}, connecting, S) ->
- {ok, NextState, NewS} = connect_bind(S),
- {next_state, NextState, NewS};
-handle_info({timeout, _Timer, bind_timeout},
- wait_bind_response, S) ->
- {next_state, connecting, close_and_retry(S)};
-%%
-%% Make sure we don't fill the message queue with rubbish
-%%
-handle_info(Info, StateName, S) ->
- ?DEBUG("eldap. Unexpected Info: ~p~nIn state: "
- "~p~n when StateData is: ~p",
- [Info, StateName, S]),
- {next_state, StateName, S}.
-
-%%----------------------------------------------------------------------
-%% Func: terminate/3
-%% Purpose: Shutdown the fsm
-%% Returns: any
-%%----------------------------------------------------------------------
-terminate(_Reason, _StateName, _StatData) -> ok.
-
-%%----------------------------------------------------------------------
-%% Func: code_change/4
-%% Purpose: Convert process state when code is changed
-%% Returns: {ok, NewState, NewStateData}
-%%----------------------------------------------------------------------
-code_change(_OldVsn, StateName, S, _Extra) ->
- {ok, StateName, S}.
-
-%%%----------------------------------------------------------------------
-%%% Internal functions
-%%%----------------------------------------------------------------------
-dequeue_commands(S) ->
- case queue:out(S#eldap.req_q) of
- {{value, {Event, From}}, Q} ->
- case process_command(S#eldap{req_q = Q}, Event, From) of
- {_, active, NewS} -> dequeue_commands(NewS);
- Res -> Res
- end;
- {empty, _} -> {next_state, active, S}
- end.
-
-process_command(S, Event, From) ->
- case send_command(Event, From, S) of
- {ok, NewS} ->
- case Event of
- {bind, _, _} -> {next_state, active_bind, NewS};
- _ -> {next_state, active, NewS}
- end;
- {error, _Reason} ->
- Q = queue:in_r({Event, From}, S#eldap.req_q),
- NewS = close_and_retry(S#eldap{req_q = Q}),
- {next_state, connecting, NewS}
- end.
-
-send_command(Command, From, S) ->
- Id = bump_id(S),
- {Name, Request} = gen_req(Command),
- Message = #'LDAPMessage'{messageID = Id,
- protocolOp = {Name, Request}},
- ?DEBUG("~p~n", [{Name, Request}]),
- {ok, Bytes} = asn1rt:encode('ELDAPv3', 'LDAPMessage',
- Message),
- case (S#eldap.sockmod):send(S#eldap.fd, Bytes) of
- ok ->
- Timer = erlang:start_timer(?CMD_TIMEOUT, self(),
- {cmd_timeout, Id}),
- New_dict = dict:store(Id,
- [{Timer, Command, From, Name}], S#eldap.dict),
- {ok, S#eldap{id = Id, dict = New_dict}};
- Error -> Error
- end.
-
-gen_req({search, A}) ->
- {searchRequest,
- #'SearchRequest'{baseObject = A#eldap_search.base,
- scope = A#eldap_search.scope,
- derefAliases = A#eldap_search.deref_aliases,
- sizeLimit = A#eldap_search.limit,
- timeLimit = A#eldap_search.timeout,
- typesOnly = A#eldap_search.types_only,
- filter = A#eldap_search.filter,
- attributes = A#eldap_search.attributes}};
-gen_req({add, Entry, Attrs}) ->
- {addRequest,
- #'AddRequest'{entry = Entry, attributes = Attrs}};
-gen_req({delete, Entry}) -> {delRequest, Entry};
-gen_req({modify, Obj, Mod}) ->
- {modifyRequest,
- #'ModifyRequest'{object = Obj, modification = Mod}};
-gen_req({modify_dn, Entry, NewRDN, DelOldRDN,
- NewSup}) ->
- {modDNRequest,
- #'ModifyDNRequest'{entry = Entry, newrdn = NewRDN,
- deleteoldrdn = DelOldRDN, newSuperior = NewSup}};
-gen_req({modify_passwd, DN, Passwd}) ->
- {ok, ReqVal} = asn1rt:encode('ELDAPv3',
- 'PasswdModifyRequestValue',
- #'PasswdModifyRequestValue'{userIdentity = DN,
- newPasswd =
- Passwd}),
- {extendedReq,
- #'ExtendedRequest'{requestName = ?passwdModifyOID,
- requestValue = iolist_to_binary(ReqVal)}};
-gen_req({bind, RootDN, Passwd}) ->
- {bindRequest,
- #'BindRequest'{version = ?LDAP_VERSION, name = RootDN,
- authentication = {simple, Passwd}}}.
-
-%%-----------------------------------------------------------------------
-%% recvd_packet
-%% Deals with incoming packets in the active state
-%% Will return one of:
-%% {ok, NewS} - Don't reply to client yet as this is part of a search
-%% result and we haven't got all the answers yet.
-%% {reply, Result, From, NewS} - Reply with result to client From
-%% {error, Reason}
-%% {'EXIT', Reason} - Broke
-%%-----------------------------------------------------------------------
-recvd_packet(Pkt, S) ->
- case asn1rt:decode('ELDAPv3', 'LDAPMessage', Pkt) of
- {ok, Msg} ->
- Op = Msg#'LDAPMessage'.protocolOp,
- ?DEBUG("~p", [Op]),
- Dict = S#eldap.dict,
- Id = Msg#'LDAPMessage'.messageID,
- {Timer, From, Name, Result_so_far} = get_op_rec(Id,
- Dict),
- Answer = case {Name, Op} of
- {searchRequest, {searchResEntry, R}}
- when is_record(R, 'SearchResultEntry') ->
- New_dict = dict:append(Id, R, Dict),
- {ok, S#eldap{dict = New_dict}};
- {searchRequest, {searchResDone, Result}} ->
- Reason = Result#'LDAPResult'.resultCode,
- if Reason == success; Reason == sizeLimitExceeded ->
- {Res, Ref} = polish(Result_so_far),
- New_dict = dict:erase(Id, Dict),
- cancel_timer(Timer),
- {reply,
- #eldap_search_result{entries = Res,
- referrals = Ref},
- From, S#eldap{dict = New_dict}};
- true ->
- New_dict = dict:erase(Id, Dict),
- cancel_timer(Timer),
- {reply, {error, Reason}, From,
- S#eldap{dict = New_dict}}
- end;
- {searchRequest, {searchResRef, R}} ->
- New_dict = dict:append(Id, R, Dict),
- {ok, S#eldap{dict = New_dict}};
- {addRequest, {addResponse, Result}} ->
- New_dict = dict:erase(Id, Dict),
- cancel_timer(Timer),
- Reply = check_reply(Result, From),
- {reply, Reply, From, S#eldap{dict = New_dict}};
- {delRequest, {delResponse, Result}} ->
- New_dict = dict:erase(Id, Dict),
- cancel_timer(Timer),
- Reply = check_reply(Result, From),
- {reply, Reply, From, S#eldap{dict = New_dict}};
- {modifyRequest, {modifyResponse, Result}} ->
- New_dict = dict:erase(Id, Dict),
- cancel_timer(Timer),
- Reply = check_reply(Result, From),
- {reply, Reply, From, S#eldap{dict = New_dict}};
- {modDNRequest, {modDNResponse, Result}} ->
- New_dict = dict:erase(Id, Dict),
- cancel_timer(Timer),
- Reply = check_reply(Result, From),
- {reply, Reply, From, S#eldap{dict = New_dict}};
- {bindRequest, {bindResponse, Result}} ->
- New_dict = dict:erase(Id, Dict),
- cancel_timer(Timer),
- Reply = check_bind_reply(Result, From),
- {reply, Reply, From, S#eldap{dict = New_dict}};
- {extendedReq, {extendedResp, Result}} ->
- New_dict = dict:erase(Id, Dict),
- cancel_timer(Timer),
- Reply = check_extended_reply(Result, From),
- {reply, Reply, From, S#eldap{dict = New_dict}};
- {OtherName, OtherResult} ->
- New_dict = dict:erase(Id, Dict),
- cancel_timer(Timer),
- {reply,
- {error, {invalid_result, OtherName, OtherResult}},
- From, S#eldap{dict = New_dict}}
- end,
- {response, Answer, Name};
- Error -> Error
- end.
-
-check_reply(#'LDAPResult'{resultCode = success},
- _From) ->
- ok;
-check_reply(#'LDAPResult'{resultCode = Reason},
- _From) ->
- {error, Reason};
-check_reply(Other, _From) -> {error, Other}.
-
-check_bind_reply(#'BindResponse'{resultCode = success},
- _From) ->
- ok;
-check_bind_reply(#'BindResponse'{resultCode = Reason},
- _From) ->
- {error, Reason};
-check_bind_reply(Other, _From) -> {error, Other}.
-
-%% TODO: process reply depending on requestName:
-%% this requires BER-decoding of #'ExtendedResponse'.response
-check_extended_reply(#'ExtendedResponse'{resultCode =
- success},
- _From) ->
- ok;
-check_extended_reply(#'ExtendedResponse'{resultCode =
- Reason},
- _From) ->
- {error, Reason};
-check_extended_reply(Other, _From) -> {error, Other}.
-
-get_op_rec(Id, Dict) ->
- case dict:find(Id, Dict) of
- {ok, [{Timer, _Command, From, Name} | Res]} ->
- {Timer, From, Name, Res};
- error -> throw({error, unkown_id})
- end.
-
-%%-----------------------------------------------------------------------
-%% recvd_wait_bind_response packet
-%% Deals with incoming packets in the wait_bind_response state
-%% Will return one of:
-%% bound - Success - move to active state
-%% {fail_bind, Reason} - Failed
-%% {error, Reason}
-%% {'EXIT', Reason} - Broken packet
-%%-----------------------------------------------------------------------
-recvd_wait_bind_response(Pkt, S) ->
- case asn1rt:decode('ELDAPv3', 'LDAPMessage', Pkt) of
- {ok, Msg} ->
- ?DEBUG("~p", [Msg]),
- check_id(S#eldap.id, Msg#'LDAPMessage'.messageID),
- case Msg#'LDAPMessage'.protocolOp of
- {bindResponse, Result} ->
- case Result#'BindResponse'.resultCode of
- success -> bound;
- Error -> {fail_bind, Error}
- end
- end;
- Else -> {fail_bind, Else}
- end.
-
-check_id(Id, Id) -> ok;
-check_id(_, _) -> throw({error, wrong_bind_id}).
-
-%%-----------------------------------------------------------------------
-%% General Helpers
-%%-----------------------------------------------------------------------
-
-cancel_timer(Timer) ->
- erlang:cancel_timer(Timer),
- receive {timeout, Timer, _} -> ok after 0 -> ok end.
-
-
-close_and_retry(S, Timeout) ->
- catch (S#eldap.sockmod):close(S#eldap.fd),
- Queue = dict:fold(fun (_Id,
- [{Timer, Command, From, _Name} | _], Q) ->
- cancel_timer(Timer),
- queue:in_r({Command, From}, Q);
- (_, _, Q) -> Q
- end,
- S#eldap.req_q, S#eldap.dict),
- erlang:send_after(Timeout, self(),
- {timeout, retry_connect}),
- S#eldap{fd = undefined, req_q = Queue, dict = dict:new()}.
-
-close_and_retry(S) ->
- close_and_retry(S, ?RETRY_TIMEOUT).
-
-report_bind_failure(Host, Port, Reason) ->
- ?WARNING_MSG("LDAP bind failed on ~s:~p~nReason: ~p",
- [Host, Port, Reason]).
-
-%%-----------------------------------------------------------------------
-%% Sort out timed out commands
-%%-----------------------------------------------------------------------
-cmd_timeout(Timer, Id, S) ->
- Dict = S#eldap.dict,
- case dict:find(Id, Dict) of
- {ok, [{Timer, _Command, From, Name} | Res]} ->
- case Name of
- searchRequest ->
- {Res1, Ref1} = polish(Res),
- New_dict = dict:erase(Id, Dict),
- {reply, From,
- {timeout,
- #eldap_search_result{entries = Res1, referrals = Ref1}},
- S#eldap{dict = New_dict}};
- _ ->
- New_dict = dict:erase(Id, Dict),
- {reply, From, {error, timeout},
- S#eldap{dict = New_dict}}
- end;
- error -> {error, timed_out_cmd_not_in_dict}
- end.
-
-%%-----------------------------------------------------------------------
-%% Common stuff for results
-%%-----------------------------------------------------------------------
-%%%
-%%% Polish the returned search result
-%%%
-
-polish(Entries) -> polish(Entries, [], []).
-
-polish([H | T], Res, Ref)
- when is_record(H, 'SearchResultEntry') ->
- ObjectName = H#'SearchResultEntry'.objectName,
- F = fun ({_, A, V}) -> {A, V} end,
- Attrs = lists:map(F, H#'SearchResultEntry'.attributes),
- polish(T,
- [#eldap_entry{object_name = ObjectName,
- attributes = Attrs}
- | Res],
- Ref);
-polish([H | T], Res,
- Ref) -> % No special treatment of referrals at the moment.
- polish(T, Res, [H | Ref]);
-polish([], Res, Ref) -> {Res, Ref}.
-
-%%-----------------------------------------------------------------------
-%% Connect to next server in list and attempt to bind to it.
-%%-----------------------------------------------------------------------
-connect_bind(S) ->
- Host = next_host(S#eldap.host, S#eldap.hosts),
- ?INFO_MSG("LDAP connection on ~s:~p",
- [Host, S#eldap.port]),
- Opts = if S#eldap.tls == tls ->
- [{packet, asn1}, {active, true}, {keepalive, true},
- binary
- | S#eldap.tls_options];
- true ->
- [{packet, asn1}, {active, true}, {keepalive, true},
- {send_timeout, ?SEND_TIMEOUT}, binary]
- end,
- HostS = binary_to_list(Host),
- SocketData = case S#eldap.tls of
- tls ->
- SockMod = ssl, ssl:connect(HostS, S#eldap.port, Opts);
- %% starttls -> %% TODO: Implement STARTTLS;
- _ ->
- SockMod = gen_tcp,
- gen_tcp:connect(HostS, S#eldap.port, Opts)
- end,
- case SocketData of
- {ok, Socket} ->
- case bind_request(Socket, S#eldap{sockmod = SockMod}) of
- {ok, NewS} ->
- Timer = erlang:start_timer(?BIND_TIMEOUT, self(),
- {timeout, bind_timeout}),
- {ok, wait_bind_response,
- NewS#eldap{fd = Socket, sockmod = SockMod, host = Host,
- bind_timer = Timer}};
- {error, Reason} ->
- report_bind_failure(Host, S#eldap.port, Reason),
- NewS = close_and_retry(S),
- {ok, connecting, NewS#eldap{host = Host}}
- end;
- {error, Reason} ->
- ?ERROR_MSG("LDAP connection failed:~n** Server: "
- "~s:~p~n** Reason: ~p~n** Socket options: ~p",
- [Host, S#eldap.port, Reason, Opts]),
- NewS = close_and_retry(S),
- {ok, connecting, NewS#eldap{host = Host}}
- end.
-
-bind_request(Socket, S) ->
- Id = bump_id(S),
- Req = #'BindRequest'{version = S#eldap.version,
- name = S#eldap.rootdn,
- authentication = {simple, S#eldap.passwd}},
- Message = #'LDAPMessage'{messageID = Id,
- protocolOp = {bindRequest, Req}},
- ?DEBUG("Bind Request Message:~p~n", [Message]),
- {ok, Bytes} = asn1rt:encode('ELDAPv3', 'LDAPMessage',
- Message),
- case (S#eldap.sockmod):send(Socket, Bytes) of
- ok -> {ok, S#eldap{id = Id}};
- Error -> Error
- end.
-
-%% Given last tried Server, find next one to try
-next_host(undefined, [H | _]) ->
- H; % First time, take first
-next_host(Host,
- Hosts) -> % Find next in turn
- next_host(Host, Hosts, Hosts).
-
-%%% --------------------------------------------------------------------
-%%% Verify the input data
-%%% --------------------------------------------------------------------
-%%% --------------------------------------------------------------------
-%%% Get and Validate the initial configuration
-%%% --------------------------------------------------------------------
-%% get_atom(Key, List) ->
-%% case lists:keysearch(Key, 1, List) of
-%% {value, {Key, Value}} when is_atom(Value) ->
-%% Value;
-%% {value, {Key, _Value}} ->
-%% throw({error, "Bad Value in Config for " ++ atom_to_list(Key)});
-%% false ->
-%% throw({error, "No Entry in Config for " ++ atom_to_list(Key)})
-%% end.
-%%% --------------------------------------------------------------------
-%%% Other Stuff
-%%% --------------------------------------------------------------------
-next_host(Host, [Host], Hosts) ->
- hd(Hosts); % Wrap back to first
-next_host(Host, [Host | Tail], _Hosts) ->
- hd(Tail); % Take next
-next_host(_Host, [], Hosts) ->
- hd(Hosts); % Never connected before? (shouldn't happen)
-next_host(Host, [_ | T], Hosts) ->
- next_host(Host, T, Hosts).
-
-bump_id(#eldap{id = Id})
- when Id > (?MAX_TRANSACTION_ID) ->
- ?MIN_TRANSACTION_ID;
-bump_id(#eldap{id = Id}) -> Id + 1.
diff --git a/src/eldap/eldap.hrl b/src/eldap/eldap.hrl
deleted file mode 100644
index 30ec0e954..000000000
--- a/src/eldap/eldap.hrl
+++ /dev/null
@@ -1,64 +0,0 @@
-%%%----------------------------------------------------------------------
-%%%
-%%% ejabberd, Copyright (C) 2002-2013 ProcessOne
-%%%
-%%% This program is free software; you can redistribute it and/or
-%%% modify it under the terms of the GNU General Public License as
-%%% published by the Free Software Foundation; either version 2 of the
-%%% License, or (at your option) any later version.
-%%%
-%%% This program is distributed in the hope that it will be useful,
-%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
-%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-%%% General Public License for more details.
-%%%
-%%% You should have received a copy of the GNU General Public License
-%%% along with this program; if not, write to the Free Software
-%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-%%% 02111-1307 USA
-%%%
-%%%----------------------------------------------------------------------
-
--define(LDAP_PORT, 389).
-
--define(LDAPS_PORT, 636).
-
--type scope() :: baseObject | singleLevel | wholeSubtree.
-
--record(eldap_search,
- {scope = wholeSubtree :: scope(),
- base = <<"">> :: binary(),
- filter :: eldap:filter(),
- limit = 0 :: non_neg_integer(),
- attributes = [] :: [binary()],
- types_only = false :: boolean(),
- deref_aliases = neverDerefAliases :: neverDerefAliases |
- derefInSearching |
- derefFindingBaseObj |
- derefAlways,
- timeout = 0 :: non_neg_integer()}).
-
--record(eldap_search_result, {entries = [] :: [eldap_entry()],
- referrals = [] :: list()}).
-
--record(eldap_entry, {object_name = <<>> :: binary(),
- attributes = [] :: [{binary(), [binary()]}]}).
-
--type tlsopts() :: [{encrypt, tls | starttls | none} |
- {tls_cacertfile, binary() | undefined} |
- {tls_depth, non_neg_integer() | undefined} |
- {tls_verify, hard | soft | false}].
-
--record(eldap_config, {servers = [] :: [binary()],
- backups = [] :: [binary()],
- tls_options = [] :: tlsopts(),
- port = ?LDAP_PORT :: inet:port_number(),
- dn = <<"">> :: binary(),
- password = <<"">> :: binary(),
- base = <<"">> :: binary(),
- deref_aliases = never :: never | searching |
- finding | always}).
-
--type eldap_config() :: #eldap_config{}.
--type eldap_search() :: #eldap_search{}.
--type eldap_entry() :: #eldap_entry{}.
diff --git a/src/eldap/eldap_filter.erl b/src/eldap/eldap_filter.erl
deleted file mode 100644
index 6771fc2af..000000000
--- a/src/eldap/eldap_filter.erl
+++ /dev/null
@@ -1,191 +0,0 @@
-%%%----------------------------------------------------------------------
-%%% File: eldap_filter.erl
-%%% Purpose: Converts String Representation of
-%%% LDAP Search Filter (RFC 2254)
-%%% to eldap's representation of filter
-%%% Author: Evgeniy Khramtsov <ekhramtsov@process-one.net>
-%%%
-%%%
-%%% ejabberd, Copyright (C) 2002-2013 ProcessOne
-%%%
-%%% This program is free software; you can redistribute it and/or
-%%% modify it under the terms of the GNU General Public License as
-%%% published by the Free Software Foundation; either version 2 of the
-%%% License, or (at your option) any later version.
-%%%
-%%% This program is distributed in the hope that it will be useful,
-%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
-%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-%%% General Public License for more details.
-%%%
-%%% You should have received a copy of the GNU General Public License
-%%% along with this program; if not, write to the Free Software
-%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-%%% 02111-1307 USA
-%%%
-%%%----------------------------------------------------------------------
--module(eldap_filter).
-
-%% TODO: remove this when new regexp module will be used
--export([parse/1, parse/2, do_sub/2]).
-
-%%====================================================================
-%% API
-%%====================================================================
-%%%-------------------------------------------------------------------
-%%% Arity: parse/1
-%%% Function: parse(RFC2254_Filter) -> {ok, EldapFilter} |
-%%% {error, bad_filter}
-%%%
-%%% RFC2254_Filter = string().
-%%%
-%%% Description: Converts String Representation of LDAP Search Filter (RFC 2254)
-%%% to eldap's representation of filter.
-%%%
-%%% Example:
-%%% > eldap_filter:parse("(&(!(uid<=100))(mail=*))").
-%%%
-%%% {ok,{'and',[{'not',{lessOrEqual,{'AttributeValueAssertion',"uid","100"}}},
-%%% {present,"mail"}]}}
-%%%-------------------------------------------------------------------
--spec parse(binary()) -> {error, any()} | {ok, eldap:filter()}.
-
-parse(L) ->
- parse(L, []).
-
-%%%-------------------------------------------------------------------
-%%% Arity: parse/2
-%%% Function: parse(RFC2254_Filter, [SubstValue |...]) ->
-%%% {ok, EldapFilter} |
-%%% {error, bad_filter} |
-%%% {error, bad_regexp} |
-%%% {error, max_substitute_recursion}
-%%%
-%%% SubstValue = {RegExp, Value} | {RegExp, Value, N},
-%%% RFC2254_Filter = RegExp = Value = string(),
-%%% N = integer().
-%%%
-%%% Description: The same as parse/1, but substitutes N or all occurences
-%%% of RegExp with Value *after* parsing.
-%%%
-%%% Example:
-%%% > eldap_filter:parse(
-%%% "(|(mail=%u@%d)(jid=%u@%d))",
-%%% [{"%u", "xramtsov"},{"%d","gmail.com"}]).
-%%%
-%%% {ok,{'or',[{equalityMatch,{'AttributeValueAssertion',
-%%% "mail",
-%%% "xramtsov@gmail.com"}},
-%%% {equalityMatch,{'AttributeValueAssertion',
-%%% "jid",
-%%% "xramtsov@gmail.com"}}]}}
-%%%-------------------------------------------------------------------
--spec parse(binary(), [{binary(), binary()} |
- {binary(), binary(), pos_integer()}]) ->
- {error, any()} | {ok, eldap:filter()}.
-
-parse(L, SList) ->
- case catch eldap_filter_yecc:parse(scan(binary_to_list(L), SList)) of
- {'EXIT', _} = Err ->
- {error, Err};
- {error, {_, _, Msg}} ->
- {error, Msg};
- {ok, Result} ->
- {ok, Result};
- {regexp, Err} ->
- {error, Err}
- end.
-
-%%====================================================================
-%% Internal functions
-%%====================================================================
--define(do_scan(L), scan(Rest, <<>>, [{L, 1} | check(Buf, S) ++ Result], L, S)).
-
-scan(L, SList) ->
- scan(L, <<"">>, [], undefined, SList).
-
-scan("=*)" ++ Rest, Buf, Result, '(', S) ->
- scan(Rest, <<>>, [{')', 1}, {'=*', 1} | check(Buf, S) ++ Result], ')', S);
-scan(":dn" ++ Rest, Buf, Result, '(', S) -> ?do_scan(':dn');
-scan(":=" ++ Rest, Buf, Result, '(', S) -> ?do_scan(':=');
-scan(":=" ++ Rest, Buf, Result, ':dn', S) -> ?do_scan(':=');
-scan(":=" ++ Rest, Buf, Result, ':', S) -> ?do_scan(':=');
-scan("~=" ++ Rest, Buf, Result, '(', S) -> ?do_scan('~=');
-scan(">=" ++ Rest, Buf, Result, '(', S) -> ?do_scan('>=');
-scan("<=" ++ Rest, Buf, Result, '(', S) -> ?do_scan('<=');
-scan("=" ++ Rest, Buf, Result, '(', S) -> ?do_scan('=');
-scan(":" ++ Rest, Buf, Result, '(', S) -> ?do_scan(':');
-scan(":" ++ Rest, Buf, Result, ':dn', S) -> ?do_scan(':');
-scan("&" ++ Rest, Buf, Result, '(', S) when Buf==<<"">> -> ?do_scan('&');
-scan("|" ++ Rest, Buf, Result, '(', S) when Buf==<<"">> -> ?do_scan('|');
-scan("!" ++ Rest, Buf, Result, '(', S) when Buf==<<"">> -> ?do_scan('!');
-scan("*" ++ Rest, Buf, Result, '*', S) -> ?do_scan('*');
-scan("*" ++ Rest, Buf, Result, '=', S) -> ?do_scan('*');
-scan("(" ++ Rest, Buf, Result, _, S) -> ?do_scan('(');
-scan(")" ++ Rest, Buf, Result, _, S) -> ?do_scan(')');
-scan([Letter | Rest], Buf, Result, PreviosAtom, S) ->
- scan(Rest, <<Buf/binary, Letter>>, Result, PreviosAtom, S);
-scan([], Buf, Result, _, S) ->
- lists:reverse(check(Buf, S) ++ Result).
-
-check(<<>>, _) ->
- [];
-check(Buf, S) ->
- [{str, 1, binary_to_list(do_sub(Buf, S))}].
-
--define(MAX_RECURSION, 100).
-
--spec do_sub(binary(), [{binary(), binary()} |
- {binary(), binary(), pos_integer()}]) -> binary().
-
-do_sub(S, []) ->
- S;
-do_sub(<<>>, _) ->
- <<>>;
-do_sub(S, [{RegExp, New} | T]) ->
- Result = do_sub(S, {RegExp, replace_amps(New)}, 1),
- do_sub(Result, T);
-do_sub(S, [{RegExp, New, Times} | T]) ->
- Result = do_sub(S, {RegExp, replace_amps(New), Times}, 1),
- do_sub(Result, T).
-
-do_sub(S, {RegExp, New}, Iter) ->
- case ejabberd_regexp:run(S, RegExp) of
- match ->
- case ejabberd_regexp:replace(S, RegExp, New) of
- NewS when Iter =< ?MAX_RECURSION ->
- do_sub(NewS, {RegExp, New}, Iter+1);
- _NewS when Iter > ?MAX_RECURSION ->
- erlang:error(max_substitute_recursion)
- end;
- nomatch ->
- S;
- _ ->
- erlang:error(bad_regexp)
- end;
-
-do_sub(S, {_, _, N}, _) when N<1 ->
- S;
-
-do_sub(S, {RegExp, New, Times}, Iter) ->
- case ejabberd_regexp:run(S, RegExp) of
- match ->
- case ejabberd_regexp:replace(S, RegExp, New) of
- NewS when Iter < Times ->
- do_sub(NewS, {RegExp, New, Times}, Iter+1);
- NewS ->
- NewS
- end;
- nomatch ->
- S;
- _ ->
- erlang:error(bad_regexp)
- end.
-
-replace_amps(Bin) ->
- list_to_binary(
- lists:flatmap(
- fun($&) -> "\\&";
- ($\\) -> "\\\\";
- (Chr) -> [Chr]
- end, binary_to_list(Bin))).
diff --git a/src/eldap/eldap_filter_yecc.yrl b/src/eldap/eldap_filter_yecc.yrl
deleted file mode 100644
index a70ea3e74..000000000
--- a/src/eldap/eldap_filter_yecc.yrl
+++ /dev/null
@@ -1,71 +0,0 @@
-Nonterminals
-filter filtercomp filterlist item
-simple present substring extensible
-initial any final matchingrule xattr
-attr value.
-
-Terminals str
-'(' ')' '&' '|' '!' '=' '~=' '>=' '<=' '=*' '*' ':dn' ':' ':='.
-
-Rootsymbol filter.
-
-filter -> '(' filtercomp ')': '$2'.
-filtercomp -> '&' filterlist: 'and'('$2').
-filtercomp -> '|' filterlist: 'or'('$2').
-filtercomp -> '!' filter: 'not'('$2').
-filtercomp -> item: '$1'.
-filterlist -> filter: '$1'.
-filterlist -> filter filterlist: flatten(['$1', '$2']).
-
-item -> simple: '$1'.
-item -> present: '$1'.
-item -> substring: '$1'.
-item -> extensible: '$1'.
-
-simple -> attr '=' value: equal('$1', '$3').
-simple -> attr '~=' value: approx('$1', '$3').
-simple -> attr '>=' value: greater('$1', '$3').
-simple -> attr '<=' value: less('$1', '$3').
-
-present -> attr '=*': present('$1').
-
-substring -> attr '=' initial '*' any: substrings('$1', ['$3', '$5']).
-substring -> attr '=' '*' any final: substrings('$1', ['$4', '$5']).
-substring -> attr '=' initial '*' any final: substrings('$1', ['$3', '$5', '$6']).
-substring -> attr '=' '*' any: substrings('$1', ['$4']).
-any -> any value '*': 'any'('$1', '$2').
-any -> '$empty': [].
-initial -> value: initial('$1').
-final -> value: final('$1').
-
-extensible -> xattr ':dn' ':' matchingrule ':=' value: extensible('$6', ['$1', '$4']).
-extensible -> xattr ':' matchingrule ':=' value: extensible('$5', ['$1', '$3']).
-extensible -> xattr ':dn' ':=' value: extensible('$4', ['$1']).
-extensible -> xattr ':=' value: extensible('$3', ['$1']).
-extensible -> ':dn' ':' matchingrule ':=' value: extensible('$5', ['$3']).
-extensible -> ':' matchingrule ':=' value: extensible('$4', ['$2']).
-xattr -> value: xattr('$1').
-matchingrule -> value: matchingrule('$1').
-
-attr -> str: value_of('$1').
-value -> str: value_of('$1').
-
-Erlang code.
-
-'and'(Value) -> eldap:'and'(Value).
-'or'(Value) -> eldap:'or'(Value).
-'not'(Value) -> eldap:'not'(Value).
-equal(Desc, Value) -> eldap:equalityMatch(Desc, Value).
-approx(Desc, Value) -> eldap:approxMatch(Desc, Value).
-greater(Desc, Value) -> eldap:greaterOrEqual(Desc, Value).
-less(Desc, Value) -> eldap:lessOrEqual(Desc, Value).
-present(Value) -> eldap:present(Value).
-extensible(Value, Opts) -> eldap:extensibleMatch(Value, Opts).
-substrings(Desc, ValueList) -> eldap:substrings(Desc, flatten(ValueList)).
-initial(Value) -> {initial, Value}.
-final(Value) -> {final, Value}.
-'any'(Token, Value) -> [Token, {any, Value}].
-xattr(Value) -> {type, Value}.
-matchingrule(Value) -> {matchingRule, Value}.
-value_of(Token) -> iolist_to_binary(element(3, Token)).
-flatten(List) -> lists:flatten(List).
diff --git a/src/eldap/eldap_pool.erl b/src/eldap/eldap_pool.erl
deleted file mode 100644
index 1f52999ef..000000000
--- a/src/eldap/eldap_pool.erl
+++ /dev/null
@@ -1,86 +0,0 @@
-%%%-------------------------------------------------------------------
-%%% File : eldap_pool.erl
-%%% Author : Evgeniy Khramtsov <xram@jabber.ru>
-%%% Purpose : LDAP connections pool
-%%% Created : 12 Nov 2006 by Evgeniy Khramtsov <xram@jabber.ru>
-%%%
-%%%
-%%% ejabberd, Copyright (C) 2002-2013 ProcessOne
-%%%
-%%% This program is free software; you can redistribute it and/or
-%%% modify it under the terms of the GNU General Public License as
-%%% published by the Free Software Foundation; either version 2 of the
-%%% License, or (at your option) any later version.
-%%%
-%%% This program is distributed in the hope that it will be useful,
-%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
-%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-%%% General Public License for more details.
-%%%
-%%% You should have received a copy of the GNU General Public License
-%%% along with this program; if not, write to the Free Software
-%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-%%% 02111-1307 USA
-%%%
-%%%-------------------------------------------------------------------
-
--module(eldap_pool).
-
--author('xram@jabber.ru').
-
-%% API
--export([start_link/7, bind/3, search/2,
- modify_passwd/3]).
-
--include("ejabberd.hrl").
-
-%%====================================================================
-%% API
-%%====================================================================
-bind(PoolName, DN, Passwd) ->
- do_request(PoolName, {bind, [DN, Passwd]}).
-
-search(PoolName, Opts) ->
- do_request(PoolName, {search, [Opts]}).
-
-modify_passwd(PoolName, DN, Passwd) ->
- do_request(PoolName, {modify_passwd, [DN, Passwd]}).
-
-start_link(Name, Hosts, Backups, Port, Rootdn, Passwd,
- Opts) ->
- PoolName = make_id(Name),
- pg2:create(PoolName),
- lists:foreach(fun (Host) ->
- ID = list_to_binary(erlang:ref_to_list(make_ref())),
- case catch eldap:start_link(ID, [Host | Backups],
- Port, Rootdn, Passwd,
- Opts)
- of
- {ok, Pid} -> pg2:join(PoolName, Pid);
- Err ->
- ?INFO_MSG("Err = ~p", [Err]),
- error
- end
- end,
- Hosts).
-
-%%====================================================================
-%% Internal functions
-%%====================================================================
-do_request(Name, {F, Args}) ->
- case pg2:get_closest_pid(make_id(Name)) of
- Pid when is_pid(Pid) ->
- case catch apply(eldap, F, [Pid | Args]) of
- {'EXIT', {timeout, _}} ->
- ?ERROR_MSG("LDAP request failed: timed out", []);
- {'EXIT', Reason} ->
- ?ERROR_MSG("LDAP request failed: eldap:~p(~p)~nReason: ~p",
- [F, Args, Reason]),
- {error, Reason};
- Reply -> Reply
- end;
- Err -> Err
- end.
-
-make_id(Name) ->
- jlib:binary_to_atom(<<"eldap_pool_", Name/binary>>).
diff --git a/src/eldap/eldap_utils.erl b/src/eldap/eldap_utils.erl
deleted file mode 100644
index 2e149d8b6..000000000
--- a/src/eldap/eldap_utils.erl
+++ /dev/null
@@ -1,354 +0,0 @@
-%%%----------------------------------------------------------------------
-%%% File : eldap_utils.erl
-%%% Author : Mickael Remond <mremond@process-one.net>
-%%% Purpose : ejabberd LDAP helper functions
-%%% Created : 12 Oct 2006 by Mickael Remond <mremond@process-one.net>
-%%%
-%%%
-%%% ejabberd, Copyright (C) 2002-2013 ProcessOne
-%%%
-%%% This program is free software; you can redistribute it and/or
-%%% modify it under the terms of the GNU General Public License as
-%%% published by the Free Software Foundation; either version 2 of the
-%%% License, or (at your option) any later version.
-%%%
-%%% This program is distributed in the hope that it will be useful,
-%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
-%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-%%% General Public License for more details.
-%%%
-%%% You should have received a copy of the GNU General Public License
-%%% along with this program; if not, write to the Free Software
-%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-%%% 02111-1307 USA
-%%%
-%%%----------------------------------------------------------------------
-
--module(eldap_utils).
--author('mremond@process-one.net').
-
--export([generate_subfilter/1,
- find_ldap_attrs/2,
- get_ldap_attr/2,
- get_user_part/2,
- make_filter/2,
- get_state/2,
- case_insensitive_match/2,
- get_opt/3,
- get_opt/4,
- get_config/2,
- decode_octet_string/3,
- uids_domain_subst/2]).
-
--include("ejabberd.hrl").
--include("eldap.hrl").
-
-%% Generate an 'or' LDAP query on one or several attributes
-%% If there is only one attribute
-generate_subfilter([UID]) ->
- subfilter(UID);
-%% If there is several attributes
-generate_subfilter(UIDs) ->
- iolist_to_binary(["(|", [subfilter(UID) || UID <- UIDs], ")"]).
-%% Subfilter for a single attribute
-
-subfilter({UIDAttr, UIDAttrFormat}) ->
-%% The default UiDAttrFormat is %u
- <<$(, UIDAttr/binary, $=, UIDAttrFormat/binary, $)>>;
-%% The default UiDAttrFormat is <<"%u">>
-subfilter({UIDAttr}) ->
- <<$(, UIDAttr/binary, $=, "%u)">>.
-
-%% Not tail-recursive, but it is not very terribly.
-%% It stops finding on the first not empty value.
--spec find_ldap_attrs([{binary()} | {binary(), binary()}],
- [{binary(), [binary()]}]) -> <<>> | {binary(), binary()}.
-
-find_ldap_attrs([{Attr} | Rest], Attributes) ->
- find_ldap_attrs([{Attr, <<"%u">>} | Rest], Attributes);
-find_ldap_attrs([{Attr, Format} | Rest], Attributes) ->
- case get_ldap_attr(Attr, Attributes) of
- Value when is_binary(Value), Value /= <<>> ->
- {Value, Format};
- _ ->
- find_ldap_attrs(Rest, Attributes)
- end;
-find_ldap_attrs([], _) ->
- <<>>.
-
--spec get_ldap_attr(binary(), [{binary(), [binary()]}]) -> binary().
-
-get_ldap_attr(LDAPAttr, Attributes) ->
- Res = lists:filter(
- fun({Name, _}) ->
- case_insensitive_match(Name, LDAPAttr)
- end, Attributes),
- case Res of
- [{_, [Value|_]}] -> Value;
- _ -> <<>>
- end.
-
--spec get_user_part(binary(), binary()) -> {ok, binary()} | {error, badmatch}.
-
-get_user_part(String, Pattern) ->
- F = fun(S, P) ->
- First = str:str(P, <<"%u">>),
- TailLength = byte_size(P) - (First+1),
- str:sub_string(S, First, byte_size(S) - TailLength)
- end,
- case catch F(String, Pattern) of
- {'EXIT', _} ->
- {error, badmatch};
- Result ->
- case catch ejabberd_regexp:replace(Pattern, <<"%u">>, Result) of
- {'EXIT', _} ->
- {error, badmatch};
- StringRes ->
- case case_insensitive_match(StringRes, String) of
- true ->
- {ok, Result};
- false ->
- {error, badmatch}
- end
- end
- end.
-
--spec make_filter([{binary(), [binary()]}], [{binary(), binary()}]) -> any().
-
-make_filter(Data, UIDs) ->
- NewUIDs = [{U, eldap_filter:do_sub(
- UF, [{<<"%u">>, <<"*%u*">>, 1}])} || {U, UF} <- UIDs],
- Filter = lists:flatmap(
- fun({Name, [Value | _]}) ->
- case Name of
- <<"%u">> when Value /= <<"">> ->
- case eldap_filter:parse(
- generate_subfilter(NewUIDs),
- [{<<"%u">>, Value}]) of
- {ok, F} -> [F];
- _ -> []
- end;
- _ when Value /= <<"">> ->
- [eldap:substrings(
- Name,
- [{any, Value}])];
- _ ->
- []
- end
- end, Data),
- case Filter of
- [F] ->
- F;
- _ ->
- eldap:'and'(Filter)
- end.
-
--spec case_insensitive_match(binary(), binary()) -> boolean().
-
-case_insensitive_match(X, Y) ->
- X1 = str:to_lower(X),
- Y1 = str:to_lower(Y),
- if
- X1 == Y1 -> true;
- true -> false
- end.
-
-get_state(Server, Module) ->
- Proc = gen_mod:get_module_proc(Server, Module),
- gen_server:call(Proc, get_state).
-
-%% From the list of uids attribute:
-%% we look from alias domain (%d) and make the substitution
-%% with the actual host domain
-%% This help when you need to configure many virtual domains.
--spec uids_domain_subst(binary(), [{binary(), binary()}]) ->
- [{binary(), binary()}].
-
-uids_domain_subst(Host, UIDs) ->
- lists:map(fun({U,V}) ->
- {U, eldap_filter:do_sub(V,[{<<"%d">>, Host}])};
- (A) -> A
- end,
- UIDs).
-
--spec get_opt({atom(), binary()}, list(), fun()) -> any().
-
-get_opt({Key, Host}, Opts, F) ->
- get_opt({Key, Host}, Opts, F, undefined).
-
--spec get_opt({atom(), binary()}, list(), fun(), any()) -> any().
-
-get_opt({Key, Host}, Opts, F, Default) ->
- case gen_mod:get_opt(Key, Opts, F, undefined) of
- undefined ->
- ejabberd_config:get_local_option(
- {Key, Host}, F, Default);
- Val ->
- Val
- end.
-
--spec get_config(binary(), list()) -> eldap_config().
-
-get_config(Host, Opts) ->
- Servers = get_opt({ldap_servers, Host}, Opts,
- fun(L) ->
- [iolist_to_binary(H) || H <- L]
- end, [<<"localhost">>]),
- Backups = get_opt({ldap_backups, Host}, Opts,
- fun(L) ->
- [iolist_to_binary(H) || H <- L]
- end, []),
- Encrypt = get_opt({ldap_encrypt, Host}, Opts,
- fun(tls) -> tls;
- (starttls) -> starttls;
- (none) -> none
- end, none),
- TLSVerify = get_opt({ldap_tls_verify, Host}, Opts,
- fun(hard) -> hard;
- (soft) -> soft;
- (false) -> false
- end, false),
- TLSCAFile = get_opt({ldap_tls_cacertfile, Host}, Opts,
- fun iolist_to_binary/1),
- TLSDepth = get_opt({ldap_tls_depth, Host}, Opts,
- fun(I) when is_integer(I), I>=0 -> I end),
- Port = get_opt({ldap_port, Host}, Opts,
- fun(I) when is_integer(I), I>0 -> I end,
- case Encrypt of
- tls -> ?LDAPS_PORT;
- starttls -> ?LDAP_PORT;
- _ -> ?LDAP_PORT
- end),
- RootDN = get_opt({ldap_rootdn, Host}, Opts,
- fun iolist_to_binary/1,
- <<"">>),
- Password = get_opt({ldap_password, Host}, Opts,
- fun iolist_to_binary/1,
- <<"">>),
- Base = get_opt({ldap_base, Host}, Opts,
- fun iolist_to_binary/1,
- <<"">>),
- DerefAliases = get_opt({deref_aliases, Host}, Opts,
- fun(never) -> never;
- (searching) -> searching;
- (finding) -> finding;
- (always) -> always
- end, never),
- #eldap_config{servers = Servers,
- backups = Backups,
- tls_options = [{encrypt, Encrypt},
- {tls_verify, TLSVerify},
- {tls_cacertfile, TLSCAFile},
- {tls_depth, TLSDepth}],
- port = Port,
- dn = RootDN,
- password = Password,
- base = Base,
- deref_aliases = DerefAliases}.
-
-%%----------------------------------------
-%% Borrowed from asn1rt_ber_bin_v2.erl
-%%----------------------------------------
-
-%%% The tag-number for universal types
--define(N_BOOLEAN, 1).
--define(N_INTEGER, 2).
--define(N_BIT_STRING, 3).
--define(N_OCTET_STRING, 4).
--define(N_NULL, 5).
--define(N_OBJECT_IDENTIFIER, 6).
--define(N_OBJECT_DESCRIPTOR, 7).
--define(N_EXTERNAL, 8).
--define(N_REAL, 9).
--define(N_ENUMERATED, 10).
--define(N_EMBEDDED_PDV, 11).
--define(N_SEQUENCE, 16).
--define(N_SET, 17).
--define(N_NumericString, 18).
--define(N_PrintableString, 19).
--define(N_TeletexString, 20).
--define(N_VideotexString, 21).
--define(N_IA5String, 22).
--define(N_UTCTime, 23).
--define(N_GeneralizedTime, 24).
--define(N_GraphicString, 25).
--define(N_VisibleString, 26).
--define(N_GeneralString, 27).
--define(N_UniversalString, 28).
--define(N_BMPString, 30).
-
-decode_octet_string(Buffer, Range, Tags) ->
-% NewTags = new_tags(HasTag,#tag{class=?UNIVERSAL,number=?N_OCTET_STRING}),
- decode_restricted_string(Buffer, Range, Tags).
-
-decode_restricted_string(Tlv, Range, TagsIn) ->
- Val = match_tags(Tlv, TagsIn),
- Val2 =
- case Val of
- PartList = [_H|_T] -> % constructed val
- collect_parts(PartList);
- Bin ->
- Bin
- end,
- check_and_convert_restricted_string(Val2, Range).
-
-check_and_convert_restricted_string(Val, Range) ->
- {StrLen,NewVal} = if is_binary(Val) ->
- {size(Val), Val};
- true ->
- {length(Val), list_to_binary(Val)}
- end,
- case Range of
- [] -> % No length constraint
- NewVal;
- {Lb,Ub} when StrLen >= Lb, Ub >= StrLen -> % variable length constraint
- NewVal;
- {{Lb,_Ub},[]} when StrLen >= Lb ->
- NewVal;
- {{Lb,_Ub},_Ext=[Min|_]} when StrLen >= Lb; StrLen >= Min ->
- NewVal;
- {{Lb1,Ub1},{Lb2,Ub2}} when StrLen >= Lb1, StrLen =< Ub1;
- StrLen =< Ub2, StrLen >= Lb2 ->
- NewVal;
- StrLen -> % fixed length constraint
- NewVal;
- {_,_} ->
- exit({error,{asn1,{length,Range,Val}}});
- _Len when is_integer(_Len) ->
- exit({error,{asn1,{length,Range,Val}}});
- _ -> % some strange constraint that we don't support yet
- NewVal
- end.
-
-%%----------------------------------------
-%% Decode the in buffer to bits
-%%----------------------------------------
-match_tags({T,V},[T]) ->
- V;
-match_tags({T,V}, [T|Tt]) ->
- match_tags(V,Tt);
-match_tags([{T,V}],[T|Tt]) ->
- match_tags(V, Tt);
-match_tags(Vlist = [{T,_V}|_], [T]) ->
- Vlist;
-match_tags(Tlv, []) ->
- Tlv;
-match_tags({Tag,_V},[T|_Tt]) ->
- {error,{asn1,{wrong_tag,{Tag,T}}}}.
-
-collect_parts(TlvList) ->
- collect_parts(TlvList,[]).
-
-collect_parts([{_,L}|Rest],Acc) when is_list(L) ->
- collect_parts(Rest,[collect_parts(L)|Acc]);
-collect_parts([{?N_BIT_STRING,<<Unused,Bits/binary>>}|Rest],_Acc) ->
- collect_parts_bit(Rest,[Bits],Unused);
-collect_parts([{_T,V}|Rest],Acc) ->
- collect_parts(Rest,[V|Acc]);
-collect_parts([],Acc) ->
- list_to_binary(lists:reverse(Acc)).
-
-collect_parts_bit([{?N_BIT_STRING,<<Unused,Bits/binary>>}|Rest],Acc,Uacc) ->
- collect_parts_bit(Rest,[Bits|Acc],Unused+Uacc);
-collect_parts_bit([],Acc,Uacc) ->
- list_to_binary([Uacc|lists:reverse(Acc)]).