1<?php
2if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../../../../../../../').'/');
3$CONF_DIR = DOKU_INC.'conf';
4if(file_exists($CONF_DIR)) {
5   if(!defined('DOKU_CONF')) define('DOKU_CONF',DOKU_INC.'conf/');
6}
7else {
8    require_once(DOKU_INC. 'inc/preload.php');
9 }
10require_once DOKU_INC.'inc/utf8.php';
11
12// some ACL level defines
13  define('AUTH_NONE',0);
14  define('AUTH_READ',1);
15  define('AUTH_EDIT',2);
16  define('AUTH_CREATE',4);
17  define('AUTH_UPLOAD',8);
18  define('AUTH_DELETE',16);
19  define('AUTH_ADMIN',255);
20  global $AUTH_ACL;
21
22  global $cache_authname; $cache_authname = array();
23  global $config_cascade;
24  global $Dwfck_conf_values;
25  $AUTH_ACL = array();
26
27 //load ACL into a global array XXX
28 $auth_file = DOKU_CONF. '/acl.auth.php';
29 if(isset( $_COOKIE['FCK_animal_inc'] )) {
30   $animal_inc = $_COOKIE['FCK_animal_inc'];
31    $auth_file = $animal_inc.'conf/acl.auth.php';
32}
33
34  $AUTH_ACL = file($auth_file);
35
36/**
37 * Returns the maximum rights a user has for
38 * the given ID or its namespace
39 *
40 * @author  Andreas Gohr <andi@splitbrain.org>
41 *
42 * @param  string  $id     page ID
43 * @param  string  $user   Username
44 * @param  array   $groups Array of groups the user is in
45 * @return int             permission level
46 */
47function auth_aclcheck($id,$user,$groups, $_auth=1){
48
49  global $AUTH_ACL;
50  $AUTH_ACL = auth_loadACL($AUTH_ACL);
51  if($_auth == 255) {
52        return 255;
53  }
54  elseif(isset($_SESSION['dwfck_acl']) && $_SESSION['dwfck_acl'] == 255) {
55      return 255;
56  }
57    //make sure groups is an array
58    if(!is_array($groups)) $groups = array();
59
60    if(!auth_isCaseSensitive()) {
61        $user   = utf8_strtolower($user);
62        $groups = array_map('utf8_strtolower', $groups);
63    }
64    $user   = auth_cleanUser($user);
65    $groups = array_map('auth_cleanGroup', (array) $groups);
66    $user   = auth_nameencode($user);
67
68    //prepend groups with @ and nameencode
69    $cnt = count($groups);
70    for($i = 0; $i < $cnt; $i++) {
71        $groups[$i] = '@'.auth_nameencode($groups[$i]);
72    }
73
74    $ns   = getNS($id);
75    $perm = -1;
76
77    if($user || count($groups)) {
78        //add ALL group
79        $groups[] = '@ALL';
80        //add User
81        if($user) $groups[] = $user;
82    } else {
83        $groups[] = '@ALL';
84    }
85
86    //check exact match first
87    $matches = preg_grep('/^'.preg_quote($id, '/').'[ \t]+([^ \t]+)[ \t]+/', $AUTH_ACL);
88    if(count($matches)) {
89        foreach($matches as $match) {
90            $match = preg_replace('/#.*$/', '', $match); //ignore comments
91            $acl   = preg_split('/[ \t]+/', $match);
92            if(!auth_isCaseSensitive() && $acl[1] !== '@ALL') {
93                $acl[1] = utf8_strtolower($acl[1]);
94            }
95            if(!in_array($acl[1], $groups)) {
96                continue;
97            }
98            if($acl[2] > AUTH_DELETE) $acl[2] = AUTH_DELETE; //no admins in the ACL!
99            if($acl[2] > $perm) {
100                $perm = $acl[2];
101            }
102        }
103        if($perm > -1) {
104            //we had a match - return it
105            return (int) $perm;
106        }
107    }
108
109    //still here? do the namespace checks
110    if($ns) {
111        $path = $ns.':*';
112    } else {
113        $path = '*'; //root document
114    }
115
116    do {
117        $matches = preg_grep('/^'.preg_quote($path, '/').'[ \t]+([^ \t]+)[ \t]+/', $AUTH_ACL);
118        if(count($matches)) {
119            foreach($matches as $match) {
120                $match = preg_replace('/#.*$/', '', $match); //ignore comments
121                $acl   = preg_split('/[ \t]+/', $match);
122                if(!auth_isCaseSensitive() && $acl[1] !== '@ALL') {
123                    $acl[1] = utf8_strtolower($acl[1]);
124                }
125                if(!in_array($acl[1], $groups)) {
126                    continue;
127                }
128                if($acl[2] > AUTH_DELETE) $acl[2] = AUTH_DELETE; //no admins in the ACL!
129                if($acl[2] > $perm) {
130                    $perm = $acl[2];
131                }
132            }
133            //we had a match - return it
134            if($perm != -1) {
135                return (int) $perm;
136            }
137        }
138        //get next higher namespace
139        $ns = getNS($ns);
140
141        if($path != '*') {
142            $path = $ns.':*';
143            if($path == ':*') $path = '*';
144        } else {
145            //we did this already
146            //looks like there is something wrong with the ACL
147            //break here
148
149            return AUTH_NONE;
150        }
151    } while(1); //this should never loop endless
152    return AUTH_NONE;
153}
154
155function auth_isCaseSensitive() {
156  global $Dwfck_conf_values;
157  if(!isset($Dwfck_conf_values['plugin'])) return false;
158  $ckgdoku = $Dwfck_conf_values['plugin']['ckgdoku'];
159  if(isset($ckgdoku['auth_ci']) && $ckgdoku['auth_ci']) {
160     return false;
161  }
162  return true;
163}
164
165function auth_nameencode($name,$skip_group=false){
166  global $cache_authname;
167  $cache =& $cache_authname;
168  $name  = (string) $name;
169
170  // never encode wildcard FS#1955
171  if($name == '%USER%') return $name;
172    if($name == '%GROUP%') return $name;
173
174  if (!isset($cache[$name][$skip_group])) {
175    if($skip_group && $name{0} =='@'){
176            $cache[$name][$skip_group] = '@'.preg_replace_callback(
177                '/([\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f])/',
178                'auth_nameencode_callback', substr($name, 1)
179            );
180    }else{
181            $cache[$name][$skip_group] = preg_replace_callback(
182                '/([\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f])/',
183                'auth_nameencode_callback', $name
184            );
185    }
186  }
187
188  return $cache[$name][$skip_group];
189}
190
191/**
192 * callback encodes the matches
193 *
194 * @param array $matches first complete match, next matching subpatterms
195 * @return string
196 */
197function auth_nameencode_callback($matches) {
198    return '%'.dechex(ord(substr($matches[1],-1)));
199}
200
201
202function getNS($id){
203  $pos = strrpos((string)$id,':');
204  if($pos!==false){
205    return substr((string)$id,0,$pos);
206  }
207  return false;
208}
209
210/**
211 * Remove unwanted chars from ID
212 *
213 * Cleans a given ID to only use allowed characters. Accented characters are
214 * converted to unaccented ones
215 *
216 * @author Andreas Gohr <andi@splitbrain.org>
217 * @param  string  $raw_id    The pageid to clean
218 * @param  boolean $ascii     Force ASCII
219 * @param  boolean $media     Allow leading or trailing _ for media files
220 */
221function cleanID($raw_id,$ascii=false,$media=false){
222  global $dwfck_conf;
223
224  static $sepcharpat = null;
225  static $cache = array();
226
227  // check if it's already in the memory cache
228  if (isset($cache[(string)$raw_id])) {
229    return $cache[(string)$raw_id];
230    }
231
232
233  $sepchar = $dwfck_conf['sepchar'];
234  if($sepcharpat == null) // build string only once to save clock cycles
235    $sepcharpat = '#\\'.$sepchar.'+#';
236
237  $id = trim((string)$raw_id);
238  $id = utf8_strtolower($id);
239
240  //alternative namespace seperator
241  $id = strtr($id,';',':');
242  if($dwfck_conf['useslash']){
243    $id = strtr($id,'/',':');
244  }else{
245    $id = strtr($id,'/',$sepchar);
246  }
247
248  if($dwfck_conf['deaccent'] == 2 || $ascii) $id = utf8_romanize($id);
249  if($dwfck_conf['deaccent'] || $ascii) $id = utf8_deaccent($id,-1);
250
251  //remove specials
252  $id = utf8_stripspecials($id,$sepchar,'\*');
253
254  if($ascii) $id = utf8_strip($id);
255
256  //clean up
257  $id = preg_replace($sepcharpat,$sepchar,$id);
258  $id = preg_replace('#:+#',':',$id);
259  $id = ($media ? trim($id,':.-') : trim($id,':._-'));
260  $id = preg_replace('#:[:\._\-]+#',':',$id);
261
262  $cache[(string)$raw_id] = $id;
263  return($id);
264}
265
266
267/**
268 * Loads the ACL setup and handle user wildcards
269 *
270 * @author Andreas Gohr <andi@splitbrain.org>
271 * @returns array
272 */
273function auth_loadACL($acl_file){
274    global $config_cascade;
275
276    $acl = $acl_file;
277    $sess_id = session_id();
278    if(!isset($sess_id) || $sess_id != $_COOKIE['FCK_NmSp_acl']) {
279           session_id($_COOKIE['FCK_NmSp_acl']);
280           session_start();
281           if(isset($_SESSION['dwfck_client'])) {
282             $_SERVER['REMOTE_USER'] = $_SESSION['dwfck_client'];
283           }
284    }
285    else {
286           if(isset($_SESSION['dwfck_client'])) {
287             $_SERVER['REMOTE_USER'] = $_SESSION['dwfck_client'];
288           }
289    }
290    //support user wildcard
291    if(isset($_SERVER['REMOTE_USER'])){
292        $len = count($acl);
293        for($i=0; $i<$len; $i++){
294            if($acl[$i]{0} == '#') continue;
295            list($id,$rest) = preg_split('/\s+/',$acl[$i],2);
296            $id   = str_replace('%USER%',cleanID($_SERVER['REMOTE_USER']),$id);
297            $rest = str_replace('%USER%',auth_nameencode($_SERVER['REMOTE_USER']),$rest);
298            $acl[$i] = "$id\t$rest";
299        }
300    }
301    else {
302       $acl = str_replace('%USER%',$user,$acl);  // fall-back, in case client not found
303    }
304    return $acl;
305}
306
307function checkacl_write_debug($data) {
308
309  return;
310  if (!$handle = fopen('acl.txt', 'a')) {
311    return;
312    }
313
314    fwrite($handle, "$data\n");
315    fclose($handle);
316
317}
318
319 function get_conf_array($str) {
320     $str = preg_replace('/\s+/',"",$str);
321     return explode(';;', $str);
322  }
323
324 function has_acl_auth($path) {
325
326 }
327
328
329function auth_cleanUser($user) {
330        return $user;
331}
332
333function auth_cleanGroup($group) {
334        return $group;
335    }
336