📄 handle_d2cs.c
字号:
/* * Copyright (C) 2000,2001 Onlyer (onlyer@263.net) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include "common/setup_before.h"#include <stddef.h>#include <stdlib.h>#ifdef HAVE_STRING_H# include <string.h>#else# ifdef HAVE_STRINGS_H# include <strings.h># endif#endif#include "compat/strcasecmp.h"#include "connection.h"#include "realm.h"#include "account.h"#include "account_wrap.h"#include "game.h"#include "d2cs/d2cs_bnetd_protocol.h"#include "common/bnethash.h"#include "common/bnethashconv.h"#include "common/eventlog.h"#include "common/queue.h"#include "common/packet.h"#include "common/addr.h"#include "common/bn_type.h"#include "prefs.h"#include "common/util.h"#include "common/field_sizes.h"#include "handle_d2cs.h"#include "common/tag.h"#include "common/xalloc.h"#include "common/setup_after.h"static int on_d2cs_accountloginreq(t_connection * c, t_packet const * packet);static int on_d2cs_charloginreq(t_connection * c, t_packet const * packet);static int on_d2cs_authreply(t_connection * c, t_packet const * packet);static int on_d2cs_gameinforeply(t_connection * c, t_packet const * packet);extern int handle_d2cs_packet(t_connection * c, t_packet const * packet){ if (!c) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection"); return -1; } if (!packet) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL packet"); return -1; } if (packet_get_class(packet)!=packet_class_d2cs_bnetd) { eventlog(eventlog_level_error,__FUNCTION__,"got bad packet class %d", packet_get_class(packet)); return -1; } switch (conn_get_state(c)) { case conn_state_connected: switch (packet_get_type(packet)) { case D2CS_BNETD_AUTHREPLY: on_d2cs_authreply(c,packet); break; default: eventlog(eventlog_level_error,__FUNCTION__, "got unknown packet type %d",packet_get_type(packet)); break; } break; case conn_state_loggedin: switch (packet_get_type(packet)) { case D2CS_BNETD_ACCOUNTLOGINREQ: on_d2cs_accountloginreq(c,packet); break; case D2CS_BNETD_CHARLOGINREQ: on_d2cs_charloginreq(c,packet); break; case D2CS_BNETD_GAMEINFOREPLY: on_d2cs_gameinforeply(c,packet); break; default: eventlog(eventlog_level_error,__FUNCTION__, "got unknown packet type %d",packet_get_type(packet)); break; } break; default: eventlog(eventlog_level_error,__FUNCTION__, "got unknown connection state %d",conn_get_state(c)); break; } return 0;}static int on_d2cs_authreply(t_connection * c, t_packet const * packet){ t_packet * rpacket; unsigned int version; unsigned int try_version; unsigned int reply; char const * realmname; t_realm * realm; if (packet_get_size(packet)<sizeof(t_d2cs_bnetd_authreply)) { eventlog(eventlog_level_error,__FUNCTION__,"got bad packet size"); return -1; } if (!(realmname=packet_get_str_const(packet,sizeof(t_d2cs_bnetd_authreply),REALM_NAME_LEN))) { eventlog(eventlog_level_error,__FUNCTION__,"got bad realmname"); return -1; } if (!(realm=realmlist_find_realm(realmname))) { realm=realmlist_find_realm_by_ip(conn_get_addr(c)); /* should not fail - checked in handle_init_packet() handle_init.c */ eventlog(eventlog_level_warn,__FUNCTION__, "warn: realm name mismatch %s %s", realm_get_name(realm), realmname); if (!(prefs_allow_d2cs_setname())) { /* fail if allow_d2cs_setname = false */ eventlog(eventlog_level_error,__FUNCTION__, "d2cs not allowed to set realm name"); return -1; } if (realm_get_active(realm)) { /* fail if realm already active */ eventlog(eventlog_level_error,__FUNCTION__, "cannot set realm name to %s (realm already active)"); return -1; } realm_set_name(realm,realmname); } version=prefs_get_d2cs_version(); try_version=bn_int_get(packet->u.d2cs_bnetd_authreply.version); if (version && version != try_version) { eventlog(eventlog_level_error,__FUNCTION__,"d2cs version mismatch 0x%X - 0x%X", try_version,version); reply=BNETD_D2CS_AUTHREPLY_BAD_VERSION; } else { reply=BNETD_D2CS_AUTHREPLY_SUCCEED; } if (reply==BNETD_D2CS_AUTHREPLY_SUCCEED) { eventlog(eventlog_level_info,__FUNCTION__,"d2cs %s authed", addr_num_to_ip_str(conn_get_addr(c))); conn_set_state(c,conn_state_loggedin); realm_active(realm,c); } else { eventlog(eventlog_level_error,__FUNCTION__,"failed to auth d2cs %s", addr_num_to_ip_str(conn_get_addr(c))); } if ((rpacket=packet_create(packet_class_d2cs_bnetd))) { packet_set_size(rpacket,sizeof(t_bnetd_d2cs_authreply)); packet_set_type(rpacket,BNETD_D2CS_AUTHREPLY); bn_int_set(&rpacket->u.bnetd_d2cs_authreply.h.seqno,1); bn_int_set(&rpacket->u.bnetd_d2cs_authreply.reply,reply); conn_push_outqueue(c,rpacket); packet_del_ref(rpacket); } return 0;}static int on_d2cs_accountloginreq(t_connection * c, t_packet const * packet){ unsigned int sessionkey; unsigned int sessionnum; unsigned int salt; char const * account; char const * tname; t_connection * client; int reply; t_packet * rpacket; struct { bn_int salt; bn_int sessionkey; bn_int sessionnum; bn_int secret; bn_int passhash[5]; } temp; t_hash secret_hash; char const * pass_str; t_hash passhash; t_hash try_hash; if (packet_get_size(packet)<sizeof(t_d2cs_bnetd_accountloginreq)) { eventlog(eventlog_level_error,__FUNCTION__,"got bad packet size"); return -1; } if (!(account=packet_get_str_const(packet,sizeof(t_d2cs_bnetd_accountloginreq),USER_NAME_MAX))) { eventlog(eventlog_level_error,__FUNCTION__,"missing or too long account name"); return -1; } sessionkey=bn_int_get(packet->u.d2cs_bnetd_accountloginreq.sessionkey); sessionnum=bn_int_get(packet->u.d2cs_bnetd_accountloginreq.sessionnum); salt=bn_int_get(packet->u.d2cs_bnetd_accountloginreq.seqno); if (!(client=connlist_find_connection_by_sessionnum(sessionnum))) { eventlog(eventlog_level_error,__FUNCTION__,"sessionnum %d not found",sessionnum); reply=BNETD_D2CS_ACCOUNTLOGINREPLY_FAILED; } else if (sessionkey!=conn_get_sessionkey(client)) { eventlog(eventlog_level_error,__FUNCTION__,"sessionkey %d not match",sessionkey); reply=BNETD_D2CS_ACCOUNTLOGINREPLY_FAILED; } else if (!(tname=conn_get_username(client))) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL username"); reply=BNETD_D2CS_ACCOUNTLOGINREPLY_FAILED; } else if (strcasecmp(account,tname)) { eventlog(eventlog_level_error,__FUNCTION__,"username %s not match",account); reply=BNETD_D2CS_ACCOUNTLOGINREPLY_FAILED; } else { bn_int_set(&temp.salt,salt); bn_int_set(&temp.sessionkey,sessionkey); bn_int_set(&temp.sessionnum,sessionnum); bn_int_set(&temp.secret,conn_get_secret(client)); pass_str=account_get_pass(conn_get_account(client)); if (hash_set_str(&passhash,pass_str)<0) { reply=BNETD_D2CS_ACCOUNTLOGINREPLY_FAILED; } else { hash_to_bnhash((t_hash const *)&passhash,temp.passhash); bnet_hash(&secret_hash,sizeof(temp),&temp); bnhash_to_hash(packet->u.d2cs_bnetd_accountloginreq.secret_hash,&try_hash); if (hash_eq(try_hash,secret_hash)==1) { eventlog(eventlog_level_debug,__FUNCTION__,"user %s loggedin on d2cs", account); reply=BNETD_D2CS_ACCOUNTLOGINREPLY_SUCCEED; } else { eventlog(eventlog_level_error,__FUNCTION__,"user %s hash not match", account); reply=BNETD_D2CS_ACCOUNTLOGINREPLY_FAILED; } } } if ((rpacket=packet_create(packet_class_d2cs_bnetd))) { packet_set_size(rpacket,sizeof(t_bnetd_d2cs_accountloginreply)); packet_set_type(rpacket,BNETD_D2CS_ACCOUNTLOGINREPLY); bn_int_set(&rpacket->u.bnetd_d2cs_accountloginreply.h.seqno, bn_int_get(packet->u.d2cs_bnetd_accountloginreq.h.seqno)); bn_int_set(&rpacket->u.bnetd_d2cs_accountloginreply.reply,reply); conn_push_outqueue(c,rpacket); packet_del_ref(rpacket); } return 0;}#define CHAR_PORTRAIT_LEN 0x30static int on_d2cs_charloginreq(t_connection * c, t_packet const * packet){ t_connection * client; char const * charname; char const * portrait; char const * clienttag; char * temp; unsigned int sessionnum; t_realm * realm; char const * realmname; unsigned int pos, reply; t_packet * rpacket; if (packet_get_size(packet)<sizeof(t_d2cs_bnetd_charloginreq)) { eventlog(eventlog_level_error,__FUNCTION__,"got bad packet size"); return -1; } sessionnum=bn_int_get(packet->u.d2cs_bnetd_charloginreq.sessionnum); pos=sizeof(t_d2cs_bnetd_charloginreq); if (!(charname=packet_get_str_const(packet,pos,CHAR_NAME_LEN))) { eventlog(eventlog_level_error,__FUNCTION__,"got bad character name"); return -1; } pos+=strlen(charname)+1; if (!(portrait=packet_get_str_const(packet,pos,CHAR_PORTRAIT_LEN))) { eventlog(eventlog_level_error,__FUNCTION__,"got bad character portrait"); return -1; } if (!(client=connlist_find_connection_by_sessionnum(sessionnum))) { eventlog(eventlog_level_error,__FUNCTION__,"user %d not found",sessionnum); reply = BNETD_D2CS_CHARLOGINREPLY_FAILED; } else if (!(clienttag=clienttag_uint_to_str(conn_get_clienttag(client)))) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL clienttag"); reply = BNETD_D2CS_CHARLOGINREPLY_FAILED; } else if (!(realm=conn_get_realm(client))) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL realm"); reply = BNETD_D2CS_CHARLOGINREPLY_FAILED; } else { char revtag[8]; realmname = realm_get_name(realm); temp=xmalloc(strlen(clienttag)+strlen(realmname)+1+strlen(charname)+1+ strlen(portrait)+1); reply = BNETD_D2CS_CHARLOGINREPLY_SUCCEED; strcpy(revtag,clienttag); strreverse(revtag); sprintf(temp,"%4s%s,%s,%s",revtag,realmname,charname,portrait); conn_set_charname(client,charname); conn_set_realminfo(client,temp); xfree(temp); eventlog(eventlog_level_debug,__FUNCTION__, "loaded portrait for character %s",charname); } if ((rpacket=packet_create(packet_class_d2cs_bnetd))) { packet_set_size(rpacket,sizeof(t_bnetd_d2cs_charloginreply)); packet_set_type(rpacket,BNETD_D2CS_CHARLOGINREPLY); bn_int_set(&rpacket->u.bnetd_d2cs_charloginreply.h.seqno, bn_int_get(packet->u.d2cs_bnetd_charloginreq.h.seqno)); bn_int_set(&rpacket->u.bnetd_d2cs_charloginreply.reply,reply); conn_push_outqueue(c,rpacket); packet_del_ref(rpacket); } return 0;}extern int handle_d2cs_init(t_connection * c){ t_packet * packet; if ((packet=packet_create(packet_class_d2cs_bnetd))) { packet_set_size(packet,sizeof(t_bnetd_d2cs_authreq)); packet_set_type(packet,BNETD_D2CS_AUTHREQ); bn_int_set(&packet->u.bnetd_d2cs_authreq.h.seqno,1); bn_int_set(&packet->u.bnetd_d2cs_authreq.sessionnum,conn_get_sessionnum(c)); conn_push_outqueue(c,packet); packet_del_ref(packet); } eventlog(eventlog_level_info,__FUNCTION__,"sent init packet to d2cs (sessionnum=%d)", conn_get_sessionnum(c)); return 0;}extern int send_d2cs_gameinforeq(t_connection * c){ t_packet * packet; t_game * game; t_realm * realm; if (!(c)) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL conn"); return -1; } if (!(game = conn_get_game(c))) { eventlog(eventlog_level_error,__FUNCTION__,"conn had NULL game"); return -1; } if (!(realm = conn_get_realm(c))) { eventlog(eventlog_level_error,__FUNCTION__,"conn had NULL realm"); return -1; } if ((packet=packet_create(packet_class_d2cs_bnetd))) { packet_set_size(packet,sizeof(t_bnetd_d2cs_gameinforeq)); packet_set_type(packet,BNETD_D2CS_GAMEINFOREQ); bn_int_set(&packet->u.bnetd_d2cs_gameinforeq.h.seqno,0); packet_append_string(packet,game_get_name(game)); conn_push_outqueue(realm_get_conn(realm),packet); packet_del_ref(packet); } return 0;}static int on_d2cs_gameinforeply(t_connection * c, t_packet const * packet){ t_game * game; char const * gamename; unsigned int difficulty; t_game_difficulty diff; if (!(c)) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection"); return -1; } if (!(gamename = packet_get_str_const(packet,sizeof(t_d2cs_bnetd_gameinforeply),GAME_NAME_LEN))) { eventlog(eventlog_level_error,__FUNCTION__,"missing or too long gamename"); return -1; } if (!(game = gamelist_find_game(gamename,CLIENTTAG_DIABLO2DV_UINT,game_type_diablo2closed)) && !(game = gamelist_find_game(gamename,CLIENTTAG_DIABLO2XP_UINT,game_type_diablo2closed))) { eventlog(eventlog_level_error,__FUNCTION__,"reply for unknown game \"%s\"",gamename); return -1; } difficulty = bn_byte_get(packet->u.d2cs_bnetd_gameinforeply.difficulty); switch (difficulty) { case 0: diff = game_difficulty_normal; break; case 1: diff = game_difficulty_nightmare; break; case 2: diff = game_difficulty_hell; break; default: diff = game_difficulty_none; } game_set_difficulty(game,diff); return 0; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -