• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

polserver / polserver / 21108840797

18 Jan 2026 08:35AM UTC coverage: 60.508% (+0.02%) from 60.492%
21108840797

push

github

web-flow
ClangTidy readability-else-after-return (#857)

* trigger tidy

* Automated clang-tidy change: readability-else-after-return

* compile test

* rerun

* Automated clang-tidy change: readability-else-after-return

* trigger..

* Automated clang-tidy change: readability-else-after-return

* manually removed a few

* Automated clang-tidy change: readability-else-after-return

* removed duplicate code

* fix remaining warnings

* fixed scope

---------

Co-authored-by: Clang Tidy <clang-tidy@users.noreply.github.com>

837 of 1874 new or added lines in 151 files covered. (44.66%)

46 existing lines in 25 files now uncovered.

44448 of 73458 relevant lines covered (60.51%)

525066.38 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

51.2
/pol-core/pol/login.cpp
1
/** @file
2
 *
3
 * @par History
4
 * - 2005/01/24 Shinigami: added message handler for packet 0xd9 (Spy on Client 2)
5
 * - 2005/01/27 Shinigami: using little/big endian functions provided by endian.h
6
 * - 2005/04/03 Shinigami: send_feature_enable() call moved from start_client_char()
7
 *                         to send_start() to send before char selection
8
 * - 2005/04/03 Shinigami: FLAG_UPTO_SIX_CHARACTERS disabled in uo_feature_enable
9
 * - 2005/04/04 Shinigami: added candelete script
10
 * - 2005/08/29 Shinigami: get-/setspyonclient2 renamed to get-/setclientinfo
11
 * - 2007/07/09 Shinigami: modified PKTOUT_8C.new_key to not conflict with UO:KR detection
12
 *                         added message handler for packet 0xe4 (UO:KR Verifier Response)
13
 * - 2008/02/09 Shinigami: removed hardcoded MAX_CHARS from send_start()
14
 * - 2009/07/23 MuadDib:   updates for new Enum::Packet Out ID
15
 * - 2009/08/06 MuadDib:   Removed PasswordOnlyHash support
16
 * - 2009/09/06 Turley:    Changed Version checks to bitfield client->ClientType
17
 * - 2009/12/04 Turley:    Crypto cleanup - Tomi
18
 * - 2010/01/14 Turley:    fixed ip byteorder for pkt 0xa8 if hostname is given - Arkham
19
 */
20

21

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 "../plib/uoexpansion.h"
32
#include "accounts/account.h"
33
#include "accounts/accounts.h"
34
#include "core.h"
35
#include "crypt/cryptbase.h"
36
#include "globals/settings.h"
37
#include "globals/uvars.h"
38
#include "mobile/charactr.h"
39
#include "network/client.h"
40
#include "network/packethelper.h"
41
#include "network/packets.h"
42
#include "network/pktdef.h"
43
#include "network/pktin.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
{
62
  Network::PktHelper::PacketOut<Network::PktOut_82> msg;
×
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 )
2✔
70
{
71
  if ( networkManager.servers[i]->acct_match.empty() )
2✔
72
    return true;
2✔
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 ip_check( Network::Client* client, int i )
4✔
84
{
85
  if ( networkManager.servers[i]->ip_match.empty() )
4✔
86
    return true;
×
87

88
  for ( unsigned j = 0; j < networkManager.servers[i]->ip_match.size(); ++j )
6✔
89
  {
90
    unsigned int addr1part, addr2part;
91
    struct sockaddr_in* sockin = reinterpret_cast<struct sockaddr_in*>( &client->ipaddr );
4✔
92

93
    addr1part =
4✔
94
        networkManager.servers[i]->ip_match[j] & networkManager.servers[i]->ip_match_mask[j];
4✔
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];
4✔
99
#endif
100
    if ( addr1part == addr2part )
4✔
101
      return true;
2✔
102
  }
103
  return false;
2✔
104
}
105

106
bool proxy_check( Network::Client* client, int i )
2✔
107
{
108
  bool is_proxied = client->ipaddr_proxy.sa_family != AF_UNSPEC;
2✔
109

110
  if ( networkManager.servers[i]->proxy_match.empty() )
2✔
111
  {
112
    // If there is no ProxyMatch element but client is connecting through proxy
113
    // do not present this server.
114
    return !is_proxied;
2✔
115
  }
116

117
  if ( !is_proxied )
×
118
  {
119
    // This server has ProxyMatch element(s) but client is not connecting through proxy
120
    // so do not present this server.
121
    return false;
×
122
  }
123

124
  for ( unsigned j = 0; j < networkManager.servers[i]->proxy_match.size(); ++j )
×
125
  {
126
    unsigned int addr1part, addr2part;
127
    struct sockaddr_in* sockin = reinterpret_cast<struct sockaddr_in*>( &client->ipaddr_proxy );
×
128

129
    addr1part =
×
130
        networkManager.servers[i]->proxy_match[j] & networkManager.servers[i]->proxy_match_mask[j];
×
131
#ifdef _WIN32
132
    addr2part = sockin->sin_addr.S_un.S_addr & networkManager.servers[i]->proxy_match_mask[j];
133
#else
134
    addr2part = sockin->sin_addr.s_addr & networkManager.servers[i]->proxy_match_mask[j];
×
135
#endif
136
    if ( addr1part == addr2part )
×
137
      return true;
×
138
  }
139
  return false;
×
140
}
141

142
bool server_applies( Network::Client* client, int i )
4✔
143
{
144
  return ip_check( client, i ) && proxy_check( client, i ) && acct_check( client, i );
4✔
145
}
146

147
void loginserver_login( Network::Client* client, PKTIN_80* msg )
2✔
148
{
149
  unsigned idx;
150

151
  if ( Network::is_banned_ip( client ) )
2✔
152
  {
153
    send_login_error( client, LOGIN_ERROR_ACCOUNT_BLOCKED );
×
154
    client->Disconnect();
×
155
    return;
×
156
  }
157

158
  Accounts::Account* acct = Accounts::find_account( msg->name );
2✔
159
  if ( !acct )
2✔
160
  {
161
    send_login_error( client, LOGIN_ERROR_NO_ACCOUNT );
×
162
    client->Disconnect();
×
163
    return;
×
164
  }
165
  if ( Plib::systemstate.config.min_cmdlevel_to_login > acct->default_cmdlevel() )
2✔
166
  {
167
    send_login_error( client, LOGIN_ERROR_MISC );
×
168
    client->Disconnect();
×
169
    return;
×
170
  }
171

172
  bool correct_password = false;
2✔
173

174
  std::string msgpass = msg->password;
2✔
175
  std::string acctname = acct->name();
2✔
176
  std::string temp;
2✔
177
  Clib::MD5_Encrypt( acctname + msgpass, temp );  // MD5
2✔
178
  correct_password = Clib::MD5_Compare( acct->passwordhash(), temp );
2✔
179

180
  if ( !correct_password )
2✔
181
  {
182
    send_login_error( client, LOGIN_ERROR_WRONG_PASSWORD );
×
183
    client->Disconnect();
×
184
    POLLOGLN( "Incorrect password for account {} from {}", acct->name(), client->ipaddrAsString() );
×
185
    return;
×
186
  }
187

188
  if ( Plib::systemstate.config.retain_cleartext_passwords )
2✔
189
  {
NEW
190
    if ( acct->password().empty() )
×
NEW
191
      acct->set_password( msgpass );
×
192
  }
193

194

195
  if ( !acct->enabled() || acct->banned() )
2✔
196
  {
197
    send_login_error( client, LOGIN_ERROR_ACCOUNT_BLOCKED );
×
198
    client->Disconnect();
×
199
    return;
×
200
  }
201

202
  POLLOG_INFOLN( "Account {} logged in from {}", acct->name(), client->ipaddrAsString() );
2✔
203

204
  client->acct = acct;
2✔
205

206
  Network::PktHelper::PacketOut<Network::PktOut_A8> msgA8;
2✔
207
  msgA8->offset += 2;
2✔
208
  msgA8->Write<u8>( 0xFFu );
2✔
209
  msgA8->offset += 2;  // servcount
2✔
210

211
  unsigned short servcount = 0;
2✔
212

213

214
  for ( idx = 0; idx < networkManager.servers.size(); idx++ )
6✔
215
  {
216
    ServerDescription* server = networkManager.servers[idx];
4✔
217

218
    if ( !server->hostname.empty() )
4✔
219
    {
220
      struct hostent* he =
221
          gethostbyname( server->hostname.c_str() );  // FIXME: here is a potential server lockup
×
222
      if ( he != nullptr && he->h_addr_list[0] )
×
223
      {
224
        char* addr = he->h_addr_list[0];
×
225
        server->ip[0] = addr[3];
×
226
        server->ip[1] = addr[2];
×
227
        server->ip[2] = addr[1];
×
228
        server->ip[3] = addr[0];
×
229
      }
×
230
      else
231
      {
232
        POLLOGLN( "gethostbyname(\"{}\") failed for server {}", server->hostname, server->name );
×
233
        continue;
×
234
      }
235
    }
236

237
    if ( server_applies( client, idx ) )
4✔
238
    {
239
      ++servcount;
2✔
240
      msgA8->WriteFlipped<u16>( idx + 1u );
2✔
241
      msgA8->Write( Clib::strUtf8ToCp1252( server->name ).c_str(), 30 );
2✔
242
      msgA8->WriteFlipped<u16>( idx + 1u );
2✔
243
      msgA8->offset += 2;  // u8 percentfull, s8 timezone
2✔
244
      msgA8->Write( server->ip, 4 );
2✔
245
    }
246
  }
247
  u16 len = msgA8->offset;
2✔
248
  msgA8->offset = 1;
2✔
249
  msgA8->WriteFlipped<u16>( len );
2✔
250
  msgA8->offset++;
2✔
251
  msgA8->WriteFlipped<u16>( servcount );
2✔
252

253
  msgA8.Send( client, len );
2✔
254

255
  if ( servcount == 0 )
2✔
256
  {
257
    POLLOGLN( "No applicable servers for client connecting from {}", client->ipaddrAsString() );
×
258
  }
259
}
2✔
260

261
void handle_A4( Network::Client* /*client*/, PKTIN_A4* /*msg*/ ) {}
×
262

263
void handle_D9( Network::Client* client, PKTIN_D9* msg )
×
264
{
265
  PKTIN_D9 _msg;  // got crashes here under *nix -> modify a new local instance
266
  // Transform Little-Endian <-> Big-Endian
267
  _msg.instance = cfBEu32( msg->instance );              // Unique Instance ID of UO
×
268
  _msg.os_major = cfBEu32( msg->os_major );              // OS Major
×
269
  _msg.os_minor = cfBEu32( msg->os_minor );              // OS Minor
×
270
  _msg.os_revision = cfBEu32( msg->os_revision );        // OS Revision
×
271
  _msg.cpu_family = cfBEu32( msg->cpu_family );          // CPU Family
×
272
  _msg.cpu_model = cfBEu32( msg->cpu_model );            // CPU Model
×
273
  _msg.cpu_clockspeed = cfBEu32( msg->cpu_clockspeed );  // CPU Clock Speed [Mhz]
×
274
  _msg.memory = cfBEu32( msg->memory );                  // Memory [MB]
×
275
  _msg.screen_width = cfBEu32( msg->screen_width );      // Screen Width
×
276
  _msg.screen_height = cfBEu32( msg->screen_height );    // Screen Height
×
277
  _msg.screen_depth = cfBEu32( msg->screen_depth );      // Screen Depth [Bit]
×
278
  _msg.directx_major = cfBEu16( msg->directx_major );    // DirectX Major
×
279
  _msg.directx_minor = cfBEu16( msg->directx_minor );    // DirectX Minor
×
280

281
  for ( unsigned i = 0; i < sizeof( msg->video_description ) / sizeof( msg->video_description[0] );
×
282
        ++i )
283
    _msg.video_description[i] =
×
284
        cfBEu16( msg->video_description[i] );  // Video Card Description [wide-character]
×
285

286
  _msg.video_vendor = cfBEu32( msg->video_vendor );  // Video Card Vendor ID
×
287
  _msg.video_device = cfBEu32( msg->video_device );  // Video Card Device ID
×
288
  _msg.video_memory = cfBEu32( msg->video_memory );  // Video Card Memory [MB]
×
289

290
  for ( unsigned i = 0; i < sizeof( msg->langcode ) / sizeof( msg->langcode[0] ); ++i )
×
291
    _msg.langcode[i] = cfBEu16( msg->langcode[i] );  // Language Code [wide-character]
×
292

293
  client->setclientinfo( &_msg );
×
294
}
×
295

296
void select_server( Network::Client* client, PKTIN_A0* msg )  // Relay player to a certain IP
2✔
297
{
298
  unsigned servernum = cfBEu16( msg->servernum ) - 1;
2✔
299

300
  if ( servernum >= networkManager.servers.size() )
2✔
301
  {
302
    client->forceDisconnect();
×
303
    return;
×
304
  }
305

306
  ServerDescription* svr = networkManager.servers[servernum];
2✔
307

308
  Network::PktHelper::PacketOut<Network::PktOut_8C> rsp;
2✔
309
  rsp->Write<u8>( svr->ip[3] );
2✔
310
  rsp->Write<u8>( svr->ip[2] );
2✔
311
  rsp->Write<u8>( svr->ip[1] );
2✔
312
  rsp->Write<u8>( svr->ip[0] );
2✔
313

314
  if ( client->listen_port != 0 )
2✔
315
    rsp->WriteFlipped<u16>( client->listen_port );
2✔
316
  else
317
    rsp->WriteFlipped<u16>( svr->port );
×
318
  // MuadDib Added new seed system. This is for transferring KR/6017/Normal client detection from
319
  // loginserver
320
  // to the gameserver. Allows keeping client flags from remote loginserver to gameserver for 6017
321
  // and kr
322
  // packets.
323

324
  unsigned int nseed = 0xFEFE0000 | client->ClientType;
2✔
325
  rsp->WriteFlipped<u32>( nseed );  // This was set to 0xffffffff in the past but this will conflict
2✔
326
                                    // with UO:KR detection
327

328
  rsp.Send( client );
2✔
329

330
  client->init_crypto( &nseed, Crypt::CCryptBase::typeGame );
2✔
331
}
2✔
332

333
void send_start( Network::Client* client )
2✔
334
{
335
  send_feature_enable(
2✔
336
      client );  // Shinigami: moved from start_client_char() to send before char selection
337

338
  u8 char_slots = client->acct->expansion().getCharSlots( settingsManager.ssopt.features );
2✔
339
  // client always expects at least 5 chars
340
  u8 char_count = std::max( char_slots, 5_u8 );
2✔
341

342
  Network::PktHelper::PacketOut<Network::PktOut_A9> msg;
2✔
343
  msg->offset += 2;
2✔
344
  msg->Write<u8>( char_count );
2✔
345

346
  for ( u8 i = 0; i < char_count; i++ )
12✔
347
  {
348
    if ( i < char_slots )  // Small kludge to have a minimum of 5 chars in the packet
10✔
349
    {
350
      // name only 30 long rest is password seems to fix the password promt problem
351
      Mobile::Character* chr = client->acct->get_character( i );
10✔
352
      if ( chr )
10✔
353
      {
354
        msg->Write( Clib::strUtf8ToCp1252( chr->name() ).c_str(), 30, false );
2✔
355
        msg->offset += 30;  // password
2✔
356
      }
357
      else
358
        msg->offset += 60;
8✔
359
    }
360
    else
361
      msg->offset += 60;
×
362
  }
363

364
  msg->Write<u8>( gamestate.startlocations.size() );
2✔
365

366
  for ( size_t i = 0; i < gamestate.startlocations.size(); i++ )
20✔
367
  {
368
    msg->Write<u8>( i );
18✔
369
    if ( client->ClientType & Network::CLIENTTYPE_70130 )
18✔
370
    {
371
      msg->Write( Clib::strUtf8ToCp1252( gamestate.startlocations[i]->city ).c_str(), 32, false );
×
372
      msg->Write( Clib::strUtf8ToCp1252( gamestate.startlocations[i]->desc ).c_str(), 32, false );
×
373

374
      Pos3d coord = gamestate.startlocations[i]->coords[0];
×
375

376
      msg->WriteFlipped<u32>( coord.x() );
×
377
      msg->WriteFlipped<u32>( coord.y() );
×
378
      msg->WriteFlipped<s32>( coord.z() );
×
379
      msg->WriteFlipped<u32>( gamestate.startlocations[i]->mapid );        // MapID
×
380
      msg->WriteFlipped<u32>( gamestate.startlocations[i]->cliloc_desc );  // Cliloc Description
×
381
      msg->offset += 4;
×
382
    }
383
    else
384
    {
385
      msg->Write( Clib::strUtf8ToCp1252( gamestate.startlocations[i]->city ).c_str(), 31, false );
18✔
386
      msg->Write( Clib::strUtf8ToCp1252( gamestate.startlocations[i]->desc ).c_str(), 31, false );
18✔
387
    }
388
  }
389

390
  auto clientflag =
391
      client->acct->expansion().calculateFeatureFlags( settingsManager.ssopt.features );
2✔
392

393
  msg->WriteFlipped<u32>( static_cast<u32>( clientflag ) );
2✔
394
  u16 len = msg->offset;
2✔
395
  msg->offset = 1;
2✔
396
  msg->WriteFlipped<u16>( len );
2✔
397
  msg.Send( client, len );
2✔
398
}
2✔
399

400
void login2( Network::Client* client, PKTIN_91* msg )  // Gameserver login and character listing
2✔
401
{
402
  client->start_encrypted_server_stream();
2✔
403

404
  if ( Network::is_banned_ip( client ) )
2✔
405
  {
406
    send_login_error( client, LOGIN_ERROR_ACCOUNT_BLOCKED );
×
407
    client->Disconnect();
×
408
    return;
×
409
  }
410

411
  /* Hmm, might have to re-search for account.
412
     For now, we already have the account in client->acct.
413
     Might work different if real loginservers were used. */
414
  Accounts::Account* acct = Accounts::find_account( msg->name );
2✔
415
  if ( acct == nullptr )
2✔
416
  {
417
    send_login_error( client, LOGIN_ERROR_NO_ACCOUNT );
×
418
    client->Disconnect();
×
419
    return;
×
420
  }
421

422
  // First check the password - if wrong, you can't find out anything else.
423
  bool correct_password = false;
2✔
424

425
  // dave changed 6/5/3, always authenticate with hashed user+pass
426
  std::string msgpass = msg->password;
2✔
427
  std::string acctname = acct->name();
2✔
428
  std::string temp;
2✔
429
  Clib::MD5_Encrypt( acctname + msgpass, temp );  // MD5
2✔
430
  correct_password = Clib::MD5_Compare( acct->passwordhash(), temp );
2✔
431

432
  if ( !correct_password )
2✔
433
  {
434
    send_login_error( client, LOGIN_ERROR_WRONG_PASSWORD );
×
435
    client->Disconnect();
×
436
    POLLOGLN( "Incorrect password for account {} from {}", acct->name(), client->ipaddrAsString() );
×
437
    return;
×
438
  }
439

440
  // write out cleartext if necessary
441
  if ( Plib::systemstate.config.retain_cleartext_passwords )
2✔
442
  {
NEW
443
    if ( acct->password().empty() )
×
NEW
444
      acct->set_password( msgpass );
×
445
  }
446

447

448
  if ( !acct->enabled() || acct->banned() )
2✔
449
  {
450
    send_login_error( client, LOGIN_ERROR_ACCOUNT_BLOCKED );
×
451
    client->Disconnect();
×
452
    return;
×
453
  }
454

455
  //
456
  // Dave moved the max_clients check to pol.cpp so character cmdlevel could be checked.
457
  //
458

459
  POLLOGLN( "Account {} logged in from {}", acct->name(), client->ipaddrAsString() );
2✔
460

461
  // ENHANCEMENT: could authenticate with real loginservers.
462

463
  client->acct = acct;
2✔
464
  /* NOTE: acct->client is not set here.  It is possible that another client
465
     is still connected, or a connection is stuck open, or similar.  When
466
     a character is selected, if another client is connected, measures will
467
     be taken. */
468

469
  // Tell the client about the starting locations and his characters (up to 5).
470

471
  // MuadDib Added new seed system. This is for transferring KR/6017/Normal client detection from
472
  // loginserver
473
  // to the gameserver. Allows keeping client flags from remote loginserver to gameserver for 6017
474
  // and kr
475
  // packets.
476
  client->ClientType = cfBEu16( msg->unk3_4_ClientType );
2✔
477

478
  send_start( client );
2✔
479
}
2✔
480

481
void delete_character( Accounts::Account* acct, Mobile::Character* chr, int charidx )
3✔
482
{
483
  if ( !chr->logged_in() )
3✔
484
  {
485
    POLLOGLN( "Account {} deleting character {:#x}", acct->name(), chr->serial );
3✔
486

487
    chr->acct.clear();
3✔
488
    acct->clear_character( charidx );
3✔
489
    chr->on_delete_from_account();
3✔
490
    chr->destroy();
3✔
491
  }
492
}
3✔
493

494

495
void handle_delete_character( Network::Client* client, PKTIN_83* msg )
×
496
{
497
  u32 charidx = cfBEu32( msg->charidx );
×
498

499
  if ( ( charidx >= Plib::systemstate.config.character_slots ) || ( client->acct == nullptr ) ||
×
500
       ( client->acct->get_character( charidx ) == nullptr ) )
×
501
  {
502
    send_login_error( client, LOGIN_ERROR_MISC );
×
503
    client->Disconnect();
×
504
    return;
×
505
  }
506

507
  Accounts::Account* acct = client->acct;
×
508
  Mobile::Character* chr = acct->get_character( charidx );
×
509
  if ( chr->client != nullptr || ( !Plib::systemstate.config.allow_multi_clients_per_account &&
×
510
                                   acct->has_active_characters() ) )
×
511
  {
512
    send_login_error( client, LOGIN_ERROR_OTHER_CHAR_INUSE );
×
513
    client->Disconnect();
×
514
    return;
×
515
  }
516

517
  if ( can_delete_character( chr, DELETE_BY_PLAYER ) )
×
518
  {
519
    call_ondelete_scripts( chr );
×
520
    delete_character( acct, chr, charidx );
×
521
  }
522

523
  send_start( client );
×
524
}
525

526
void KR_Verifier_Response( Network::Client* /*client*/, PKTIN_E4* /*msg*/ )
×
527
{
528
  //
529
}
×
530
}  // namespace Core
531
}  // namespace Pol
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc