From 6446032a1b248c32c5ae89f1d362d8b0a6b09f7b Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Fri, 19 Feb 2016 13:02:33 +0100 Subject: eldap: unbindRequest --- lib/eldap/doc/src/eldap.xml | 3 ++- lib/eldap/src/eldap.erl | 20 +++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/eldap/doc/src/eldap.xml b/lib/eldap/doc/src/eldap.xml index 8f4479a730..7c4b76819f 100644 --- a/lib/eldap/doc/src/eldap.xml +++ b/lib/eldap/doc/src/eldap.xml @@ -88,7 +88,8 @@ filter() See present/1, substrings/2, Handle = handle() -

Shutdown the connection.

+

Shutdown the connection after sending an unbindRequest to the server. If the connection is tls the connection + will be closed with ssl:close/1, otherwise with gen_tcp:close/1.

diff --git a/lib/eldap/src/eldap.erl b/lib/eldap/src/eldap.erl index ae47c815c9..3e3f945e63 100644 --- a/lib/eldap/src/eldap.erl +++ b/lib/eldap/src/eldap.erl @@ -531,6 +531,7 @@ loop(Cpid, Data) -> ?MODULE:loop(Cpid, NewData); {_From, close} -> + {no_reply,_NewData} = do_unbind(Data), unlink(Cpid), exit(closed); @@ -578,7 +579,6 @@ loop(Cpid, Data) -> %%% -------------------------------------------------------------------- %%% startTLS Request %%% -------------------------------------------------------------------- - do_start_tls(Data=#eldap{using_tls=true}, _, _) -> {{error,tls_already_started}, Data}; do_start_tls(Data=#eldap{fd=FD} , TlsOptions, Timeout) -> @@ -897,6 +897,24 @@ do_modify_dn_0(Data, Entry, NewRDN, DelOldRDN, NewSup) -> log2(Data, "modify DN reply = ~p~n", [Resp]), check_reply(Data#eldap{id = Id}, Resp, modDNResponse). +%%%-------------------------------------------------------------------- +%%% unbindRequest +%%%-------------------------------------------------------------------- +do_unbind(Data) -> + Req = "", + log2(Data, "unbind request = ~p (has no reply)~n", [Req]), + send_request(Data#eldap.fd, Data, Data#eldap.id, {unbindRequest, Req}), + case Data#eldap.using_tls of + true -> ssl:close(Data#eldap.fd); + false -> gen_tcp:close(Data#eldap.fd) + end, + {no_reply, Data#eldap{binddn = (#eldap{})#eldap.binddn, + passwd = (#eldap{})#eldap.passwd, + fd = (#eldap{})#eldap.fd, + using_tls = false + }}. + + %%% -------------------------------------------------------------------- %%% Send an LDAP request and receive the answer %%% -------------------------------------------------------------------- -- cgit v1.2.3 From 445647da64872f1728c7dc180542b693e7bf866e Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Fri, 19 Feb 2016 16:08:30 +0100 Subject: eldap: referral resultCode --- lib/eldap/doc/src/eldap.xml | 97 ++++++++++++++++++++++++++---------- lib/eldap/src/eldap.erl | 68 ++++++++++++++++++------- lib/eldap/test/eldap_basic_SUITE.erl | 94 ++++++++++++++++++++++++++++++---- 3 files changed, 206 insertions(+), 53 deletions(-) (limited to 'lib') diff --git a/lib/eldap/doc/src/eldap.xml b/lib/eldap/doc/src/eldap.xml index 8f4479a730..70add6619d 100644 --- a/lib/eldap/doc/src/eldap.xml +++ b/lib/eldap/doc/src/eldap.xml @@ -4,7 +4,7 @@
- 20122013 + 20122016 Ericsson AB. All Rights Reserved. @@ -29,7 +29,7 @@ B
eldap - Eldap Functions + LDAP Client

This module provides a client api to the Lightweight Directory Access Protocol (LDAP).

@@ -40,20 +40,67 @@

The above publications can be found at IETF.

-

Types

-
-handle()    Connection handle
-attribute() {Type = string(), Values=[string()]}
-modify_op() See mod_add/2, mod_delete/2, mod_replace/2
-scope()     See baseObject/0, singleLevel/0, wholeSubtree/0
-dereference() See neverDerefAliases/0, derefInSearching/0, derefFindingBaseObj/0, derefAlways/0
-filter()    See present/1, substrings/2,
-                equalityMatch/2, greaterOrEqual/2, lessOrEqual/2,
-                approxMatch/2, extensibleMatch/2,
-                'and'/1, 'or'/1, 'not'/1.
-    
-

+ +
+ DATA TYPES +

Type definitions that are used more than once in this module: +

+ + handle() +

Connection handle

+ + attribute() = +

{Type = string(), Values=[string()]}

+ + modify_op() +

See + mod_add/2, + mod_delete/2, + mod_replace/2 +

+ + scope() +

See + baseObject/0, + singleLevel/0, + wholeSubtree/0 +

+ + dereference() +

See + neverDerefAliases/0, + derefInSearching/0, + derefFindingBaseObj/0, + derefAlways/0 +

+ + filter() +

See + present/1, + substrings/2, + equalityMatch/2, + greaterOrEqual/2, + lessOrEqual/2, + approxMatch/2, + extensibleMatch/2, + 'and'/1, + 'or'/1, + 'not'/1 +

+ + return_value() = +

ok | {ok, {referral,referrals()}} | {error,Error} +

+ + referrals() = +

[Address = string()] The contents of Address is server dependent. +

+ +
+
+ + open([Host]) -> {ok, Handle} | {error, Reason} @@ -92,14 +139,14 @@ filter() See present/1, substrings/2, - start_tls(Handle, Options) -> ok | {error,Error} + start_tls(Handle, Options) -> return_value() Upgrade a connection to TLS.

Same as start_tls(Handle, Options, infinity)

- start_tls(Handle, Options, Timeout) -> ok | {error,Error} + start_tls(Handle, Options, Timeout) -> return_value() Upgrade a connection to TLS. Handle = handle() @@ -128,7 +175,7 @@ filter() See present/1, substrings/2, - simple_bind(Handle, Dn, Password) -> ok | {error, Reason} + simple_bind(Handle, Dn, Password) -> return_value() Authenticate the connection. Handle = handle() @@ -140,7 +187,7 @@ filter() See present/1, substrings/2, - add(Handle, Dn, [Attribute]) -> ok | {error, Reason} + add(Handle, Dn, [Attribute]) -> return_value() Add an entry. Handle = handle() @@ -161,7 +208,7 @@ filter() See present/1, substrings/2, - delete(Handle, Dn) -> ok | {error, Reason} + delete(Handle, Dn) -> return_value() Delete an entry. Dn = string() @@ -203,7 +250,7 @@ filter() See present/1, substrings/2, - modify(Handle, Dn, [ModifyOp]) -> ok | {error, Reason} + modify(Handle, Dn, [ModifyOp]) -> return_value() Modify an entry. Dn = string() @@ -219,7 +266,7 @@ filter() See present/1, substrings/2, - modify_password(Handle, Dn, NewPasswd) -> ok | {ok, GenPasswd} | {error, Reason} + modify_password(Handle, Dn, NewPasswd) -> return_value() | {ok, GenPasswd} Modify the password of a user. Dn = string() @@ -230,7 +277,7 @@ filter() See present/1, substrings/2, - modify_password(Handle, Dn, NewPasswd, OldPasswd) -> ok | {ok, GenPasswd} | {error, Reason} + modify_password(Handle, Dn, NewPasswd, OldPasswd) -> return_value() | {ok, GenPasswd} Modify the password of a user. Dn = string() @@ -259,7 +306,7 @@ filter() See present/1, substrings/2, - modify_dn(Handle, Dn, NewRDN, DeleteOldRDN, NewSupDN) -> ok | {error, Reason} + modify_dn(Handle, Dn, NewRDN, DeleteOldRDN, NewSupDN) -> return_value() Modify the DN of an entry. Dn = string() @@ -279,7 +326,7 @@ filter() See present/1, substrings/2, - search(Handle, SearchOptions) -> {ok, #eldap_search_result{}} | {error, Reason} + search(Handle, SearchOptions) -> {ok, #eldap_search_result{}} | {ok, {referral,referrals()}} | {error, Reason} Search the Directory SearchOptions = #eldap_search{} | [SearchOption] diff --git a/lib/eldap/src/eldap.erl b/lib/eldap/src/eldap.erl index ae47c815c9..8b73860a6d 100644 --- a/lib/eldap/src/eldap.erl +++ b/lib/eldap/src/eldap.erl @@ -19,7 +19,9 @@ extensibleMatch/2, approxMatch/2,search/2,substrings/2,present/1, 'and'/1,'or'/1,'not'/1,modify/3, mod_add/2, mod_delete/2, - mod_replace/2, add/3, delete/2, modify_dn/5,parse_dn/1, + mod_replace/2, add/3, + delete/2, delete/3, + modify_dn/5,parse_dn/1, parse_ldap_url/1]). -export([neverDerefAliases/0, derefInSearching/0, @@ -188,7 +190,10 @@ add_attrs(Attrs) -> %%% ) %%% -------------------------------------------------------------------- delete(Handle, Entry) when is_pid(Handle), is_list(Entry) -> - send(Handle, {delete, Entry}), + delete(Handle, Entry, asn1_NOVALUE). + +delete(Handle, Entry, Controls) when is_pid(Handle), is_list(Entry) -> + send(Handle, {delete, Entry, Controls}), recv(Handle). %%% -------------------------------------------------------------------- @@ -504,8 +509,8 @@ loop(Cpid, Data) -> send(From,Res), ?MODULE:loop(Cpid, NewData); - {From, {delete, Entry}} -> - {Res,NewData} = do_delete(Data, Entry), + {From, {delete, Entry, Controls}} -> + {Res,NewData} = do_delete(Data, Entry, Controls), send(From,Res), ?MODULE:loop(Cpid, NewData); @@ -593,8 +598,9 @@ do_start_tls(Data=#eldap{fd=FD} , TlsOptions, Timeout) -> {error,Error} -> {{error,Error}, Data} end; - {error,Error} -> {{error,Error},Data}; - Else -> {{error,Else},Data} + {{ok,Val},NewData} -> {{ok,Val},NewData}; + {error,Error} -> {{error,Error},Data}; + Else -> {{error,Else},Data} end. -define(START_TLS_OID, "1.3.6.1.4.1.1466.20037"). @@ -611,6 +617,8 @@ exec_extended_req_reply(Data, {ok,Msg}) when case Result#'ExtendedResponse'.resultCode of success -> {ok,Data}; + referral -> + {{ok, {referral,Result#'ExtendedResponse'.referral}}, Data}; Error -> {error, {response,Error}} end; @@ -639,9 +647,10 @@ do_the_simple_bind(Data, Dn, Passwd) -> case catch exec_simple_bind(Data#eldap{binddn = Dn, passwd = Passwd, id = bump_id(Data)}) of - {ok,NewData} -> {ok,NewData}; - {error,Emsg} -> {{error,Emsg},Data}; - Else -> {{error,Else},Data} + {ok,NewData} -> {ok,NewData}; + {{ok,Val},NewData} -> {{ok,Val},NewData}; + {error,Emsg} -> {{error,Emsg},Data}; + Else -> {{error,Else},Data} end. exec_simple_bind(Data) -> @@ -659,6 +668,7 @@ exec_simple_bind_reply(Data, {ok,Msg}) when {bindResponse, Result} -> case Result#'BindResponse'.resultCode of success -> {ok,Data}; + referral -> {{ok, {referral,Msg#'BindResponse'.referral}}, Data}; Error -> {error, Error} end; Other -> {error, Other} @@ -675,6 +685,7 @@ do_search(Data, A) -> case catch do_search_0(Data, A) of {error,Emsg} -> {ldap_closed_p(Data, Emsg),Data}; {'EXIT',Error} -> {ldap_closed_p(Data, Error),Data}; + {{ok,Val},NewData} -> {{ok,Val},NewData}; {ok,Res,Ref,NewData} -> {{ok,polish(Res, Ref)},NewData}; {{error,Reason},NewData} -> {{error,Reason},NewData}; Else -> {ldap_closed_p(Data, Else),Data} @@ -732,6 +743,8 @@ collect_search_responses(Data, S, ID, {ok,Msg}, Acc, Ref) success -> log2(Data, "search reply = searchResDone ~n", []), {ok,Acc,Ref,Data}; + referral -> + {{ok, {referral,R#'LDAPResult'.referral}}, Data}; Reason -> {{error,Reason},Data} end; @@ -761,6 +774,7 @@ do_add(Data, Entry, Attrs) -> {error,Emsg} -> {ldap_closed_p(Data, Emsg),Data}; {'EXIT',Error} -> {ldap_closed_p(Data, Error),Data}; {ok,NewData} -> {ok,NewData}; + {{ok,Val},NewData} -> {{ok,Val},NewData}; Else -> {ldap_closed_p(Data, Else),Data} end. @@ -779,19 +793,20 @@ do_add_0(Data, Entry, Attrs) -> %%% deleteRequest %%% -------------------------------------------------------------------- -do_delete(Data, Entry) -> - case catch do_delete_0(Data, Entry) of +do_delete(Data, Entry, Controls) -> + case catch do_delete_0(Data, Entry, Controls) of {error,Emsg} -> {ldap_closed_p(Data, Emsg),Data}; {'EXIT',Error} -> {ldap_closed_p(Data, Error),Data}; {ok,NewData} -> {ok,NewData}; + {{ok,Val},NewData} -> {{ok,Val},NewData}; Else -> {ldap_closed_p(Data, Else),Data} end. -do_delete_0(Data, Entry) -> +do_delete_0(Data, Entry, Controls) -> S = Data#eldap.fd, Id = bump_id(Data), log2(Data, "del request = ~p~n", [Entry]), - Resp = request(S, Data, Id, {delRequest, Entry}), + Resp = request(S, Data, Id, {delRequest, Entry, Controls}), log2(Data, "del reply = ~p~n", [Resp]), check_reply(Data#eldap{id = Id}, Resp, delResponse). @@ -805,6 +820,7 @@ do_modify(Data, Obj, Mod) -> {error,Emsg} -> {ldap_closed_p(Data, Emsg),Data}; {'EXIT',Error} -> {ldap_closed_p(Data, Error),Data}; {ok,NewData} -> {ok,NewData}; + {{ok,Val},NewData} -> {{ok,Val},NewData}; Else -> {ldap_closed_p(Data, Else),Data} end. @@ -830,6 +846,7 @@ do_passwd_modify(Data, Dn, NewPasswd, OldPasswd) -> {error,Emsg} -> {ldap_closed_p(Data, Emsg),Data}; {'EXIT',Error} -> {ldap_closed_p(Data, Error),Data}; {ok,NewData} -> {ok,NewData}; + {{ok,Val},NewData} -> {{ok,Val},NewData}; {ok,Passwd,NewData} -> {{ok, Passwd},NewData}; Else -> {ldap_closed_p(Data, Else),Data} end. @@ -865,6 +882,8 @@ exec_passwd_modify_reply(Data, {ok,Msg}) when throw(Error) end end; + referral -> + {{ok, {referral,Result#'ExtendedResponse'.referral}}, Data}; Error -> {error, {response,Error}} end; @@ -882,6 +901,7 @@ do_modify_dn(Data, Entry, NewRDN, DelOldRDN, NewSup) -> {error,Emsg} -> {ldap_closed_p(Data, Emsg),Data}; {'EXIT',Error} -> {ldap_closed_p(Data, Error),Data}; {ok,NewData} -> {ok,NewData}; + {{ok,Val},NewData} -> {{ok,Val},NewData}; Else -> {ldap_closed_p(Data, Else),Data} end. @@ -900,15 +920,26 @@ do_modify_dn_0(Data, Entry, NewRDN, DelOldRDN, NewSup) -> %%% -------------------------------------------------------------------- %%% Send an LDAP request and receive the answer %%% -------------------------------------------------------------------- - request(S, Data, ID, Request) -> send_request(S, Data, ID, Request), recv_response(S, Data). -send_request(S, Data, ID, Request) -> - Message = #'LDAPMessage'{messageID = ID, - protocolOp = Request}, - {ok,Bytes} = 'ELDAPv3':encode('LDAPMessage', Message), +send_request(S, Data, Id, {T,P}) -> + send_the_LDAPMessage(S, Data, #'LDAPMessage'{messageID = Id, + protocolOp = {T,P}}); +send_request(S, Data, Id, {T,P,asn1_NOVALUE}) -> + send_the_LDAPMessage(S, Data, #'LDAPMessage'{messageID = Id, + protocolOp = {T,P}}); +send_request(S, Data, Id, {T,P,Controls0}) -> + Controls = [#'Control'{controlType=F1, + criticality=F2, + controlValue=F3} || {control,F1,F2,F3} <- Controls0], + send_the_LDAPMessage(S, Data, #'LDAPMessage'{messageID = Id, + protocolOp = {T,P}, + controls = Controls}). + +send_the_LDAPMessage(S, Data, LDAPMessage) -> + {ok,Bytes} = 'ELDAPv3':encode('LDAPMessage', LDAPMessage), case do_send(S, Data, Bytes) of {error,Reason} -> throw({gen_tcp_error,Reason}); Else -> Else @@ -942,6 +973,7 @@ check_reply(Data, {ok,Msg}, Op) when {Op, Result} -> case Result#'LDAPResult'.resultCode of success -> {ok,Data}; + referral -> {{ok, {referral,Result#'LDAPResult'.referral}}, Data}; Error -> {error, Error} end; Other -> {error, Other} diff --git a/lib/eldap/test/eldap_basic_SUITE.erl b/lib/eldap/test/eldap_basic_SUITE.erl index 638a609346..8414ca6e46 100644 --- a/lib/eldap/test/eldap_basic_SUITE.erl +++ b/lib/eldap/test/eldap_basic_SUITE.erl @@ -30,6 +30,11 @@ -define(TIMEOUT, 120000). % 2 min + +%% Control to delete a referral object: +-define(manageDsaIT, {control,"2.16.840.1.113730.3.4.2",false,asn1_NOVALUE}). + + all() -> [app, appup, @@ -59,6 +64,7 @@ groups() -> {api_bound, [], [add_when_bound, add_already_exists, more_add, + add_referral, search_filter_equalityMatch, search_filter_substring_any, search_filter_initial, @@ -67,8 +73,11 @@ groups() -> search_filter_or, search_filter_and_not, search_two_hits, + search_referral, modify, + modify_referral, delete, + delete_referral, modify_dn_delete_old, modify_dn_keep_old]}, {v4_connections, [], connection_tests()}, @@ -92,11 +101,16 @@ connection_tests() -> init_per_suite(Config) -> SSL_available = init_ssl_certs_et_al(Config), - LDAP_server = find_first_server(false, [{config,eldap_server}, {config,ldap_server}, {"localhost",9876}]), + LDAP_server = find_first_server(false, [{config,eldap_server}, + {config,ldap_server}, + {"localhost",9876}, + {"aramis.otp.ericsson.se",9876}]), LDAPS_server = case SSL_available of true -> - find_first_server(true, [{config,ldaps_server}, {"localhost",9877}]); + find_first_server(true, [{config,ldaps_server}, + {"localhost",9877}, + {"aramis.otp.ericsson.se",9877}]); false -> undefined end, @@ -454,6 +468,16 @@ more_add(Config) -> [{"objectclass", ["organizationalUnit"]}, {"ou", ["Team"]}]). +%%%---------------------------------------------------------------- +add_referral(Config) -> + H = ?config(handle, Config), + BasePath = ?config(eldap_path, Config), + {ok,{referral,["ldap://nowhere.example.com"++_]}} = + eldap:add(H, "cn=Foo Bar,dc=notHere," ++ BasePath, + [{"objectclass", ["person"]}, + {"cn", ["Foo Bar"]}, + {"sn", ["Bar"]}, + {"telephoneNumber", ["555-1232", "555-5432"]}]). %%%---------------------------------------------------------------- search_filter_equalityMatch(Config) -> @@ -568,6 +592,16 @@ search_two_hits(Config) -> %% Restore the database: [ok=eldap:delete(H,DN) || DN <- ExpectedDNs]. +%%%---------------------------------------------------------------- +search_referral(Config) -> + H = ?config(handle, Config), + BasePath = ?config(eldap_path, Config), + DN = "cn=Santa Claus,dc=notHere," ++ BasePath, + {ok,{referral,["ldap://nowhere.example.com"++_]}} = + eldap:search(H, #eldap_search{base = DN, + filter = eldap:present("description"), + scope=eldap:singleLevel()}). + %%%---------------------------------------------------------------- modify(Config) -> H = ?config(handle, Config), @@ -601,6 +635,19 @@ modify(Config) -> %% restore the orignal version: restore_original_object(H, DN, OriginalAttrs). +%%%---------------------------------------------------------------- +modify_referral(Config) -> + H = ?config(handle, Config), + BasePath = ?config(eldap_path, Config), + %% The object to modify + DN = "cn=Foo Bar,dc=notHere," ++ BasePath, + + %% Do a change + Mod = [eldap:mod_replace("telephoneNumber", ["555-12345"]), + eldap:mod_add("description", ["Nice guy"])], + {ok,{referral,["ldap://nowhere.example.com"++_]}} = + eldap:modify(H, DN, Mod). + %%%---------------------------------------------------------------- delete(Config) -> H = ?config(handle, Config), @@ -619,6 +666,14 @@ delete(Config) -> %% And restore the object for subsequent tests restore_original_object(H, DN, OriginalAttrs). +%%%---------------------------------------------------------------- +delete_referral(Config) -> + H = ?config(handle, Config), + BasePath = ?config(eldap_path, Config), + %% The element to play with: + DN = "cn=Jonas Jonsson,dc=notHere," ++ BasePath, + {ok,{referral,["ldap://nowhere.example.com"++_]}} = eldap:delete(H, DN). + %%%---------------------------------------------------------------- modify_dn_delete_old(Config) -> H = ?config(handle, Config), @@ -817,25 +872,44 @@ delete_old_contents(H, Path) -> {filter, eldap:present("objectclass")}, {scope, eldap:wholeSubtree()}]) of - {ok, #eldap_search_result{entries=Entries}} -> + {ok, _R=#eldap_search_result{entries=Entries}} -> + case eldap:delete(H, "dc=notHere,"++Path, [?manageDsaIT]) of + ok -> ok; + {error,noSuchObject} -> ok; + Other -> ct:fail("eldap:delete notHere ret ~p",[Other]) + end, [ok = eldap:delete(H,DN) || #eldap_entry{object_name=DN} <- Entries]; _Res -> ignore end. + +-define(ok(X), ok(?MODULE,?LINE,X)). + add_new_contents(H, Path, MyHost) -> - ok(eldap:add(H,"dc=ericsson,dc=se", + ?ok(eldap:add(H,"dc=ericsson,dc=se", [{"objectclass", ["dcObject", "organization"]}, {"dc", ["ericsson"]}, {"o", ["Testing"]}])), - ok(eldap:add(H,Path, + ?ok(eldap:add(H,Path, [{"objectclass", ["dcObject", "organization"]}, {"dc", [MyHost]}, - {"o", ["Test machine"]}])). - - -ok({error,entryAlreadyExists}) -> ok; -ok(X) -> ok=X. + {"o", ["Test machine"]}])), + ?ok(eldap:add(H, "dc=notHere,"++Path, + [{"objectclass", ["referral", + "dcObject" + ]}, + {"ref", ["ldap://nowhere.example.com/notHere,"++Path]}, + {"dc", ["notHere"]} + ])). + + + +ok(_, _, {error,entryAlreadyExists}) -> ok; +ok(_, _, ok) -> ok; +ok(MODULE, LINE, X) -> + ct:pal("~p:~p add_new_contents: ret from eldap:add = ~p",[MODULE,LINE,X]), + X. -- cgit v1.2.3 From 78c4295b233befa4938334969ef33153c1ba9f49 Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Mon, 22 Feb 2016 19:22:44 +0100 Subject: eldap: experimental impl of controls in LDAPMessage --- lib/eldap/src/eldap.erl | 167 ++++++++++++++++++++++++++++-------------------- 1 file changed, 98 insertions(+), 69 deletions(-) (limited to 'lib') diff --git a/lib/eldap/src/eldap.erl b/lib/eldap/src/eldap.erl index 8b73860a6d..f6d2e014a3 100644 --- a/lib/eldap/src/eldap.erl +++ b/lib/eldap/src/eldap.erl @@ -10,16 +10,21 @@ %%% See MIT-LICENSE at the top dir for licensing information. %%% -------------------------------------------------------------------- -vc('$Id$ '). --export([open/1,open/2,simple_bind/3,controlling_process/2, - start_tls/2, start_tls/3, - modify_password/3, modify_password/4, +-export([open/1, open/2, + simple_bind/3, simple_bind/4, + controlling_process/2, + start_tls/2, start_tls/3, start_tls/4, + modify_password/3, modify_password/4, modify_password/5, getopts/2, baseObject/0,singleLevel/0,wholeSubtree/0,close/1, equalityMatch/2,greaterOrEqual/2,lessOrEqual/2, extensibleMatch/2, - approxMatch/2,search/2,substrings/2,present/1, - 'and'/1,'or'/1,'not'/1,modify/3, mod_add/2, mod_delete/2, - mod_replace/2, add/3, + search/2, search/3, + approxMatch/2,substrings/2,present/1, + 'and'/1,'or'/1,'not'/1,mod_add/2, mod_delete/2, + mod_replace/2, + modify/3, modify/4, + add/3, add/4, delete/2, delete/3, modify_dn/5,parse_dn/1, parse_ldap_url/1]). @@ -93,7 +98,10 @@ start_tls(Handle, TlsOptions) -> start_tls(Handle, TlsOptions, infinity). start_tls(Handle, TlsOptions, Timeout) -> - send(Handle, {start_tls,TlsOptions,Timeout}), + start_tls(Handle, TlsOptions, Timeout, asn1_NOVALUE). + +start_tls(Handle, TlsOptions, Timeout, Controls) -> + send(Handle, {start_tls,TlsOptions,Timeout,Controls}), recv(Handle). %%% -------------------------------------------------------------------- @@ -110,7 +118,11 @@ modify_password(Handle, Dn, NewPasswd) -> modify_password(Handle, Dn, NewPasswd, OldPasswd) when is_pid(Handle), is_list(Dn), is_list(NewPasswd), is_list(OldPasswd) -> - send(Handle, {passwd_modify,optional(Dn),optional(NewPasswd),optional(OldPasswd)}), + modify_password(Handle, Dn, NewPasswd, OldPasswd, asn1_NOVALUE). + +modify_password(Handle, Dn, NewPasswd, OldPasswd, Controls) + when is_pid(Handle), is_list(Dn), is_list(NewPasswd), is_list(OldPasswd) -> + send(Handle, {passwd_modify,optional(Dn),optional(NewPasswd),optional(OldPasswd),Controls}), recv(Handle). %%% -------------------------------------------------------------------- @@ -149,7 +161,10 @@ controlling_process(Handle, Pid) when is_pid(Handle), is_pid(Pid) -> %%% Returns: ok | {error, Error} %%% -------------------------------------------------------------------- simple_bind(Handle, Dn, Passwd) when is_pid(Handle) -> - send(Handle, {simple_bind, Dn, Passwd}), + simple_bind(Handle, Dn, Passwd, asn1_NOVALUE). + +simple_bind(Handle, Dn, Passwd, Controls) when is_pid(Handle) -> + send(Handle, {simple_bind, Dn, Passwd, Controls}), recv(Handle). %%% -------------------------------------------------------------------- @@ -166,7 +181,10 @@ simple_bind(Handle, Dn, Passwd) when is_pid(Handle) -> %%% ) %%% -------------------------------------------------------------------- add(Handle, Entry, Attributes) when is_pid(Handle),is_list(Entry),is_list(Attributes) -> - send(Handle, {add, Entry, add_attrs(Attributes)}), + add(Handle, Entry, Attributes, asn1_NOVALUE). + +add(Handle, Entry, Attributes, Controls) when is_pid(Handle),is_list(Entry),is_list(Attributes) -> + send(Handle, {add, Entry, add_attrs(Attributes), Controls}), recv(Handle). %%% Do sanity check ! @@ -208,7 +226,10 @@ delete(Handle, Entry, Controls) when is_pid(Handle), is_list(Entry) -> %%% ) %%% -------------------------------------------------------------------- modify(Handle, Object, Mods) when is_pid(Handle), is_list(Object), is_list(Mods) -> - send(Handle, {modify, Object, Mods}), + modify(Handle, Object, Mods, asn1_NOVALUE). + +modify(Handle, Object, Mods, Controls) when is_pid(Handle), is_list(Object), is_list(Mods) -> + send(Handle, {modify, Object, Mods, Controls}), recv(Handle). %%% @@ -240,9 +261,13 @@ m(Operation, Type, Values) -> %%% ) %%% -------------------------------------------------------------------- modify_dn(Handle, Entry, NewRDN, DelOldRDN, NewSup) + when is_pid(Handle),is_list(Entry),is_list(NewRDN),is_atom(DelOldRDN),is_list(NewSup) -> + modify_dn(Handle, Entry, NewRDN, DelOldRDN, NewSup, asn1_NOVALUE). + +modify_dn(Handle, Entry, NewRDN, DelOldRDN, NewSup, Controls) when is_pid(Handle),is_list(Entry),is_list(NewRDN),is_atom(DelOldRDN),is_list(NewSup) -> send(Handle, {modify_dn, Entry, NewRDN, - bool_p(DelOldRDN), optional(NewSup)}), + bool_p(DelOldRDN), optional(NewSup), Controls}), recv(Handle). %%% Sanity checks ! @@ -277,16 +302,19 @@ optional(Value) -> Value. %%% []}} %%% %%% -------------------------------------------------------------------- -search(Handle, A) when is_pid(Handle), is_record(A, eldap_search) -> - call_search(Handle, A); -search(Handle, L) when is_pid(Handle), is_list(L) -> +search(Handle, X) when is_pid(Handle), is_record(X,eldap_search) ; is_list(X) -> + search(Handle, X, asn1_NOVALUE). + +search(Handle, A, Controls) when is_pid(Handle), is_record(A, eldap_search) -> + call_search(Handle, A, Controls); +search(Handle, L, Controls) when is_pid(Handle), is_list(L) -> case catch parse_search_args(L) of {error, Emsg} -> {error, Emsg}; - A when is_record(A, eldap_search) -> call_search(Handle, A) + A when is_record(A, eldap_search) -> call_search(Handle, A, Controls) end. -call_search(Handle, A) -> - send(Handle, {search, A}), +call_search(Handle, A, Controls) -> + send(Handle, {search, A, Controls}), recv(Handle). parse_search_args(Args) -> @@ -489,23 +517,23 @@ do_connect(Host, Data, Opts) when Data#eldap.ldaps == true -> loop(Cpid, Data) -> receive - {From, {search, A}} -> - {Res,NewData} = do_search(Data, A), + {From, {search, A, Controls}} -> + {Res,NewData} = do_search(Data, A, Controls), send(From,Res), ?MODULE:loop(Cpid, NewData); - {From, {modify, Obj, Mod}} -> - {Res,NewData} = do_modify(Data, Obj, Mod), + {From, {modify, Obj, Mod, Controls}} -> + {Res,NewData} = do_modify(Data, Obj, Mod, Controls), send(From,Res), ?MODULE:loop(Cpid, NewData); - {From, {modify_dn, Obj, NewRDN, DelOldRDN, NewSup}} -> - {Res,NewData} = do_modify_dn(Data, Obj, NewRDN, DelOldRDN, NewSup), + {From, {modify_dn, Obj, NewRDN, DelOldRDN, NewSup, Controls}} -> + {Res,NewData} = do_modify_dn(Data, Obj, NewRDN, DelOldRDN, NewSup, Controls), send(From,Res), ?MODULE:loop(Cpid, NewData); - {From, {add, Entry, Attrs}} -> - {Res,NewData} = do_add(Data, Entry, Attrs), + {From, {add, Entry, Attrs, Controls}} -> + {Res,NewData} = do_add(Data, Entry, Attrs, Controls), send(From,Res), ?MODULE:loop(Cpid, NewData); @@ -514,8 +542,8 @@ loop(Cpid, Data) -> send(From,Res), ?MODULE:loop(Cpid, NewData); - {From, {simple_bind, Dn, Passwd}} -> - {Res,NewData} = do_simple_bind(Data, Dn, Passwd), + {From, {simple_bind, Dn, Passwd, Controls}} -> + {Res,NewData} = do_simple_bind(Data, Dn, Passwd, Controls), send(From,Res), ?MODULE:loop(Cpid, NewData); @@ -525,13 +553,13 @@ loop(Cpid, Data) -> ?PRINT("New Cpid is: ~p~n",[NewCpid]), ?MODULE:loop(NewCpid, Data); - {From, {start_tls,TlsOptions,Timeout}} -> - {Res,NewData} = do_start_tls(Data, TlsOptions, Timeout), + {From, {start_tls,TlsOptions,Timeout,Controls}} -> + {Res,NewData} = do_start_tls(Data, TlsOptions, Timeout, Controls), send(From,Res), ?MODULE:loop(Cpid, NewData); - {From, {passwd_modify,Dn,NewPasswd,OldPasswd}} -> - {Res,NewData} = do_passwd_modify(Data, Dn, NewPasswd, OldPasswd), + {From, {passwd_modify,Dn,NewPasswd,OldPasswd,Controls}} -> + {Res,NewData} = do_passwd_modify(Data, Dn, NewPasswd, OldPasswd, Controls), send(From, Res), ?MODULE:loop(Cpid, NewData); @@ -584,10 +612,10 @@ loop(Cpid, Data) -> %%% startTLS Request %%% -------------------------------------------------------------------- -do_start_tls(Data=#eldap{using_tls=true}, _, _) -> +do_start_tls(Data=#eldap{using_tls=true}, _, _, _) -> {{error,tls_already_started}, Data}; -do_start_tls(Data=#eldap{fd=FD} , TlsOptions, Timeout) -> - case catch exec_start_tls(Data) of +do_start_tls(Data=#eldap{fd=FD} , TlsOptions, Timeout, Controls) -> + case catch exec_start_tls(Data, Controls) of {ok,NewData} -> case ssl:connect(FD,TlsOptions,Timeout) of {ok, SslSocket} -> @@ -605,9 +633,9 @@ do_start_tls(Data=#eldap{fd=FD} , TlsOptions, Timeout) -> -define(START_TLS_OID, "1.3.6.1.4.1.1466.20037"). -exec_start_tls(Data) -> +exec_start_tls(Data, Controls) -> Req = #'ExtendedRequest'{requestName = ?START_TLS_OID}, - Reply = request(Data#eldap.fd, Data, Data#eldap.id, {extendedReq, Req}), + Reply = request(Data#eldap.fd, Data, Data#eldap.id, {extendedReq, Req, Controls}), exec_extended_req_reply(Data, Reply). exec_extended_req_reply(Data, {ok,Msg}) when @@ -634,31 +662,32 @@ exec_extended_req_reply(_, Error) -> %%% Authenticate ourselves to the directory using %%% simple authentication. -do_simple_bind(Data, anon, anon) -> %% For testing - do_the_simple_bind(Data, "", ""); -do_simple_bind(Data, Dn, _Passwd) when Dn=="",Data#eldap.anon_auth==false -> +do_simple_bind(Data, anon, anon, Controls) -> %% For testing + do_the_simple_bind(Data, "", "", Controls); +do_simple_bind(Data, Dn, _Passwd,_) when Dn=="",Data#eldap.anon_auth==false -> {{error,anonymous_auth},Data}; -do_simple_bind(Data, _Dn, Passwd) when Passwd=="",Data#eldap.anon_auth==false -> +do_simple_bind(Data, _Dn, Passwd,_) when Passwd=="",Data#eldap.anon_auth==false -> {{error,anonymous_auth},Data}; -do_simple_bind(Data, Dn, Passwd) -> - do_the_simple_bind(Data, Dn, Passwd). +do_simple_bind(Data, Dn, Passwd, Controls) -> + do_the_simple_bind(Data, Dn, Passwd, Controls). -do_the_simple_bind(Data, Dn, Passwd) -> +do_the_simple_bind(Data, Dn, Passwd, Controls) -> case catch exec_simple_bind(Data#eldap{binddn = Dn, passwd = Passwd, - id = bump_id(Data)}) of + id = bump_id(Data)}, + Controls) of {ok,NewData} -> {ok,NewData}; {{ok,Val},NewData} -> {{ok,Val},NewData}; {error,Emsg} -> {{error,Emsg},Data}; Else -> {{error,Else},Data} end. -exec_simple_bind(Data) -> +exec_simple_bind(Data, Controls) -> Req = #'BindRequest'{version = Data#eldap.version, name = Data#eldap.binddn, authentication = {simple, Data#eldap.passwd}}, log2(Data, "bind request = ~p~n", [Req]), - Reply = request(Data#eldap.fd, Data, Data#eldap.id, {bindRequest, Req}), + Reply = request(Data#eldap.fd, Data, Data#eldap.id, {bindRequest, Req, Controls}), log2(Data, "bind reply = ~p~n", [Reply]), exec_simple_bind_reply(Data, Reply). @@ -681,8 +710,8 @@ exec_simple_bind_reply(_, Error) -> %%% searchRequest %%% -------------------------------------------------------------------- -do_search(Data, A) -> - case catch do_search_0(Data, A) of +do_search(Data, A, Controls) -> + case catch do_search_0(Data, A, Controls) of {error,Emsg} -> {ldap_closed_p(Data, Emsg),Data}; {'EXIT',Error} -> {ldap_closed_p(Data, Error),Data}; {{ok,Val},NewData} -> {{ok,Val},NewData}; @@ -711,7 +740,7 @@ polish_result([H|T]) when is_record(H, 'SearchResultEntry') -> polish_result([]) -> []. -do_search_0(Data, A) -> +do_search_0(Data, A, Controls) -> Req = #'SearchRequest'{baseObject = A#eldap_search.base, scope = v_scope(A#eldap_search.scope), derefAliases = v_deref(A#eldap_search.deref), @@ -722,15 +751,15 @@ do_search_0(Data, A) -> attributes = v_attributes(A#eldap_search.attributes) }, Id = bump_id(Data), - collect_search_responses(Data#eldap{id=Id}, Req, Id). + collect_search_responses(Data#eldap{id=Id}, Req, Id, Controls). %%% The returned answers cames in one packet per entry %%% mixed with possible referals -collect_search_responses(Data, Req, ID) -> +collect_search_responses(Data, Req, ID, Controls) -> S = Data#eldap.fd, log2(Data, "search request = ~p~n", [Req]), - send_request(S, Data, ID, {searchRequest, Req}), + send_request(S, Data, ID, {searchRequest, Req, Controls}), Resp = recv_response(S, Data), log2(Data, "search reply = ~p~n", [Resp]), collect_search_responses(Data, S, ID, Resp, [], []). @@ -769,8 +798,8 @@ collect_search_responses(_, _, _, Else, _, _) -> %%% addRequest %%% -------------------------------------------------------------------- -do_add(Data, Entry, Attrs) -> - case catch do_add_0(Data, Entry, Attrs) of +do_add(Data, Entry, Attrs, Controls) -> + case catch do_add_0(Data, Entry, Attrs, Controls) of {error,Emsg} -> {ldap_closed_p(Data, Emsg),Data}; {'EXIT',Error} -> {ldap_closed_p(Data, Error),Data}; {ok,NewData} -> {ok,NewData}; @@ -778,13 +807,13 @@ do_add(Data, Entry, Attrs) -> Else -> {ldap_closed_p(Data, Else),Data} end. -do_add_0(Data, Entry, Attrs) -> +do_add_0(Data, Entry, Attrs, Controls) -> Req = #'AddRequest'{entry = Entry, attributes = Attrs}, S = Data#eldap.fd, Id = bump_id(Data), log2(Data, "add request = ~p~n", [Req]), - Resp = request(S, Data, Id, {addRequest, Req}), + Resp = request(S, Data, Id, {addRequest, Req, Controls}), log2(Data, "add reply = ~p~n", [Resp]), check_reply(Data#eldap{id = Id}, Resp, addResponse). @@ -815,8 +844,8 @@ do_delete_0(Data, Entry, Controls) -> %%% modifyRequest %%% -------------------------------------------------------------------- -do_modify(Data, Obj, Mod) -> - case catch do_modify_0(Data, Obj, Mod) of +do_modify(Data, Obj, Mod, Controls) -> + case catch do_modify_0(Data, Obj, Mod, Controls) of {error,Emsg} -> {ldap_closed_p(Data, Emsg),Data}; {'EXIT',Error} -> {ldap_closed_p(Data, Error),Data}; {ok,NewData} -> {ok,NewData}; @@ -824,14 +853,14 @@ do_modify(Data, Obj, Mod) -> Else -> {ldap_closed_p(Data, Else),Data} end. -do_modify_0(Data, Obj, Mod) -> +do_modify_0(Data, Obj, Mod, Controls) -> v_modifications(Mod), Req = #'ModifyRequest'{object = Obj, changes = Mod}, S = Data#eldap.fd, Id = bump_id(Data), log2(Data, "modify request = ~p~n", [Req]), - Resp = request(S, Data, Id, {modifyRequest, Req}), + Resp = request(S, Data, Id, {modifyRequest, Req, Controls}), log2(Data, "modify reply = ~p~n", [Resp]), check_reply(Data#eldap{id = Id}, Resp, modifyResponse). @@ -841,8 +870,8 @@ do_modify_0(Data, Obj, Mod) -> -define(PASSWD_MODIFY_OID, "1.3.6.1.4.1.4203.1.11.1"). -do_passwd_modify(Data, Dn, NewPasswd, OldPasswd) -> - case catch do_passwd_modify_0(Data, Dn, NewPasswd, OldPasswd) of +do_passwd_modify(Data, Dn, NewPasswd, OldPasswd, Controls) -> + case catch do_passwd_modify_0(Data, Dn, NewPasswd, OldPasswd, Controls) of {error,Emsg} -> {ldap_closed_p(Data, Emsg),Data}; {'EXIT',Error} -> {ldap_closed_p(Data, Error),Data}; {ok,NewData} -> {ok,NewData}; @@ -851,7 +880,7 @@ do_passwd_modify(Data, Dn, NewPasswd, OldPasswd) -> Else -> {ldap_closed_p(Data, Else),Data} end. -do_passwd_modify_0(Data, Dn, NewPasswd, OldPasswd) -> +do_passwd_modify_0(Data, Dn, NewPasswd, OldPasswd, Controls) -> Req = #'PasswdModifyRequestValue'{userIdentity = Dn, oldPasswd = OldPasswd, newPasswd = NewPasswd}, @@ -861,7 +890,7 @@ do_passwd_modify_0(Data, Dn, NewPasswd, OldPasswd) -> requestValue = Bytes}, Id = bump_id(Data), log2(Data, "extended request = ~p~n", [ExtReq]), - Reply = request(Data#eldap.fd, Data, Id, {extendedReq, ExtReq}), + Reply = request(Data#eldap.fd, Data, Id, {extendedReq, ExtReq, Controls}), log2(Data, "modify password reply = ~p~n", [Reply]), exec_passwd_modify_reply(Data#eldap{id = Id}, Reply). @@ -896,8 +925,8 @@ exec_passwd_modify_reply(_, Error) -> %%% modifyDNRequest %%% -------------------------------------------------------------------- -do_modify_dn(Data, Entry, NewRDN, DelOldRDN, NewSup) -> - case catch do_modify_dn_0(Data, Entry, NewRDN, DelOldRDN, NewSup) of +do_modify_dn(Data, Entry, NewRDN, DelOldRDN, NewSup, Controls) -> + case catch do_modify_dn_0(Data, Entry, NewRDN, DelOldRDN, NewSup, Controls) of {error,Emsg} -> {ldap_closed_p(Data, Emsg),Data}; {'EXIT',Error} -> {ldap_closed_p(Data, Error),Data}; {ok,NewData} -> {ok,NewData}; @@ -905,7 +934,7 @@ do_modify_dn(Data, Entry, NewRDN, DelOldRDN, NewSup) -> Else -> {ldap_closed_p(Data, Else),Data} end. -do_modify_dn_0(Data, Entry, NewRDN, DelOldRDN, NewSup) -> +do_modify_dn_0(Data, Entry, NewRDN, DelOldRDN, NewSup, Controls) -> Req = #'ModifyDNRequest'{entry = Entry, newrdn = NewRDN, deleteoldrdn = DelOldRDN, @@ -913,7 +942,7 @@ do_modify_dn_0(Data, Entry, NewRDN, DelOldRDN, NewSup) -> S = Data#eldap.fd, Id = bump_id(Data), log2(Data, "modify DN request = ~p~n", [Req]), - Resp = request(S, Data, Id, {modDNRequest, Req}), + Resp = request(S, Data, Id, {modDNRequest, Req, Controls}), log2(Data, "modify DN reply = ~p~n", [Resp]), check_reply(Data#eldap{id = Id}, Resp, modDNResponse). -- cgit v1.2.3