xref: /dokuwiki/inc/auth.php (revision 8b06d178223afa83719d5719942e315c41adc596)
1ed7b5f09Sandi<?php
215fae107Sandi/**
315fae107Sandi * Authentication library
415fae107Sandi *
515fae107Sandi * Including this file will automatically try to login
615fae107Sandi * a user by calling auth_login()
715fae107Sandi *
815fae107Sandi * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
915fae107Sandi * @author     Andreas Gohr <andi@splitbrain.org>
1015fae107Sandi */
1115fae107Sandi
12ed7b5f09Sandi  if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../').'/');
13ed7b5f09Sandi  require_once(DOKU_INC.'inc/common.php');
14ed7b5f09Sandi  require_once(DOKU_INC.'inc/io.php');
15ed7b5f09Sandi  require_once(DOKU_INC.'inc/blowfish.php');
16ed7b5f09Sandi  require_once(DOKU_INC.'inc/mail.php');
17*8b06d178Schris
18*8b06d178Schris  // load the the backend auth functions and instantiate the auth object
19*8b06d178Schris  if (@file_exists(DOKU_INC.'inc/auth/'.$conf['authtype'].'.class.php')) {
20*8b06d178Schris      require_once(DOKU_INC.'inc/auth/basic.class.php');
21*8b06d178Schris      require_once(DOKU_INC.'inc/auth/'.$conf['authtype'].'.class.php');
22*8b06d178Schris
23*8b06d178Schris      $auth_class = "auth_".$conf['authtype'];
24*8b06d178Schris      if (!class_exists($auth_class)) $auth_class = "auth_basic";
25*8b06d178Schris      $auth = new $auth_class();
26*8b06d178Schris
27*8b06d178Schris      // interface between current dokuwiki/old auth system and new style auth object
28*8b06d178Schris      function auth_canDo($fn) {
29*8b06d178Schris	    global $auth;
30*8b06d178Schris		return method_exists($auth, $fn);
31*8b06d178Schris	  }
32*8b06d178Schris
33*8b06d178Schris	  // mandatory functions - these should exist
34*8b06d178Schris      function auth_checkPass($user,$pass) {
35*8b06d178Schris	    global $auth;
36*8b06d178Schris		return method_exists($auth,'checkPass') ? $auth->checkPass($user, $pass) : false;
37*8b06d178Schris	  }
38*8b06d178Schris
39*8b06d178Schris	  function auth_getUserData($user) {
40*8b06d178Schris	    global $auth;
41*8b06d178Schris		return method_exists($auth, 'getUserData') ? $auth->getUserData($user) : false;
42*8b06d178Schris	  }
43*8b06d178Schris
44*8b06d178Schris	  // optional functions, behave gracefully if these don't exist;
45*8b06d178Schris	  // potential calling code should query whether these exist in advance
46*8b06d178Schris      function auth_createUser($user,$pass,$name,$mail) {
47*8b06d178Schris	    global $auth;
48*8b06d178Schris		return method_exists($auth, 'createUser') ? $auth->createUser($user,$pass,$name,$mail) : null;
49*8b06d178Schris	  }
50*8b06d178Schris
51*8b06d178Schris	  function auth_modifyUser($user, $changes) {
52*8b06d178Schris	    global $auth;
53*8b06d178Schris		return method_exists($auth, 'modifyUser') ? $auth->modifyUser($user,$changes) : false;
54*8b06d178Schris	  }
55*8b06d178Schris
56*8b06d178Schris      function auth_deleteUsers($users) {
57*8b06d178Schris	    global $auth;
58*8b06d178Schris		return method_exists($auth, 'deleteUsers') ? $auth->deleteUsers($users) : 0;
59*8b06d178Schris	  }
60*8b06d178Schris
61*8b06d178Schris	  // other functions, will only be accessed by new code
62*8b06d178Schris	  //- these must query auth_canDo() or test method existence themselves.
63*8b06d178Schris
64*8b06d178Schris  } else {
65*8b06d178Schris    // old style auth functions
66f62ea8a1Sandi    require_once(DOKU_INC.'inc/auth/'.$conf['authtype'].'.php');
67*8b06d178Schris    $auth = null;
68*8b06d178Schris
69*8b06d178Schris	// new function, allows other parts of dokuwiki to know what they can and can't do
70*8b06d178Schris	function auth_canDo($fn) { return function_exists("auth_$fn"); }
71*8b06d178Schris  }
72f3f0262cSandi
731e866646Sandi  if (!defined('DOKU_COOKIE')) define('DOKU_COOKIE', 'DW'.md5($conf['title']));
74e65afed4SSameer D. Sahasrabuddhe
7515fae107Sandi  // some ACL level defines
76f3f0262cSandi  define('AUTH_NONE',0);
77f3f0262cSandi  define('AUTH_READ',1);
78f3f0262cSandi  define('AUTH_EDIT',2);
79f3f0262cSandi  define('AUTH_CREATE',4);
80f3f0262cSandi  define('AUTH_UPLOAD',8);
818ef6b7caSandi  define('AUTH_DELETE',16);
8210a76f6fSfrank  define('AUTH_ADMIN',255);
83f3f0262cSandi
84f3f0262cSandi  if($conf['useacl']){
85132bdbfeSandi    auth_login($_REQUEST['u'],$_REQUEST['p'],$_REQUEST['r']);
8615fae107Sandi    //load ACL into a global array
87e7cb32dcSAndreas Gohr    if(is_readable(DOKU_CONF.'acl.auth.php')){
88e7cb32dcSAndreas Gohr      $AUTH_ACL = file(DOKU_CONF.'acl.auth.php');
8911799630Sandi    }else{
9011799630Sandi      $AUTH_ACL = array();
9111799630Sandi    }
92f3f0262cSandi  }
93f3f0262cSandi
94f3f0262cSandi/**
95f3f0262cSandi * This tries to login the user based on the sent auth credentials
96f3f0262cSandi *
97f3f0262cSandi * The authentication works like this: if a username was given
9815fae107Sandi * a new login is assumed and user/password are checked. If they
9915fae107Sandi * are correct the password is encrypted with blowfish and stored
10015fae107Sandi * together with the username in a cookie - the same info is stored
10115fae107Sandi * in the session, too. Additonally a browserID is stored in the
10215fae107Sandi * session.
10315fae107Sandi *
10415fae107Sandi * If no username was given the cookie is checked: if the username,
10515fae107Sandi * crypted password and browserID match between session and cookie
10615fae107Sandi * no further testing is done and the user is accepted
10715fae107Sandi *
10815fae107Sandi * If a cookie was found but no session info was availabe the
109136ce040Sandi * blowfish encrypted password from the cookie is decrypted and
11015fae107Sandi * together with username rechecked by calling this function again.
111f3f0262cSandi *
112f3f0262cSandi * On a successful login $_SERVER[REMOTE_USER] and $USERINFO
113f3f0262cSandi * are set.
11415fae107Sandi *
11515fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
11615fae107Sandi *
11715fae107Sandi * @param   string  $user    Username
11815fae107Sandi * @param   string  $pass    Cleartext Password
11915fae107Sandi * @param   bool    $sticky  Cookie should not expire
12015fae107Sandi * @return  bool             true on successful auth
121f3f0262cSandi*/
122132bdbfeSandifunction auth_login($user,$pass,$sticky=false){
123f3f0262cSandi  global $USERINFO;
124f3f0262cSandi  global $conf;
125f3f0262cSandi  global $lang;
126132bdbfeSandi  $sticky ? $sticky = true : $sticky = false; //sanity check
127f3f0262cSandi
128f3f0262cSandi  if(isset($user)){
129132bdbfeSandi    //usual login
130f3f0262cSandi    if (auth_checkPass($user,$pass)){
131132bdbfeSandi      // make logininfo globally available
132f3f0262cSandi      $_SERVER['REMOTE_USER'] = $user;
133132bdbfeSandi      $USERINFO = auth_getUserData($user); //FIXME move all references to session
134132bdbfeSandi
135132bdbfeSandi      // set cookie
136132bdbfeSandi      $pass   = PMA_blowfish_encrypt($pass,auth_cookiesalt());
137132bdbfeSandi      $cookie = base64_encode("$user|$sticky|$pass");
138132bdbfeSandi      if($sticky) $time = time()+60*60*24*365; //one year
139e65afed4SSameer D. Sahasrabuddhe      setcookie(DOKU_COOKIE,$cookie,$time,'/');
140132bdbfeSandi
141132bdbfeSandi      // set session
142132bdbfeSandi      $_SESSION[$conf['title']]['auth']['user'] = $user;
143132bdbfeSandi      $_SESSION[$conf['title']]['auth']['pass'] = $pass;
144132bdbfeSandi      $_SESSION[$conf['title']]['auth']['buid'] = auth_browseruid();
145132bdbfeSandi      $_SESSION[$conf['title']]['auth']['info'] = $USERINFO;
146132bdbfeSandi      return true;
147f3f0262cSandi    }else{
148f3f0262cSandi      //invalid credentials - log off
149f3f0262cSandi      msg($lang['badlogin'],-1);
150f3f0262cSandi      auth_logoff();
151132bdbfeSandi      return false;
152f3f0262cSandi    }
153f3f0262cSandi  }else{
154132bdbfeSandi    // read cookie information
155e65afed4SSameer D. Sahasrabuddhe    $cookie = base64_decode($_COOKIE[DOKU_COOKIE]);
156132bdbfeSandi    list($user,$sticky,$pass) = split('\|',$cookie,3);
157132bdbfeSandi    // get session info
158132bdbfeSandi    $session = $_SESSION[$conf['title']]['auth'];
159132bdbfeSandi
160132bdbfeSandi    if($user && $pass){
161132bdbfeSandi      // we got a cookie - see if we can trust it
162132bdbfeSandi      if(isset($session) &&
163132bdbfeSandi        ($session['user'] == $user) &&
164132bdbfeSandi        ($session['pass'] == $pass) &&  //still crypted
165132bdbfeSandi        ($session['buid'] == auth_browseruid()) ){
166132bdbfeSandi        // he has session, cookie and browser right - let him in
167132bdbfeSandi        $_SERVER['REMOTE_USER'] = $user;
168132bdbfeSandi        $USERINFO = $session['info']; //FIXME move all references to session
169132bdbfeSandi        return true;
170132bdbfeSandi      }
171132bdbfeSandi      // no we don't trust it yet - recheck pass
172132bdbfeSandi      $pass = PMA_blowfish_decrypt($pass,auth_cookiesalt());
173132bdbfeSandi      return auth_login($user,$pass,$sticky);
174132bdbfeSandi    }
175132bdbfeSandi  }
176f3f0262cSandi  //just to be sure
177f3f0262cSandi  auth_logoff();
178132bdbfeSandi  return false;
179f3f0262cSandi}
180132bdbfeSandi
181132bdbfeSandi/**
182136ce040Sandi * Builds a pseudo UID from browser and IP data
183132bdbfeSandi *
184132bdbfeSandi * This is neither unique nor unfakable - still it adds some
185136ce040Sandi * security. Using the first part of the IP makes sure
186136ce040Sandi * proxy farms like AOLs are stil okay.
18715fae107Sandi *
18815fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
18915fae107Sandi *
19015fae107Sandi * @return  string  a MD5 sum of various browser headers
191132bdbfeSandi */
192132bdbfeSandifunction auth_browseruid(){
193132bdbfeSandi  $uid  = '';
194132bdbfeSandi  $uid .= $_SERVER['HTTP_USER_AGENT'];
195132bdbfeSandi  $uid .= $_SERVER['HTTP_ACCEPT_ENCODING'];
196132bdbfeSandi  $uid .= $_SERVER['HTTP_ACCEPT_LANGUAGE'];
197132bdbfeSandi  $uid .= $_SERVER['HTTP_ACCEPT_CHARSET'];
198136ce040Sandi  $uid .= substr($_SERVER['REMOTE_ADDR'],0,strpos($_SERVER['REMOTE_ADDR'],'.'));
199132bdbfeSandi  return md5($uid);
200132bdbfeSandi}
201132bdbfeSandi
202132bdbfeSandi/**
203132bdbfeSandi * Creates a random key to encrypt the password in cookies
20415fae107Sandi *
20515fae107Sandi * This function tries to read the password for encrypting
20698407a7aSandi * cookies from $conf['metadir'].'/_htcookiesalt'
20715fae107Sandi * if no such file is found a random key is created and
20815fae107Sandi * and stored in this file.
20915fae107Sandi *
21015fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
21115fae107Sandi *
21215fae107Sandi * @return  string
213132bdbfeSandi */
214132bdbfeSandifunction auth_cookiesalt(){
215132bdbfeSandi  global $conf;
21698407a7aSandi  $file = $conf['metadir'].'/_htcookiesalt';
217132bdbfeSandi  $salt = io_readFile($file);
218132bdbfeSandi  if(empty($salt)){
219132bdbfeSandi    $salt = uniqid(rand(),true);
220132bdbfeSandi    io_saveFile($file,$salt);
221132bdbfeSandi  }
222132bdbfeSandi  return $salt;
223f3f0262cSandi}
224f3f0262cSandi
225f3f0262cSandi/**
226f3f0262cSandi * This clears all authenticationdata and thus log the user
227f3f0262cSandi * off
22815fae107Sandi *
22915fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
230f3f0262cSandi */
231f3f0262cSandifunction auth_logoff(){
232f3f0262cSandi  global $conf;
233f3f0262cSandi  global $USERINFO;
234*8b06d178Schris  global $INFO, $ID;
23537065e65Sandi
23637065e65Sandi  if(isset($_SESSION[$conf['title']]['auth']['user']))
237132bdbfeSandi    unset($_SESSION[$conf['title']]['auth']['user']);
23837065e65Sandi  if(isset($_SESSION[$conf['title']]['auth']['pass']))
239132bdbfeSandi    unset($_SESSION[$conf['title']]['auth']['pass']);
24037065e65Sandi  if(isset($_SESSION[$conf['title']]['auth']['info']))
241132bdbfeSandi    unset($_SESSION[$conf['title']]['auth']['info']);
24237065e65Sandi  if(isset($_SERVER['REMOTE_USER']))
243f3f0262cSandi    unset($_SERVER['REMOTE_USER']);
244132bdbfeSandi  $USERINFO=null; //FIXME
2451e866646Sandi  setcookie(DOKU_COOKIE,'',time()-600000,'/');
246f3f0262cSandi}
247f3f0262cSandi
248f3f0262cSandi/**
24915fae107Sandi * Convinience function for auth_aclcheck()
25015fae107Sandi *
25115fae107Sandi * This checks the permissions for the current user
25215fae107Sandi *
25315fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
25415fae107Sandi *
25515fae107Sandi * @param  string  $id  page ID
25615fae107Sandi * @return int          permission level
257f3f0262cSandi */
258f3f0262cSandifunction auth_quickaclcheck($id){
259f3f0262cSandi  global $conf;
260f3f0262cSandi  global $USERINFO;
261f3f0262cSandi  # if no ACL is used always return upload rights
262f3f0262cSandi  if(!$conf['useacl']) return AUTH_UPLOAD;
263f3f0262cSandi  return auth_aclcheck($id,$_SERVER['REMOTE_USER'],$USERINFO['grps']);
264f3f0262cSandi}
265f3f0262cSandi
266f3f0262cSandi/**
267f3f0262cSandi * Returns the maximum rights a user has for
268f3f0262cSandi * the given ID or its namespace
26915fae107Sandi *
27015fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
27115fae107Sandi *
27215fae107Sandi * @param  string  $id     page ID
27315fae107Sandi * @param  string  $user   Username
27415fae107Sandi * @param  array   $groups Array of groups the user is in
27515fae107Sandi * @return int             permission level
276f3f0262cSandi */
277f3f0262cSandifunction auth_aclcheck($id,$user,$groups){
278f3f0262cSandi  global $conf;
279f3f0262cSandi  global $AUTH_ACL;
280f3f0262cSandi
281f3f0262cSandi  # if no ACL is used always return upload rights
282f3f0262cSandi  if(!$conf['useacl']) return AUTH_UPLOAD;
283f3f0262cSandi
28410a76f6fSfrank  //if user is superuser return 255 (acl_admin)
28510a76f6fSfrank  if($conf['superuser'] == $user) { return AUTH_ADMIN; }
28610a76f6fSfrank
287074cf26bSandi  //make sure groups is an array
288074cf26bSandi  if(!is_array($groups)) $groups = array();
289074cf26bSandi
29010a76f6fSfrank  //prepend groups with @
2912cd2db38Sandi  $cnt = count($groups);
2922cd2db38Sandi  for($i=0; $i<$cnt; $i++){
29310a76f6fSfrank    $groups[$i] = '@'.$groups[$i];
29410a76f6fSfrank  }
29510a76f6fSfrank  //if user is in superuser group return 255 (acl_admin)
29610a76f6fSfrank  if(in_array($conf['superuser'], $groups)) { return AUTH_ADMIN; }
29710a76f6fSfrank
298f3f0262cSandi  $ns    = getNS($id);
299f3f0262cSandi  $perm  = -1;
300f3f0262cSandi
301f3f0262cSandi  if($user){
302f3f0262cSandi    //add ALL group
303f3f0262cSandi    $groups[] = '@ALL';
304f3f0262cSandi    //add User
305f3f0262cSandi    $groups[] = $user;
306f3f0262cSandi    //build regexp
307f3f0262cSandi    $regexp   = join('|',$groups);
308f3f0262cSandi  }else{
309f3f0262cSandi    $regexp = '@ALL';
310f3f0262cSandi  }
311f3f0262cSandi
312f3f0262cSandi  //check exact match first
313f3f0262cSandi  $matches = preg_grep('/^'.$id.'\s+('.$regexp.')\s+/',$AUTH_ACL);
314f3f0262cSandi  if(count($matches)){
315f3f0262cSandi    foreach($matches as $match){
316f3f0262cSandi      $match = preg_replace('/#.*$/','',$match); //ignore comments
317f3f0262cSandi      $acl   = preg_split('/\s+/',$match);
3188ef6b7caSandi      if($acl[2] > AUTH_DELETE) $acl[2] = AUTH_DELETE; //no admins in the ACL!
319f3f0262cSandi      if($acl[2] > $perm){
320f3f0262cSandi        $perm = $acl[2];
321f3f0262cSandi      }
322f3f0262cSandi    }
323f3f0262cSandi    if($perm > -1){
324f3f0262cSandi      //we had a match - return it
325f3f0262cSandi      return $perm;
326f3f0262cSandi    }
327f3f0262cSandi  }
328f3f0262cSandi
329f3f0262cSandi  //still here? do the namespace checks
330f3f0262cSandi  if($ns){
331f3f0262cSandi    $path = $ns.':\*';
332f3f0262cSandi  }else{
333f3f0262cSandi    $path = '\*'; //root document
334f3f0262cSandi  }
335f3f0262cSandi
336f3f0262cSandi  do{
337f3f0262cSandi    $matches = preg_grep('/^'.$path.'\s+('.$regexp.')\s+/',$AUTH_ACL);
338f3f0262cSandi    if(count($matches)){
339f3f0262cSandi      foreach($matches as $match){
340f3f0262cSandi        $match = preg_replace('/#.*$/','',$match); //ignore comments
341f3f0262cSandi        $acl   = preg_split('/\s+/',$match);
3428ef6b7caSandi        if($acl[2] > AUTH_DELETE) $acl[2] = AUTH_DELETE; //no admins in the ACL!
343f3f0262cSandi        if($acl[2] > $perm){
344f3f0262cSandi          $perm = $acl[2];
345f3f0262cSandi        }
346f3f0262cSandi      }
347f3f0262cSandi      //we had a match - return it
348f3f0262cSandi      return $perm;
349f3f0262cSandi    }
350f3f0262cSandi
351f3f0262cSandi    //get next higher namespace
352f3f0262cSandi    $ns   = getNS($ns);
353f3f0262cSandi
354f3f0262cSandi    if($path != '\*'){
355f3f0262cSandi      $path = $ns.':\*';
356f3f0262cSandi      if($path == ':\*') $path = '\*';
357f3f0262cSandi    }else{
358f3f0262cSandi      //we did this already
359f3f0262cSandi      //looks like there is something wrong with the ACL
360f3f0262cSandi      //break here
361d5ce66f6SAndreas Gohr      msg('No ACL setup yet! Denying access to everyone.');
362d5ce66f6SAndreas Gohr      return AUTH_NONE;
363f3f0262cSandi    }
364f3f0262cSandi  }while(1); //this should never loop endless
36552a5af8dSandi
36652a5af8dSandi  //still here? return no permissions
36752a5af8dSandi  return AUTH_NONE;
368f3f0262cSandi}
369f3f0262cSandi
370f3f0262cSandi/**
371f3f0262cSandi * Create a pronouncable password
372f3f0262cSandi *
37315fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
37415fae107Sandi * @link    http://www.phpbuilder.com/annotate/message.php3?id=1014451
37515fae107Sandi *
37615fae107Sandi * @return string  pronouncable password
377f3f0262cSandi */
378f3f0262cSandifunction auth_pwgen(){
379f3f0262cSandi  $pw = '';
380f3f0262cSandi  $c  = 'bcdfghjklmnprstvwz'; //consonants except hard to speak ones
381f3f0262cSandi  $v  = 'aeiou';              //vowels
382f3f0262cSandi  $a  = $c.$v;                //both
383f3f0262cSandi
384f3f0262cSandi  //use two syllables...
385f3f0262cSandi  for($i=0;$i < 2; $i++){
386f3f0262cSandi    $pw .= $c[rand(0, strlen($c)-1)];
387f3f0262cSandi    $pw .= $v[rand(0, strlen($v)-1)];
388f3f0262cSandi    $pw .= $a[rand(0, strlen($a)-1)];
389f3f0262cSandi  }
390f3f0262cSandi  //... and add a nice number
391f3f0262cSandi  $pw .= rand(10,99);
392f3f0262cSandi
393f3f0262cSandi  return $pw;
394f3f0262cSandi}
395f3f0262cSandi
396f3f0262cSandi/**
397f3f0262cSandi * Sends a password to the given user
398f3f0262cSandi *
39915fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
40015fae107Sandi *
40115fae107Sandi * @return bool  true on success
402f3f0262cSandi */
403f3f0262cSandifunction auth_sendPassword($user,$password){
404f3f0262cSandi  global $conf;
405f3f0262cSandi  global $lang;
406f3f0262cSandi  $hdrs  = '';
40787ddda95Sandi  $userinfo = auth_getUserData($user);
408f3f0262cSandi
40987ddda95Sandi  if(!$userinfo['mail']) return false;
410f3f0262cSandi
411f3f0262cSandi  $text = rawLocale('password');
412ed7b5f09Sandi  $text = str_replace('@DOKUWIKIURL@',DOKU_URL,$text);
41387ddda95Sandi  $text = str_replace('@FULLNAME@',$userinfo['name'],$text);
414f3f0262cSandi  $text = str_replace('@LOGIN@',$user,$text);
415f3f0262cSandi  $text = str_replace('@PASSWORD@',$password,$text);
416f3f0262cSandi  $text = str_replace('@TITLE@',$conf['title'],$text);
417f3f0262cSandi
41844f669e9Sandi  return mail_send($userinfo['name'].' <'.$userinfo['mail'].'>',
41944f669e9Sandi                   $lang['regpwmail'],
42044f669e9Sandi                   $text,
42144f669e9Sandi                   $conf['mailfrom']);
422f3f0262cSandi}
423f3f0262cSandi
424f3f0262cSandi/**
42515fae107Sandi * Register a new user
426f3f0262cSandi *
42715fae107Sandi * This registers a new user - Data is read directly from $_POST
42815fae107Sandi *
42915fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
43015fae107Sandi *
43115fae107Sandi * @return bool  true on success, false on any error
432f3f0262cSandi */
433f3f0262cSandifunction register(){
434f3f0262cSandi  global $lang;
435eb5d07e4Sjan  global $conf;
436f3f0262cSandi
437f3f0262cSandi  if(!$_POST['save']) return false;
438640145a5Sandi
439f3f0262cSandi  //clean username
440f3f0262cSandi  $_POST['login'] = preg_replace('/.*:/','',$_POST['login']);
441f3f0262cSandi  $_POST['login'] = cleanID($_POST['login']);
442f3f0262cSandi  //clean fullname and email
443f3f0262cSandi  $_POST['fullname'] = trim(str_replace(':','',$_POST['fullname']));
444f3f0262cSandi  $_POST['email']    = trim(str_replace(':','',$_POST['email']));
445f3f0262cSandi
446f3f0262cSandi  if( empty($_POST['login']) ||
447f3f0262cSandi      empty($_POST['fullname']) ||
448f3f0262cSandi      empty($_POST['email']) ){
449f3f0262cSandi    msg($lang['regmissing'],-1);
450f3f0262cSandi    return false;
451f3f0262cSandi  }
452f3f0262cSandi
453cab2716aSmatthias.grimm  if ($conf['autopasswd']) {
454cab2716aSmatthias.grimm    $pass = auth_pwgen();                // automatically generate password
455cab2716aSmatthias.grimm  } elseif (empty($_POST['pass']) ||
456cab2716aSmatthias.grimm            empty($_POST['passchk'])) {
457bf12ec81Sjan    msg($lang['regmissing'], -1);        // complain about missing passwords
458cab2716aSmatthias.grimm    return false;
459cab2716aSmatthias.grimm  } elseif ($_POST['pass'] != $_POST['passchk']) {
460bf12ec81Sjan    msg($lang['regbadpass'], -1);      // complain about misspelled passwords
461cab2716aSmatthias.grimm    return false;
462cab2716aSmatthias.grimm  } else {
463cab2716aSmatthias.grimm    $pass = $_POST['pass'];              // accept checked and valid password
464cab2716aSmatthias.grimm  }
465cab2716aSmatthias.grimm
466f3f0262cSandi  //check mail
46744f669e9Sandi  if(!mail_isvalid($_POST['email'])){
468f3f0262cSandi    msg($lang['regbadmail'],-1);
469f3f0262cSandi    return false;
470f3f0262cSandi  }
471f3f0262cSandi
472f3f0262cSandi  //okay try to create the user
4737c37db8aSmatthias.grimm  $pass = auth_createUser($_POST['login'],$pass,$_POST['fullname'],$_POST['email']);
474f3f0262cSandi  if(empty($pass)){
475f3f0262cSandi    msg($lang['reguexists'],-1);
476f3f0262cSandi    return false;
477f3f0262cSandi  }
478f3f0262cSandi
479cab2716aSmatthias.grimm  if (!$conf['autopasswd']) {
480cab2716aSmatthias.grimm    msg($lang['regsuccess2'],1);
481cab2716aSmatthias.grimm    return true;
482cab2716aSmatthias.grimm  }
483cab2716aSmatthias.grimm
484cab2716aSmatthias.grimm  // autogenerated password? then send him the password
485f3f0262cSandi  if (auth_sendPassword($_POST['login'],$pass)){
486f3f0262cSandi    msg($lang['regsuccess'],1);
487f3f0262cSandi    return true;
488f3f0262cSandi  }else{
489f3f0262cSandi    msg($lang['regmailfail'],-1);
490f3f0262cSandi    return false;
491f3f0262cSandi  }
492f3f0262cSandi}
493f3f0262cSandi
49410a76f6fSfrank/**
495*8b06d178Schris * Update user profile
496*8b06d178Schris *
497*8b06d178Schris * @author    Christopher Smith <chris@jalakai.co.uk>
498*8b06d178Schris */
499*8b06d178Schrisfunction updateprofile() {
500*8b06d178Schris  global $conf;
501*8b06d178Schris  global $INFO;
502*8b06d178Schris  global $lang;
503*8b06d178Schris
504*8b06d178Schris  if(!$_POST['save']) return false;
505*8b06d178Schris
506*8b06d178Schris  // should not be able to get here without modifyUser being possible...
507*8b06d178Schris  if(!auth_canDo('modifyUser')) {
508*8b06d178Schris    msg($lang['profna'],-1);
509*8b06d178Schris    return false;
510*8b06d178Schris  }
511*8b06d178Schris
512*8b06d178Schris  if ($_POST['newpass'] != $_POST['passchk']) {
513*8b06d178Schris    msg($lang['regbadpass'], -1);      // complain about misspelled passwords
514*8b06d178Schris    return false;
515*8b06d178Schris  }
516*8b06d178Schris
517*8b06d178Schris  //clean fullname and email
518*8b06d178Schris  $_POST['fullname'] = trim(str_replace(':','',$_POST['fullname']));
519*8b06d178Schris  $_POST['email']    = trim(str_replace(':','',$_POST['email']));
520*8b06d178Schris
521*8b06d178Schris  if (empty($_POST['fullname']) || empty($_POST['email'])) {
522*8b06d178Schris    msg($lang['profnoempty'],-1);
523*8b06d178Schris    return false;
524*8b06d178Schris  }
525*8b06d178Schris
526*8b06d178Schris  if (!mail_isvalid($_POST['email'])){
527*8b06d178Schris    msg($lang['regbadmail'],-1);
528*8b06d178Schris    return false;
529*8b06d178Schris  }
530*8b06d178Schris
531*8b06d178Schris  if ($_POST['fullname'] != $INFO['userinfo']['name']) $changes['name'] = $_POST['fullname'];
532*8b06d178Schris  if ($_POST['email']    != $INFO['userinfo']['mail']) $changes['mail'] = $_POST['email'];
533*8b06d178Schris  if (!empty($_POST['newpass']))  $changes['pass'] = $_POST['newpass'];
534*8b06d178Schris
535*8b06d178Schris  if (!count($changes)) {
536*8b06d178Schris    msg($lang['profnochange'], -1);
537*8b06d178Schris    return false;
538*8b06d178Schris  }
539*8b06d178Schris
540*8b06d178Schris  if ($conf['profileconfirm']) {
541*8b06d178Schris      if (!auth_verifyPassword($_POST['oldpass'],$INFO['userinfo']['pass'])) {
542*8b06d178Schris      msg($lang['badlogin'],-1);
543*8b06d178Schris      return false;
544*8b06d178Schris    }
545*8b06d178Schris  }
546*8b06d178Schris
547*8b06d178Schris  return auth_modifyUser($_SERVER['REMOTE_USER'], $changes);
548*8b06d178Schris}
549*8b06d178Schris
550*8b06d178Schris/**
551*8b06d178Schris * Send a  new password
552*8b06d178Schris *
553*8b06d178Schris * @author Benoit Chesneau <benoit@bchesneau.info>
554*8b06d178Schris * @author Chris Smith <chris@jalakai.co.uk>
555*8b06d178Schris *
556*8b06d178Schris * @return bool true on success, false on any error
557*8b06d178Schris*/
558*8b06d178Schrisfunction act_resendpwd(){
559*8b06d178Schris    global $lang;
560*8b06d178Schris    global $conf;
561*8b06d178Schris
562*8b06d178Schris    if(!$_POST['save']) return false;
563*8b06d178Schris
564*8b06d178Schris    // should not be able to get here without modifyUser being possible...
565*8b06d178Schris	if(!auth_canDo('modifyUser')) {
566*8b06d178Schris      msg($lang['resendna'],-1);
567*8b06d178Schris      return false;
568*8b06d178Schris	}
569*8b06d178Schris
570*8b06d178Schris    if (empty($_POST['login'])) {
571*8b06d178Schris      msg($lang['resendpwdmissing'], -1);
572*8b06d178Schris      return false;
573*8b06d178Schris    } else {
574*8b06d178Schris      $user = $_POST['login'];
575*8b06d178Schris    }
576*8b06d178Schris
577*8b06d178Schris    $userinfo = auth_getUserData($user);
578*8b06d178Schris    if(!$userinfo['mail']) {
579*8b06d178Schris      msg($lang['resendpwdnouser'], -1);
580*8b06d178Schris      return false;
581*8b06d178Schris    }
582*8b06d178Schris
583*8b06d178Schris    $pass = auth_pwgen();
584*8b06d178Schris    if (!auth_modifyUser($user,array('pass' => $pass))) {
585*8b06d178Schris      msg('error modifying user data',-1);
586*8b06d178Schris      return false;
587*8b06d178Schris    }
588*8b06d178Schris
589*8b06d178Schris    if (auth_sendPassword($user,$pass)) {
590*8b06d178Schris      msg($lang['resendpwdsuccess'],1);
591*8b06d178Schris    } else {
592*8b06d178Schris      msg($lang['regmailfail'],-1);
593*8b06d178Schris    }
594*8b06d178Schris    return true;
595*8b06d178Schris}
596*8b06d178Schris
597*8b06d178Schris/**
59810a76f6fSfrank * Uses a regular expresion to check if a given mail address is valid
59910a76f6fSfrank *
60010a76f6fSfrank * May not be completly RFC conform!
60110a76f6fSfrank *
60210a76f6fSfrank * @link    http://www.webmasterworld.com/forum88/135.htm
60310a76f6fSfrank *
60410a76f6fSfrank * @param   string $email the address to check
60510a76f6fSfrank * @return  bool          true if address is valid
60610a76f6fSfrank */
60710a76f6fSfrankfunction isvalidemail($email){
60810a76f6fSfrank  return eregi("^[0-9a-z]([-_.]?[0-9a-z])*@[0-9a-z]([-.]?[0-9a-z])*\\.[a-z]{2,4}$", $email);
60910a76f6fSfrank}
61010a76f6fSfrank
611b0855b11Sandi/**
612b0855b11Sandi * Encrypts a password using the given method and salt
613b0855b11Sandi *
614b0855b11Sandi * If the selected method needs a salt and none was given, a random one
615b0855b11Sandi * is chosen.
616b0855b11Sandi *
617b0855b11Sandi * The following methods are understood:
618b0855b11Sandi *
619b0855b11Sandi *   smd5  - Salted MD5 hashing
620b0855b11Sandi *   md5   - Simple MD5 hashing
621b0855b11Sandi *   sha1  - SHA1 hashing
622b0855b11Sandi *   ssha  - Salted SHA1 hashing
623d7be6245Sandi *   crypt - Unix crypt
624d7be6245Sandi *   mysql - MySQL password (old method)
625d7be6245Sandi *   my411 - MySQL 4.1.1 password
626b0855b11Sandi *
627b0855b11Sandi * @author  Andreas Gohr <andi@splitbrain.org>
628b0855b11Sandi * @return  string  The crypted password
629b0855b11Sandi */
630b0855b11Sandifunction auth_cryptPassword($clear,$method='',$salt=''){
631b0855b11Sandi  global $conf;
632b0855b11Sandi  if(empty($method)) $method = $conf['passcrypt'];
63310a76f6fSfrank
634b0855b11Sandi  //prepare a salt
635b0855b11Sandi  if(empty($salt)) $salt = md5(uniqid(rand(), true));
636b0855b11Sandi
637b0855b11Sandi  switch(strtolower($method)){
638b0855b11Sandi    case 'smd5':
639b0855b11Sandi        return crypt($clear,'$1$'.substr($salt,0,8).'$');
640b0855b11Sandi    case 'md5':
641b0855b11Sandi      return md5($clear);
642b0855b11Sandi    case 'sha1':
643b0855b11Sandi      return sha1($clear);
644b0855b11Sandi    case 'ssha':
645b0855b11Sandi      $salt=substr($salt,0,4);
646d6e54e02Smatthiasgrimm      return '{SSHA}'.base64_encode(pack("H*", sha1($clear.$salt)).$salt);
647b0855b11Sandi    case 'crypt':
648b0855b11Sandi      return crypt($clear,substr($salt,0,2));
649d7be6245Sandi    case 'mysql':
650d7be6245Sandi      //from http://www.php.net/mysql comment by <soren at byu dot edu>
651d7be6245Sandi      $nr=0x50305735;
652d7be6245Sandi      $nr2=0x12345671;
653d7be6245Sandi      $add=7;
654d7be6245Sandi      $charArr = preg_split("//", $clear);
655d7be6245Sandi      foreach ($charArr as $char) {
656d7be6245Sandi        if (($char == '') || ($char == ' ') || ($char == '\t')) continue;
657d7be6245Sandi        $charVal = ord($char);
658d7be6245Sandi        $nr ^= ((($nr & 63) + $add) * $charVal) + ($nr << 8);
659d7be6245Sandi        $nr2 += ($nr2 << 8) ^ $nr;
660d7be6245Sandi        $add += $charVal;
661d7be6245Sandi      }
662d7be6245Sandi      return sprintf("%08x%08x", ($nr & 0x7fffffff), ($nr2 & 0x7fffffff));
663d7be6245Sandi    case 'my411':
664d7be6245Sandi      return '*'.sha1(pack("H*", sha1($clear)));
665b0855b11Sandi    default:
666b0855b11Sandi      msg("Unsupported crypt method $method",-1);
667b0855b11Sandi  }
668b0855b11Sandi}
669b0855b11Sandi
670b0855b11Sandi/**
671b0855b11Sandi * Verifies a cleartext password against a crypted hash
672b0855b11Sandi *
673b0855b11Sandi * The method and salt used for the crypted hash is determined automatically
674b0855b11Sandi * then the clear text password is crypted using the same method. If both hashs
675b0855b11Sandi * match true is is returned else false
676b0855b11Sandi *
677b0855b11Sandi * @author  Andreas Gohr <andi@splitbrain.org>
678b0855b11Sandi * @return  bool
679b0855b11Sandi */
680b0855b11Sandifunction auth_verifyPassword($clear,$crypt){
681b0855b11Sandi  $method='';
682b0855b11Sandi  $salt='';
683b0855b11Sandi
684b0855b11Sandi  //determine the used method and salt
685d7be6245Sandi  $len = strlen($crypt);
686b0855b11Sandi  if(substr($crypt,0,3) == '$1$'){
687b0855b11Sandi    $method = 'smd5';
688b0855b11Sandi    $salt   = substr($crypt,3,8);
689b0855b11Sandi  }elseif(substr($crypt,0,6) == '{SSHA}'){
690b0855b11Sandi    $method = 'ssha';
691b0855b11Sandi    $salt   = substr(base64_decode(substr($crypt, 6)),20);
692d7be6245Sandi  }elseif($len == 32){
693b0855b11Sandi    $method = 'md5';
694d7be6245Sandi  }elseif($len == 40){
695b0855b11Sandi    $method = 'sha1';
696d7be6245Sandi  }elseif($len == 16){
697d7be6245Sandi    $method = 'mysql';
698d7be6245Sandi  }elseif($len == 41 && $crypt[0] == '*'){
699d7be6245Sandi    $method = 'my411';
700b0855b11Sandi  }else{
701b0855b11Sandi    $method = 'crypt';
702b0855b11Sandi    $salt   = substr($crypt,0,2);
703b0855b11Sandi  }
704b0855b11Sandi
705b0855b11Sandi  //crypt and compare
706b0855b11Sandi  if(auth_cryptPassword($clear,$method,$salt) === $crypt){
707b0855b11Sandi    return true;
708b0855b11Sandi  }
709b0855b11Sandi  return false;
710b0855b11Sandi}
711340756e4Sandi
712340756e4Sandi//Setup VIM: ex: et ts=2 enc=utf-8 :
713