Merge branch 'main/rendor-staging' into main/atys-live
[ryzomcore.git] / web / public_php / login / r2_login.php
blobb0a8a2d79c2a1b13109f223a91362d8399e06864
1 <?php
3 error_reporting(E_ERROR | E_PARSE);
4 set_error_handler('err_callback');
6 // For error handling, buffer all output
7 ob_start('ob_callback_r2login');
9 include_once('config.php');
10 include_once('login_translations.php');
11 include_once('../tools/nel_message.php');
12 include_once('../tools/domain_info.php');
13 include_once('login_service_itf.php');
14 include_once('../ring/join_shard.php');
17 function get_salt($password)
19 if ($password[0] == '$')
21 $salt = substr($password, 0, 19);
23 else
25 $salt = substr($password, 0, 2);
27 return $salt;
30 // see errorMsg
31 function errorMsgBlock($errNum=GENERIC_ERROR_NUM) // $mixedArgs
33 $args = func_get_args();
34 return '0:'.call_user_func_array('errorMsg', $args);
37 class LoginCb extends CLoginServiceWeb
39 // receive the login result sent back by the LS
40 function loginResult($userId, $cookie, $resultCode, $errorString)
42 global $RingWebHost, $RingWebHostPHP;
43 global $domainId;
45 if ($resultCode == 0 && $cookie != "")
47 // gather the domain information (server version, patch urls and backup patch url
48 global $DBHost, $DBUserName, $DBPassword, $DBName, $AutoInsertInRing;
50 $link = mysqli_connect($DBHost, $DBUserName, $DBPassword) or die (errorMsgBlock(3004, 'main', $DBHost, $DBUserName));
51 mysqli_select_db ($link, $DBName) or die (errorMsgBlock(3005, 'main', $DBName, $DBHost, $DBUserName));
52 $query = "SELECT * FROM domain WHERE domain_id=$domainId";
53 $result = mysqli_query ($link, $query) or die (errorMsgBlock(3006, $query, 'main', $DBName, $DBHost, $DBUserName, mysqli_error($link)));
55 if( mysqli_num_rows($result) != 1)
57 die(errorMsgBlock(3001, $domainId));
59 $row = mysqli_fetch_array($result);
61 // set the cookie
62 setcookie ( "ryzomId" , $cookie, 0, "/");
63 $_COOKIE["ryzomId"] = $cookie; // make it available immediately
65 // Auto-join an available mainland shard
66 global $FSHostLuaMode, $FSHostResultStr;
67 $FSHostLuaMode = false;
68 $res = joinMainland($userId, $domainId, $row["domain_name"]);
70 if ($res)
72 // return the cookie to the user, il will then be used as an auth to browse the site and to connect to the shard
73 //echo "1#".$cookie."#http://".$RingWebHost."/ring/web_start.php\n";
74 // use this line to use woopra stats
75 // echo "1#".$cookie."#".$FSHostResultStr."#http://".$RingWebHost."/ring/web_start.php#http://".$RingWebHostPHP."/ring/#1\n";
76 echo "1#".$cookie."#".$FSHostResultStr."#http://".$RingWebHost."/ring/web_start.php#http://".$RingWebHostPHP."/ring/\n";
77 // return the ring domain information
78 echo $row["patch_version"]."#".$row["backup_patch_url"]."#".$row["patch_urls"];
80 else
82 global $JoinSessionResultCode, $JoinSessionResultMsg;
83 echo errorMsgBlock(BASE_TRANSLATED_RSM_ERROR_NUM + $JoinSessionResultCode, $JoinSessionResultCode, $JoinSessionResultMsg, $userId);
86 else
88 // empty cookie, this mean the user id can't be validated by the LS
89 echo errorMsgBlock(BASE_TRANSLATED_LS_ERROR_NUM + $resultCode, $resultCode, $errorString, $userId);
94 class CWwwLog
96 //function CWwwLog() {}
99 * Return the log directory. Create it if it does not exist, or return false if creation failed.
101 function getSafeLogDir()
103 // Examples:
104 // __FILE__ = r:\code\ryzom\www\login\config.php
105 // $_SERVER['PATH_TRANSLATED'] = 'r:/code/ryzom/www/login//r2_login.php'
106 // $_SERVER['SCRIPT_FILENAME'] = 'r:/code/ryzom/www/login//r2_login.php'
107 global $LogRelativePath;
108 $pathInfo = pathinfo(__FILE__);
109 $logPath = $pathInfo['dirname'].'/'.$LogRelativePath;
110 if (!is_dir($logPath))
112 $res = mkdir($LogPath, 0700);
113 return $res ? $logPath : false;
115 return $logPath;
118 function logStr($str)
120 $logPath = $this->getSafeLogDir();
121 if ($logPath !== false)
123 $fp = fopen($logPath.'/r2_login_'.date('Y-m-d').'.log', 'a');
124 fwrite($fp, date('Y-m-d H:i:s').' ('.$_SERVER['REMOTE_ADDR'].':'.$_SERVER['REQUEST_URI']."): $str\n");
125 fclose($fp);
130 // Callback called on end of output buffering
131 function ob_callback_r2login($buffer)
133 // Log only in case of error or malformed result string
134 $blockHd = substr($buffer, 0, 2);
135 if ($blockHd != '1:')
137 $logFile = new CWwwLog();
138 $logFile->logStr(str_replace("\n",'\n',$buffer));
140 return $buffer; // sent to output
143 // Callback called on error
144 function err_callback($errno, $errmsg, $filename, $linenum, $vars)
146 $logFile = new CWwwLog();
147 $logFile->logStr("PHP ERROR/$errno $errmsg ($filename:$linenum)");
148 $logFile->logStr("PHP CALLSTACK/" . print_r(debug_backtrace(), TRUE));
149 // Never die after an error
152 if (!isset($_GET['cmd']))
154 die (errorMsgBlock(3002));
157 // check for 'clear password' tag
158 if (!isset($_GET['cp']))
160 $cp = 0;
162 else
164 $cp = $_GET['cp'];
167 $submittedLang = isset($_GET['lg']) ? $_GET['lg'] : 'unknown';
168 if (isset($_GET['dbg']) && ($_GET['dbg'] == 1))
169 $DisplayDbg = true;
171 switch($_GET['cmd'])
173 case 'ask':
174 // client ask for a login salt
175 askSalt($_GET['login'], $submittedLang);
176 die();
177 case 'login':
178 $domainId = -1;
179 // client sent is login info
180 if (!checkUserValidity($_GET['login'], $_GET['password'], $_GET['clientApplication'], $cp, $id, $reason, $priv, $extended, $domainId, $submittedLang))
182 echo '0:'.$reason;
184 else
187 // retreive the domain info
188 $domainInfo = getDomainInfo($domainId);
190 // if we need to create missing ring info
191 if ($AutoCreateRingInfo)
193 // check if the ring user exist, and create it if not
194 $ringDb = mysqli_connect($DBHost, $RingDBUserName, $RingDBPassword) or die(errorMsgBlock(3004, 'Ring', $DBHost, $RingDBUserName));
195 mysqli_select_db ($ringDb, $domainInfo['ring_db_name']) or die(errorMsgBlock(3005, 'Ring', $domainInfo['ring_db_name'], $DBHost, $RingDBUserName));
196 $query = "SELECT user_id FROM ring_users where user_id = '".$id."'";
197 $result = mysqli_query ($ringDb, $query) or die(errorMsgBlock(3006, $query, 'Ring', $domainInfo['ring_db_name'], $DBHost, $RingDBUserName, mysqli_error($ringDb)));
199 if (mysqli_num_rows($result) == 0)
201 // no ring user record, build one
202 $login = mysqli_real_escape_string($ringDb, $_GET['login']);
203 $query = "INSERT INTO ring_users SET user_id = '$id', user_name = '$login', user_type='ut_pioneer'";
204 $result = mysqli_query ($ringDb, $query) or die(errorMsgBlock(3006, $query, 'Ring', $domainInfo['ring_db_name'], $DBHost, $RingDBUserName, mysqli_error($ringDb)));
208 // // check domain status
209 // if ($domainInfo['status'] == "ds_close")
210 // {
211 // // the domain is closed
212 // echo "0:Server is currently closed";
213 // die;
214 // }
215 // else if ($domainInfo['status'] == "ds_dev" && strstr($priv, ":DEV:") == false)
216 // {
217 // // the domain is open to dev only
218 // echo "0:You are not allowed to connect now, retry later";
219 // die;
220 // }
221 // else if ($domainInfo['status'] == "ds_restricted")
222 // {
223 // // check for one of the needed privilege
224 // if ( strstr($priv, ":DEV:") == false
225 // && strstr($priv, ":SGM:") == false
226 // && strstr($priv, ":GM:") == false
227 // && strstr($priv, ":EG:") == false)
228 // {
229 // // the domain is open to privileged user only
230 // echo "0:You are not allowed to connect now, retry later";
231 // die;
232 // }
233 // }
235 // store the web host for this domain
236 global $RingWebHost, $RingWebHostPHP;
237 $RingWebHost = $domainInfo['web_host'];
238 $RingWebHostPHP = $domainInfo['web_host_php'];
240 $LSaddr = explode(":", $domainInfo['login_address']);
242 // ask for a session cookie to the login service
243 $login = new LoginCb;
244 $res = "";
245 $login->connect($LSaddr[0], $LSaddr[1], $res);
246 // $lsProxy = new CLoginServiceWebProxy;
247 $login->login($id, $_SERVER["REMOTE_ADDR"], $domainId);
249 // wait for the return message
250 // $lsSkel = new CLoginServiceWebSkel;
251 if (!$login->waitCallback())
253 die(errorMsgBlock(3003));
256 //the rest of the process is done in the callback function
260 // no more to do (other global statement are old garbage)
261 die();
263 // ----------------------------------------------------------------------------------------
264 // Functions
265 // ----------------------------------------------------------------------------------------
267 // $reason contains the reason why the check failed or success
268 // return true if the check is ok
269 function checkUserValidity ($login, $password, $clientApplication, $cp, &$id, &$reason, &$priv, &$extended, &$domainId, $lang)
271 global $DBHost, $DBUserName, $DBPassword, $DBName, $AcceptUnknownUser;
273 setMsgLanguage($lang);
275 $link = mysqli_connect($DBHost, $DBUserName, $DBPassword) or die (errorMsgBlock(3004, 'main', $DBHost, $DBUserName));
276 mysqli_select_db ($link, $DBName) or die (errorMsgBlock(3005, 'main', $DBName, $DBHost, $DBUserName));
278 // we map the client application to the domain name
279 $domainName = mysqli_real_escape_string($link, $clientApplication);
281 // retreive the domain id
282 $query = "SELECT domain_id FROM domain WHERE domain_name='$domainName'";
283 $result = mysqli_query ($link, $query) or die (errorMsgBlock(3006, $query, 'main', $DBName, $DBHost, $DBUserName, mysqli_error($link)));
285 if (mysqli_num_rows($result) == 0)
287 // unrecoverable error, we must giveup
288 $reason = errorMsg(3007, $domainName);
289 mysqli_close($link);
290 return false;
293 $row = mysqli_fetch_array($result);
294 $domainId = $row[0];
296 // retreive the domain info
297 $domainInfo = getDomainInfo($domainId);
299 // convert the domain status enum into the privilege access set
300 $accessPriv = strtoupper(substr($domainInfo['status'], 3));
302 // now, retrieve the user infos
303 $login = mysqli_real_escape_string($link, $login);
304 $query = "SELECT * FROM user where Login='$login'";
305 $result = mysqli_query ($link, $query) or die (errorMsgBlock(3006, $query, 'main', $DBName, $DBHost, $DBUserName, mysqli_error($link)));
307 if (mysqli_num_rows ($result) == 0)
309 if ($AcceptUnknownUser)
311 // login doesn't exist, create it
312 $password = mysqli_real_escape_string($link, $password);
313 $query = "INSERT INTO user (Login, Password) VALUES ('$login', '$password')";
314 $result = mysqli_query ($link, $query) or die (errorMsgBlock(3006, $query, 'main', $DBName, $DBHost, $DBUserName, mysqli_error($link)));
316 // get the user to have his UId
317 $query = "SELECT * FROM user WHERE Login='$login'";
318 $result = mysqli_query ($link, $query) or die (errorMsgBlock(3006, $query, 'main', $DBName, $DBHost, $DBUserName, mysqli_error($link)));
320 if (mysqli_num_rows ($result) == 1)
322 $reason = errorMsg(3008, $login);
323 $row = mysqli_fetch_assoc ($result);
324 $id = $row["UId"];
325 $priv = $row["Privilege"];
326 $extended = $row["ExtendedPrivilege"];
328 // add the default permission
329 $query = "INSERT INTO permission (UId, DomainId, AccessPrivilege) VALUES ('$id', '$domainId', '$accessPriv')";
330 $result = mysqli_query ($link, $query) or die (errorMsgBlock(3006, $query, 'main', $DBName, $DBHost, $DBUserName, mysqli_error($link)));
332 $res = false;
334 else
336 $reason = errorMsg(3009, $login);
337 $res = false;
340 else
342 $reason = errorMsg(2001, $login, 'checkUserValidity');
345 else
347 $row = mysqli_fetch_assoc ($result);
348 $salt = get_salt($row["Password"]);
349 if (($cp && $row["Password"] == $password) || (!$cp && $row["Password"] == crypt($password, $salt)))
351 // Store the real login (with correct case)
352 $_GET['login'] = $row['Login'];
353 // check if the user can use this application
355 $clientApplication = mysqli_real_escape_string($link, $clientApplication);
356 $query = "SELECT * FROM permission WHERE UId='".$row["UId"]."' AND DomainId='$domainId'";
357 $result = mysqli_query ($link, $query) or die (errorMsgBlock(3006, $query, 'main', $DBName, $DBHost, $DBUserName, mysqli_error($link)));
358 if (mysqli_num_rows ($result) == 0)
360 if ($AcceptUnknownUser)
362 // add default permission
363 $query = "INSERT INTO permission (UId, DomainId, ShardId, AccessPrivilege) VALUES ('".$row["UId"]."', '$domainId', -1, '$domainStatus')";
364 $result = mysqli_query ($link, $query) or die (errorMsgBlock(3006, $query, 'main', $DBName, $DBHost, $DBUserName, mysqli_error($link)));
366 $reason = errorMsg(3010);
367 $res = false;
369 else
371 // no permission
372 $reason = errorMsg(3011, $clientApplication, $domainName);
373 $res = false;
376 else
378 // check that the access privilege for the domain
379 $permission = mysqli_fetch_assoc($result);
381 if (!strstr($permission['AccessPrivilege'], $accessPriv))
383 // no right to connect
384 if ($AcceptUnknownUser)
386 // set an additionnal privilege for this player
387 $query = "UPDATE permission set AccessPrivilege='".$permission['AccessPrivilege'].",$accessPriv' WHERE PermissionId=".$permission['PermissionId'];
388 $result = mysqli_query ($link, $query) or die (errorMsgBlock(3006, $query, 'main', $DBName, $DBHost, $DBUserName, mysqli_error($link)));
390 $reason = errorMsg(3012, $accessPriv);
391 $res = false;
393 else
395 // no permission
396 $reason = errorMsg(3013, $clientApplication, $domainName, $accessPriv);
397 $res = false;
400 else
403 // // check if the user not already online
405 // if ($row["State"] != "Offline")
406 // {
407 // $reason = "$login is already online and ";
408 // // ask the LS to remove the client
409 // if (disconnectClient ($row["ShardId"], $row["UId"], $tempres))
410 // {
411 // $reason = $reason."was just disconnected. Now you can retry the identification (error code 54)";
413 // $query = "update shard set NbPlayers=NbPlayers-1 where ShardId=".$row["ShardId"];
414 // $result = mysqli_query ($link, $query) or die ("Can't execute the query: '$query' errno:".mysqli_errno($link).": ".mysqli_error($link));
416 // $query = "update user set ShardId=-1, State='Offline' where UId=".$row["UId"];
417 // $result = mysqli_query ($link, $query) or die ("Can't execute the query: '$query' errno:".mysqli_errno($link).": ".mysqli_error($link));
418 // }
419 // else
420 // {
421 // $reason = $reason."can't be disconnected: $tempres (error code 55)";
422 // }
423 // $res = false;
424 // }
425 // else
426 // {
427 $id = $row["UId"];
428 $priv = $row["Privilege"];
429 $extended = $row["ExtendedPrivilege"];
430 $res = true;
431 // }
435 else
437 $reason = errorMsg(2004, 'user');
438 $res = false;
441 mysqli_close($link);
442 return $res;
445 function askSalt($login, $lang)
447 global $PHP_SELF;
448 global $DBHost, $DBUserName, $DBPassword, $DBName;
449 global $AcceptUnknownUser;
451 setMsgLanguage($lang);
453 $link = mysqli_connect($DBHost, $DBUserName, $DBPassword) or die (errorMsgBlock(3004, 'main', $DBHost, $DBUserName));
454 mysqli_select_db ($link, $DBName) or die (errorMsgBlock(3005, 'main', $DBName, $DBHost, $DBUserName));
456 $login = mysqli_real_escape_string($link, $login);
457 $query = "SELECT Password FROM user WHERE Login='$login'";
458 $result = mysqli_query ($link, $query) or die (errorMsgBlock(3006, $query, 'main', $DBName, $DBHost, $DBUserName, mysqli_error($link)));
460 if (mysqli_num_rows ($result) != 1)
462 if ($AcceptUnknownUser)
464 // just accept the client and return a default salk
465 echo "1:AA";
466 die;
468 else
470 die (errorMsgBlock(2001, $login, 'askSalt'));
471 // Check if this is not an unconfirmed account
472 /*$query = "SELECT GamePassword, Language FROM signup_data WHERE login='$login'";
473 $result = mysqli_query($link, $query) or die (errorMsgBlock(3006, $query, 'main', $DBName, $DBHost, $DBUserName, mysqli_error($link)));
475 if (mysqli_num_rows($result) == 0)
477 // no user record, reject it
478 die (errorMsgBlock(2001, $login, 'askSalt'));
480 else if (mysqli_num_rows($result) == 1)
482 // one unconfirmed record, let the client send the encrypted password to get the corresponding email address
483 $row = mysqli_fetch_assoc($result);
484 $salt = substr($row['GamePassword'], 0, 2);
486 else
488 if ($lang == 'unknown')
490 // several matching records => display a multi-language message now
491 $languages = array();
492 while ($row = mysqli_fetch_assoc($result))
494 $languages[$row['Language']] = true;
496 setMsgLanguage(array_keys($languages));
498 die (errorMsgBlock(2003));
502 else
504 $res_array = mysqli_fetch_assoc($result);
505 $salt = get_salt($res_array['Password']);
508 echo "1:".$salt;
509 mysqli_close($link);