~ubuntu-branches/ubuntu/precise/ejabberd/precise-proposed

« back to all changes in this revision

Viewing changes to src/eldap/eldap.erl

  • Committer: Bazaar Package Importer
  • Author(s): Konstantin Khomoutov, Konstantin Khomoutov
  • Date: 2010-07-26 20:36:14 UTC
  • mfrom: (1.1.15 upstream)
  • Revision ID: james.westby@ubuntu.com-20100726203614-s3asj0k5ym3bxhdw
Tags: 2.1.4-1
[ Konstantin Khomoutov ]
* Do not prevent ejabberd_debug from being installed and used
  as this was implemented upstream as the default behavior.
* Add build dependency on erlang-parsetools.
* Add 'sharedscripts' option to logrotate config.
* Update VCS references in control file to point to git.deb.at.
* Add group sticky bit to permissions on the log directory --
  this should make log files owned by the group "adm".
* Explicitly set umask to 027 before starting erl.
* Add patch with fix for EJAB-953 (closes: #590389).
* Fix call to setup_ejabberd in postinst.
* Fix owner/permissions for log files when upgrading.
* Minor fixes and clarifications in ejabberdctl.8 manual page.
* Refresh reopen-log.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
33
33
 
34
34
%%% Modified by Alexey Shchepin <alexey@sevcom.net>
35
35
 
36
 
%%% Modified by Evgeniy Khramtsov <xram@jabber.ru>
 
36
%%% Modified by Evgeniy Khramtsov <ekhramtsov@process-one.net>
37
37
%%% Implemented queue for bind() requests to prevent pending binds.
 
38
%%% Implemented extensibleMatch/2 function.
 
39
%%% Implemented LDAP Extended Operations (currently only Password Modify
 
40
%%%   is supported - RFC 3062).
38
41
 
39
42
%%% Modified by Christophe Romain <christophe.romain@process-one.net>
40
43
%%% Improve error case handling
71
74
 
72
75
-export([baseObject/0,singleLevel/0,wholeSubtree/0,close/1,
73
76
         equalityMatch/2,greaterOrEqual/2,lessOrEqual/2,
74
 
         approxMatch/2,search/2,substrings/2,present/1,
 
77
         approxMatch/2,search/2,substrings/2,present/1,extensibleMatch/2,
75
78
         'and'/1,'or'/1,'not'/1,modify/3, mod_add/2, mod_delete/2,
76
 
         mod_replace/2, add/3, delete/2, modify_dn/5, bind/3]).
 
79
         mod_replace/2, add/3, delete/2, modify_dn/5, modify_passwd/3, bind/3]).
77
80
-export([get_status/1]).
78
81
 
79
82
%% gen_fsm callbacks
127
130
    Reg_name = list_to_atom("eldap_" ++ Name),
128
131
    gen_fsm:start_link({local, Reg_name}, ?MODULE, [], []).
129
132
 
130
 
start_link(Name, Hosts, Port, Rootdn, Passwd, Encrypt) ->
 
133
start_link(Name, Hosts, Port, Rootdn, Passwd, Opts) ->
131
134
    Reg_name = list_to_atom("eldap_" ++ Name),
132
 
    gen_fsm:start_link({local, Reg_name}, ?MODULE, {Hosts, Port, Rootdn, Passwd, Encrypt}, []).
 
135
    gen_fsm:start_link({local, Reg_name}, ?MODULE,
 
136
                       {Hosts, Port, Rootdn, Passwd, Opts}, []).
133
137
 
134
138
%%% --------------------------------------------------------------------
135
139
%%% Get status of connection.
239
243
      {modify_dn, Entry, NewRDN, bool_p(DelOldRDN), optional(NewSup)},
240
244
      ?CALL_TIMEOUT).
241
245
 
 
246
modify_passwd(Handle, DN, Passwd) when is_list(DN), is_list(Passwd) ->
 
247
    Handle1 = get_handle(Handle),
 
248
    gen_fsm:sync_send_event(
 
249
      Handle1, {modify_passwd, DN, Passwd}, ?CALL_TIMEOUT).
242
250
 
243
251
%%% --------------------------------------------------------------------
244
252
%%% Bind.
374
382
    {substrings,#'SubstringFilter'{type = Type,
375
383
                                   substrings = Ss}}.
376
384
 
 
385
%%%
 
386
%%% extensibleMatch filter.
 
387
%%% FIXME: Describe the purpose of this filter.
 
388
%%%
 
389
%%% Value   ::= string( <attribute> )
 
390
%%% Opts    ::= listof( {matchingRule, Str} | {type, Str} | {dnAttributes, true} )
 
391
%%%
 
392
%%% Example: extensibleMatch("Fred", [{matchingRule, "1.2.3.4.5"}, {type, "cn"}]).
 
393
%%%
 
394
extensibleMatch(Value, Opts) when is_list(Value), is_list(Opts) ->
 
395
        MRA = #'MatchingRuleAssertion'{matchValue=Value},
 
396
        {extensibleMatch, extensibleMatch_opts(Opts, MRA)}.
 
397
 
 
398
extensibleMatch_opts([{matchingRule, Rule} | Opts], MRA) when is_list(Rule) ->
 
399
        extensibleMatch_opts(Opts, MRA#'MatchingRuleAssertion'{matchingRule=Rule});
 
400
extensibleMatch_opts([{type, Desc} | Opts], MRA) when is_list(Desc) ->
 
401
        extensibleMatch_opts(Opts, MRA#'MatchingRuleAssertion'{type=Desc});
 
402
extensibleMatch_opts([{dnAttributes, true} | Opts], MRA) ->
 
403
        extensibleMatch_opts(Opts, MRA#'MatchingRuleAssertion'{dnAttributes=true});
 
404
extensibleMatch_opts([_ | Opts], MRA) ->
 
405
        extensibleMatch_opts(Opts, MRA);
 
406
extensibleMatch_opts([], MRA) ->
 
407
        MRA.
377
408
 
378
409
get_handle(Pid) when is_pid(Pid)    -> Pid;
379
410
get_handle(Atom) when is_atom(Atom) -> Atom;
393
424
%%----------------------------------------------------------------------
394
425
init([]) ->
395
426
    case get_config() of
396
 
        {ok, Hosts, Rootdn, Passwd, Encrypt} ->
397
 
            init({Hosts, Rootdn, Passwd, Encrypt});
 
427
        {ok, Hosts, Rootdn, Passwd, Opts} ->
 
428
            init({Hosts, Rootdn, Passwd, Opts});
398
429
        {error, Reason} ->
399
430
            {stop, Reason}
400
431
    end;
401
 
init({Hosts, Port, Rootdn, Passwd, Encrypt}) ->
 
432
init({Hosts, Port, Rootdn, Passwd, Opts}) ->
402
433
    catch ssl:start(),
403
 
    {X1,X2,X3} = erlang:now(),
404
 
    ssl:seed(integer_to_list(X1) ++ integer_to_list(X2) ++ integer_to_list(X3)),
 
434
    ssl:seed(randoms:get_string()),
 
435
    Encrypt = case proplists:get_value(encrypt, Opts) of
 
436
                  tls -> tls;
 
437
                  _ -> none
 
438
              end,
405
439
    PortTemp = case Port of
406
440
                   undefined ->
407
441
                       case Encrypt of
414
448
                       end;
415
449
                   PT -> PT
416
450
               end,
417
 
    TLSOpts = [verify_none],
 
451
    TLSOpts = case proplists:get_value(tls_verify, Opts) of
 
452
                  soft ->
 
453
                      [{verify, 1}];
 
454
                  hard ->
 
455
                      [{verify, 2}];
 
456
                  _ ->
 
457
                      [{verify, 0}]
 
458
              end,
418
459
    {ok, connecting, #eldap{hosts = Hosts,
419
460
                            port = PortTemp,
420
461
                            rootdn = Rootdn,
671
712
                        deleteoldrdn = DelOldRDN,
672
713
                        newSuperior  = NewSup}};
673
714
 
 
715
gen_req({modify_passwd, DN, Passwd}) ->
 
716
    {ok, ReqVal} = asn1rt:encode(
 
717
                     'ELDAPv3', 'PasswdModifyRequestValue',
 
718
                     #'PasswdModifyRequestValue'{
 
719
                                  userIdentity = DN,
 
720
                                  newPasswd = Passwd}),
 
721
    {extendedReq,
 
722
     #'ExtendedRequest'{requestName = ?passwdModifyOID,
 
723
                        requestValue = list_to_binary(ReqVal)}};
 
724
 
674
725
gen_req({bind, RootDN, Passwd}) ->
675
726
    {bindRequest,
676
727
     #'BindRequest'{version        = ?LDAP_VERSION,
745
796
                    cancel_timer(Timer),
746
797
                    Reply = check_bind_reply(Result, From),
747
798
                    {reply, Reply, From, S#eldap{dict = New_dict}};
 
799
                {extendedReq, {extendedResp, Result}} ->
 
800
                    New_dict = dict:erase(Id, Dict),
 
801
                    cancel_timer(Timer),
 
802
                    Reply = check_extended_reply(Result, From),
 
803
                    {reply, Reply, From, S#eldap{dict = New_dict}};
748
804
                {OtherName, OtherResult} ->
749
805
                    New_dict = dict:erase(Id, Dict),
750
806
                    cancel_timer(Timer),
769
825
check_bind_reply(Other, _From) ->
770
826
    {error, Other}.
771
827
 
 
828
%% TODO: process reply depending on requestName:
 
829
%% this requires BER-decoding of #'ExtendedResponse'.response
 
830
check_extended_reply(#'ExtendedResponse'{resultCode = success}, _From) ->
 
831
    ok;
 
832
check_extended_reply(#'ExtendedResponse'{resultCode = Reason}, _From) ->
 
833
    {error, Reason};
 
834
check_extended_reply(Other, _From) ->
 
835
    {error, Other}.
 
836
 
772
837
get_op_rec(Id, Dict) ->
773
838
    case dict:find(Id, Dict) of
774
839
        {ok, [{Timer, _Command, From, Name}|Res]} ->
904
969
                     tls ->
905
970
                         SockMod = ssl,
906
971
                         SslOpts = [{packet, asn1}, {active, true}, {keepalive, true},
907
 
                                    binary],
 
972
                                    binary | S#eldap.tls_options],
908
973
                         ssl:connect(Host, S#eldap.port, SslOpts);
909
974
                     %% starttls -> %% TODO: Implement STARTTLS;
910
975
                     _ ->
973
1038
v_filter({approxMatch,AV})    -> {approxMatch,AV};
974
1039
v_filter({present,A})         -> {present,A};
975
1040
v_filter({substrings,S}) when is_record(S,'SubstringFilter') -> {substrings,S};
 
1041
v_filter({extensibleMatch, S}) when is_record(S, 'MatchingRuleAssertion') ->
 
1042
    {extensibleMatch, S};
976
1043
v_filter(_Filter) -> throw({error,concat(["unknown filter: ",_Filter])}).
977
1044
 
978
1045
v_modifications(Mods) ->
1018
1085
    case file:consult(File) of
1019
1086
        {ok, Entries} ->
1020
1087
            case catch parse(Entries) of
1021
 
                {ok, Hosts, Port, Rootdn, Passwd, Encrypt} ->
1022
 
                    {ok, Hosts, Port, Rootdn, Passwd, Encrypt};
 
1088
                {ok, Hosts, Port, Rootdn, Passwd, Opts} ->
 
1089
                    {ok, Hosts, Port, Rootdn, Passwd, Opts};
1023
1090
                {error, Reason} ->
1024
1091
                    {error, Reason};
1025
1092
                {'EXIT', Reason} ->
1035
1102
     get_integer(port, Entries),
1036
1103
     get_list(rootdn, Entries),
1037
1104
     get_list(passwd, Entries),
1038
 
     get_atom(encrypt, Entries)}.
 
1105
     get_list(options, Entries)}.
1039
1106
 
1040
1107
get_integer(Key, List) ->
1041
1108
    case lists:keysearch(Key, 1, List) of
1057
1124
            throw({error, "No Entry in Config for " ++ atom_to_list(Key)})
1058
1125
    end.
1059
1126
 
1060
 
get_atom(Key, List) ->
1061
 
    case lists:keysearch(Key, 1, List) of
1062
 
        {value, {Key, Value}} when is_atom(Value) ->
1063
 
            Value;
1064
 
        {value, {Key, _Value}} ->
1065
 
            throw({error, "Bad Value in Config for " ++ atom_to_list(Key)});
1066
 
        false ->
1067
 
            throw({error, "No Entry in Config for " ++ atom_to_list(Key)})
1068
 
    end.
 
1127
%% get_atom(Key, List) ->
 
1128
%%     case lists:keysearch(Key, 1, List) of
 
1129
%%      {value, {Key, Value}} when is_atom(Value) ->
 
1130
%%          Value;
 
1131
%%      {value, {Key, _Value}} ->
 
1132
%%          throw({error, "Bad Value in Config for " ++ atom_to_list(Key)});
 
1133
%%      false ->
 
1134
%%          throw({error, "No Entry in Config for " ++ atom_to_list(Key)})
 
1135
%%     end.
1069
1136
 
1070
1137
get_hosts(Key, List) ->
1071
1138
    lists:map(fun({Key1, {A,B,C,D}}) when is_integer(A),