1%% ``Licensed under the Apache License, Version 2.0 (the "License");
2%% you may not use this file except in compliance with the License.
3%% You may obtain a copy of the License at
4%%
5%%     http://www.apache.org/licenses/LICENSE-2.0
6%%
7%% Unless required by applicable law or agreed to in writing, software
8%% distributed under the License is distributed on an "AS IS" BASIS,
9%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10%% See the License for the specific language governing permissions and
11%% limitations under the License.
12%%
13%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
14%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
15%% AB. All Rights Reserved.''
16%%
17%%     $Id: mod_auth_mnesia.erl,v 1.2 2010/03/04 13:54:19 maria Exp $
18%%
19-module(mod_auth_mnesia).
20-export([get_user/2,
21	 list_group_members/2,
22	 add_user/2,
23	 add_group_member/3,
24	 list_users/1,
25	 delete_user/2,
26	 list_groups/1,
27	 delete_group_member/3,
28	 delete_group/2]).
29
30-export([store_user/5, store_user/6,
31	 store_group_member/5, store_group_member/6,
32	 list_group_members/3, list_group_members/4,
33	 list_groups/2, list_groups/3,
34	 list_users/2, list_users/3,
35	 remove_user/4, remove_user/5,
36	 remove_group_member/5, remove_group_member/6,
37	 remove_group/4, remove_group/5]).
38
39-export([store_directory_data/2]).
40
41-include("httpd.hrl").
42-include("mod_auth.hrl").
43
44
45
46store_directory_data(Directory, DirData) ->
47    %% We don't need to do anything here, we could ofcourse check that the appropriate
48    %% mnesia tables has been created prior to starting the http server.
49    ok.
50
51
52%%
53%% API
54%%
55
56%% Compatibility API
57
58
59store_user(UserName, Password, Port, Dir, AccessPassword) ->
60   %% AccessPassword is ignored - was not used in previous version
61   DirData = [{path,Dir},{port,Port}],
62   UStruct = #httpd_user{username = UserName,
63			 password = Password},
64   add_user(DirData, UStruct).
65
66store_user(UserName, Password, Addr, Port, Dir, AccessPassword) ->
67   %% AccessPassword is ignored - was not used in previous version
68   DirData = [{path,Dir},{bind_address,Addr},{port,Port}],
69   UStruct = #httpd_user{username = UserName,
70			 password = Password},
71   add_user(DirData, UStruct).
72
73store_group_member(GroupName, UserName, Port, Dir, AccessPassword) ->
74   DirData = [{path,Dir},{port,Port}],
75   add_group_member(DirData, GroupName, UserName).
76
77store_group_member(GroupName, UserName, Addr, Port, Dir, AccessPassword) ->
78   DirData = [{path,Dir},{bind_address,Addr},{port,Port}],
79   add_group_member(DirData, GroupName, UserName).
80
81list_group_members(GroupName, Port, Dir) ->
82   DirData = [{path,Dir},{port,Port}],
83   list_group_members(DirData, GroupName).
84
85list_group_members(GroupName, Addr, Port, Dir) ->
86   DirData = [{path,Dir},{bind_address,Addr},{port,Port}],
87   list_group_members(DirData, GroupName).
88
89list_groups(Port, Dir) ->
90   DirData = [{path,Dir},{port,Port}],
91   list_groups(DirData).
92
93list_groups(Addr, Port, Dir) ->
94   DirData = [{path,Dir},{bind_address,Addr},{port,Port}],
95   list_groups(DirData).
96
97list_users(Port, Dir) ->
98   DirData = [{path,Dir},{port,Port}],
99   list_users(DirData).
100
101list_users(Addr, Port, Dir) ->
102   DirData = [{path,Dir},{bind_address,Addr},{port,Port}],
103   list_users(DirData).
104
105remove_user(UserName, Port, Dir, _AccessPassword) ->
106   DirData = [{path,Dir},{port,Port}],
107   delete_user(DirData, UserName).
108
109remove_user(UserName, Addr, Port, Dir, _AccessPassword) ->
110   DirData = [{path,Dir},{bind_address,Addr},{port,Port}],
111   delete_user(DirData, UserName).
112
113remove_group_member(GroupName,UserName,Port,Dir,_AccessPassword) ->
114   DirData = [{path,Dir},{port,Port}],
115   delete_group_member(DirData, GroupName, UserName).
116
117remove_group_member(GroupName,UserName,Addr,Port,Dir,_AccessPassword) ->
118   DirData = [{path,Dir},{bind_address,Addr},{port,Port}],
119   delete_group_member(DirData, GroupName, UserName).
120
121remove_group(GroupName,Port,Dir,_AccessPassword) ->
122   DirData = [{path,Dir},{port,Port}],
123   delete_group(DirData, GroupName).
124
125remove_group(GroupName,Addr,Port,Dir,_AccessPassword) ->
126   DirData = [{path,Dir},{bind_address,Addr},{port,Port}],
127   delete_group(DirData, GroupName).
128
129%%
130%% Storage format of users in the mnesia table:
131%% httpd_user records
132%%
133
134add_user(DirData, UStruct) ->
135    {Addr, Port, Dir} = lookup_common(DirData),
136    UserName = UStruct#httpd_user.username,
137    Password = UStruct#httpd_user.password,
138    Data     = UStruct#httpd_user.user_data,
139    User=#httpd_user{username={UserName,Addr,Port,Dir},
140		     password=Password,
141		     user_data=Data},
142    case mnesia:transaction(fun() -> mnesia:write(User) end) of
143	{aborted,Reason} ->
144	    {error,Reason};
145	_ ->
146	    true
147    end.
148
149get_user(DirData, UserName) ->
150    {Addr, Port, Dir} = lookup_common(DirData),
151    case mnesia:transaction(fun() ->
152				    mnesia:read({httpd_user,
153						 {UserName,Addr,Port,Dir}})
154			    end) of
155	{aborted,Reason} ->
156	    {error, Reason};
157	{'atomic',[]} ->
158	    {error, no_such_user};
159	{'atomic', [Record]} when record(Record, httpd_user) ->
160	    {ok, Record#httpd_user{username=UserName}};
161	Other ->
162	    {error, no_such_user}
163    end.
164
165list_users(DirData) ->
166    {Addr, Port, Dir} = lookup_common(DirData),
167    case mnesia:transaction(fun() ->
168				    mnesia:match_object({httpd_user,
169							 {'_',Addr,Port,Dir},'_','_'})
170			    end) of
171	{aborted,Reason} ->
172	    {error,Reason};
173	{'atomic',Users} ->
174	    {ok,
175	     lists:foldr(fun({httpd_user, {UserName, AnyAddr, AnyPort, AnyDir},
176			      Password, Data}, Acc) ->
177				 [UserName|Acc]
178			 end,
179			 [], Users)}
180    end.
181
182delete_user(DirData, UserName) ->
183    {Addr, Port, Dir} = lookup_common(DirData),
184    case mnesia:transaction(fun() ->
185				    mnesia:delete({httpd_user,
186						   {UserName,Addr,Port,Dir}})
187			    end) of
188	{aborted,Reason} ->
189	    {error,Reason};
190	_ ->
191	    true
192    end.
193
194%%
195%% Storage of groups in the mnesia table:
196%% Multiple instances of {#httpd_group, User}
197%%
198
199add_group_member(DirData, GroupName, User) ->
200    {Addr, Port, Dir} = lookup_common(DirData),
201    Group=#httpd_group{name={GroupName, Addr, Port, Dir}, userlist=User},
202    case mnesia:transaction(fun() -> mnesia:write(Group) end) of
203	{aborted,Reason} ->
204	    {error,Reason};
205	_ ->
206	    true
207    end.
208
209list_group_members(DirData, GroupName) ->
210    {Addr, Port, Dir} = lookup_common(DirData),
211    case mnesia:transaction(fun() ->
212				    mnesia:read({httpd_group,
213						 {GroupName,Addr,Port,Dir}})
214			    end) of
215	{aborted, Reason} ->
216	    {error,Reason};
217	{'atomic', Members} ->
218	    {ok,[UserName || {httpd_group,{AnyGroupName,AnyAddr,AnyPort,AnyDir},UserName} <- Members,
219			     AnyGroupName == GroupName, AnyAddr == Addr,
220			     AnyPort == Port, AnyDir == Dir]}
221  end.
222
223list_groups(DirData) ->
224    {Addr, Port, Dir} = lookup_common(DirData),
225    case mnesia:transaction(fun() ->
226				    mnesia:match_object({httpd_group,
227							 {'_',Addr,Port,Dir},'_'})
228			    end) of
229	{aborted, Reason} ->
230	    {error, Reason};
231	{'atomic', Groups} ->
232	    GroupNames=
233		[GroupName || {httpd_group,{GroupName,AnyAddr,AnyPort,AnyDir}, UserName} <- Groups,
234			      AnyAddr == Addr, AnyPort == AnyPort, AnyDir == Dir],
235	    {ok, httpd_util:uniq(lists:sort(GroupNames))}
236    end.
237
238delete_group_member(DirData, GroupName, UserName) ->
239    {Addr, Port, Dir} = lookup_common(DirData),
240    Group = #httpd_group{name={GroupName, Addr, Port, Dir}, userlist=UserName},
241    case mnesia:transaction(fun() -> mnesia:delete_object(Group) end) of
242	{aborted,Reason} ->
243	    {error,Reason};
244	_ ->
245	    true
246    end.
247
248%% THIS IS WRONG (?) !
249%% Should first match out all httpd_group records for this group and then
250%% do mnesia:delete on those. Or ?
251
252delete_group(DirData, GroupName) ->
253    {Addr, Port, Dir} = lookup_common(DirData),
254    case mnesia:transaction(fun() ->
255				    mnesia:delete({httpd_group,
256						   {GroupName,Addr,Port,Dir}})
257			    end) of
258	{aborted,Reason} ->
259	    {error,Reason};
260	_ ->
261	    true
262    end.
263
264%% Utility functions.
265
266lookup_common(DirData) ->
267    Dir = httpd_util:key1search(DirData, path),
268    Port = httpd_util:key1search(DirData, port),
269    Addr = httpd_util:key1search(DirData, bind_address),
270    {Addr, Port, Dir}.
271