xref: /dokuwiki/inc/auth.php (revision f5cb575df722c05fc0a6ba960bd2a79d5ed5621c)
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');
178b06d178Schris
188b06d178Schris  // load the the backend auth functions and instantiate the auth object
198b06d178Schris  if (@file_exists(DOKU_INC.'inc/auth/'.$conf['authtype'].'.class.php')) {
208b06d178Schris      require_once(DOKU_INC.'inc/auth/basic.class.php');
218b06d178Schris      require_once(DOKU_INC.'inc/auth/'.$conf['authtype'].'.class.php');
228b06d178Schris
238b06d178Schris      $auth_class = "auth_".$conf['authtype'];
248b06d178Schris      if (!class_exists($auth_class)) $auth_class = "auth_basic";
258b06d178Schris      $auth = new $auth_class();
26d2dde4ebSMatthias Grimm      if ($auth->success == false) {
27d2dde4ebSMatthias Grimm          msg($lang['authmodfailed'],-1);
28d2dde4ebSMatthias Grimm          unset($auth);
29d2dde4ebSMatthias Grimm      }
308b06d178Schris
318b06d178Schris      // interface between current dokuwiki/old auth system and new style auth object
328b06d178Schris      function auth_canDo($fn) {
338b06d178Schris        global $auth;
348b06d178Schris        return method_exists($auth, $fn);
358b06d178Schris      }
368b06d178Schris
378b06d178Schris      // mandatory functions - these should exist
388b06d178Schris      function auth_checkPass($user,$pass) {
398b06d178Schris        global $auth;
408b06d178Schris        return method_exists($auth,'checkPass') ? $auth->checkPass($user, $pass) : false;
418b06d178Schris      }
428b06d178Schris
438b06d178Schris      function auth_getUserData($user) {
448b06d178Schris        global $auth;
458b06d178Schris        return method_exists($auth, 'getUserData') ? $auth->getUserData($user) : false;
468b06d178Schris      }
478b06d178Schris
488b06d178Schris      // optional functions, behave gracefully if these don't exist;
498b06d178Schris      // potential calling code should query whether these exist in advance
508b06d178Schris      function auth_createUser($user,$pass,$name,$mail) {
518b06d178Schris        global $auth;
528b06d178Schris        return method_exists($auth, 'createUser') ? $auth->createUser($user,$pass,$name,$mail) : null;
538b06d178Schris      }
548b06d178Schris
558b06d178Schris      function auth_modifyUser($user, $changes) {
568b06d178Schris        global $auth;
578b06d178Schris        return method_exists($auth, 'modifyUser') ? $auth->modifyUser($user,$changes) : false;
588b06d178Schris      }
598b06d178Schris
608b06d178Schris      function auth_deleteUsers($users) {
618b06d178Schris        global $auth;
628b06d178Schris        return method_exists($auth, 'deleteUsers') ? $auth->deleteUsers($users) : 0;
638b06d178Schris      }
648b06d178Schris
658b06d178Schris      // other functions, will only be accessed by new code
668b06d178Schris      //- these must query auth_canDo() or test method existence themselves.
678b06d178Schris
688b06d178Schris  } else {
698b06d178Schris    // old style auth functions
70f62ea8a1Sandi    require_once(DOKU_INC.'inc/auth/'.$conf['authtype'].'.php');
718b06d178Schris    $auth = null;
728b06d178Schris
738b06d178Schris    // new function, allows other parts of dokuwiki to know what they can and can't do
748b06d178Schris    function auth_canDo($fn) { return function_exists("auth_$fn"); }
758b06d178Schris  }
76f3f0262cSandi
771e866646Sandi  if (!defined('DOKU_COOKIE')) define('DOKU_COOKIE', 'DW'.md5($conf['title']));
78e65afed4SSameer D. Sahasrabuddhe
7915fae107Sandi  // some ACL level defines
80f3f0262cSandi  define('AUTH_NONE',0);
81f3f0262cSandi  define('AUTH_READ',1);
82f3f0262cSandi  define('AUTH_EDIT',2);
83f3f0262cSandi  define('AUTH_CREATE',4);
84f3f0262cSandi  define('AUTH_UPLOAD',8);
858ef6b7caSandi  define('AUTH_DELETE',16);
8610a76f6fSfrank  define('AUTH_ADMIN',255);
87f3f0262cSandi
88*f5cb575dSAndreas Gohr  // do the login either by cookie or provided credentials
89f3f0262cSandi  if($conf['useacl']){
90*f5cb575dSAndreas Gohr    // external trust mechanism in place?
91*f5cb575dSAndreas Gohr    if(auth_canDo('trustExternal') && !is_null($auth)){
92*f5cb575dSAndreas Gohr      $auth->trustExternal($_REQUEST['u'],$_REQUEST['p'],$_REQUEST['r']);
93*f5cb575dSAndreas Gohr    }else{
94132bdbfeSandi      auth_login($_REQUEST['u'],$_REQUEST['p'],$_REQUEST['r']);
95*f5cb575dSAndreas Gohr    }
96*f5cb575dSAndreas Gohr
9715fae107Sandi    //load ACL into a global array
98e7cb32dcSAndreas Gohr    if(is_readable(DOKU_CONF.'acl.auth.php')){
99e7cb32dcSAndreas Gohr      $AUTH_ACL = file(DOKU_CONF.'acl.auth.php');
10011799630Sandi    }else{
10111799630Sandi      $AUTH_ACL = array();
10211799630Sandi    }
103f3f0262cSandi  }
104f3f0262cSandi
105f3f0262cSandi/**
106f3f0262cSandi * This tries to login the user based on the sent auth credentials
107f3f0262cSandi *
108f3f0262cSandi * The authentication works like this: if a username was given
10915fae107Sandi * a new login is assumed and user/password are checked. If they
11015fae107Sandi * are correct the password is encrypted with blowfish and stored
11115fae107Sandi * together with the username in a cookie - the same info is stored
11215fae107Sandi * in the session, too. Additonally a browserID is stored in the
11315fae107Sandi * session.
11415fae107Sandi *
11515fae107Sandi * If no username was given the cookie is checked: if the username,
11615fae107Sandi * crypted password and browserID match between session and cookie
11715fae107Sandi * no further testing is done and the user is accepted
11815fae107Sandi *
11915fae107Sandi * If a cookie was found but no session info was availabe the
120136ce040Sandi * blowfish encrypted password from the cookie is decrypted and
12115fae107Sandi * together with username rechecked by calling this function again.
122f3f0262cSandi *
123f3f0262cSandi * On a successful login $_SERVER[REMOTE_USER] and $USERINFO
124f3f0262cSandi * are set.
12515fae107Sandi *
12615fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
12715fae107Sandi *
12815fae107Sandi * @param   string  $user    Username
12915fae107Sandi * @param   string  $pass    Cleartext Password
13015fae107Sandi * @param   bool    $sticky  Cookie should not expire
13115fae107Sandi * @return  bool             true on successful auth
132f3f0262cSandi*/
133132bdbfeSandifunction auth_login($user,$pass,$sticky=false){
134f3f0262cSandi  global $USERINFO;
135f3f0262cSandi  global $conf;
136f3f0262cSandi  global $lang;
137132bdbfeSandi  $sticky ? $sticky = true : $sticky = false; //sanity check
138f3f0262cSandi
139f3f0262cSandi  if(isset($user)){
140132bdbfeSandi    //usual login
141f3f0262cSandi    if (auth_checkPass($user,$pass)){
142132bdbfeSandi      // make logininfo globally available
143f3f0262cSandi      $_SERVER['REMOTE_USER'] = $user;
144132bdbfeSandi      $USERINFO = auth_getUserData($user); //FIXME move all references to session
145132bdbfeSandi
146132bdbfeSandi      // set cookie
147132bdbfeSandi      $pass   = PMA_blowfish_encrypt($pass,auth_cookiesalt());
148132bdbfeSandi      $cookie = base64_encode("$user|$sticky|$pass");
149132bdbfeSandi      if($sticky) $time = time()+60*60*24*365; //one year
150e65afed4SSameer D. Sahasrabuddhe      setcookie(DOKU_COOKIE,$cookie,$time,'/');
151132bdbfeSandi
152132bdbfeSandi      // set session
153132bdbfeSandi      $_SESSION[$conf['title']]['auth']['user'] = $user;
154132bdbfeSandi      $_SESSION[$conf['title']]['auth']['pass'] = $pass;
155132bdbfeSandi      $_SESSION[$conf['title']]['auth']['buid'] = auth_browseruid();
156132bdbfeSandi      $_SESSION[$conf['title']]['auth']['info'] = $USERINFO;
157132bdbfeSandi      return true;
158f3f0262cSandi    }else{
159f3f0262cSandi      //invalid credentials - log off
160f3f0262cSandi      msg($lang['badlogin'],-1);
161f3f0262cSandi      auth_logoff();
162132bdbfeSandi      return false;
163f3f0262cSandi    }
164f3f0262cSandi  }else{
165132bdbfeSandi    // read cookie information
166e65afed4SSameer D. Sahasrabuddhe    $cookie = base64_decode($_COOKIE[DOKU_COOKIE]);
167132bdbfeSandi    list($user,$sticky,$pass) = split('\|',$cookie,3);
168132bdbfeSandi    // get session info
169132bdbfeSandi    $session = $_SESSION[$conf['title']]['auth'];
170132bdbfeSandi
171132bdbfeSandi    if($user && $pass){
172132bdbfeSandi      // we got a cookie - see if we can trust it
173132bdbfeSandi      if(isset($session) &&
174132bdbfeSandi        ($session['user'] == $user) &&
175132bdbfeSandi        ($session['pass'] == $pass) &&  //still crypted
176132bdbfeSandi        ($session['buid'] == auth_browseruid()) ){
177132bdbfeSandi        // he has session, cookie and browser right - let him in
178132bdbfeSandi        $_SERVER['REMOTE_USER'] = $user;
179132bdbfeSandi        $USERINFO = $session['info']; //FIXME move all references to session
180132bdbfeSandi        return true;
181132bdbfeSandi      }
182132bdbfeSandi      // no we don't trust it yet - recheck pass
183132bdbfeSandi      $pass = PMA_blowfish_decrypt($pass,auth_cookiesalt());
184132bdbfeSandi      return auth_login($user,$pass,$sticky);
185132bdbfeSandi    }
186132bdbfeSandi  }
187f3f0262cSandi  //just to be sure
188f3f0262cSandi  auth_logoff();
189132bdbfeSandi  return false;
190f3f0262cSandi}
191132bdbfeSandi
192132bdbfeSandi/**
193136ce040Sandi * Builds a pseudo UID from browser and IP data
194132bdbfeSandi *
195132bdbfeSandi * This is neither unique nor unfakable - still it adds some
196136ce040Sandi * security. Using the first part of the IP makes sure
197136ce040Sandi * proxy farms like AOLs are stil okay.
19815fae107Sandi *
19915fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
20015fae107Sandi *
20115fae107Sandi * @return  string  a MD5 sum of various browser headers
202132bdbfeSandi */
203132bdbfeSandifunction auth_browseruid(){
204132bdbfeSandi  $uid  = '';
205132bdbfeSandi  $uid .= $_SERVER['HTTP_USER_AGENT'];
206132bdbfeSandi  $uid .= $_SERVER['HTTP_ACCEPT_ENCODING'];
207132bdbfeSandi  $uid .= $_SERVER['HTTP_ACCEPT_LANGUAGE'];
208132bdbfeSandi  $uid .= $_SERVER['HTTP_ACCEPT_CHARSET'];
209136ce040Sandi  $uid .= substr($_SERVER['REMOTE_ADDR'],0,strpos($_SERVER['REMOTE_ADDR'],'.'));
210132bdbfeSandi  return md5($uid);
211132bdbfeSandi}
212132bdbfeSandi
213132bdbfeSandi/**
214132bdbfeSandi * Creates a random key to encrypt the password in cookies
21515fae107Sandi *
21615fae107Sandi * This function tries to read the password for encrypting
21798407a7aSandi * cookies from $conf['metadir'].'/_htcookiesalt'
21815fae107Sandi * if no such file is found a random key is created and
21915fae107Sandi * and stored in this file.
22015fae107Sandi *
22115fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
22215fae107Sandi *
22315fae107Sandi * @return  string
224132bdbfeSandi */
225132bdbfeSandifunction auth_cookiesalt(){
226132bdbfeSandi  global $conf;
22798407a7aSandi  $file = $conf['metadir'].'/_htcookiesalt';
228132bdbfeSandi  $salt = io_readFile($file);
229132bdbfeSandi  if(empty($salt)){
230132bdbfeSandi    $salt = uniqid(rand(),true);
231132bdbfeSandi    io_saveFile($file,$salt);
232132bdbfeSandi  }
233132bdbfeSandi  return $salt;
234f3f0262cSandi}
235f3f0262cSandi
236f3f0262cSandi/**
237f3f0262cSandi * This clears all authenticationdata and thus log the user
238f3f0262cSandi * off
23915fae107Sandi *
24015fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
241f3f0262cSandi */
242f3f0262cSandifunction auth_logoff(){
243f3f0262cSandi  global $conf;
244f3f0262cSandi  global $USERINFO;
2458b06d178Schris  global $INFO, $ID;
24637065e65Sandi
24737065e65Sandi  if(isset($_SESSION[$conf['title']]['auth']['user']))
248132bdbfeSandi    unset($_SESSION[$conf['title']]['auth']['user']);
24937065e65Sandi  if(isset($_SESSION[$conf['title']]['auth']['pass']))
250132bdbfeSandi    unset($_SESSION[$conf['title']]['auth']['pass']);
25137065e65Sandi  if(isset($_SESSION[$conf['title']]['auth']['info']))
252132bdbfeSandi    unset($_SESSION[$conf['title']]['auth']['info']);
25337065e65Sandi  if(isset($_SERVER['REMOTE_USER']))
254f3f0262cSandi    unset($_SERVER['REMOTE_USER']);
255132bdbfeSandi  $USERINFO=null; //FIXME
2561e866646Sandi  setcookie(DOKU_COOKIE,'',time()-600000,'/');
257f3f0262cSandi}
258f3f0262cSandi
259f3f0262cSandi/**
26015fae107Sandi * Convinience function for auth_aclcheck()
26115fae107Sandi *
26215fae107Sandi * This checks the permissions for the current user
26315fae107Sandi *
26415fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
26515fae107Sandi *
26615fae107Sandi * @param  string  $id  page ID
26715fae107Sandi * @return int          permission level
268f3f0262cSandi */
269f3f0262cSandifunction auth_quickaclcheck($id){
270f3f0262cSandi  global $conf;
271f3f0262cSandi  global $USERINFO;
272f3f0262cSandi  # if no ACL is used always return upload rights
273f3f0262cSandi  if(!$conf['useacl']) return AUTH_UPLOAD;
274f3f0262cSandi  return auth_aclcheck($id,$_SERVER['REMOTE_USER'],$USERINFO['grps']);
275f3f0262cSandi}
276f3f0262cSandi
277f3f0262cSandi/**
278f3f0262cSandi * Returns the maximum rights a user has for
279f3f0262cSandi * the given ID or its namespace
28015fae107Sandi *
28115fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
28215fae107Sandi *
28315fae107Sandi * @param  string  $id     page ID
28415fae107Sandi * @param  string  $user   Username
28515fae107Sandi * @param  array   $groups Array of groups the user is in
28615fae107Sandi * @return int             permission level
287f3f0262cSandi */
288f3f0262cSandifunction auth_aclcheck($id,$user,$groups){
289f3f0262cSandi  global $conf;
290f3f0262cSandi  global $AUTH_ACL;
291f3f0262cSandi
292f3f0262cSandi  # if no ACL is used always return upload rights
293f3f0262cSandi  if(!$conf['useacl']) return AUTH_UPLOAD;
294f3f0262cSandi
29510a76f6fSfrank  //if user is superuser return 255 (acl_admin)
29610a76f6fSfrank  if($conf['superuser'] == $user) { return AUTH_ADMIN; }
29710a76f6fSfrank
298074cf26bSandi  //make sure groups is an array
299074cf26bSandi  if(!is_array($groups)) $groups = array();
300074cf26bSandi
30110a76f6fSfrank  //prepend groups with @
3022cd2db38Sandi  $cnt = count($groups);
3032cd2db38Sandi  for($i=0; $i<$cnt; $i++){
30410a76f6fSfrank    $groups[$i] = '@'.$groups[$i];
30510a76f6fSfrank  }
30610a76f6fSfrank  //if user is in superuser group return 255 (acl_admin)
30710a76f6fSfrank  if(in_array($conf['superuser'], $groups)) { return AUTH_ADMIN; }
30810a76f6fSfrank
309f3f0262cSandi  $ns    = getNS($id);
310f3f0262cSandi  $perm  = -1;
311f3f0262cSandi
312f3f0262cSandi  if($user){
313f3f0262cSandi    //add ALL group
314f3f0262cSandi    $groups[] = '@ALL';
315f3f0262cSandi    //add User
316f3f0262cSandi    $groups[] = $user;
317f3f0262cSandi    //build regexp
318f3f0262cSandi    $regexp   = join('|',$groups);
319f3f0262cSandi  }else{
320f3f0262cSandi    $regexp = '@ALL';
321f3f0262cSandi  }
322f3f0262cSandi
323f3f0262cSandi  //check exact match first
32442905504SAndreas Gohr  $matches = preg_grep('/^'.preg_quote($id,'/').'\s+('.$regexp.')\s+/',$AUTH_ACL);
325f3f0262cSandi  if(count($matches)){
326f3f0262cSandi    foreach($matches as $match){
327f3f0262cSandi      $match = preg_replace('/#.*$/','',$match); //ignore comments
328f3f0262cSandi      $acl   = preg_split('/\s+/',$match);
3298ef6b7caSandi      if($acl[2] > AUTH_DELETE) $acl[2] = AUTH_DELETE; //no admins in the ACL!
330f3f0262cSandi      if($acl[2] > $perm){
331f3f0262cSandi        $perm = $acl[2];
332f3f0262cSandi      }
333f3f0262cSandi    }
334f3f0262cSandi    if($perm > -1){
335f3f0262cSandi      //we had a match - return it
336f3f0262cSandi      return $perm;
337f3f0262cSandi    }
338f3f0262cSandi  }
339f3f0262cSandi
340f3f0262cSandi  //still here? do the namespace checks
341f3f0262cSandi  if($ns){
342f3f0262cSandi    $path = $ns.':\*';
343f3f0262cSandi  }else{
344f3f0262cSandi    $path = '\*'; //root document
345f3f0262cSandi  }
346f3f0262cSandi
347f3f0262cSandi  do{
348f3f0262cSandi    $matches = preg_grep('/^'.$path.'\s+('.$regexp.')\s+/',$AUTH_ACL);
349f3f0262cSandi    if(count($matches)){
350f3f0262cSandi      foreach($matches as $match){
351f3f0262cSandi        $match = preg_replace('/#.*$/','',$match); //ignore comments
352f3f0262cSandi        $acl   = preg_split('/\s+/',$match);
3538ef6b7caSandi        if($acl[2] > AUTH_DELETE) $acl[2] = AUTH_DELETE; //no admins in the ACL!
354f3f0262cSandi        if($acl[2] > $perm){
355f3f0262cSandi          $perm = $acl[2];
356f3f0262cSandi        }
357f3f0262cSandi      }
358f3f0262cSandi      //we had a match - return it
359f3f0262cSandi      return $perm;
360f3f0262cSandi    }
361f3f0262cSandi
362f3f0262cSandi    //get next higher namespace
363f3f0262cSandi    $ns   = getNS($ns);
364f3f0262cSandi
365f3f0262cSandi    if($path != '\*'){
366f3f0262cSandi      $path = $ns.':\*';
367f3f0262cSandi      if($path == ':\*') $path = '\*';
368f3f0262cSandi    }else{
369f3f0262cSandi      //we did this already
370f3f0262cSandi      //looks like there is something wrong with the ACL
371f3f0262cSandi      //break here
372d5ce66f6SAndreas Gohr      msg('No ACL setup yet! Denying access to everyone.');
373d5ce66f6SAndreas Gohr      return AUTH_NONE;
374f3f0262cSandi    }
375f3f0262cSandi  }while(1); //this should never loop endless
37652a5af8dSandi
37752a5af8dSandi  //still here? return no permissions
37852a5af8dSandi  return AUTH_NONE;
379f3f0262cSandi}
380f3f0262cSandi
381f3f0262cSandi/**
382f3f0262cSandi * Create a pronouncable password
383f3f0262cSandi *
38415fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
38515fae107Sandi * @link    http://www.phpbuilder.com/annotate/message.php3?id=1014451
38615fae107Sandi *
38715fae107Sandi * @return string  pronouncable password
388f3f0262cSandi */
389f3f0262cSandifunction auth_pwgen(){
390f3f0262cSandi  $pw = '';
391f3f0262cSandi  $c  = 'bcdfghjklmnprstvwz'; //consonants except hard to speak ones
392f3f0262cSandi  $v  = 'aeiou';              //vowels
393f3f0262cSandi  $a  = $c.$v;                //both
394f3f0262cSandi
395f3f0262cSandi  //use two syllables...
396f3f0262cSandi  for($i=0;$i < 2; $i++){
397f3f0262cSandi    $pw .= $c[rand(0, strlen($c)-1)];
398f3f0262cSandi    $pw .= $v[rand(0, strlen($v)-1)];
399f3f0262cSandi    $pw .= $a[rand(0, strlen($a)-1)];
400f3f0262cSandi  }
401f3f0262cSandi  //... and add a nice number
402f3f0262cSandi  $pw .= rand(10,99);
403f3f0262cSandi
404f3f0262cSandi  return $pw;
405f3f0262cSandi}
406f3f0262cSandi
407f3f0262cSandi/**
408f3f0262cSandi * Sends a password to the given user
409f3f0262cSandi *
41015fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
41115fae107Sandi *
41215fae107Sandi * @return bool  true on success
413f3f0262cSandi */
414f3f0262cSandifunction auth_sendPassword($user,$password){
415f3f0262cSandi  global $conf;
416f3f0262cSandi  global $lang;
417f3f0262cSandi  $hdrs  = '';
41887ddda95Sandi  $userinfo = auth_getUserData($user);
419f3f0262cSandi
42087ddda95Sandi  if(!$userinfo['mail']) return false;
421f3f0262cSandi
422f3f0262cSandi  $text = rawLocale('password');
423ed7b5f09Sandi  $text = str_replace('@DOKUWIKIURL@',DOKU_URL,$text);
42487ddda95Sandi  $text = str_replace('@FULLNAME@',$userinfo['name'],$text);
425f3f0262cSandi  $text = str_replace('@LOGIN@',$user,$text);
426f3f0262cSandi  $text = str_replace('@PASSWORD@',$password,$text);
427f3f0262cSandi  $text = str_replace('@TITLE@',$conf['title'],$text);
428f3f0262cSandi
42944f669e9Sandi  return mail_send($userinfo['name'].' <'.$userinfo['mail'].'>',
43044f669e9Sandi                   $lang['regpwmail'],
43144f669e9Sandi                   $text,
43244f669e9Sandi                   $conf['mailfrom']);
433f3f0262cSandi}
434f3f0262cSandi
435f3f0262cSandi/**
43615fae107Sandi * Register a new user
437f3f0262cSandi *
43815fae107Sandi * This registers a new user - Data is read directly from $_POST
43915fae107Sandi *
44015fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
44115fae107Sandi *
44215fae107Sandi * @return bool  true on success, false on any error
443f3f0262cSandi */
444f3f0262cSandifunction register(){
445f3f0262cSandi  global $lang;
446eb5d07e4Sjan  global $conf;
447f3f0262cSandi
448f3f0262cSandi  if(!$_POST['save']) return false;
449640145a5Sandi
450f3f0262cSandi  //clean username
451f3f0262cSandi  $_POST['login'] = preg_replace('/.*:/','',$_POST['login']);
452f3f0262cSandi  $_POST['login'] = cleanID($_POST['login']);
453f3f0262cSandi  //clean fullname and email
454f3f0262cSandi  $_POST['fullname'] = trim(str_replace(':','',$_POST['fullname']));
455f3f0262cSandi  $_POST['email']    = trim(str_replace(':','',$_POST['email']));
456f3f0262cSandi
457f3f0262cSandi  if( empty($_POST['login']) ||
458f3f0262cSandi      empty($_POST['fullname']) ||
459f3f0262cSandi      empty($_POST['email']) ){
460f3f0262cSandi    msg($lang['regmissing'],-1);
461f3f0262cSandi    return false;
462f3f0262cSandi  }
463f3f0262cSandi
464cab2716aSmatthias.grimm  if ($conf['autopasswd']) {
465cab2716aSmatthias.grimm    $pass = auth_pwgen();                // automatically generate password
466cab2716aSmatthias.grimm  } elseif (empty($_POST['pass']) ||
467cab2716aSmatthias.grimm            empty($_POST['passchk'])) {
468bf12ec81Sjan    msg($lang['regmissing'], -1);        // complain about missing passwords
469cab2716aSmatthias.grimm    return false;
470cab2716aSmatthias.grimm  } elseif ($_POST['pass'] != $_POST['passchk']) {
471bf12ec81Sjan    msg($lang['regbadpass'], -1);      // complain about misspelled passwords
472cab2716aSmatthias.grimm    return false;
473cab2716aSmatthias.grimm  } else {
474cab2716aSmatthias.grimm    $pass = $_POST['pass'];              // accept checked and valid password
475cab2716aSmatthias.grimm  }
476cab2716aSmatthias.grimm
477f3f0262cSandi  //check mail
47844f669e9Sandi  if(!mail_isvalid($_POST['email'])){
479f3f0262cSandi    msg($lang['regbadmail'],-1);
480f3f0262cSandi    return false;
481f3f0262cSandi  }
482f3f0262cSandi
483f3f0262cSandi  //okay try to create the user
4847c37db8aSmatthias.grimm  $pass = auth_createUser($_POST['login'],$pass,$_POST['fullname'],$_POST['email']);
485f3f0262cSandi  if(empty($pass)){
486f3f0262cSandi    msg($lang['reguexists'],-1);
487f3f0262cSandi    return false;
488f3f0262cSandi  }
489f3f0262cSandi
490cab2716aSmatthias.grimm  if (!$conf['autopasswd']) {
491cab2716aSmatthias.grimm    msg($lang['regsuccess2'],1);
492cab2716aSmatthias.grimm    return true;
493cab2716aSmatthias.grimm  }
494cab2716aSmatthias.grimm
495cab2716aSmatthias.grimm  // autogenerated password? then send him the password
496f3f0262cSandi  if (auth_sendPassword($_POST['login'],$pass)){
497f3f0262cSandi    msg($lang['regsuccess'],1);
498f3f0262cSandi    return true;
499f3f0262cSandi  }else{
500f3f0262cSandi    msg($lang['regmailfail'],-1);
501f3f0262cSandi    return false;
502f3f0262cSandi  }
503f3f0262cSandi}
504f3f0262cSandi
50510a76f6fSfrank/**
5068b06d178Schris * Update user profile
5078b06d178Schris *
5088b06d178Schris * @author    Christopher Smith <chris@jalakai.co.uk>
5098b06d178Schris */
5108b06d178Schrisfunction updateprofile() {
5118b06d178Schris  global $conf;
5128b06d178Schris  global $INFO;
5138b06d178Schris  global $lang;
5148b06d178Schris
5158b06d178Schris  if(!$_POST['save']) return false;
5168b06d178Schris
5178b06d178Schris  // should not be able to get here without modifyUser being possible...
5188b06d178Schris  if(!auth_canDo('modifyUser')) {
5198b06d178Schris    msg($lang['profna'],-1);
5208b06d178Schris    return false;
5218b06d178Schris  }
5228b06d178Schris
5238b06d178Schris  if ($_POST['newpass'] != $_POST['passchk']) {
5248b06d178Schris    msg($lang['regbadpass'], -1);      // complain about misspelled passwords
5258b06d178Schris    return false;
5268b06d178Schris  }
5278b06d178Schris
5288b06d178Schris  //clean fullname and email
5298b06d178Schris  $_POST['fullname'] = trim(str_replace(':','',$_POST['fullname']));
5308b06d178Schris  $_POST['email']    = trim(str_replace(':','',$_POST['email']));
5318b06d178Schris
5328b06d178Schris  if (empty($_POST['fullname']) || empty($_POST['email'])) {
5338b06d178Schris    msg($lang['profnoempty'],-1);
5348b06d178Schris    return false;
5358b06d178Schris  }
5368b06d178Schris
5378b06d178Schris  if (!mail_isvalid($_POST['email'])){
5388b06d178Schris    msg($lang['regbadmail'],-1);
5398b06d178Schris    return false;
5408b06d178Schris  }
5418b06d178Schris
5428b06d178Schris  if ($_POST['fullname'] != $INFO['userinfo']['name']) $changes['name'] = $_POST['fullname'];
5438b06d178Schris  if ($_POST['email']    != $INFO['userinfo']['mail']) $changes['mail'] = $_POST['email'];
5448b06d178Schris  if (!empty($_POST['newpass']))  $changes['pass'] = $_POST['newpass'];
5458b06d178Schris
5468b06d178Schris  if (!count($changes)) {
5478b06d178Schris    msg($lang['profnochange'], -1);
5488b06d178Schris    return false;
5498b06d178Schris  }
5508b06d178Schris
5518b06d178Schris  if ($conf['profileconfirm']) {
5528b06d178Schris      if (!auth_verifyPassword($_POST['oldpass'],$INFO['userinfo']['pass'])) {
5538b06d178Schris      msg($lang['badlogin'],-1);
5548b06d178Schris      return false;
5558b06d178Schris    }
5568b06d178Schris  }
5578b06d178Schris
5588b06d178Schris  return auth_modifyUser($_SERVER['REMOTE_USER'], $changes);
5598b06d178Schris}
5608b06d178Schris
5618b06d178Schris/**
5628b06d178Schris * Send a  new password
5638b06d178Schris *
5648b06d178Schris * @author Benoit Chesneau <benoit@bchesneau.info>
5658b06d178Schris * @author Chris Smith <chris@jalakai.co.uk>
5668b06d178Schris *
5678b06d178Schris * @return bool true on success, false on any error
5688b06d178Schris*/
5698b06d178Schrisfunction act_resendpwd(){
5708b06d178Schris    global $lang;
5718b06d178Schris    global $conf;
5728b06d178Schris
5738b06d178Schris    if(!$_POST['save']) return false;
5748b06d178Schris
5758b06d178Schris    // should not be able to get here without modifyUser being possible...
5768b06d178Schris	if(!auth_canDo('modifyUser')) {
5778b06d178Schris      msg($lang['resendna'],-1);
5788b06d178Schris      return false;
5798b06d178Schris	}
5808b06d178Schris
5818b06d178Schris    if (empty($_POST['login'])) {
5828b06d178Schris      msg($lang['resendpwdmissing'], -1);
5838b06d178Schris      return false;
5848b06d178Schris    } else {
5858b06d178Schris      $user = $_POST['login'];
5868b06d178Schris    }
5878b06d178Schris
5888b06d178Schris    $userinfo = auth_getUserData($user);
5898b06d178Schris    if(!$userinfo['mail']) {
5908b06d178Schris      msg($lang['resendpwdnouser'], -1);
5918b06d178Schris      return false;
5928b06d178Schris    }
5938b06d178Schris
5948b06d178Schris    $pass = auth_pwgen();
5958b06d178Schris    if (!auth_modifyUser($user,array('pass' => $pass))) {
5968b06d178Schris      msg('error modifying user data',-1);
5978b06d178Schris      return false;
5988b06d178Schris    }
5998b06d178Schris
6008b06d178Schris    if (auth_sendPassword($user,$pass)) {
6018b06d178Schris      msg($lang['resendpwdsuccess'],1);
6028b06d178Schris    } else {
6038b06d178Schris      msg($lang['regmailfail'],-1);
6048b06d178Schris    }
6058b06d178Schris    return true;
6068b06d178Schris}
6078b06d178Schris
6088b06d178Schris/**
60910a76f6fSfrank * Uses a regular expresion to check if a given mail address is valid
61010a76f6fSfrank *
61110a76f6fSfrank * May not be completly RFC conform!
61210a76f6fSfrank *
61310a76f6fSfrank * @link    http://www.webmasterworld.com/forum88/135.htm
61410a76f6fSfrank *
61510a76f6fSfrank * @param   string $email the address to check
61610a76f6fSfrank * @return  bool          true if address is valid
61710a76f6fSfrank */
61810a76f6fSfrankfunction isvalidemail($email){
61910a76f6fSfrank  return eregi("^[0-9a-z]([-_.]?[0-9a-z])*@[0-9a-z]([-.]?[0-9a-z])*\\.[a-z]{2,4}$", $email);
62010a76f6fSfrank}
62110a76f6fSfrank
622b0855b11Sandi/**
623b0855b11Sandi * Encrypts a password using the given method and salt
624b0855b11Sandi *
625b0855b11Sandi * If the selected method needs a salt and none was given, a random one
626b0855b11Sandi * is chosen.
627b0855b11Sandi *
628b0855b11Sandi * The following methods are understood:
629b0855b11Sandi *
630b0855b11Sandi *   smd5  - Salted MD5 hashing
631b0855b11Sandi *   md5   - Simple MD5 hashing
632b0855b11Sandi *   sha1  - SHA1 hashing
633b0855b11Sandi *   ssha  - Salted SHA1 hashing
634d7be6245Sandi *   crypt - Unix crypt
635d7be6245Sandi *   mysql - MySQL password (old method)
636d7be6245Sandi *   my411 - MySQL 4.1.1 password
637b0855b11Sandi *
638b0855b11Sandi * @author  Andreas Gohr <andi@splitbrain.org>
639b0855b11Sandi * @return  string  The crypted password
640b0855b11Sandi */
641b0855b11Sandifunction auth_cryptPassword($clear,$method='',$salt=''){
642b0855b11Sandi  global $conf;
643b0855b11Sandi  if(empty($method)) $method = $conf['passcrypt'];
64410a76f6fSfrank
645b0855b11Sandi  //prepare a salt
646b0855b11Sandi  if(empty($salt)) $salt = md5(uniqid(rand(), true));
647b0855b11Sandi
648b0855b11Sandi  switch(strtolower($method)){
649b0855b11Sandi    case 'smd5':
650b0855b11Sandi        return crypt($clear,'$1$'.substr($salt,0,8).'$');
651b0855b11Sandi    case 'md5':
652b0855b11Sandi      return md5($clear);
653b0855b11Sandi    case 'sha1':
654b0855b11Sandi      return sha1($clear);
655b0855b11Sandi    case 'ssha':
656b0855b11Sandi      $salt=substr($salt,0,4);
657d6e54e02Smatthiasgrimm      return '{SSHA}'.base64_encode(pack("H*", sha1($clear.$salt)).$salt);
658b0855b11Sandi    case 'crypt':
659b0855b11Sandi      return crypt($clear,substr($salt,0,2));
660d7be6245Sandi    case 'mysql':
661d7be6245Sandi      //from http://www.php.net/mysql comment by <soren at byu dot edu>
662d7be6245Sandi      $nr=0x50305735;
663d7be6245Sandi      $nr2=0x12345671;
664d7be6245Sandi      $add=7;
665d7be6245Sandi      $charArr = preg_split("//", $clear);
666d7be6245Sandi      foreach ($charArr as $char) {
667d7be6245Sandi        if (($char == '') || ($char == ' ') || ($char == '\t')) continue;
668d7be6245Sandi        $charVal = ord($char);
669d7be6245Sandi        $nr ^= ((($nr & 63) + $add) * $charVal) + ($nr << 8);
670d7be6245Sandi        $nr2 += ($nr2 << 8) ^ $nr;
671d7be6245Sandi        $add += $charVal;
672d7be6245Sandi      }
673d7be6245Sandi      return sprintf("%08x%08x", ($nr & 0x7fffffff), ($nr2 & 0x7fffffff));
674d7be6245Sandi    case 'my411':
675d7be6245Sandi      return '*'.sha1(pack("H*", sha1($clear)));
676b0855b11Sandi    default:
677b0855b11Sandi      msg("Unsupported crypt method $method",-1);
678b0855b11Sandi  }
679b0855b11Sandi}
680b0855b11Sandi
681b0855b11Sandi/**
682b0855b11Sandi * Verifies a cleartext password against a crypted hash
683b0855b11Sandi *
684b0855b11Sandi * The method and salt used for the crypted hash is determined automatically
685b0855b11Sandi * then the clear text password is crypted using the same method. If both hashs
686b0855b11Sandi * match true is is returned else false
687b0855b11Sandi *
688b0855b11Sandi * @author  Andreas Gohr <andi@splitbrain.org>
689b0855b11Sandi * @return  bool
690b0855b11Sandi */
691b0855b11Sandifunction auth_verifyPassword($clear,$crypt){
692b0855b11Sandi  $method='';
693b0855b11Sandi  $salt='';
694b0855b11Sandi
695b0855b11Sandi  //determine the used method and salt
696d7be6245Sandi  $len = strlen($crypt);
697b0855b11Sandi  if(substr($crypt,0,3) == '$1$'){
698b0855b11Sandi    $method = 'smd5';
699b0855b11Sandi    $salt   = substr($crypt,3,8);
700b0855b11Sandi  }elseif(substr($crypt,0,6) == '{SSHA}'){
701b0855b11Sandi    $method = 'ssha';
702b0855b11Sandi    $salt   = substr(base64_decode(substr($crypt, 6)),20);
703d7be6245Sandi  }elseif($len == 32){
704b0855b11Sandi    $method = 'md5';
705d7be6245Sandi  }elseif($len == 40){
706b0855b11Sandi    $method = 'sha1';
707d7be6245Sandi  }elseif($len == 16){
708d7be6245Sandi    $method = 'mysql';
709d7be6245Sandi  }elseif($len == 41 && $crypt[0] == '*'){
710d7be6245Sandi    $method = 'my411';
711b0855b11Sandi  }else{
712b0855b11Sandi    $method = 'crypt';
713b0855b11Sandi    $salt   = substr($crypt,0,2);
714b0855b11Sandi  }
715b0855b11Sandi
716b0855b11Sandi  //crypt and compare
717b0855b11Sandi  if(auth_cryptPassword($clear,$method,$salt) === $crypt){
718b0855b11Sandi    return true;
719b0855b11Sandi  }
720b0855b11Sandi  return false;
721b0855b11Sandi}
722340756e4Sandi
723340756e4Sandi//Setup VIM: ex: et ts=2 enc=utf-8 :
724