1<? 2require_once("inc/common.php"); 3require_once("inc/io.php"); 4require_once("inc/blowfish.php"); 5# load the the auth functions 6require_once('inc/auth_'.$conf['authtype'].'.php'); 7 8# some ACL level defines 9define('AUTH_NONE',0); 10define('AUTH_READ',1); 11define('AUTH_EDIT',2); 12define('AUTH_CREATE',4); 13define('AUTH_UPLOAD',8); 14define('AUTH_GRANT',255); 15 16if($conf['useacl']){ 17 auth_login($_REQUEST['u'],$_REQUEST['p'],$_REQUEST['r']); 18 # load ACL into a global array 19 $AUTH_ACL = file('conf/acl.auth'); 20} 21 22/** 23 * This tries to login the user based on the sent auth credentials 24 * 25 * FIXME: Description no longer valid! 26 * 27 * The authentication works like this: if a username was given 28 * a new login is assumed and user/password are checked - if they 29 * are correct a random authtoken is created which is stored in 30 * the session _and_ in a cookie. 31 * The user stays logged in as long as the session and the cookie 32 * match. This still isn't the securest method but requires an 33 * attacker to steal an existing session _and_ the authtoken 34 * cookie. The actual password is only transfered once per login. 35 * 36 * On a successful login $_SERVER[REMOTE_USER] and $USERINFO 37 * are set. 38*/ 39function auth_login($user,$pass,$sticky=false){ 40 global $USERINFO; 41 global $conf; 42 global $lang; 43 $sticky ? $sticky = true : $sticky = false; //sanity check 44 45 if(isset($user)){ 46 //usual login 47 if (auth_checkPass($user,$pass)){ 48 // make logininfo globally available 49 $_SERVER['REMOTE_USER'] = $user; 50 $USERINFO = auth_getUserData($user); //FIXME move all references to session 51 52 // set cookie 53 $pass = PMA_blowfish_encrypt($pass,auth_cookiesalt()); 54 $cookie = base64_encode("$user|$sticky|$pass"); 55 if($sticky) $time = time()+60*60*24*365; //one year 56 setcookie('DokuWikiAUTH',$cookie,$time); 57 58 // set session 59 $_SESSION[$conf['title']]['auth']['user'] = $user; 60 $_SESSION[$conf['title']]['auth']['pass'] = $pass; 61 $_SESSION[$conf['title']]['auth']['buid'] = auth_browseruid(); 62 $_SESSION[$conf['title']]['auth']['info'] = $USERINFO; 63 return true; 64 }else{ 65 //invalid credentials - log off 66 msg($lang['badlogin'],-1); 67 auth_logoff(); 68 return false; 69 } 70 }else{ 71 // read cookie information 72 $cookie = base64_decode($_COOKIE['DokuWikiAUTH']); 73 list($user,$sticky,$pass) = split('\|',$cookie,3); 74 // get session info 75 $session = $_SESSION[$conf['title']]['auth']; 76 77 if($user && $pass){ 78 // we got a cookie - see if we can trust it 79 if(isset($session) && 80 ($session['user'] == $user) && 81 ($session['pass'] == $pass) && //still crypted 82 ($session['buid'] == auth_browseruid()) ){ 83 // he has session, cookie and browser right - let him in 84 $_SERVER['REMOTE_USER'] = $user; 85 $USERINFO = $session['info']; //FIXME move all references to session 86 return true; 87 } 88 // no we don't trust it yet - recheck pass 89 $pass = PMA_blowfish_decrypt($pass,auth_cookiesalt()); 90 return auth_login($user,$pass,$sticky); 91 } 92 } 93 //just to be sure 94 auth_logoff(); 95 return false; 96} 97 98/** 99 * Builds a pseudo UID from browserdata 100 * 101 * This is neither unique nor unfakable - still it adds some 102 * security 103 */ 104function auth_browseruid(){ 105 $uid = ''; 106 $uid .= $_SERVER['HTTP_USER_AGENT']; 107 $uid .= $_SERVER['HTTP_ACCEPT_ENCODING']; 108 $uid .= $_SERVER['HTTP_ACCEPT_LANGUAGE']; 109 $uid .= $_SERVER['HTTP_ACCEPT_CHARSET']; 110 return md5($uid); 111} 112 113/** 114 * Creates a random key to encrypt the password in cookies 115 */ 116function auth_cookiesalt(){ 117 global $conf; 118 $file = $conf['datadir'].'/.cache/cookiesalt'; 119 $salt = io_readFile($file); 120 if(empty($salt)){ 121 $salt = uniqid(rand(),true); 122 io_saveFile($file,$salt); 123 } 124 return $salt; 125} 126 127/** 128 * This clears all authenticationdata and thus log the user 129 * off 130 */ 131function auth_logoff(){ 132 global $conf; 133 global $USERINFO; 134 unset($_SESSION[$conf['title']]['auth']['user']); 135 unset($_SESSION[$conf['title']]['auth']['pass']); 136 unset($_SESSION[$conf['title']]['auth']['info']); 137 unset($_SERVER['REMOTE_USER']); 138 $USERINFO=null; //FIXME 139 setcookie('DokuWikiAUTH','',time()-3600); 140} 141 142/** 143 * Convinience function for auth_aclcheck 144 */ 145function auth_quickaclcheck($id){ 146 global $conf; 147 global $USERINFO; 148 # if no ACL is used always return upload rights 149 if(!$conf['useacl']) return AUTH_UPLOAD; 150 return auth_aclcheck($id,$_SERVER['REMOTE_USER'],$USERINFO['grps']); 151} 152 153/** 154 * Returns the maximum rights a user has for 155 * the given ID or its namespace 156 */ 157function auth_aclcheck($id,$user,$groups){ 158 global $conf; 159 global $AUTH_ACL; 160 161 # if no ACL is used always return upload rights 162 if(!$conf['useacl']) return AUTH_UPLOAD; 163 164 $ns = getNS($id); 165 $perm = -1; 166 167 if($user){ 168 //prepend groups with @ 169 for($i=0; $i<count($groups); $i++){ 170 $groups[$i] = '@'.$groups[$i]; 171 } 172 //add ALL group 173 $groups[] = '@ALL'; 174 //add User 175 $groups[] = $user; 176 //build regexp 177 $regexp = join('|',$groups); 178 }else{ 179 $regexp = '@ALL'; 180 } 181 182 //check exact match first 183 $matches = preg_grep('/^'.$id.'\s+('.$regexp.')\s+/',$AUTH_ACL); 184 if(count($matches)){ 185 foreach($matches as $match){ 186 $match = preg_replace('/#.*$/','',$match); //ignore comments 187 $acl = preg_split('/\s+/',$match); 188 if($acl[2] > $perm){ 189 $perm = $acl[2]; 190 } 191 } 192 if($perm > -1){ 193 //we had a match - return it 194 return $perm; 195 } 196 } 197 198 //still here? do the namespace checks 199 if($ns){ 200 $path = $ns.':\*'; 201 }else{ 202 $path = '\*'; //root document 203 } 204 205 do{ 206 $matches = preg_grep('/^'.$path.'\s+('.$regexp.')\s+/',$AUTH_ACL); 207 if(count($matches)){ 208 foreach($matches as $match){ 209 $match = preg_replace('/#.*$/','',$match); //ignore comments 210 $acl = preg_split('/\s+/',$match); 211 if($acl[2] > $perm){ 212 $perm = $acl[2]; 213 } 214 } 215 //we had a match - return it 216 return $perm; 217 } 218 219 //get next higher namespace 220 $ns = getNS($ns); 221 222 if($path != '\*'){ 223 $path = $ns.':\*'; 224 if($path == ':\*') $path = '\*'; 225 }else{ 226 //we did this already 227 //looks like there is something wrong with the ACL 228 //break here 229 return $perm; 230 } 231 }while(1); //this should never loop endless 232} 233 234/** 235 * Create a pronouncable password 236 * 237 * @see: http://www.phpbuilder.com/annotate/message.php3?id=1014451 238 */ 239function auth_pwgen(){ 240 $pw = ''; 241 $c = 'bcdfghjklmnprstvwz'; //consonants except hard to speak ones 242 $v = 'aeiou'; //vowels 243 $a = $c.$v; //both 244 245 //use two syllables... 246 for($i=0;$i < 2; $i++){ 247 $pw .= $c[rand(0, strlen($c)-1)]; 248 $pw .= $v[rand(0, strlen($v)-1)]; 249 $pw .= $a[rand(0, strlen($a)-1)]; 250 } 251 //... and add a nice number 252 $pw .= rand(10,99); 253 254 return $pw; 255} 256 257/** 258 * Sends a password to the given user 259 * 260 * returns true on success 261 */ 262function auth_sendPassword($user,$password){ 263 global $conf; 264 global $lang; 265 $users = auth_loadUserData(); 266 $hdrs = ''; 267 268 if(!$users[$user]['mail']) return false; 269 270 $text = rawLocale('password'); 271 $text = str_replace('@DOKUWIKIURL@',getBaseURL(true),$text); 272 $text = str_replace('@FULLNAME@',$users[$user]['name'],$text); 273 $text = str_replace('@LOGIN@',$user,$text); 274 $text = str_replace('@PASSWORD@',$password,$text); 275 $text = str_replace('@TITLE@',$conf['title'],$text); 276 277 if (!empty($conf['mailfrom'])) { 278 $hdrs = 'From: '.$conf['mailfrom']."\n"; 279 } 280 return @mail($users[$user]['mail'],$lang['regpwmail'],$text,$hdrs); 281} 282 283/** 284 * The new user registration - we get our info directly from 285 * $_POST 286 * 287 * It returns true on success and false on any error 288 */ 289function register(){ 290 global $lang; 291 global $conf; 292 293 if(!$_POST['save']) return false; 294 if(!$conf['openregister']) return false; 295 296 //clean username 297 $_POST['login'] = preg_replace('/.*:/','',$_POST['login']); 298 $_POST['login'] = cleanID($_POST['login']); 299 //clean fullname and email 300 $_POST['fullname'] = trim(str_replace(':','',$_POST['fullname'])); 301 $_POST['email'] = trim(str_replace(':','',$_POST['email'])); 302 303 if( empty($_POST['login']) || 304 empty($_POST['fullname']) || 305 empty($_POST['email']) ){ 306 msg($lang['regmissing'],-1); 307 return false; 308 } 309 310 //check mail 311 if(!isvalidemail($_POST['email'])){ 312 msg($lang['regbadmail'],-1); 313 return false; 314 } 315 316 //okay try to create the user 317 $pass = auth_createUser($_POST['login'],$_POST['fullname'],$_POST['email']); 318 if(empty($pass)){ 319 msg($lang['reguexists'],-1); 320 return false; 321 } 322 323 //send him the password 324 if (auth_sendPassword($_POST['login'],$pass)){ 325 msg($lang['regsuccess'],1); 326 return true; 327 }else{ 328 msg($lang['regmailfail'],-1); 329 return false; 330 } 331} 332 333/** 334 * Uses a regular expresion to check if a given mail address is valid 335 * 336 * @see http://www.webmasterworld.com/forum88/135.htm 337 * 338 * May not be completly RFC conform! 339 */ 340function isvalidemail($email){ 341 return eregi("^[0-9a-z]([-_.]?[0-9a-z])*@[0-9a-z]([-.]?[0-9a-z])*\\.[a-z]{2,4}$", $email); 342} 343 344?> 345