Pol  Revision:cb584c9
login.cpp
Go to the documentation of this file.
1 
22 #include <cstring>
23 #include <string>
24 
25 #include "../clib/clib.h"
26 #include "../clib/clib_MD5.h"
27 #include "../clib/clib_endian.h"
28 #include "../clib/logfacility.h"
29 #include "../clib/rawtypes.h"
30 #include "../plib/systemstate.h"
31 #include "accounts/account.h"
32 #include "accounts/accounts.h"
33 #include "core.h"
34 #include "crypt/cryptbase.h"
35 #include "globals/settings.h"
36 #include "globals/uvars.h"
37 #include "mobile/charactr.h"
38 #include "network/client.h"
39 #include "network/packethelper.h"
40 #include "network/packets.h"
41 #include "pktdef.h"
42 #include "pktin.h"
43 #include "polcfg.h"
44 #include "servdesc.h"
45 #include "startloc.h"
46 #include "ufunc.h"
47 
48 namespace Pol
49 {
50 namespace Network
51 {
52 bool is_banned_ip( Client* client );
53 }
54 
55 namespace Core
56 {
57 void call_ondelete_scripts( Mobile::Character* chr );
58 bool can_delete_character( Mobile::Character* chr, int delete_by );
59 
60 void send_login_error( Network::Client* client, unsigned char reason )
61 {
63  msg->Write<u8>( reason );
64  msg.Send( client );
65 }
66 
67 // TODO: rewrite this loop to use stl algorithms + stlutil.h case insensitive compare function
68 // -- and I'm leaving the warning here to remember that --
69 bool acct_check( Network::Client* client, int i )
70 {
71  if ( networkManager.servers[i]->acct_match.empty() )
72  return true;
73 
74  for ( unsigned j = 0; j < networkManager.servers[i]->acct_match.size(); ++j )
75  {
76  if ( stricmp( networkManager.servers[i]->acct_match[j].c_str(), client->acct->name() ) == 0 )
77  return true;
78  }
79 
80  return false;
81 }
82 
83 bool server_applies( Network::Client* client, int i )
84 {
85  if ( networkManager.servers[i]->ip_match.empty() )
86  return acct_check( client, i );
87 
88  for ( unsigned j = 0; j < networkManager.servers[i]->ip_match.size(); ++j )
89  {
90  unsigned int addr1part, addr2part;
91  struct sockaddr_in* sockin = reinterpret_cast<struct sockaddr_in*>( &client->ipaddr );
92 
93  addr1part =
94  networkManager.servers[i]->ip_match[j] & networkManager.servers[i]->ip_match_mask[j];
95 #ifdef _WIN32
96  addr2part = sockin->sin_addr.S_un.S_addr & networkManager.servers[i]->ip_match_mask[j];
97 #else
98  addr2part = sockin->sin_addr.s_addr & networkManager.servers[i]->ip_match_mask[j];
99 #endif
100  if ( addr1part == addr2part )
101  return true;
102  }
103  return false;
104 }
105 
107 {
108  unsigned idx;
109 
110  if ( Network::is_banned_ip( client ) )
111  {
113  client->Disconnect();
114  return;
115  }
116 
118  if ( !acct )
119  {
121  client->Disconnect();
122  return;
123  }
124  else if ( Plib::systemstate.config.min_cmdlevel_to_login > acct->default_cmdlevel() )
125  {
127  client->Disconnect();
128  return;
129  }
130 
131  bool correct_password = false;
132 
133  std::string msgpass = msg->password;
134  std::string acctname = acct->name();
135  std::string temp;
136  Clib::MD5_Encrypt( acctname + msgpass, temp ); // MD5
137  correct_password = Clib::MD5_Compare( acct->passwordhash(), temp );
138 
139  if ( !correct_password )
140  {
142  client->Disconnect();
143  POLLOG.Format( "Incorrect password for account {} from {}\n" )
144  << acct->name() << Network::AddressToString( &client->ipaddr );
145  return;
146  }
147  else
148  {
149  if ( Plib::systemstate.config.retain_cleartext_passwords )
150  {
151  if ( acct->password().empty() )
152  acct->set_password( msgpass );
153  }
154  }
155 
156  if ( !acct->enabled() || acct->banned() )
157  {
159  client->Disconnect();
160  return;
161  }
162 
163  POLLOG_INFO.Format( "Account {} logged in from {}\n" )
164  << acct->name() << Network::AddressToString( &client->ipaddr );
165 
166  client->acct = acct;
167 
169  msgA8->offset += 2;
170  msgA8->Write<u8>( 0xFFu );
171  msgA8->offset += 2; // servcount
172 
173  unsigned short servcount = 0;
174 
175 
176  for ( idx = 0; idx < networkManager.servers.size(); idx++ )
177  {
179 
180  if ( !server->hostname.empty() )
181  {
182  struct hostent* he =
183  gethostbyname( server->hostname.c_str() ); // FIXME: here is a potential server lockup
184  if ( he != nullptr && he->h_addr_list[0] )
185  {
186  char* addr = he->h_addr_list[0];
187  server->ip[0] = addr[3];
188  server->ip[1] = addr[2];
189  server->ip[2] = addr[1];
190  server->ip[3] = addr[0];
191  }
192  else
193  {
194  POLLOG.Format( "gethostbyname(\"{}\") failed for server {}\n" )
195  << server->hostname << server->name;
196  continue;
197  }
198  }
199 
200  if ( server_applies( client, idx ) )
201  {
202  ++servcount;
203  msgA8->WriteFlipped<u16>( idx + 1u );
204  msgA8->Write( server->name.c_str(), 30 );
205  msgA8->WriteFlipped<u16>( idx + 1u );
206  msgA8->offset += 2; // u8 percentfull, s8 timezone
207  msgA8->Write( server->ip, 4 );
208  }
209  }
210  u16 len = msgA8->offset;
211  msgA8->offset = 1;
212  msgA8->WriteFlipped<u16>( len );
213  msgA8->offset++;
214  msgA8->WriteFlipped<u16>( servcount );
215 
216  msgA8.Send( client, len );
217 
218  if ( servcount == 0 )
219  {
220  POLLOG.Format( "No applicable servers for client connecting from {}\n" )
221  << Network::AddressToString( &client->ipaddr );
222  }
223 }
224 
225 void handle_A4( Network::Client* /*client*/, PKTIN_A4* /*msg*/ ) {}
226 
227 void handle_D9( Network::Client* client, PKTIN_D9* msg )
228 {
229  PKTIN_D9 _msg; // got crashes here under *nix -> modify a new local instance
230  // Transform Little-Endian <-> Big-Endian
231  _msg.instance = cfBEu32( msg->instance ); // Unique Instance ID of UO
232  _msg.os_major = cfBEu32( msg->os_major ); // OS Major
233  _msg.os_minor = cfBEu32( msg->os_minor ); // OS Minor
234  _msg.os_revision = cfBEu32( msg->os_revision ); // OS Revision
235  _msg.cpu_family = cfBEu32( msg->cpu_family ); // CPU Family
236  _msg.cpu_model = cfBEu32( msg->cpu_model ); // CPU Model
237  _msg.cpu_clockspeed = cfBEu32( msg->cpu_clockspeed ); // CPU Clock Speed [Mhz]
238  _msg.memory = cfBEu32( msg->memory ); // Memory [MB]
239  _msg.screen_width = cfBEu32( msg->screen_width ); // Screen Width
240  _msg.screen_height = cfBEu32( msg->screen_height ); // Screen Height
241  _msg.screen_depth = cfBEu32( msg->screen_depth ); // Screen Depth [Bit]
242  _msg.directx_major = cfBEu16( msg->directx_major ); // DirectX Major
243  _msg.directx_minor = cfBEu16( msg->directx_minor ); // DirectX Minor
244 
245  for ( unsigned i = 0; i < sizeof( msg->video_description ) / sizeof( msg->video_description[0] );
246  ++i )
247  _msg.video_description[i] =
248  cfBEu16( msg->video_description[i] ); // Video Card Description [wide-character]
249 
250  _msg.video_vendor = cfBEu32( msg->video_vendor ); // Video Card Vendor ID
251  _msg.video_device = cfBEu32( msg->video_device ); // Video Card Device ID
252  _msg.video_memory = cfBEu32( msg->video_memory ); // Video Card Memory [MB]
253 
254  for ( unsigned i = 0; i < sizeof( msg->langcode ) / sizeof( msg->langcode[0] ); ++i )
255  _msg.langcode[i] = cfBEu16( msg->langcode[i] ); // Language Code [wide-character]
256 
257  client->setclientinfo( &_msg );
258 }
259 
260 void select_server( Network::Client* client, PKTIN_A0* msg ) // Relay player to a certain IP
261 {
262  unsigned servernum = cfBEu16( msg->servernum ) - 1;
263 
264  if ( servernum >= networkManager.servers.size() )
265  {
266  client->forceDisconnect();
267  return;
268  }
269 
270  ServerDescription* svr = networkManager.servers[servernum];
271 
273  rsp->Write<u8>( svr->ip[3] );
274  rsp->Write<u8>( svr->ip[2] );
275  rsp->Write<u8>( svr->ip[1] );
276  rsp->Write<u8>( svr->ip[0] );
277 
278  if ( client->listen_port != 0 )
279  rsp->WriteFlipped<u16>( client->listen_port );
280  else
281  rsp->WriteFlipped<u16>( svr->port );
282  // MuadDib Added new seed system. This is for transferring KR/6017/Normal client detection from
283  // loginserver
284  // to the gameserver. Allows keeping client flags from remote loginserver to gameserver for 6017
285  // and kr
286  // packets.
287 
288  unsigned int nseed = 0xFEFE0000 | client->ClientType;
289  rsp->WriteFlipped<u32>( nseed ); // This was set to 0xffffffff in the past but this will conflict
290  // with UO:KR detection
291 
292  rsp.Send( client );
293 
294  client->cryptengine->Init( &nseed, Crypt::CCryptBase::typeGame );
295 }
296 
298 {
300  client ); // Shinigami: moved from start_client_char() to send before char selection
301 
302  unsigned i;
303  u32 clientflag; // sets client flags
304  unsigned char char_slots; // number of slots according to expansion, avoids crashing people
305  unsigned char char_count; // number of chars to send: Max(char_slots, 5)
306 
307  char_slots = static_cast<u8>(
309  .character_slots ); // sets it first to be the number defined in the config
310  // TODO: Per account character slots? (With the actual character_slots defining maximum)
311 
312  // If more than 6 chars and no AOS, only send 5. Client is so boring sometimes...
313  if ( char_slots >= 6 && !( client->UOExpansionFlag & Network::AOS ) )
314  char_slots = 5;
315 
316  char_count = 5; // UO always expects a minimum of 5? What a kludge...
317  if ( char_slots > char_count ) // Max(char_slots, 5)
318  char_count = char_slots;
319 
321  msg->offset += 2;
322  msg->Write<u8>( char_count );
323 
324  for ( i = 0; i < char_count; i++ )
325  {
326  if ( i < char_slots ) // Small kludge to have a minimum of 5 chars in the packet
327  {
328  // name only 30 long rest is password seems to fix the password promt problem
329  Mobile::Character* chr = client->acct->get_character( i );
330  if ( chr )
331  {
332  msg->Write( chr->name().c_str(), 30, false );
333  msg->offset += 30; // password
334  }
335  else
336  msg->offset += 60;
337  }
338  else
339  msg->offset += 60;
340  }
341 
342  msg->Write<u8>( gamestate.startlocations.size() );
343 
344  for ( i = 0; i < gamestate.startlocations.size(); i++ )
345  {
346  msg->Write<u8>( i );
347  if ( client->ClientType & Network::CLIENTTYPE_70130 )
348  {
349  msg->Write( gamestate.startlocations[i]->city.c_str(), 32, false );
350  msg->Write( gamestate.startlocations[i]->desc.c_str(), 32, false );
351 
352  Coordinate coord = gamestate.startlocations[i]->coords[0];
353 
354  msg->WriteFlipped<u32>( coord.x );
355  msg->WriteFlipped<u32>( coord.y );
356  msg->WriteFlipped<s32>( coord.z );
357  msg->WriteFlipped<u32>( gamestate.startlocations[i]->mapid ); // MapID
358  msg->WriteFlipped<u32>( gamestate.startlocations[i]->cliloc_desc ); // Cliloc Description
359  msg->offset += 4;
360  }
361  else
362  {
363  msg->Write( gamestate.startlocations[i]->city.c_str(), 31, false );
364  msg->Write( gamestate.startlocations[i]->desc.c_str(), 31, false );
365  }
366  }
367 
368  clientflag = settingsManager.ssopt.uo_feature_enable; // 'default' flags. Maybe auto-enable them
369  // according to the expansion?
370 
371  clientflag |= PKTOUT_A9::FLAG_SEND_UO3D_TYPE; // Let UO3D (KR,SA) send 0xE1 packet
372 
373  // Change this to a function for clarity? -- Nando
374  if ( char_slots == 7 )
375  clientflag |= PKTOUT_A9::FLAG_UPTO_SEVEN_CHARACTERS; // 7th Character flag
376  else if ( char_slots == 6 )
377  clientflag |= PKTOUT_A9::FLAG_UPTO_SIX_CHARACTERS; // 6th Character Flag
378  else if ( char_slots == 1 )
379  clientflag |= 0x14; // Only one character (SIEGE (0x04) + LIMIT_CHAR (0x10))
380 
381  msg->WriteFlipped<u32>( clientflag );
382  u16 len = msg->offset;
383  msg->offset = 1;
384  msg->WriteFlipped<u16>( len );
385  msg.Send( client, len );
386 }
387 
388 void login2( Network::Client* client, PKTIN_91* msg ) // Gameserver login and character listing
389 {
390  client->encrypt_server_stream = 1;
391 
392  if ( Network::is_banned_ip( client ) )
393  {
395  client->Disconnect();
396  return;
397  }
398 
399  /* Hmm, might have to re-search for account.
400  For now, we already have the account in client->acct.
401  Might work different if real loginservers were used. */
403  if ( acct == nullptr )
404  {
406  client->Disconnect();
407  return;
408  }
409 
410  // First check the password - if wrong, you can't find out anything else.
411  bool correct_password = false;
412 
413  // dave changed 6/5/3, always authenticate with hashed user+pass
414  std::string msgpass = msg->password;
415  std::string acctname = acct->name();
416  std::string temp;
417  Clib::MD5_Encrypt( acctname + msgpass, temp ); // MD5
418  correct_password = Clib::MD5_Compare( acct->passwordhash(), temp );
419 
420  if ( !correct_password )
421  {
423  client->Disconnect();
424  POLLOG.Format( "Incorrect password for account {} from {}\n" )
425  << acct->name() << Network::AddressToString( &client->ipaddr );
426  return;
427  }
428  else
429  {
430  // write out cleartext if necessary
431  if ( Plib::systemstate.config.retain_cleartext_passwords )
432  {
433  if ( acct->password().empty() )
434  acct->set_password( msgpass );
435  }
436  }
437 
438  if ( !acct->enabled() || acct->banned() )
439  {
441  client->Disconnect();
442  return;
443  }
444 
445  //
446  // Dave moved the max_clients check to pol.cpp so character cmdlevel could be checked.
447  //
448 
449  POLLOG.Format( "Account {} logged in from {}\n" )
450  << acct->name() << Network::AddressToString( &client->ipaddr );
451 
452  // ENHANCEMENT: could authenticate with real loginservers.
453 
454  client->acct = acct;
455  /* NOTE: acct->client is not set here. It is possible that another client
456  is still connected, or a connection is stuck open, or similar. When
457  a character is selected, if another client is connected, measures will
458  be taken. */
459 
460  // Tell the client about the starting locations and his characters (up to 5).
461 
462  // MuadDib Added new seed system. This is for transferring KR/6017/Normal client detection from
463  // loginserver
464  // to the gameserver. Allows keeping client flags from remote loginserver to gameserver for 6017
465  // and kr
466  // packets.
467  client->ClientType = cfBEu16( msg->unk3_4_ClientType );
468 
469  send_start( client );
470 }
471 
472 void delete_character( Accounts::Account* acct, Mobile::Character* chr, int charidx )
473 {
474  if ( !chr->logged_in() )
475  {
476  POLLOG.Format( "Account {} deleting character 0x{:X}\n" ) << acct->name() << chr->serial;
477 
478  chr->acct.clear();
479  acct->clear_character( charidx );
480  chr->on_delete_from_account();
481  chr->destroy();
482  }
483 }
484 
485 
487 {
488  u32 charidx = cfBEu32( msg->charidx );
489 
490  if ( ( charidx >= Plib::systemstate.config.character_slots ) || ( client->acct == nullptr ) ||
491  ( client->acct->get_character( charidx ) == nullptr ) )
492  {
494  client->Disconnect();
495  return;
496  }
497 
498  Accounts::Account* acct = client->acct;
499  Mobile::Character* chr = acct->get_character( charidx );
500  if ( chr->client != nullptr || ( !Plib::systemstate.config.allow_multi_clients_per_account &&
501  acct->has_active_characters() ) )
502  {
504  client->Disconnect();
505  return;
506  }
507 
509  {
510  call_ondelete_scripts( chr );
511  delete_character( acct, chr, charidx );
512  }
513 
514  send_start( client );
515 }
516 
517 void KR_Verifier_Response( Network::Client* /*client*/, PKTIN_E4* /*msg*/ )
518 {
519  //
520 }
521 }
522 }
unsigned char u8
Definition: rawtypes.h:25
bool MD5_Encrypt(const std::string &in, std::string &out)
Definition: clib_MD5.cpp:97
bool enabled() const
Definition: account.cpp:267
void forceDisconnect()
Definition: client.h:288
#define LOGIN_ERROR_WRONG_PASSWORD
Definition: pktdef.h:66
void clear_character(int index)
Definition: account.cpp:179
SystemState systemstate
Definition: systemstate.cpp:12
sockaddr ipaddr
Definition: client.h:213
Network::Client * client
Definition: charactr.h:871
Core::PolConfig config
Definition: systemstate.h:43
Accounts::Account * acct
Definition: client.h:181
#define cfBEu32(x)
Definition: clib_endian.h:43
void send_start(Network::Client *client)
Definition: login.cpp:297
#define POLLOG_INFO
Definition: logfacility.h:213
void delete_character(Accounts::Account *acct, Mobile::Character *chr, int charidx)
Definition: login.cpp:472
char password[30]
Definition: pktin.h:328
Mobile::Character * get_character(int index)
Definition: account.cpp:169
void handle_delete_character(Network::Client *client, PKTIN_83 *msg)
Definition: login.cpp:486
#define LOGIN_ERROR_NO_ACCOUNT
Definition: pktdef.h:63
char name[30]
Definition: pktin.h:327
bool logged_in() const
Definition: charactr.cpp:428
void call_ondelete_scripts(Mobile::Character *chr)
Definition: pol.cpp:378
void loginserver_login(Network::Client *client, PKTIN_80 *msg)
Definition: login.cpp:106
bool has_active_characters()
Returns true if at least one character from this account is already logged in.
Definition: account.cpp:185
void login2(Network::Client *client, PKTIN_91 *msg)
Definition: login.cpp:388
#define LOGIN_ERROR_ACCOUNT_BLOCKED
Definition: pktdef.h:65
bool server_applies(Network::Client *client, int i)
Definition: login.cpp:83
unsigned char ip[4]
Definition: servdesc.h:23
const int DELETE_BY_PLAYER
Definition: core.h:58
bool banned() const
Definition: account.cpp:272
void KR_Verifier_Response(Network::Client *, PKTIN_E4 *)
Definition: login.cpp:517
unsigned short u16
Definition: rawtypes.h:26
unsigned int u32
Definition: rawtypes.h:27
const u16 AOS
Definition: client.h:75
void clear()
Definition: refptr.h:283
const std::string password() const
Definition: account.cpp:198
bool acct_check(Network::Client *client, int i)
Definition: login.cpp:69
void send_login_error(Network::Client *client, unsigned char reason)
Definition: login.cpp:60
NetworkManager networkManager
Definition: network.cpp:28
void send_feature_enable(Client *client)
Definition: ufunc.cpp:1953
void Send(Client *client, int len=-1) const
Definition: packethelper.h:69
const char * name() const
Definition: account.cpp:193
void set_password(std::string newpass)
Definition: account.h:62
unsigned short uo_feature_enable
Definition: ssopt.h:57
virtual void Init(void *pvSeed, int type=typeAuto)=0
signed int s32
Definition: rawtypes.h:31
const char * AddressToString(struct sockaddr *addr)
Definition: sockio.cpp:212
const std::string passwordhash() const
Definition: account.cpp:203
u16 unk3_4_ClientType
Definition: pktin.h:326
#define cfBEu16(x)
Definition: clib_endian.h:44
#define POLLOG
Definition: logfacility.h:219
u16 langcode[4]
Definition: pktin.h:483
bool encrypt_server_stream
Definition: client.h:217
#define LOGIN_ERROR_MISC
Definition: pktdef.h:69
GameState gamestate
Definition: uvars.cpp:74
void handle_A4(Network::Client *, PKTIN_A4 *)
Definition: login.cpp:225
SettingsManager settingsManager
Definition: settings.cpp:14
virtual void destroy() POL_OVERRIDE
Definition: charactr.cpp:482
Crypt::CCryptBase * cryptengine
Definition: client.h:215
u16 video_description[64]
Definition: pktin.h:475
unsigned short listen_port
Definition: client.h:194
void setclientinfo(const Core::PKTIN_D9 *msg)
Definition: client.h:175
Core::AccountRef acct
Definition: charactr.h:914
char password[30]
Definition: pktin.h:260
bool MD5_Compare(const std::string &a, const std::string &b)
Definition: clib_MD5.cpp:119
bool allow_multi_clients_per_account
Definition: polcfg.h:67
unsigned short x
Definition: startloc.h:24
bool can_delete_character(Mobile::Character *chr, int delete_by)
Definition: pol.cpp:363
StartingLocations startlocations
Definition: uvars.h:145
unsigned short y
Definition: startloc.h:25
unsigned short character_slots
Definition: polcfg.h:65
virtual std::string name() const
Definition: uobject.cpp:196
void handle_D9(Network::Client *client, PKTIN_D9 *msg)
Definition: login.cpp:227
unsigned char default_cmdlevel() const
Definition: account.cpp:282
Definition: berror.cpp:12
#define LOGIN_ERROR_OTHER_CHAR_INUSE
Definition: pktdef.h:64
char name[30]
Definition: pktin.h:259
bool is_banned_ip(Client *client)
Definition: bannedips.cpp:21
void select_server(Network::Client *client, PKTIN_A0 *msg)
Definition: login.cpp:260
Account * find_account(const char *acctname)
Definition: accounts.cpp:151