phpBB
Statistics
| Revision:

root / branches / phpBB-3_0_0 / phpBB / includes / auth.php

History | View | Annotate | Download (29.3 kB)

1
<?php
2
/**
3
*
4
* @package phpBB3
5
* @version $Id: auth.php 11310 2011-07-17 02:15:13Z git-gate $
6
* @copyright (c) 2005 phpBB Group
7
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
8
*
9
*/
10
11
/**
12
* @ignore
13
*/
14
if (!defined('IN_PHPBB'))
15
{
16
        exit;
17
}
18
19
/**
20
* Permission/Auth class
21
* @package phpBB3
22
*/
23
class auth
24
{
25
        var $acl = array();
26
        var $cache = array();
27
        var $acl_options = array();
28
        var $acl_forum_ids = false;
29
30
        /**
31
        * Init permissions
32
        */
33
        function acl(&$userdata)
34
        {
35
                global $db, $cache;
36
37
                $this->acl = $this->cache = $this->acl_options = array();
38
                $this->acl_forum_ids = false;
39
40
                if (($this->acl_options = $cache->get('_acl_options')) === false)
41
                {
42
                        $sql = 'SELECT auth_option_id, auth_option, is_global, is_local
43
                                FROM ' . ACL_OPTIONS_TABLE . '
44
                                ORDER BY auth_option_id';
45
                        $result = $db->sql_query($sql);
46
47
                        $global = $local = 0;
48
                        $this->acl_options = array();
49
                        while ($row = $db->sql_fetchrow($result))
50
                        {
51
                                if ($row['is_global'])
52
                                {
53
                                        $this->acl_options['global'][$row['auth_option']] = $global++;
54
                                }
55
56
                                if ($row['is_local'])
57
                                {
58
                                        $this->acl_options['local'][$row['auth_option']] = $local++;
59
                                }
60
61
                                $this->acl_options['id'][$row['auth_option']] = (int) $row['auth_option_id'];
62
                                $this->acl_options['option'][(int) $row['auth_option_id']] = $row['auth_option'];
63
                        }
64
                        $db->sql_freeresult($result);
65
66
                        $cache->put('_acl_options', $this->acl_options);
67
                }
68
69
                if (!trim($userdata['user_permissions']))
70
                {
71
                        $this->acl_cache($userdata);
72
                }
73
74
                // Fill ACL array
75
                $this->_fill_acl($userdata['user_permissions']);
76
77
                // Verify bitstring length with options provided...
78
                $renew = false;
79
                $global_length = sizeof($this->acl_options['global']);
80
                $local_length = sizeof($this->acl_options['local']);
81
82
                // Specify comparing length (bitstring is padded to 31 bits)
83
                $global_length = ($global_length % 31) ? ($global_length - ($global_length % 31) + 31) : $global_length;
84
                $local_length = ($local_length % 31) ? ($local_length - ($local_length % 31) + 31) : $local_length;
85
86
                // You thought we are finished now? Noooo... now compare them.
87
                foreach ($this->acl as $forum_id => $bitstring)
88
                {
89
                        if (($forum_id && strlen($bitstring) != $local_length) || (!$forum_id && strlen($bitstring) != $global_length))
90
                        {
91
                                $renew = true;
92
                                break;
93
                        }
94
                }
95
96
                // If a bitstring within the list does not match the options, we have a user with incorrect permissions set and need to renew them
97
                if ($renew)
98
                {
99
                        $this->acl_cache($userdata);
100
                        $this->_fill_acl($userdata['user_permissions']);
101
                }
102
103
                return;
104
        }
105
106
        /**
107
        * Fill ACL array with relevant bitstrings from user_permissions column
108
        * @access private
109
        */
110
        function _fill_acl($user_permissions)
111
        {
112
                $seq_cache = array();
113
                $this->acl = array();
114
                $user_permissions = explode("\n", $user_permissions);
115
116
                foreach ($user_permissions as $f => $seq)
117
                {
118
                        if ($seq)
119
                        {
120
                                $i = 0;
121
122
                                if (!isset($this->acl[$f]))
123
                                {
124
                                        $this->acl[$f] = '';
125
                                }
126
127
                                while ($subseq = substr($seq, $i, 6))
128
                                {
129
                                        if (isset($seq_cache[$subseq]))
130
                                        {
131
                                                $converted = $seq_cache[$subseq];
132
                                        }
133
                                        else
134
                                        {
135
                                                $converted = $seq_cache[$subseq] = str_pad(base_convert($subseq, 36, 2), 31, 0, STR_PAD_LEFT);
136
                                        }
137
138
                                        // We put the original bitstring into the acl array
139
                                        $this->acl[$f] .= $converted;
140
                                        $i += 6;
141
                                }
142
                        }
143
                }
144
        }
145
146
        /**
147
        * Look up an option
148
        * if the option is prefixed with !, then the result becomes negated
149
        *
150
        * If a forum id is specified the local option will be combined with a global option if one exist.
151
        * If a forum id is not specified, only the global option will be checked.
152
        */
153
        function acl_get($opt, $f = 0)
154
        {
155
                $negate = false;
156
157
                if (strpos($opt, '!') === 0)
158
                {
159
                        $negate = true;
160
                        $opt = substr($opt, 1);
161
                }
162
163
                if (!isset($this->cache[$f][$opt]))
164
                {
165
                        // We combine the global/local option with an OR because some options are global and local.
166
                        // If the user has the global permission the local one is true too and vice versa
167
                        $this->cache[$f][$opt] = false;
168
169
                        // Is this option a global permission setting?
170
                        if (isset($this->acl_options['global'][$opt]))
171
                        {
172
                                if (isset($this->acl[0]))
173
                                {
174
                                        $this->cache[$f][$opt] = $this->acl[0][$this->acl_options['global'][$opt]];
175
                                }
176
                        }
177
178
                        // Is this option a local permission setting?
179
                        // But if we check for a global option only, we won't combine the options...
180
                        if ($f != 0 && isset($this->acl_options['local'][$opt]))
181
                        {
182
                                if (isset($this->acl[$f]) && isset($this->acl[$f][$this->acl_options['local'][$opt]]))
183
                                {
184
                                        $this->cache[$f][$opt] |= $this->acl[$f][$this->acl_options['local'][$opt]];
185
                                }
186
                        }
187
                }
188
189
                // Founder always has all global options set to true...
190
                return ($negate) ? !$this->cache[$f][$opt] : $this->cache[$f][$opt];
191
        }
192
193
        /**
194
        * Get forums with the specified permission setting
195
        * if the option is prefixed with !, then the result becomes nagated
196
        *
197
        * @param bool $clean set to true if only values needs to be returned which are set/unset
198
        */
199
        function acl_getf($opt, $clean = false)
200
        {
201
                $acl_f = array();
202
                $negate = false;
203
204
                if (strpos($opt, '!') === 0)
205
                {
206
                        $negate = true;
207
                        $opt = substr($opt, 1);
208
                }
209
210
                // If we retrieve a list of forums not having permissions in, we need to get every forum_id
211
                if ($negate)
212
                {
213
                        if ($this->acl_forum_ids === false)
214
                        {
215
                                global $db;
216
217
                                $sql = 'SELECT forum_id
218
                                        FROM ' . FORUMS_TABLE;
219
220
                                if (sizeof($this->acl))
221
                                {
222
                                        $sql .= ' WHERE ' . $db->sql_in_set('forum_id', array_keys($this->acl), true);
223
                                }
224
                                $result = $db->sql_query($sql);
225
226
                                $this->acl_forum_ids = array();
227
                                while ($row = $db->sql_fetchrow($result))
228
                                {
229
                                        $this->acl_forum_ids[] = $row['forum_id'];
230
                                }
231
                                $db->sql_freeresult($result);
232
                        }
233
                }
234
235
                if (isset($this->acl_options['local'][$opt]))
236
                {
237
                        foreach ($this->acl as $f => $bitstring)
238
                        {
239
                                // Skip global settings
240
                                if (!$f)
241
                                {
242
                                        continue;
243
                                }
244
245
                                $allowed = (!isset($this->cache[$f][$opt])) ? $this->acl_get($opt, $f) : $this->cache[$f][$opt];
246
247
                                if (!$clean)
248
                                {
249
                                        $acl_f[$f][$opt] = ($negate) ? !$allowed : $allowed;
250
                                }
251
                                else
252
                                {
253
                                        if (($negate && !$allowed) || (!$negate && $allowed))
254
                                        {
255
                                                $acl_f[$f][$opt] = 1;
256
                                        }
257
                                }
258
                        }
259
                }
260
261
                // If we get forum_ids not having this permission, we need to fill the remaining parts
262
                if ($negate && sizeof($this->acl_forum_ids))
263
                {
264
                        foreach ($this->acl_forum_ids as $f)
265
                        {
266
                                $acl_f[$f][$opt] = 1;
267
                        }
268
                }
269
270
                return $acl_f;
271
        }
272
273
        /**
274
        * Get local permission state for any forum.
275
        *
276
        * Returns true if user has the permission in one or more forums, false if in no forum.
277
        * If global option is checked it returns the global state (same as acl_get($opt))
278
        * Local option has precedence...
279
        */
280
        function acl_getf_global($opt)
281
        {
282
                if (is_array($opt))
283
                {
284
                        // evaluates to true as soon as acl_getf_global is true for one option
285
                        foreach ($opt as $check_option)
286
                        {
287
                                if ($this->acl_getf_global($check_option))
288
                                {
289
                                        return true;
290
                                }
291
                        }
292
293
                        return false;
294
                }
295
296
                if (isset($this->acl_options['local'][$opt]))
297
                {
298
                        foreach ($this->acl as $f => $bitstring)
299
                        {
300
                                // Skip global settings
301
                                if (!$f)
302
                                {
303
                                        continue;
304
                                }
305
306
                                // as soon as the user has any permission we're done so return true
307
                                if ((!isset($this->cache[$f][$opt])) ? $this->acl_get($opt, $f) : $this->cache[$f][$opt])
308
                                {
309
                                        return true;
310
                                }
311
                        }
312
                }
313
                else if (isset($this->acl_options['global'][$opt]))
314
                {
315
                        return $this->acl_get($opt);
316
                }
317
318
                return false;
319
        }
320
321
        /**
322
        * Get permission settings (more than one)
323
        */
324
        function acl_gets()
325
        {
326
                $args = func_get_args();
327
                $f = array_pop($args);
328
329
                if (!is_numeric($f))
330
                {
331
                        $args[] = $f;
332
                        $f = 0;
333
                }
334
335
                // alternate syntax: acl_gets(array('m_', 'a_'), $forum_id)
336
                if (is_array($args[0]))
337
                {
338
                        $args = $args[0];
339
                }
340
341
                $acl = 0;
342
                foreach ($args as $opt)
343
                {
344
                        $acl |= $this->acl_get($opt, $f);
345
                }
346
347
                return $acl;
348
        }
349
350
        /**
351
        * Get permission listing based on user_id/options/forum_ids
352
        *
353
        * Be careful when using this function with permissions a_, m_, u_ and f_ !
354
        * It may not work correctly. When a user group grants an a_* permission,
355
        * e.g. a_foo, but the user's a_foo permission is set to "Never", then
356
        * the user does not in fact have the a_ permission.
357
        * But the user will still be listed as having the a_ permission.
358
        *
359
        * For more information see: http://tracker.phpbb.com/browse/PHPBB3-10252
360
        */
361
        function acl_get_list($user_id = false, $opts = false, $forum_id = false)
362
        {
363
                if ($user_id !== false && !is_array($user_id) && $opts === false && $forum_id === false)
364
                {
365
                        $hold_ary = array($user_id => $this->acl_raw_data_single_user($user_id));
366
                }
367
                else
368
                {
369
                        $hold_ary = $this->acl_raw_data($user_id, $opts, $forum_id);
370
                }
371
372
                $auth_ary = array();
373
                foreach ($hold_ary as $user_id => $forum_ary)
374
                {
375
                        foreach ($forum_ary as $forum_id => $auth_option_ary)
376
                        {
377
                                foreach ($auth_option_ary as $auth_option => $auth_setting)
378
                                {
379
                                        if ($auth_setting)
380
                                        {
381
                                                $auth_ary[$forum_id][$auth_option][] = $user_id;
382
                                        }
383
                                }
384
                        }
385
                }
386
387
                return $auth_ary;
388
        }
389
390
        /**
391
        * Cache data to user_permissions row
392
        */
393
        function acl_cache(&$userdata)
394
        {
395
                global $db;
396
397
                // Empty user_permissions
398
                $userdata['user_permissions'] = '';
399
400
                $hold_ary = $this->acl_raw_data_single_user($userdata['user_id']);
401
402
                // Key 0 in $hold_ary are global options, all others are forum_ids
403
404
                // If this user is founder we're going to force fill the admin options ...
405
                if ($userdata['user_type'] == USER_FOUNDER)
406
                {
407
                        foreach ($this->acl_options['global'] as $opt => $id)
408
                        {
409
                                if (strpos($opt, 'a_') === 0)
410
                                {
411
                                        $hold_ary[0][$this->acl_options['id'][$opt]] = ACL_YES;
412
                                }
413
                        }
414
                }
415
416
                $hold_str = $this->build_bitstring($hold_ary);
417
418
                if ($hold_str)
419
                {
420
                        $userdata['user_permissions'] = $hold_str;
421
422
                        $sql = 'UPDATE ' . USERS_TABLE . "
423
                                SET user_permissions = '" . $db->sql_escape($userdata['user_permissions']) . "',
424
                                        user_perm_from = 0
425
                                WHERE user_id = " . $userdata['user_id'];
426
                        $db->sql_query($sql);
427
                }
428
429
                return;
430
        }
431
432
        /**
433
        * Build bitstring from permission set
434
        */
435
        function build_bitstring(&$hold_ary)
436
        {
437
                $hold_str = '';
438
439
                if (sizeof($hold_ary))
440
                {
441
                        ksort($hold_ary);
442
443
                        $last_f = 0;
444
445
                        foreach ($hold_ary as $f => $auth_ary)
446
                        {
447
                                $ary_key = (!$f) ? 'global' : 'local';
448
449
                                $bitstring = array();
450
                                foreach ($this->acl_options[$ary_key] as $opt => $id)
451
                                {
452
                                        if (isset($auth_ary[$this->acl_options['id'][$opt]]))
453
                                        {
454
                                                $bitstring[$id] = $auth_ary[$this->acl_options['id'][$opt]];
455
456
                                                $option_key = substr($opt, 0, strpos($opt, '_') + 1);
457
458
                                                // If one option is allowed, the global permission for this option has to be allowed too
459
                                                // example: if the user has the a_ permission this means he has one or more a_* permissions
460
                                                if ($auth_ary[$this->acl_options['id'][$opt]] == ACL_YES && (!isset($bitstring[$this->acl_options[$ary_key][$option_key]]) || $bitstring[$this->acl_options[$ary_key][$option_key]] == ACL_NEVER))
461
                                                {
462
                                                        $bitstring[$this->acl_options[$ary_key][$option_key]] = ACL_YES;
463
                                                }
464
                                        }
465
                                        else
466
                                        {
467
                                                $bitstring[$id] = ACL_NEVER;
468
                                        }
469
                                }
470
471
                                // Now this bitstring defines the permission setting for the current forum $f (or global setting)
472
                                $bitstring = implode('', $bitstring);
473
474
                                // The line number indicates the id, therefore we have to add empty lines for those ids not present
475
                                $hold_str .= str_repeat("\n", $f - $last_f);
476
477
                                // Convert bitstring for storage - we do not use binary/bytes because PHP's string functions are not fully binary safe
478
                                for ($i = 0, $bit_length = strlen($bitstring); $i < $bit_length; $i += 31)
479
                                {
480
                                        $hold_str .= str_pad(base_convert(str_pad(substr($bitstring, $i, 31), 31, 0, STR_PAD_RIGHT), 2, 36), 6, 0, STR_PAD_LEFT);
481
                                }
482
483
                                $last_f = $f;
484
                        }
485
                        unset($bitstring);
486
487
                        $hold_str = rtrim($hold_str);
488
                }
489
490
                return $hold_str;
491
        }
492
493
        /**
494
        * Clear one or all users cached permission settings
495
        */
496
        function acl_clear_prefetch($user_id = false)
497
        {
498
                global $db, $cache;
499
500
                // Rebuild options cache
501
                $cache->destroy('_role_cache');
502
503
                $sql = 'SELECT *
504
                        FROM ' . ACL_ROLES_DATA_TABLE . '
505
                        ORDER BY role_id ASC';
506
                $result = $db->sql_query($sql);
507
508
                $this->role_cache = array();
509
                while ($row = $db->sql_fetchrow($result))
510
                {
511
                        $this->role_cache[$row['role_id']][$row['auth_option_id']] = (int) $row['auth_setting'];
512
                }
513
                $db->sql_freeresult($result);
514
515
                foreach ($this->role_cache as $role_id => $role_options)
516
                {
517
                        $this->role_cache[$role_id] = serialize($role_options);
518
                }
519
520
                $cache->put('_role_cache', $this->role_cache);
521
522
                // Now empty user permissions
523
                $where_sql = '';
524
525
                if ($user_id !== false)
526
                {
527
                        $user_id = (!is_array($user_id)) ? $user_id = array((int) $user_id) : array_map('intval', $user_id);
528
                        $where_sql = ' WHERE ' . $db->sql_in_set('user_id', $user_id);
529
                }
530
531
                $sql = 'UPDATE ' . USERS_TABLE . "
532
                        SET user_permissions = '',
533
                                user_perm_from = 0
534
                        $where_sql";
535
                $db->sql_query($sql);
536
537
                return;
538
        }
539
540
        /**
541
        * Get assigned roles
542
        */
543
        function acl_role_data($user_type, $role_type, $ug_id = false, $forum_id = false)
544
        {
545
                global $db;
546
547
                $roles = array();
548
549
                $sql_id = ($user_type == 'user') ? 'user_id' : 'group_id';
550
551
                $sql_ug = ($ug_id !== false) ? ((!is_array($ug_id)) ? "AND a.$sql_id = $ug_id" : 'AND ' . $db->sql_in_set("a.$sql_id", $ug_id)) : '';
552
                $sql_forum = ($forum_id !== false) ? ((!is_array($forum_id)) ? "AND a.forum_id = $forum_id" : 'AND ' . $db->sql_in_set('a.forum_id', $forum_id)) : '';
553
554
                // Grab assigned roles...
555
                $sql = 'SELECT a.auth_role_id, a.' . $sql_id . ', a.forum_id
556
                        FROM ' . (($user_type == 'user') ? ACL_USERS_TABLE : ACL_GROUPS_TABLE) . ' a, ' . ACL_ROLES_TABLE . " r
557
                        WHERE a.auth_role_id = r.role_id
558
                                AND r.role_type = '" . $db->sql_escape($role_type) . "'
559
                                $sql_ug
560
                                $sql_forum
561
                        ORDER BY r.role_order ASC";
562
                $result = $db->sql_query($sql);
563
564
                while ($row = $db->sql_fetchrow($result))
565
                {
566
                        $roles[$row[$sql_id]][$row['forum_id']] = $row['auth_role_id'];
567
                }
568
                $db->sql_freeresult($result);
569
570
                return $roles;
571
        }
572
573
        /**
574
        * Get raw acl data based on user/option/forum
575
        */
576
        function acl_raw_data($user_id = false, $opts = false, $forum_id = false)
577
        {
578
                global $db;
579
580
                $sql_user = ($user_id !== false) ? ((!is_array($user_id)) ? 'user_id = ' . (int) $user_id : $db->sql_in_set('user_id', array_map('intval', $user_id))) : '';
581
                $sql_forum = ($forum_id !== false) ? ((!is_array($forum_id)) ? 'AND a.forum_id = ' . (int) $forum_id : 'AND ' . $db->sql_in_set('a.forum_id', array_map('intval', $forum_id))) : '';
582
583
                $sql_opts = $sql_opts_select = $sql_opts_from = '';
584
                $hold_ary = array();
585
586
                if ($opts !== false)
587
                {
588
                        $sql_opts_select = ', ao.auth_option';
589
                        $sql_opts_from = ', ' . ACL_OPTIONS_TABLE . ' ao';
590
                        $this->build_auth_option_statement('ao.auth_option', $opts, $sql_opts);
591
                }
592
593
                $sql_ary = array();
594
595
                // Grab non-role settings - user-specific
596
                $sql_ary[] = 'SELECT a.user_id, a.forum_id, a.auth_setting, a.auth_option_id' . $sql_opts_select . '
597
                        FROM ' . ACL_USERS_TABLE . ' a' . $sql_opts_from . '
598
                        WHERE a.auth_role_id = 0 ' .
599
                                (($sql_opts_from) ? 'AND a.auth_option_id = ao.auth_option_id ' : '') .
600
                                (($sql_user) ? 'AND a.' . $sql_user : '') . "
601
                                $sql_forum
602
                                $sql_opts";
603
604
                // Now the role settings - user-specific
605
                $sql_ary[] = 'SELECT a.user_id, a.forum_id, r.auth_option_id, r.auth_setting, r.auth_option_id' . $sql_opts_select . '
606
                        FROM ' . ACL_USERS_TABLE . ' a, ' . ACL_ROLES_DATA_TABLE . ' r' . $sql_opts_from . '
607
                        WHERE a.auth_role_id = r.role_id ' .
608
                                (($sql_opts_from) ? 'AND r.auth_option_id = ao.auth_option_id ' : '') .
609
                                (($sql_user) ? 'AND a.' . $sql_user : '') . "
610
                                $sql_forum
611
                                $sql_opts";
612
613
                foreach ($sql_ary as $sql)
614
                {
615
                        $result = $db->sql_query($sql);
616
617
                        while ($row = $db->sql_fetchrow($result))
618
                        {
619
                                $option = ($sql_opts_select) ? $row['auth_option'] : $this->acl_options['option'][$row['auth_option_id']];
620
                                $hold_ary[$row['user_id']][$row['forum_id']][$option] = $row['auth_setting'];
621
                        }
622
                        $db->sql_freeresult($result);
623
                }
624
625
                $sql_ary = array();
626
627
                // Now grab group settings - non-role specific...
628
                $sql_ary[] = 'SELECT ug.user_id, a.forum_id, a.auth_setting, a.auth_option_id' . $sql_opts_select . '
629
                        FROM ' . ACL_GROUPS_TABLE . ' a, ' . USER_GROUP_TABLE . ' ug, ' . GROUPS_TABLE . ' g' . $sql_opts_from . '
630
                        WHERE a.auth_role_id = 0 ' .
631
                                (($sql_opts_from) ? 'AND a.auth_option_id = ao.auth_option_id ' : '') . '
632
                                AND a.group_id = ug.group_id
633
                                AND g.group_id = ug.group_id
634
                                AND ug.user_pending = 0
635
                                AND NOT (ug.group_leader = 1 AND g.group_skip_auth = 1)
636
                                ' . (($sql_user) ? 'AND ug.' . $sql_user : '') . "
637
                                $sql_forum
638
                                $sql_opts";
639
640
                // Now grab group settings - role specific...
641
                $sql_ary[] = 'SELECT ug.user_id, a.forum_id, r.auth_setting, r.auth_option_id' . $sql_opts_select . '
642
                        FROM ' . ACL_GROUPS_TABLE . ' a, ' . USER_GROUP_TABLE . ' ug, ' . GROUPS_TABLE . ' g, ' . ACL_ROLES_DATA_TABLE . ' r' . $sql_opts_from . '
643
                        WHERE a.auth_role_id = r.role_id ' .
644
                                (($sql_opts_from) ? 'AND r.auth_option_id = ao.auth_option_id ' : '') . '
645
                                AND a.group_id = ug.group_id
646
                                AND g.group_id = ug.group_id
647
                                AND ug.user_pending = 0
648
                                AND NOT (ug.group_leader = 1 AND g.group_skip_auth = 1)
649
                                ' . (($sql_user) ? 'AND ug.' . $sql_user : '') . "
650
                                $sql_forum
651
                                $sql_opts";
652
653
                foreach ($sql_ary as $sql)
654
                {
655
                        $result = $db->sql_query($sql);
656
657
                        while ($row = $db->sql_fetchrow($result))
658
                        {
659
                                $option = ($sql_opts_select) ? $row['auth_option'] : $this->acl_options['option'][$row['auth_option_id']];
660
661
                                if (!isset($hold_ary[$row['user_id']][$row['forum_id']][$option]) || (isset($hold_ary[$row['user_id']][$row['forum_id']][$option]) && $hold_ary[$row['user_id']][$row['forum_id']][$option] != ACL_NEVER))
662
                                {
663
                                        $hold_ary[$row['user_id']][$row['forum_id']][$option] = $row['auth_setting'];
664
665
                                        // If we detect ACL_NEVER, we will unset the flag option (within building the bitstring it is correctly set again)
666
                                        if ($row['auth_setting'] == ACL_NEVER)
667
                                        {
668
                                                $flag = substr($option, 0, strpos($option, '_') + 1);
669
670
                                                if (isset($hold_ary[$row['user_id']][$row['forum_id']][$flag]) && $hold_ary[$row['user_id']][$row['forum_id']][$flag] == ACL_YES)
671
                                                {
672
                                                        unset($hold_ary[$row['user_id']][$row['forum_id']][$flag]);
673
674
/*                                                        if (in_array(ACL_YES, $hold_ary[$row['user_id']][$row['forum_id']]))
675
                                                        {
676
                                                                $hold_ary[$row['user_id']][$row['forum_id']][$flag] = ACL_YES;
677
                                                        }
678
*/
679
                                                }
680
                                        }
681
                                }
682
                        }
683
                        $db->sql_freeresult($result);
684
                }
685
686
                return $hold_ary;
687
        }
688
689
        /**
690
        * Get raw user based permission settings
691
        */
692
        function acl_user_raw_data($user_id = false, $opts = false, $forum_id = false)
693
        {
694
                global $db;
695
696
                $sql_user = ($user_id !== false) ? ((!is_array($user_id)) ? 'user_id = ' . (int) $user_id : $db->sql_in_set('user_id', array_map('intval', $user_id))) : '';
697
                $sql_forum = ($forum_id !== false) ? ((!is_array($forum_id)) ? 'AND a.forum_id = ' . (int) $forum_id : 'AND ' . $db->sql_in_set('a.forum_id', array_map('intval', $forum_id))) : '';
698
699
                $sql_opts = '';
700
                $hold_ary = $sql_ary = array();
701
702
                if ($opts !== false)
703
                {
704
                        $this->build_auth_option_statement('ao.auth_option', $opts, $sql_opts);
705
                }
706
707
                // Grab user settings - non-role specific...
708
                $sql_ary[] = 'SELECT a.user_id, a.forum_id, a.auth_setting, a.auth_option_id, ao.auth_option
709
                        FROM ' . ACL_USERS_TABLE . ' a, ' . ACL_OPTIONS_TABLE . ' ao
710
                        WHERE a.auth_role_id = 0
711
                                AND a.auth_option_id = ao.auth_option_id ' .
712
                                (($sql_user) ? 'AND a.' . $sql_user : '') . "
713
                                $sql_forum
714
                                $sql_opts
715
                        ORDER BY a.forum_id, ao.auth_option";
716
717
                // Now the role settings - user-specific
718
                $sql_ary[] = 'SELECT a.user_id, a.forum_id, r.auth_option_id, r.auth_setting, r.auth_option_id, ao.auth_option
719
                        FROM ' . ACL_USERS_TABLE . ' a, ' . ACL_ROLES_DATA_TABLE . ' r, ' . ACL_OPTIONS_TABLE . ' ao
720
                        WHERE a.auth_role_id = r.role_id
721
                                AND r.auth_option_id = ao.auth_option_id ' .
722
                                (($sql_user) ? 'AND a.' . $sql_user : '') . "
723
                                $sql_forum
724
                                $sql_opts
725
                        ORDER BY a.forum_id, ao.auth_option";
726
727
                foreach ($sql_ary as $sql)
728
                {
729
                        $result = $db->sql_query($sql);
730
731
                        while ($row = $db->sql_fetchrow($result))
732
                        {
733
                                $hold_ary[$row['user_id']][$row['forum_id']][$row['auth_option']] = $row['auth_setting'];
734
                        }
735
                        $db->sql_freeresult($result);
736
                }
737
738
                return $hold_ary;
739
        }
740
741
        /**
742
        * Get raw group based permission settings
743
        */
744
        function acl_group_raw_data($group_id = false, $opts = false, $forum_id = false)
745
        {
746
                global $db;
747
748
                $sql_group = ($group_id !== false) ? ((!is_array($group_id)) ? 'group_id = ' . (int) $group_id : $db->sql_in_set('group_id', array_map('intval', $group_id))) : '';
749
                $sql_forum = ($forum_id !== false) ? ((!is_array($forum_id)) ? 'AND a.forum_id = ' . (int) $forum_id : 'AND ' . $db->sql_in_set('a.forum_id', array_map('intval', $forum_id))) : '';
750
751
                $sql_opts = '';
752
                $hold_ary = $sql_ary = array();
753
754
                if ($opts !== false)
755
                {
756
                        $this->build_auth_option_statement('ao.auth_option', $opts, $sql_opts);
757
                }
758
759
                // Grab group settings - non-role specific...
760
                $sql_ary[] = 'SELECT a.group_id, a.forum_id, a.auth_setting, a.auth_option_id, ao.auth_option
761
                        FROM ' . ACL_GROUPS_TABLE . ' a, ' . ACL_OPTIONS_TABLE . ' ao
762
                        WHERE a.auth_role_id = 0
763
                                AND a.auth_option_id = ao.auth_option_id ' .
764
                                (($sql_group) ? 'AND a.' . $sql_group : '') . "
765
                                $sql_forum
766
                                $sql_opts
767
                        ORDER BY a.forum_id, ao.auth_option";
768
769
                // Now grab group settings - role specific...
770
                $sql_ary[] = 'SELECT a.group_id, a.forum_id, r.auth_setting, r.auth_option_id, ao.auth_option
771
                        FROM ' . ACL_GROUPS_TABLE . ' a, ' . ACL_ROLES_DATA_TABLE . ' r, ' . ACL_OPTIONS_TABLE . ' ao
772
                        WHERE a.auth_role_id = r.role_id
773
                                AND r.auth_option_id = ao.auth_option_id ' .
774
                                (($sql_group) ? 'AND a.' . $sql_group : '') . "
775
                                $sql_forum
776
                                $sql_opts
777
                        ORDER BY a.forum_id, ao.auth_option";
778
779
                foreach ($sql_ary as $sql)
780
                {
781
                        $result = $db->sql_query($sql);
782
783
                        while ($row = $db->sql_fetchrow($result))
784
                        {
785
                                $hold_ary[$row['group_id']][$row['forum_id']][$row['auth_option']] = $row['auth_setting'];
786
                        }
787
                        $db->sql_freeresult($result);
788
                }
789
790
                return $hold_ary;
791
        }
792
793
        /**
794
        * Get raw acl data based on user for caching user_permissions
795
        * This function returns the same data as acl_raw_data(), but without the user id as the first key within the array.
796
        */
797
        function acl_raw_data_single_user($user_id)
798
        {
799
                global $db, $cache;
800
801
                // Check if the role-cache is there
802
                if (($this->role_cache = $cache->get('_role_cache')) === false)
803
                {
804
                        $this->role_cache = array();
805
806
                        // We pre-fetch roles
807
                        $sql = 'SELECT *
808
                                FROM ' . ACL_ROLES_DATA_TABLE . '
809
                                ORDER BY role_id ASC';
810
                        $result = $db->sql_query($sql);
811
812
                        while ($row = $db->sql_fetchrow($result))
813
                        {
814
                                $this->role_cache[$row['role_id']][$row['auth_option_id']] = (int) $row['auth_setting'];
815
                        }
816
                        $db->sql_freeresult($result);
817
818
                        foreach ($this->role_cache as $role_id => $role_options)
819
                        {
820
                                $this->role_cache[$role_id] = serialize($role_options);
821
                        }
822
823
                        $cache->put('_role_cache', $this->role_cache);
824
                }
825
826
                $hold_ary = array();
827
828
                // Grab user-specific permission settings
829
                $sql = 'SELECT forum_id, auth_option_id, auth_role_id, auth_setting
830
                        FROM ' . ACL_USERS_TABLE . '
831
                        WHERE user_id = ' . $user_id;
832
                $result = $db->sql_query($sql);
833
834
                while ($row = $db->sql_fetchrow($result))
835
                {
836
                        // If a role is assigned, assign all options included within this role. Else, only set this one option.
837
                        if ($row['auth_role_id'])
838
                        {
839
                                $hold_ary[$row['forum_id']] = (empty($hold_ary[$row['forum_id']])) ? unserialize($this->role_cache[$row['auth_role_id']]) : $hold_ary[$row['forum_id']] + unserialize($this->role_cache[$row['auth_role_id']]);
840
                        }
841
                        else
842
                        {
843
                                $hold_ary[$row['forum_id']][$row['auth_option_id']] = $row['auth_setting'];
844
                        }
845
                }
846
                $db->sql_freeresult($result);
847
848
                // Now grab group-specific permission settings
849
                $sql = 'SELECT a.forum_id, a.auth_option_id, a.auth_role_id, a.auth_setting
850
                        FROM ' . ACL_GROUPS_TABLE . ' a, ' . USER_GROUP_TABLE . ' ug, ' . GROUPS_TABLE . ' g
851
                        WHERE a.group_id = ug.group_id
852
                                AND g.group_id = ug.group_id
853
                                AND ug.user_pending = 0
854
                                AND NOT (ug.group_leader = 1 AND g.group_skip_auth = 1)
855
                                AND ug.user_id = ' . $user_id;
856
                $result = $db->sql_query($sql);
857
858
                while ($row = $db->sql_fetchrow($result))
859
                {
860
                        if (!$row['auth_role_id'])
861
                        {
862
                                $this->_set_group_hold_ary($hold_ary[$row['forum_id']], $row['auth_option_id'], $row['auth_setting']);
863
                        }
864
                        else if (!empty($this->role_cache[$row['auth_role_id']]))
865
                        {
866
                                foreach (unserialize($this->role_cache[$row['auth_role_id']]) as $option_id => $setting)
867
                                {
868
                                        $this->_set_group_hold_ary($hold_ary[$row['forum_id']], $option_id, $setting);
869
                                }
870
                        }
871
                }
872
                $db->sql_freeresult($result);
873
874
                return $hold_ary;
875
        }
876
877
        /**
878
        * Private function snippet for setting a specific piece of the hold_ary
879
        */
880
        function _set_group_hold_ary(&$hold_ary, $option_id, $setting)
881
        {
882
                if (!isset($hold_ary[$option_id]) || (isset($hold_ary[$option_id]) && $hold_ary[$option_id] != ACL_NEVER))
883
                {
884
                        $hold_ary[$option_id] = $setting;
885
886
                        // If we detect ACL_NEVER, we will unset the flag option (within building the bitstring it is correctly set again)
887
                        if ($setting == ACL_NEVER)
888
                        {
889
                                $flag = substr($this->acl_options['option'][$option_id], 0, strpos($this->acl_options['option'][$option_id], '_') + 1);
890
                                $flag = (int) $this->acl_options['id'][$flag];
891
892
                                if (isset($hold_ary[$flag]) && $hold_ary[$flag] == ACL_YES)
893
                                {
894
                                        unset($hold_ary[$flag]);
895
896
/*                                        This is uncommented, because i suspect this being slightly wrong due to mixed permission classes being possible
897
                                        if (in_array(ACL_YES, $hold_ary))
898
                                        {
899
                                                $hold_ary[$flag] = ACL_YES;
900
                                        }*/
901
                                }
902
                        }
903
                }
904
        }
905
906
        /**
907
        * Authentication plug-ins is largely down to Sergey Kanareykin, our thanks to him.
908
        */
909
        function login($username, $password, $autologin = false, $viewonline = 1, $admin = 0)
910
        {
911
                global $config, $db, $user, $phpbb_root_path, $phpEx;
912
913
                $method = trim(basename($config['auth_method']));
914
                include_once($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx);
915
916
                $method = 'login_' . $method;
917
                if (function_exists($method))
918
                {
919
                        $login = $method($username, $password, $user->ip, $user->browser, $user->forwarded_for);
920
921
                        // If the auth module wants us to create an empty profile do so and then treat the status as LOGIN_SUCCESS
922
                        if ($login['status'] == LOGIN_SUCCESS_CREATE_PROFILE)
923
                        {
924
                                // we are going to use the user_add function so include functions_user.php if it wasn't defined yet
925
                                if (!function_exists('user_add'))
926
                                {
927
                                        include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
928
                                }
929
930
                                user_add($login['user_row'], (isset($login['cp_data'])) ? $login['cp_data'] : false);
931
932
                                $sql = 'SELECT user_id, username, user_password, user_passchg, user_email, user_type
933
                                        FROM ' . USERS_TABLE . "
934
                                        WHERE username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'";
935
                                $result = $db->sql_query($sql);
936
                                $row = $db->sql_fetchrow($result);
937
                                $db->sql_freeresult($result);
938
939
                                if (!$row)
940
                                {
941
                                        return array(
942
                                                'status'                => LOGIN_ERROR_EXTERNAL_AUTH,
943
                                                'error_msg'                => 'AUTH_NO_PROFILE_CREATED',
944
                                                'user_row'                => array('user_id' => ANONYMOUS),
945
                                        );
946
                                }
947
948
                                $login = array(
949
                                        'status'        => LOGIN_SUCCESS,
950
                                        'error_msg'        => false,
951
                                        'user_row'        => $row,
952
                                );
953
                        }
954
955
                        // If login succeeded, we will log the user in... else we pass the login array through...
956
                        if ($login['status'] == LOGIN_SUCCESS)
957
                        {
958
                                $old_session_id = $user->session_id;
959
960
                                if ($admin)
961
                                {
962
                                        global $SID, $_SID;
963
964
                                        $cookie_expire = time() - 31536000;
965
                                        $user->set_cookie('u', '', $cookie_expire);
966
                                        $user->set_cookie('sid', '', $cookie_expire);
967
                                        unset($cookie_expire);
968
969
                                        $SID = '?sid=';
970
                                        $user->session_id = $_SID = '';
971
                                }
972
973
                                $result = $user->session_create($login['user_row']['user_id'], $admin, $autologin, $viewonline);
974
975
                                // Successful session creation
976
                                if ($result === true)
977
                                {
978
                                        // If admin re-authentication we remove the old session entry because a new one has been created...
979
                                        if ($admin)
980
                                        {
981
                                                // the login array is used because the user ids do not differ for re-authentication
982
                                                $sql = 'DELETE FROM ' . SESSIONS_TABLE . "
983
                                                        WHERE session_id = '" . $db->sql_escape($old_session_id) . "'
984
                                                        AND session_user_id = {$login['user_row']['user_id']}";
985
                                                $db->sql_query($sql);
986
                                        }
987
988
                                        return array(
989
                                                'status'                => LOGIN_SUCCESS,
990
                                                'error_msg'                => false,
991
                                                'user_row'                => $login['user_row'],
992
                                        );
993
                                }
994
995
                                return array(
996
                                        'status'                => LOGIN_BREAK,
997
                                        'error_msg'                => $result,
998
                                        'user_row'                => $login['user_row'],
999
                                );
1000
                        }
1001
1002
                        return $login;
1003
                }
1004
1005
                trigger_error('Authentication method not found', E_USER_ERROR);
1006
        }
1007
1008
        /**
1009
        * Fill auth_option statement for later querying based on the supplied options
1010
        */
1011
        function build_auth_option_statement($key, $auth_options, &$sql_opts)
1012
        {
1013
                global $db;
1014
1015
                if (!is_array($auth_options))
1016
                {
1017
                        if (strpos($auth_options, '%') !== false)
1018
                        {
1019
                                $sql_opts = "AND $key " . $db->sql_like_expression(str_replace('%', $db->any_char, $auth_options));
1020
                        }
1021
                        else
1022
                        {
1023
                                $sql_opts = "AND $key = '" . $db->sql_escape($auth_options) . "'";
1024
                        }
1025
                }
1026
                else
1027
                {
1028
                        $is_like_expression = false;
1029
1030
                        foreach ($auth_options as $option)
1031
                        {
1032
                                if (strpos($option, '%') !== false)
1033
                                {
1034
                                        $is_like_expression = true;
1035
                                }
1036
                        }
1037
1038
                        if (!$is_like_expression)
1039
                        {
1040
                                $sql_opts = 'AND ' . $db->sql_in_set($key, $auth_options);
1041
                        }
1042
                        else
1043
                        {
1044
                                $sql = array();
1045
1046
                                foreach ($auth_options as $option)
1047
                                {
1048
                                        if (strpos($option, '%') !== false)
1049
                                        {
1050
                                                $sql[] = $key . ' ' . $db->sql_like_expression(str_replace('%', $db->any_char, $option));
1051
                                        }
1052
                                        else
1053
                                        {
1054
                                                $sql[] = $key . " = '" . $db->sql_escape($option) . "'";
1055
                                        }
1056
                                }
1057
1058
                                $sql_opts = 'AND (' . implode(' OR ', $sql) . ')';
1059
                        }
1060
                }
1061
        }
1062
}
1063
1064
?>