1 |
85ad3d82
|
Assos Assos
|
<?php
|
2 |
|
|
|
3 |
|
|
/**
|
4 |
|
|
* @file
|
5 |
|
|
* An API module providing by-user access control lists.
|
6 |
|
|
*
|
7 |
|
|
* This module handles ACLs on behalf of other modules. The two main reasons
|
8 |
|
|
* to do this are so that modules using ACLs can share them with each
|
9 |
|
|
* other without having to actually know much about them, and so that
|
10 |
|
|
* ACLs can easily co-exist with the existing node_access system.
|
11 |
|
|
*/
|
12 |
|
|
|
13 |
|
|
/**
|
14 |
|
|
* Create a new ACL.
|
15 |
|
|
*
|
16 |
|
|
* The client module will have to keep track of the ACL. For that it can
|
17 |
|
|
* assign either a $name or a $number to this ACL.
|
18 |
|
|
*
|
19 |
|
|
* @param $module
|
20 |
|
|
* The name of the client module.
|
21 |
|
|
* @param $name
|
22 |
|
|
* An arbitrary name for this ACL, freely defined by the client module.
|
23 |
|
|
* @param $number
|
24 |
|
|
* An arbitrary number for this ACL, freely defined by the client module.
|
25 |
|
|
* @return
|
26 |
|
|
* The ID of the newly created ACL.
|
27 |
|
|
*/
|
28 |
|
|
function acl_create_acl($module, $name = NULL, $number = NULL) {
|
29 |
|
|
$acl = array(
|
30 |
|
|
'module' => $module,
|
31 |
|
|
'name' => $name,
|
32 |
|
|
'number' => $number
|
33 |
|
|
);
|
34 |
|
|
drupal_write_record('acl', $acl);
|
35 |
|
|
return $acl['acl_id'];
|
36 |
|
|
}
|
37 |
|
|
|
38 |
|
|
/**
|
39 |
|
|
* Create a new ACL (obsolete).
|
40 |
|
|
*
|
41 |
|
|
* @see acl_create_acl()
|
42 |
|
|
*/
|
43 |
|
|
function acl_create_new_acl($module, $name = NULL, $number = NULL) {
|
44 |
|
|
return acl_create_acl($module, $name, $number);
|
45 |
|
|
}
|
46 |
|
|
|
47 |
|
|
/**
|
48 |
|
|
* Delete an existing ACL.
|
49 |
|
|
*/
|
50 |
|
|
function acl_delete_acl($acl_id) {
|
51 |
|
|
db_delete('acl')
|
52 |
|
|
->condition('acl_id', $acl_id)
|
53 |
|
|
->execute();
|
54 |
|
|
db_delete('acl_user')
|
55 |
|
|
->condition('acl_id', $acl_id)
|
56 |
|
|
->execute();
|
57 |
|
|
db_delete('acl_node')
|
58 |
|
|
->condition('acl_id', $acl_id)
|
59 |
|
|
->execute();
|
60 |
|
|
}
|
61 |
|
|
|
62 |
|
|
/**
|
63 |
|
|
* Add the specified UID to an ACL.
|
64 |
|
|
*/
|
65 |
|
|
function acl_add_user($acl_id, $uid) {
|
66 |
|
|
$test_uid = db_query("SELECT uid FROM {acl_user} WHERE acl_id = :acl_id AND uid = :uid", array(
|
67 |
|
|
'acl_id' => $acl_id,
|
68 |
|
|
'uid' => $uid,
|
69 |
|
|
))->fetchField();
|
70 |
|
|
if (!$test_uid) {
|
71 |
|
|
db_insert('acl_user')
|
72 |
|
|
->fields(array(
|
73 |
|
|
'acl_id' => $acl_id,
|
74 |
|
|
'uid' => $uid,
|
75 |
|
|
))
|
76 |
|
|
->execute();
|
77 |
|
|
}
|
78 |
|
|
}
|
79 |
|
|
|
80 |
|
|
/**
|
81 |
|
|
* Remove the specified UID from an ACL.
|
82 |
|
|
*/
|
83 |
|
|
function acl_remove_user($acl_id, $uid) {
|
84 |
|
|
db_delete('acl_user')
|
85 |
|
|
->condition('acl_id', $acl_id)
|
86 |
|
|
->condition('uid', $uid)
|
87 |
|
|
->execute();
|
88 |
|
|
}
|
89 |
|
|
|
90 |
|
|
/**
|
91 |
|
|
* Provide a form to edit the ACL that can be embedded in other forms.
|
92 |
|
|
* Pass $new_acl=TRUE if you have no ACL yet, but do supply a string
|
93 |
|
|
* like 'my_module_new_acl' as $acl_id anyway.
|
94 |
|
|
*/
|
95 |
|
|
function acl_edit_form(&$form_state, $acl_id, $label = NULL, $new_acl = FALSE) {
|
96 |
|
|
$form_state['build_info']['files'][] = _acl_module_load_include('admin.inc');
|
97 |
|
|
return _acl_edit_form($acl_id, $label, $new_acl);
|
98 |
|
|
}
|
99 |
|
|
|
100 |
|
|
/**
|
101 |
|
|
* Provide access control to all nodes selected by a subquery, based upon an ACL id.
|
102 |
|
|
*/
|
103 |
|
|
function acl_add_nodes($subselect, $acl_id, $view, $update, $delete, $priority = 0) {
|
104 |
|
|
db_delete('acl_node')
|
105 |
|
|
->condition('acl_id', $acl_id)
|
106 |
|
|
->condition('nid', $subselect, 'IN')
|
107 |
|
|
->execute();
|
108 |
|
|
$subselect->addExpression($acl_id, 'acl_id');
|
109 |
|
|
$subselect->addExpression((int) $view, 'grant_view');
|
110 |
|
|
$subselect->addExpression((int) $update, 'grant_update');
|
111 |
|
|
$subselect->addExpression((int) $delete, 'grant_delete');
|
112 |
|
|
$subselect->addExpression($priority, 'priority');
|
113 |
|
|
db_insert('acl_node')
|
114 |
|
|
->from($subselect)
|
115 |
|
|
->execute();
|
116 |
|
|
}
|
117 |
|
|
|
118 |
|
|
/**
|
119 |
|
|
* Provide access control to a node based upon an ACL id.
|
120 |
|
|
*/
|
121 |
|
|
function acl_node_add_acl($nid, $acl_id, $view, $update, $delete, $priority = 0) {
|
122 |
|
|
acl_node_add_acl_record(array(
|
123 |
|
|
'acl_id' => $acl_id,
|
124 |
|
|
'nid' => $nid,
|
125 |
|
|
'grant_view' => (int) $view,
|
126 |
|
|
'grant_update' => (int) $update,
|
127 |
|
|
'grant_delete' => (int) $delete,
|
128 |
|
|
'priority' => $priority,
|
129 |
|
|
));
|
130 |
|
|
}
|
131 |
|
|
|
132 |
|
|
/**
|
133 |
|
|
* Provide access control to a node based upon an ACL id.
|
134 |
|
|
*/
|
135 |
|
|
function acl_node_add_acl_record(array $record) {
|
136 |
|
|
db_delete('acl_node')
|
137 |
|
|
->condition('acl_id', $record['acl_id'])
|
138 |
|
|
->condition('nid', $record['nid'])
|
139 |
|
|
->execute();
|
140 |
|
|
db_insert('acl_node')
|
141 |
|
|
->fields($record)
|
142 |
|
|
->execute();
|
143 |
|
|
}
|
144 |
|
|
|
145 |
|
|
/**
|
146 |
|
|
* Remove an ACL completely from a node.
|
147 |
|
|
*/
|
148 |
|
|
function acl_node_remove_acl($nid, $acl_id) {
|
149 |
|
|
db_delete('acl_node')
|
150 |
|
|
->condition('acl_id', $acl_id)
|
151 |
|
|
->condition('nid', $nid)
|
152 |
|
|
->execute();
|
153 |
|
|
}
|
154 |
|
|
|
155 |
|
|
/**
|
156 |
|
|
* Clear all of a module's ACLs from a node.
|
157 |
|
|
*/
|
158 |
|
|
function acl_node_clear_acls($nid, $module) {
|
159 |
|
|
$select = db_select('acl', 'a')
|
160 |
|
|
->fields('a', array('acl_id'))
|
161 |
|
|
->condition('a.module', $module);
|
162 |
|
|
db_delete('acl_node')
|
163 |
|
|
->condition('nid', $nid)
|
164 |
|
|
->condition('acl_id', $select, 'IN')
|
165 |
|
|
->execute();
|
166 |
|
|
}
|
167 |
|
|
|
168 |
|
|
/**
|
169 |
|
|
* Get the id of an ACL by name (+ optionally number).
|
170 |
|
|
*/
|
171 |
|
|
function acl_get_id_by_name($module, $name, $number = NULL) {
|
172 |
|
|
$query = db_select('acl', 'a')
|
173 |
|
|
->fields('a', array('acl_id'))
|
174 |
|
|
->condition('a.module', $module)
|
175 |
|
|
->condition('a.name', $name);
|
176 |
|
|
if (isset($number)) {
|
177 |
|
|
$query->condition('a.number', $number);
|
178 |
|
|
}
|
179 |
|
|
return $query->execute()->fetchField();
|
180 |
|
|
}
|
181 |
|
|
|
182 |
|
|
/**
|
183 |
|
|
* Get the id of an ACL by number.
|
184 |
|
|
*/
|
185 |
|
|
function acl_get_id_by_number($module, $number) {
|
186 |
|
|
$query = db_select('acl', 'a')
|
187 |
|
|
->fields('a', array('acl_id'))
|
188 |
|
|
->condition('a.module', $module)
|
189 |
|
|
->condition('a.number', $number);
|
190 |
|
|
return $query->execute()->fetchField();
|
191 |
|
|
}
|
192 |
|
|
|
193 |
|
|
/**
|
194 |
|
|
* Determine whether an ACL has some assigned users.
|
195 |
|
|
*/
|
196 |
|
|
function acl_has_users($acl_id) {
|
197 |
|
|
return db_query("SELECT COUNT(uid) FROM {acl_user} WHERE acl_id = :acl_id", array(
|
198 |
|
|
'acl_id' => $acl_id,
|
199 |
|
|
))->fetchField();
|
200 |
|
|
}
|
201 |
|
|
|
202 |
|
|
/**
|
203 |
|
|
* Determine whether an ACL has a specific assigned user.
|
204 |
|
|
*/
|
205 |
|
|
function acl_has_user($acl_id, $uid) {
|
206 |
|
|
return db_query("SELECT COUNT(uid) FROM {acl_user} WHERE acl_id = :acl_id AND uid = :uid", array(
|
207 |
|
|
'acl_id' => $acl_id,
|
208 |
|
|
'uid' => $uid,
|
209 |
|
|
))->fetchField();
|
210 |
|
|
}
|
211 |
|
|
|
212 |
|
|
/**
|
213 |
|
|
* Get an array of acl_ids held by a user.
|
214 |
|
|
*/
|
215 |
|
|
function acl_get_ids_by_user($module, $uid, $name = NULL, $number = NULL) {
|
216 |
|
|
$query = db_select('acl', 'a');
|
217 |
|
|
$query->join('acl_user', 'au', 'a.acl_id = au.acl_id');
|
218 |
|
|
$query
|
219 |
|
|
->fields('a', array('acl_id'))
|
220 |
|
|
->condition('a.module', $module)
|
221 |
|
|
->condition('au.uid', $uid);
|
222 |
|
|
if (isset($name)) {
|
223 |
|
|
$query->condition('a.name', $name);
|
224 |
|
|
}
|
225 |
|
|
if (isset($number)) {
|
226 |
|
|
$query->condition('a.number', $number);
|
227 |
|
|
}
|
228 |
|
|
$acl_ids = $query->execute()->fetchCol();
|
229 |
|
|
return $acl_ids;
|
230 |
|
|
}
|
231 |
|
|
|
232 |
|
|
/**
|
233 |
|
|
* Get the uids of an ACL.
|
234 |
|
|
*/
|
235 |
|
|
function acl_get_uids($acl_id) {
|
236 |
|
|
$uids = db_query("SELECT uid FROM {acl_user} WHERE acl_id = :acl_id", array(
|
237 |
|
|
'acl_id' => $acl_id,
|
238 |
|
|
))->fetchCol();
|
239 |
|
|
return $uids;
|
240 |
|
|
}
|
241 |
|
|
|
242 |
|
|
/**
|
243 |
|
|
* Implements hook_node_access_records().
|
244 |
|
|
*/
|
245 |
|
|
function acl_node_access_records($node) {
|
246 |
|
|
if (!$node->nid) {
|
247 |
|
|
return;
|
248 |
|
|
}
|
249 |
|
|
$result = db_query("SELECT n.*, 'acl' AS realm, n.acl_id AS gid, a.module FROM {acl_node} n INNER JOIN {acl} a ON n.acl_id = a.acl_id WHERE nid = :nid", array(
|
250 |
|
|
'nid' => $node->nid,
|
251 |
|
|
), array('fetch' => PDO::FETCH_ASSOC));
|
252 |
|
|
$grants = array();
|
253 |
|
|
foreach ($result as $grant) {
|
254 |
|
|
if (module_invoke($grant['module'], 'enabled')) {
|
255 |
|
|
if (acl_has_users($grant['gid'])) {
|
256 |
|
|
$grants[] = $grant;
|
257 |
|
|
}
|
258 |
|
|
else {
|
259 |
|
|
//just deny access
|
260 |
|
|
$grants[] = array(
|
261 |
|
|
'realm' => 'acl',
|
262 |
|
|
'gid' => $grant['gid'],
|
263 |
|
|
'grant_view' => 0,
|
264 |
|
|
'grant_update' => 0,
|
265 |
|
|
'grant_delete' => 0,
|
266 |
|
|
'priority' => $grant['priority'],
|
267 |
|
|
);
|
268 |
|
|
}
|
269 |
|
|
}
|
270 |
|
|
}
|
271 |
|
|
return $grants;
|
272 |
|
|
}
|
273 |
|
|
|
274 |
|
|
/**
|
275 |
|
|
* Implements hook_node_grants().
|
276 |
|
|
*/
|
277 |
|
|
function acl_node_grants($account, $op) {
|
278 |
|
|
$acl_ids = db_query("SELECT acl_id FROM {acl_user} WHERE uid = :uid", array(
|
279 |
|
|
'uid' => $account->uid,
|
280 |
|
|
))->fetchCol();
|
281 |
|
|
return (!empty($acl_ids) ? array('acl' => $acl_ids) : NULL);
|
282 |
|
|
}
|
283 |
|
|
|
284 |
|
|
/**
|
285 |
|
|
* Implements hook_node_delete().
|
286 |
|
|
*/
|
287 |
|
|
function acl_node_delete($node) {
|
288 |
|
|
db_delete('acl_node')
|
289 |
|
|
->condition('nid', $node->nid)
|
290 |
|
|
->execute();
|
291 |
|
|
}
|
292 |
|
|
|
293 |
|
|
/**
|
294 |
|
|
* Implements hook_user_cancel().
|
295 |
|
|
*/
|
296 |
|
|
function acl_user_cancel($edit, $account, $method) {
|
297 |
|
|
db_delete('acl_user')
|
298 |
|
|
->condition('uid', $account->uid)
|
299 |
|
|
->execute();
|
300 |
|
|
}
|
301 |
|
|
|
302 |
|
|
/**
|
303 |
|
|
* Helper function to load include files.
|
304 |
|
|
*/
|
305 |
|
|
function _acl_module_load_include($type) {
|
306 |
|
|
static $loaded = array();
|
307 |
|
|
|
308 |
|
|
if (!isset($loaded[$type])) {
|
309 |
|
|
$path = module_load_include($type, 'acl');
|
310 |
|
|
$loaded[$type] = drupal_get_path('module', 'acl') . "/acl.$type";
|
311 |
|
|
}
|
312 |
|
|
return $loaded[$type];
|
313 |
|
|
}
|
314 |
|
|
|
315 |
|
|
/**
|
316 |
|
|
* Implements hook_node_access_explain().
|
317 |
|
|
*/
|
318 |
|
|
function acl_node_access_explain($row) {
|
319 |
|
|
static $interpretations = array();
|
320 |
|
|
if ($row->realm == 'acl') {
|
321 |
|
|
if (!isset($interpretations[$row->gid])) {
|
322 |
|
|
$acl = db_query("SELECT * FROM {acl} WHERE acl_id = :acl_id", array(
|
323 |
|
|
'acl_id' => $row->gid,
|
324 |
|
|
))->fetchObject();
|
325 |
|
|
$acl->tag = '?';
|
326 |
|
|
if (!isset($acl->name)) {
|
327 |
|
|
$acl->tag = $acl->number;
|
328 |
|
|
}
|
329 |
|
|
elseif (!isset($acl->number)) {
|
330 |
|
|
$acl->tag = $acl->name;
|
331 |
|
|
}
|
332 |
|
|
else {
|
333 |
|
|
$acl->tag = $acl->name . '-' . $acl->number;
|
334 |
|
|
}
|
335 |
|
|
$result = db_query("SELECT u.name FROM {acl_user} au, {users} u WHERE au.acl_id = :acl_id AND au.uid = u.uid", array(
|
336 |
|
|
'acl_id' => $row->gid,
|
337 |
|
|
));
|
338 |
|
|
foreach ($result as $user) {
|
339 |
|
|
$users[] = $user->name;
|
340 |
|
|
}
|
341 |
|
|
if (isset($users)) {
|
342 |
|
|
$users = implode(', ', $users);
|
343 |
|
|
$interpretations[$row->gid] = _acl_get_explanation("$acl->module/$acl->tag: $users", $acl->acl_id, $acl->module, $acl->name, $acl->number, $users);
|
344 |
|
|
}
|
345 |
|
|
elseif ($row->gid == 0) {
|
346 |
|
|
$result = db_query("SELECT an.acl_id, a.module, a.name FROM {acl_node} an JOIN {acl} a ON an.acl_id = a.acl_id LEFT JOIN {acl_user} au ON a.acl_id = au.acl_id WHERE an.nid = :nid AND au.uid IS NULL", array(
|
347 |
|
|
'nid' => $row->nid,
|
348 |
|
|
));
|
349 |
|
|
foreach ($result as $acl) {
|
350 |
|
|
$rows[] = _acl_get_explanation("$acl->acl_id: $acl->module/$acl->tag", $acl->acl_id, $acl->module, $acl->name, $acl->number);
|
351 |
|
|
}
|
352 |
|
|
if (!empty($rows)) {
|
353 |
|
|
return implode('<br />', $rows);
|
354 |
|
|
}
|
355 |
|
|
return 'No access via ACL.';
|
356 |
|
|
}
|
357 |
|
|
else {
|
358 |
|
|
$interpretations[$row->gid] = _acl_get_explanation("$acl->module/$acl->tag: no users!", $acl->acl_id, $acl->module, $acl->name, $acl->number);
|
359 |
|
|
}
|
360 |
|
|
}
|
361 |
|
|
return $interpretations[$row->gid];
|
362 |
|
|
}
|
363 |
|
|
}
|
364 |
|
|
|
365 |
|
|
/**
|
366 |
|
|
* Helper function to ask the client for its interpretation of the given
|
367 |
|
|
* grant record.
|
368 |
|
|
*/
|
369 |
|
|
function _acl_get_explanation($text, $acl_id, $module, $name, $number, $users = NULL) {
|
370 |
|
|
$hook = $module .'_acl_explain';
|
371 |
|
|
if (function_exists($hook)) {
|
372 |
|
|
return '<span title="'. $hook($acl_id, $name, $number, $users) .'">'. $text .'</span>';
|
373 |
|
|
}
|
374 |
|
|
return $text;
|
375 |
|
|
}
|