1
%% ``The contents of this file are subject to the Erlang Public License,
2
%% Version 1.1, (the "License"); you may not use this file except in
3
%% compliance with the License. You should have received a copy of the
4
%% Erlang Public License along with this software. If not, it can be
5
%% retrieved via the world wide web at http://www.erlang.org/.
7
%% Software distributed under the License is distributed on an "AS IS"
8
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
9
%% the License for the specific language governing rights and limitations
12
%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
13
%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
14
%% AB. All Rights Reserved.''
16
%% $Id: mod_auth_server.erl,v 1.1 2008/12/17 09:53:35 mikpe Exp $
19
-module(mod_auth_server).
21
-include("httpd.hrl").
22
%% -include("mod_auth.hrl").
23
-include("httpd_verbosity.hrl").
25
-behaviour(gen_server).
29
-export([start/2, stop/2,
30
add_password/4, update_password/5,
31
add_user/5, delete_user/5, get_user/5, list_users/4,
32
add_group_member/6, delete_group_member/6, list_group_members/5,
33
delete_group/5, list_groups/4]).
36
-export([verbosity/3]).
39
-export([start_link/3,
41
handle_call/3, handle_cast/2, handle_info/2,
42
terminate/2, code_change/3]).
48
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
52
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
56
%% NOTE: This is called by httpd_misc_sup when the process is started
58
start_link(Addr, Port, Verbosity)->
59
?vlog("start_link -> entry with"
61
"~n Port: ~p", [Addr, Port]),
62
Name = make_name(Addr, Port),
63
gen_server:start_link({local, Name}, ?MODULE, [Verbosity],
64
[{timeout, infinity}]).
70
?vtrace("start -> entry with"
72
"~n Port: ~p", [Addr, Port]),
73
Name = make_name(Addr, Port),
76
Verbosity = get(auth_verbosity),
77
case (catch httpd_misc_sup:start_auth_server(Addr, Port,
80
put(auth_server, Pid),
83
exit({failed_start_auth_server, Reason});
85
exit({failed_start_auth_server, Error})
87
_ -> %% Already started...
95
?vtrace("stop -> entry with"
97
"~n Port: ~p", [Addr, Port]),
98
Name = make_name(Addr, Port),
100
undefined -> %% Already stopped
103
(catch httpd_misc_sup:stop_auth_server(Addr, Port))
109
verbosity(Addr, Port, Verbosity) ->
110
Name = make_name(Addr, Port),
111
Req = {verbosity, Verbosity},
117
add_password(Addr, Port, Dir, Password)->
118
Name = make_name(Addr, Port),
119
Req = {add_password, Dir, Password},
125
update_password(Addr, Port, Dir, Old, New) when list(New) ->
126
Name = make_name(Addr, Port),
127
Req = {update_password, Dir, Old, New},
133
add_user(Addr, Port, Dir, User, Password) ->
134
Name = make_name(Addr, Port),
135
Req = {add_user, Addr, Port, Dir, User, Password},
141
delete_user(Addr, Port, Dir, UserName, Password) ->
142
Name = make_name(Addr, Port),
143
Req = {delete_user, Addr, Port, Dir, UserName, Password},
149
get_user(Addr, Port, Dir, UserName, Password) ->
150
Name = make_name(Addr, Port),
151
Req = {get_user, Addr, Port, Dir, UserName, Password},
157
list_users(Addr, Port, Dir, Password) ->
158
Name = make_name(Addr,Port),
159
Req = {list_users, Addr, Port, Dir, Password},
163
%% add_group_member/6
165
add_group_member(Addr, Port, Dir, GroupName, UserName, Password) ->
166
Name = make_name(Addr,Port),
167
Req = {add_group_member, Addr, Port, Dir, GroupName, UserName, Password},
171
%% delete_group_member/6
173
delete_group_member(Addr, Port, Dir, GroupName, UserName, Password) ->
174
Name = make_name(Addr,Port),
175
Req = {delete_group_member, Addr, Port, Dir, GroupName, UserName, Password},
179
%% list_group_members/4
181
list_group_members(Addr, Port, Dir, Group, Password) ->
182
Name = make_name(Addr, Port),
183
Req = {list_group_members, Addr, Port, Dir, Group, Password},
189
delete_group(Addr, Port, Dir, GroupName, Password) ->
190
Name = make_name(Addr, Port),
191
Req = {delete_group, Addr, Port, Dir, GroupName, Password},
197
list_groups(Addr, Port, Dir, Password) ->
198
Name = make_name(Addr, Port),
199
Req = {list_groups, Addr, Port, Dir, Password},
203
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
205
%% Server call-back functions %%
207
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
212
init([?default_verbosity]);
216
put(verbosity,Verbosity),
217
?vlog("starting",[]),
218
{ok,#state{tab = ets:new(auth_pwd,[set,protected])}}.
224
handle_call({add_user, Addr, Port, Dir, User, AuthPwd}, _From, State) ->
225
Reply = api_call(Addr, Port, Dir, add_user, User, AuthPwd, State),
226
{reply, Reply, State};
228
%% Get data about a user
229
handle_call({get_user, Addr, Port, Dir, User, AuthPwd}, _From, State) ->
230
Reply = api_call(Addr, Port, Dir, get_user, [User], AuthPwd, State),
231
{reply, Reply, State};
233
%% Add a group member
234
handle_call({add_group_member, Addr, Port, Dir, Group, User, AuthPwd},
236
Reply = api_call(Addr, Port, Dir, add_group_member, [Group, User],
238
{reply, Reply, State};
241
handle_call({delete_group_member, Addr, Port, Dir, Group, User, AuthPwd},
243
Reply = api_call(Addr, Port, Dir, delete_group_member, [Group, User],
245
{reply, Reply, State};
247
%% List all users thats standalone users
248
handle_call({list_users, Addr, Port, Dir, AuthPwd}, _From, State)->
249
Reply = api_call(Addr, Port, Dir, list_users, [], AuthPwd, State),
250
{reply, Reply, State};
253
handle_call({delete_user, Addr, Port, Dir, User, AuthPwd}, _From, State)->
254
Reply = api_call(Addr, Port, Dir, delete_user, [User], AuthPwd, State),
255
{reply, Reply, State};
258
handle_call({delete_group, Addr, Port, Dir, Group, AuthPwd}, _From, State)->
259
Reply = api_call(Addr, Port, Dir, delete_group, [Group], AuthPwd, State),
260
{reply, Reply, State};
262
%% List the current groups
263
handle_call({list_groups, Addr, Port, Dir, AuthPwd}, _From, State)->
264
Reply = api_call(Addr, Port, Dir, list_groups, [], AuthPwd, State),
265
{reply, Reply, State};
267
%% List the members of the given group
268
handle_call({list_group_members, Addr, Port, Dir, Group, AuthPwd},
270
Reply = api_call(Addr, Port, Dir, list_group_members, [Group],
272
{reply, Reply, State};
275
%% Add password for a directory
276
handle_call({add_password, Dir, Password}, _From, State)->
277
Reply = do_add_password(Dir, Password, State),
278
{reply, Reply, State};
281
%% Update the password for a directory
283
handle_call({update_password, Dir, Old, New},_From,State)->
285
case getPassword(State, Dir) of
286
OldPwd when binary(OldPwd)->
287
case erlang:md5(Old) of
289
%% The old password is right =>
290
%% update the password to the new
291
do_update_password(Dir,New,State),
299
{reply, Reply, State};
301
handle_call(stop, _From, State)->
302
{stop, normal, State};
304
handle_call({verbosity,Verbosity},_From,State)->
305
OldVerbosity = put(verbosity,Verbosity),
306
?vlog("set verbosity: ~p -> ~p",[Verbosity,OldVerbosity]),
307
{reply,OldVerbosity,State}.
309
handle_info(Info,State)->
312
handle_cast(Request,State)->
316
terminate(Reason,State) ->
317
ets:delete(State#state.tab),
321
%% code_change({down, ToVsn}, State, Extra)
323
code_change({down, _}, #state{tab = Tab}, downgrade_to_2_6_0) ->
324
?vlog("downgrade to 2.6.0", []),
325
{ok, {state, Tab, undefined}};
328
%% code_change(FromVsn, State, Extra)
330
code_change(_, {state, Tab, _}, upgrade_from_2_6_0) ->
331
?vlog("upgrade from 2.6.0", []),
332
{ok, #state{tab = Tab}}.
335
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
337
%% The functions that really changes the data in the database %%
338
%% of users to different directories %%
340
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
344
api_call(Addr, Port, Dir, Func, Args,Password,State) ->
345
case controlPassword(Password,State,Dir) of
347
ConfigName = httpd_util:make_name("httpd_conf",Addr,Port),
348
case ets:match_object(ConfigName, {directory, Dir, '$1'}) of
349
[{directory, Dir, DirData}] ->
350
AuthMod = auth_mod_name(DirData),
351
?DEBUG("api_call -> call ~p:~p",[AuthMod,Func]),
352
Ret = (catch apply(AuthMod, Func, [DirData|Args])),
353
?DEBUG("api_call -> Ret: ~p",[ret]),
356
?DEBUG("api_call -> O: ~p",[O]),
357
{error, no_such_directory}
363
controlPassword(Password,State,Dir)when Password=:="DummyPassword"->
366
controlPassword(Password,State,Dir)->
367
case getPassword(State,Dir) of
368
Pwd when binary(Pwd)->
369
case erlang:md5(Password) of
380
getPassword(State,Dir)->
381
case lookup(State#state.tab, Dir) of
388
do_update_password(Dir, New, State) ->
389
ets:insert(State#state.tab, {Dir, erlang:md5(New)}).
391
do_add_password(Dir, Password, State) ->
392
case getPassword(State,Dir) of
393
PwdExists when binary(PwdExists) ->
394
{error, dir_protected};
396
do_update_password(Dir, Password, State)
400
auth_mod_name(DirData) ->
401
case httpd_util:key1search(DirData, auth_type, plain) of
402
plain -> mod_auth_plain;
403
mnesia -> mod_auth_mnesia;
404
dets -> mod_auth_dets
412
make_name(Addr,Port) ->
413
httpd_util:make_name("httpd_auth",Addr,Port).
417
case (catch gen_server:call(Name, Req)) of