1 /*
2  * Copyright (C) 1998  Mark Baysinger (mbaysing@ucsd.edu)
3  * Copyright (C) 1998,1999,2000,2001  Ross Combs (rocombs@cs.nmsu.edu)
4  * Copyright (C) 1999,2000  Rob Crittenden (rcrit@greyoak.com)
5  * Copyright (C) 2000,2001  Marco Ziech (mmz@gmx.net)
6  * Copyright (C) 2003 Dizzy
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  */
22 
23 #define VERSIONCHECK_INTERNAL_ACCESS
24 #include "common/setup_before.h"
25 #include <stdio.h>
26 #include <ctype.h>
27 // amadeo
28 #ifdef WIN32_GUI
29 #include <win32/winmain.h>
30 #endif
31 // NonReal:
32 #include <sys/stat.h>
33 #ifdef HAVE_STDDEF_H
34 # include <stddef.h>
35 #else
36 # ifndef NULL
37 #  define NULL ((void *)0)
38 # endif
39 #endif
40 #ifdef STDC_HEADERS		/* FIXME: remove ? */
41 # include <stdlib.h>
42 #endif
43 #ifdef HAVE_STRING_H
44 # include <string.h>
45 #else
46 # ifdef HAVE_STRINGS_H
47 #  include <strings.h>
48 # endif
49 # ifdef HAVE_MEMORY_H
50 #  include <memory.h>
51 # endif
52 #endif
53 #ifdef WIN32
54 #include "compat/socket.h"
55 #endif
56 #include "compat/strcasecmp.h"
57 #include "compat/strncasecmp.h"
58 #include "compat/strchr.h"
59 #include "compat/strdup.h"
60 #include "common/packet.h"
61 #include "common/bnet_protocol.h"
62 #include "common/tag.h"
63 #include "message.h"
64 #include "common/eventlog.h"
65 #include "command.h"
66 #include "team.h"
67 #include "account.h"
68 #include "account_wrap.h"
69 #include "realm.h"
70 #include "connection.h"
71 #include "channel.h"
72 #include "game.h"
73 #include "common/queue.h"
74 #include "tick.h"
75 #include "file.h"
76 #include "prefs.h"
77 #include "common/util.h"
78 #include "common/bnethash.h"
79 #include "common/bnethashconv.h"
80 #include "common/bn_type.h"
81 #include "common/field_sizes.h"
82 #include "ladder.h"
83 #include "adbanner.h"
84 #include "common/list.h"
85 #include "common/bnettime.h"
86 #include "common/addr.h"
87 #include "game_conv.h"
88 #include "autoupdate.h"
89 #include "character.h"
90 #include "versioncheck.h"
91 #include "anongame.h"
92 #include "handle_anongame.h"
93 #include "common/proginfo.h"
94 #include "clan.h"
95 #include "handle_bnet.h"
96 #include "handlers.h"
97 #ifdef HAVE_NETINET_IN_H
98 # include <netinet/in.h>
99 #endif
100 #include "compat/netinet_in.h"
101 #include "watch.h"
102 #include "anongame_infos.h"
103 #include "news.h"		//by Spider
104 #include "friends.h"
105 #include "server.h"
106 #include "compat/uint.h"
107 #include "common/trans.h"
108 #include "common/xalloc.h"
109 #include "common/lstr.h"
110 #include "common/setup_after.h"
111 
112 extern int last_news;
113 extern int first_news;
114 
115 /* handlers prototypes */
116 static int _client_unknown_1b(t_connection * c, t_packet const *const packet);
117 static int _client_compinfo1(t_connection * c, t_packet const *const packet);
118 static int _client_compinfo2(t_connection * c, t_packet const *const packet);
119 static int _client_countryinfo1(t_connection * c, t_packet const *const packet);
120 static int _client_countryinfo109(t_connection * c, t_packet const *const packet);
121 static int _client_unknown2b(t_connection * c, t_packet const *const packet);
122 static int _client_progident(t_connection * c, t_packet const *const packet);
123 static int _client_createaccountw3(t_connection * c, t_packet const *const packet);
124 static int _client_createacctreq1(t_connection * c, t_packet const *const packet);
125 static int _client_createacctreq2(t_connection * c, t_packet const *const packet);
126 static int _client_changepassreq(t_connection * c, t_packet const *const packet);
127 static int _client_echoreply(t_connection * c, t_packet const *const packet);
128 static int _client_authreq1(t_connection * c, t_packet const *const packet);
129 static int _client_authreq109(t_connection * c, t_packet const *const packet);
130 static int _client_regsnoopreply(t_connection * c, t_packet const *const packet);
131 static int _client_iconreq(t_connection * c, t_packet const *const packet);
132 static int _client_cdkey(t_connection * c, t_packet const *const packet);
133 static int _client_cdkey2(t_connection * c, t_packet const *const packet);
134 static int _client_cdkey3(t_connection * c, t_packet const *const packet);
135 static int _client_udpok(t_connection * c, t_packet const *const packet);
136 static int _client_fileinforeq(t_connection * c, t_packet const *const packet);
137 static int _client_statsreq(t_connection * c, t_packet const *const packet);
138 static int _client_loginreq1(t_connection * c, t_packet const *const packet);
139 static int _client_loginreq2(t_connection * c, t_packet const *const packet);
140 static int _client_loginreqw3(t_connection * c, t_packet const *const packet);
141 static int _client_pingreq(t_connection * c, t_packet const *const packet);
142 static int _client_logonproofreq(t_connection * c, t_packet const *const packet);
143 static int _client_changegameport(t_connection * c, t_packet const *const packet);
144 static int _client_friendslistreq(t_connection * c, t_packet const *const packet);
145 static int _client_friendinforeq(t_connection * c, t_packet const *const packet);
146 static int _client_atfriendscreen(t_connection * c, t_packet const *const packet);
147 static int _client_atinvitefriend(t_connection * c, t_packet const *const packet);
148 static int _client_atacceptinvite(t_connection * c, t_packet const *const packet);
149 static int _client_atacceptdeclineinvite(t_connection * c, t_packet const *const packet);
150 static int _client_motdw3(t_connection * c, t_packet const *const packet);
151 static int _client_realmlistreq(t_connection * c, t_packet const *const packet);
152 static int _client_realmlistreq110(t_connection * c, t_packet const *const packet);
153 static int _client_profilereq(t_connection * c, t_packet const *const packet);
154 static int _client_realmjoinreq109(t_connection * c, t_packet const *const packet);
155 static int _client_unknown39(t_connection * c, t_packet const *const packet);
156 static int _client_charlistreq(t_connection * c, t_packet const *const packet);
157 static int _client_adreq(t_connection * c, t_packet const *const packet);
158 static int _client_adack(t_connection * c, t_packet const *const packet);
159 static int _client_adclick(t_connection * c, t_packet const *const packet);
160 static int _client_adclick2(t_connection * c, t_packet const *const packet);
161 static int _client_statsupdate(t_connection * c, t_packet const *const packet);
162 static int _client_playerinforeq(t_connection * c, t_packet const *const packet);
163 static int _client_progident2(t_connection * c, t_packet const *const packet);
164 static int _client_joinchannel(t_connection * c, t_packet const *const packet);
165 static int _client_message(t_connection * c, t_packet const *const packet);
166 static int _client_gamelistreq(t_connection * c, t_packet const *const packet);
167 static int _client_joingame(t_connection * c, t_packet const *const packet);
168 static int _client_startgame1(t_connection * c, t_packet const *const packet);
169 static int _client_startgame3(t_connection * c, t_packet const *const packet);
170 static int _client_startgame4(t_connection * c, t_packet const *const packet);
171 static int _client_closegame(t_connection * c, t_packet const *const packet);
172 static int _client_gamereport(t_connection * c, t_packet const *const packet);
173 static int _client_leavechannel(t_connection * c, t_packet const *const packet);
174 static int _client_ladderreq(t_connection * c, t_packet const *const packet);
175 static int _client_laddersearchreq(t_connection * c, t_packet const *const packet);
176 static int _client_mapauthreq1(t_connection * c, t_packet const *const packet);
177 static int _client_mapauthreq2(t_connection * c, t_packet const *const packet);
178 static int _client_changeclient(t_connection * c, t_packet const *const packet);
179 static int _client_w3xp_clanmemberlistreq(t_connection * c, t_packet const *const packet);
180 static int _client_w3xp_clan_motdreq(t_connection * c, t_packet const *const packet);
181 static int _client_w3xp_clan_motdchg(t_connection * c, t_packet const *const packet);
182 static int _client_w3xp_clan_createreq(t_connection * c, t_packet const *const packet);
183 static int _client_w3xp_clan_createinvitereq(t_connection * c, t_packet const *const packet);
184 static int _client_w3xp_clan_createinvitereply(t_connection * c, t_packet const *const packet);
185 static int _client_w3xp_clan_disbandreq(t_connection * c, t_packet const *const packet);
186 static int _client_w3xp_clanmember_rankupdatereq(t_connection * c, t_packet const *const packet);
187 static int _client_w3xp_clanmember_removereq(t_connection * c, t_packet const *const packet);
188 static int _client_w3xp_clan_membernewchiefreq(t_connection * c, t_packet const *const packet);
189 static int _client_w3xp_clan_invitereq(t_connection * c, t_packet const *const packet);
190 static int _client_w3xp_clan_invitereply(t_connection * c, t_packet const *const packet);
191 static int _client_crashdump(t_connection * c, t_packet const *const packet);
192 static int _client_setemailreply(t_connection * c, t_packet const *const packet);
193 static int _client_changeemailreq(t_connection * c, t_packet const *const packet);
194 static int _client_getpasswordreq(t_connection * c, t_packet const *const packet);
195 static int _client_claninforeq(t_connection * c, t_packet const *const packet);
196 
197 /* connection state connected handler table */
198 static const t_htable_row bnet_htable_con[] = {
199     {CLIENT_UNKNOWN_1B, _client_unknown_1b},
200     {CLIENT_COMPINFO1, _client_compinfo1},
201     {CLIENT_COMPINFO2, _client_compinfo2},
202     {CLIENT_COUNTRYINFO1, _client_countryinfo1},
203     {CLIENT_COUNTRYINFO_109, _client_countryinfo109},
204     {CLIENT_UNKNOWN_2B, _client_unknown2b},
205     {CLIENT_PROGIDENT, _client_progident},
206     {CLIENT_CLOSEGAME, NULL},
207     {CLIENT_CREATEACCOUNT_W3, _client_createaccountw3},
208     {CLIENT_CREATEACCTREQ1, _client_createacctreq1},
209     {CLIENT_CREATEACCTREQ2, _client_createacctreq2},
210     {CLIENT_CHANGEPASSREQ, _client_changepassreq},
211     {CLIENT_ECHOREPLY, _client_echoreply},
212     {CLIENT_AUTHREQ1, _client_authreq1},
213     {CLIENT_AUTHREQ_109, _client_authreq109},
214     {CLIENT_REGSNOOPREPLY, _client_regsnoopreply},
215     {CLIENT_ICONREQ, _client_iconreq},
216     {CLIENT_CDKEY, _client_cdkey},
217     {CLIENT_CDKEY2, _client_cdkey2},
218     {CLIENT_CDKEY3, _client_cdkey3},
219     {CLIENT_UDPOK, _client_udpok},
220     {CLIENT_FILEINFOREQ, _client_fileinforeq},
221     {CLIENT_STATSREQ, _client_statsreq},
222     {CLIENT_PINGREQ, _client_pingreq},
223     {CLIENT_LOGINREQ1, _client_loginreq1},
224     {CLIENT_LOGINREQ2, _client_loginreq2},
225     {CLIENT_LOGINREQ_W3, _client_loginreqw3},
226     {CLIENT_LOGONPROOFREQ, _client_logonproofreq},
227     /* After this packet we know to translate the packets to the normal IDs */
228     {CLIENT_CHANGECLIENT, _client_changeclient},
229     {CLIENT_GETPASSWORDREQ, _client_getpasswordreq},
230     {CLIENT_CHANGEEMAILREQ, _client_changeemailreq},
231     {CLIENT_CRASHDUMP, _client_crashdump},
232     {-1, NULL}
233 };
234 
235 /* connection state loggedin handlers */
236 static const t_htable_row bnet_htable_log[] = {
237     {CLIENT_CHANGEGAMEPORT, _client_changegameport},
238     {CLIENT_FRIENDSLISTREQ, _client_friendslistreq},
239     {CLIENT_FRIENDINFOREQ, _client_friendinforeq},
240     {CLIENT_ARRANGEDTEAM_FRIENDSCREEN, _client_atfriendscreen},
241     {CLIENT_ARRANGEDTEAM_INVITE_FRIEND, _client_atinvitefriend},
242     {CLIENT_ARRANGEDTEAM_ACCEPT_INVITE, _client_atacceptinvite},
243     {CLIENT_ARRANGEDTEAM_ACCEPT_DECLINE_INVITE, _client_atacceptdeclineinvite},
244     /* anongame packet (44ff) handled in handle_anongame.c */
245     {CLIENT_FINDANONGAME, handle_anongame_packet},
246     {CLIENT_FILEINFOREQ, _client_fileinforeq},
247     {CLIENT_MOTD_W3, _client_motdw3},
248     {CLIENT_REALMLISTREQ, _client_realmlistreq},
249     {CLIENT_REALMLISTREQ_110, _client_realmlistreq110},
250     {CLIENT_PROFILEREQ, _client_profilereq},
251     {CLIENT_REALMJOINREQ_109, _client_realmjoinreq109},
252     {CLIENT_UNKNOWN_37, _client_charlistreq},
253     {CLIENT_UNKNOWN_39, _client_unknown39},
254     {CLIENT_ECHOREPLY, _client_echoreply},
255     {CLIENT_PINGREQ, _client_pingreq},
256     {CLIENT_ADREQ, _client_adreq},
257     {CLIENT_ADACK, _client_adack},
258     {CLIENT_ADCLICK, _client_adclick},
259     {CLIENT_ADCLICK2, _client_adclick2},
260     {CLIENT_STATSREQ, _client_statsreq},
261     {CLIENT_STATSUPDATE, _client_statsupdate},
262     {CLIENT_PLAYERINFOREQ, _client_playerinforeq},
263     {CLIENT_PROGIDENT2, _client_progident2},
264     {CLIENT_JOINCHANNEL, _client_joinchannel},
265     {CLIENT_MESSAGE, _client_message},
266     {CLIENT_GAMELISTREQ, _client_gamelistreq},
267     {CLIENT_JOIN_GAME, _client_joingame},
268     {CLIENT_STARTGAME1, _client_startgame1},
269     {CLIENT_STARTGAME3, _client_startgame3},
270     {CLIENT_STARTGAME4, _client_startgame4},
271     {CLIENT_CLOSEGAME, _client_closegame},
272     {CLIENT_CLOSEGAME2, _client_closegame},
273     {CLIENT_GAME_REPORT, _client_gamereport},
274     {CLIENT_LEAVECHANNEL, _client_leavechannel},
275     {CLIENT_LADDERREQ, _client_ladderreq},
276     {CLIENT_LADDERSEARCHREQ, _client_laddersearchreq},
277     {CLIENT_MAPAUTHREQ1, _client_mapauthreq1},
278     {CLIENT_MAPAUTHREQ2, _client_mapauthreq2},
279     {CLIENT_W3XP_CLAN_DISBANDREQ, _client_w3xp_clan_disbandreq},
280     {CLIENT_W3XP_CLANMEMBERLIST_REQ, _client_w3xp_clanmemberlistreq},
281     {CLIENT_W3XP_CLAN_MOTDCHG, _client_w3xp_clan_motdchg},
282     {CLIENT_W3XP_CLAN_MOTDREQ, _client_w3xp_clan_motdreq},
283     {CLIENT_W3XP_CLAN_CREATEREQ, _client_w3xp_clan_createreq},
284     {CLIENT_W3XP_CLAN_CREATEINVITEREQ, _client_w3xp_clan_createinvitereq},
285     {CLIENT_W3XP_CLAN_CREATEINVITEREPLY, _client_w3xp_clan_createinvitereply},
286     {CLIENT_W3XP_CLANMEMBER_RANKUPDATE_REQ, _client_w3xp_clanmember_rankupdatereq},
287     {CLIENT_W3XP_CLANMEMBER_REMOVE_REQ, _client_w3xp_clanmember_removereq},
288     {CLIENT_W3XP_CLAN_MEMBERNEWCHIEFREQ, _client_w3xp_clan_membernewchiefreq},
289     {CLIENT_W3XP_CLAN_INVITEREQ, _client_w3xp_clan_invitereq},
290     {CLIENT_W3XP_CLAN_INVITEREPLY, _client_w3xp_clan_invitereply},
291     {CLIENT_CRASHDUMP, _client_crashdump},
292     {CLIENT_SETEMAILREPLY, _client_setemailreply},
293     {CLIENT_CLANINFOREQ, _client_claninforeq},
294     {CLIENT_NULL, NULL},
295     {-1, NULL}
296 };
297 
298 /* main handler function */
299 static int handle(const t_htable_row * htable, int type, t_connection * c, t_packet const *const packet);
300 
handle_bnet_packet(t_connection * c,t_packet const * const packet)301 extern int handle_bnet_packet(t_connection * c, t_packet const *const packet)
302 {
303     if (!c) {
304 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got NULL connection", conn_get_socket(c));
305 	return -1;
306     }
307     if (!packet) {
308 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got NULL packet", conn_get_socket(c));
309 	return -1;
310     }
311     if (packet_get_class(packet) != packet_class_bnet) {
312 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad packet (class %d)", conn_get_socket(c), (int) packet_get_class(packet));
313 	return -1;
314     }
315 
316     switch (conn_get_state(c)) {
317 	case conn_state_connected:
318 	    switch (handle(bnet_htable_con, packet_get_type(packet), c, packet)) {
319 		case 1:
320 		    eventlog(eventlog_level_error, __FUNCTION__, "[%d] unknown (unlogged in) bnet packet type 0x%04x, len %u", conn_get_socket(c), packet_get_type(packet), packet_get_size(packet));
321 		    break;
322 		case -1:
323 		    eventlog(eventlog_level_error, __FUNCTION__, "[%d] (unlogged in) got error handling packet type 0x%04x, len %u", conn_get_socket(c), packet_get_type(packet), packet_get_size(packet));
324 		    break;
325 	    };
326 	    break;
327 
328 	case conn_state_loggedin:
329 	    switch (handle(bnet_htable_log, packet_get_type(packet), c, packet)) {
330 		case 1:
331 		    eventlog(eventlog_level_error, __FUNCTION__, "[%d] unknown (logged in) bnet packet type 0x%04x, len %u", conn_get_socket(c), packet_get_type(packet), packet_get_size(packet));
332 		    break;
333 		case -1:
334 		    eventlog(eventlog_level_error, __FUNCTION__, "[%d] (logged in) got error handling packet type 0x%04x, len %u", conn_get_socket(c), packet_get_type(packet), packet_get_size(packet));
335 		    break;
336 	    };
337 	    break;
338 
339 	case conn_state_untrusted:
340 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] unknown (untrusted) bnet packet type 0x%04x, len %u", conn_get_socket(c), packet_get_type(packet), packet_get_size(packet));
341 	    break;
342 
343 	default:
344 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] invalid login state %d", conn_get_socket(c), conn_get_state(c));
345     };
346 
347     return 0;
348 }
349 
handle(const t_htable_row * htable,int type,t_connection * c,t_packet const * const packet)350 static int handle(const t_htable_row * htable, int type, t_connection * c, t_packet const *const packet)
351 {
352     t_htable_row const *p;
353     int res = 1;
354 
355     for (p = htable; p->type != -1; p++)
356 	if (p->type == type) {
357 	    res = 0;
358 	    if (p->handler != NULL)
359 		res = p->handler(c, packet);
360 	    if (res != 2)
361 		break;		/* return 2 means we want to continue parsing */
362 	}
363 
364     return res;
365 }
366 
367 /* checks if a clienttag is in the allowed_clients list
368  * @ctag : clienttag integer to check
369  * if it's allowed returns 0
370  * if it's not allowed returns -1
371  */
_check_allowed_client(t_clienttag ctag)372 static int _check_allowed_client(t_clienttag ctag)
373 {
374     char *list, *p, *q;
375 
376     /* by default allow all */
377     if (!prefs_get_allowed_clients())
378 	return 0;
379 
380     /* this shortcut check should make server as fast as before if
381      * the configuration is left in default mode */
382     if (!strcasecmp(prefs_get_allowed_clients(), "all"))
383 	return 0;
384 
385     list = xstrdup(prefs_get_allowed_clients());
386     p = list;
387     do {
388 	q = strchr(p, ',');
389 	if (q)
390 	    *q = '\0';
391 	if (!strcasecmp(p, "all"))
392 	    goto ok;
393 	if (strlen(p) != 4)
394 	    continue;
395 	if (ctag == tag_case_str_to_uint(p))
396 	    goto ok;		/* client allowed */
397 	if (q)
398 	    p = q + 1;
399     } while (q);
400     xfree((void *) list);
401 
402     return -1;			/* client NOT allowed */
403 
404   ok:
405     xfree((void *) list);
406     return 0;
407 }
408 
409 /* handlers for bnet packets */
_client_unknown_1b(t_connection * c,t_packet const * const packet)410 static int _client_unknown_1b(t_connection * c, t_packet const *const packet)
411 {
412     if (packet_get_size(packet) < sizeof(t_client_unknown_1b)) {
413 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad UNKNOWN_1B packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_unknown_1b), packet_get_size(packet));
414 	return -1;
415     }
416 
417     {
418 	unsigned int newip;
419 	unsigned short newport;
420 
421 	eventlog(eventlog_level_debug, __FUNCTION__, "[%d] UNKNOWN_1B unknown1=0x%04hx", conn_get_socket(c), bn_short_get(packet->u.client_unknown_1b.unknown1));
422 	eventlog(eventlog_level_debug, __FUNCTION__, "[%d] UNKNOWN_1B unknown2=0x%08x", conn_get_socket(c), bn_int_get(packet->u.client_unknown_1b.unknown2));
423 	eventlog(eventlog_level_debug, __FUNCTION__, "[%d] UNKNOWN_1B unknown3=0x%08x", conn_get_socket(c), bn_int_get(packet->u.client_unknown_1b.unknown3));
424 
425 	newip = bn_int_nget(packet->u.client_unknown_1b.ip);
426 	newport = bn_short_nget(packet->u.client_unknown_1b.port);
427 
428 	eventlog(eventlog_level_info, __FUNCTION__, "[%d] UNKNOWN_1B set new UDP address to %s", conn_get_socket(c), addr_num_to_addr_str(newip, newport));
429 	conn_set_game_addr(c, newip);
430 	conn_set_game_port(c, newport);
431     }
432     return 0;
433 }
434 
_client_compinfo1(t_connection * c,t_packet const * const packet)435 static int _client_compinfo1(t_connection * c, t_packet const *const packet)
436 {
437     t_packet *rpacket;
438 
439     if (packet_get_size(packet) < sizeof(t_client_compinfo1)) {
440 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad COMPINFO1 packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_compinfo1), packet_get_size(packet));
441 	return -1;
442     }
443 
444     {
445 	char const *host;
446 	char const *user;
447 
448 	if (!(host = packet_get_str_const(packet, sizeof(t_client_compinfo1), MAX_WINHOST_STR))) {
449 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad COMPINFO1 packet (missing or too long host)", conn_get_socket(c));
450 	    return -1;
451 	}
452 	if (!(user = packet_get_str_const(packet, sizeof(t_client_compinfo1) + strlen(host) + 1, MAX_WINUSER_STR))) {
453 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad COMPINFO1 packet (missing or too long user)", conn_get_socket(c));
454 	    return -1;
455 	}
456 
457 	conn_set_host(c, host);
458 	conn_set_user(c, user);
459     }
460 
461     if ((rpacket = packet_create(packet_class_bnet))) {
462 	packet_set_size(rpacket, sizeof(t_server_compreply));
463 	packet_set_type(rpacket, SERVER_COMPREPLY);
464 	bn_int_set(&rpacket->u.server_compreply.reg_version, SERVER_COMPREPLY_REG_VERSION);
465 	bn_int_set(&rpacket->u.server_compreply.reg_auth, SERVER_COMPREPLY_REG_AUTH);
466 	bn_int_set(&rpacket->u.server_compreply.client_id, SERVER_COMPREPLY_CLIENT_ID);
467 	bn_int_set(&rpacket->u.server_compreply.client_token, SERVER_COMPREPLY_CLIENT_TOKEN);
468 	conn_push_outqueue(c, rpacket);
469 	packet_del_ref(rpacket);
470     }
471     if ((rpacket = packet_create(packet_class_bnet))) {
472 	packet_set_size(rpacket, sizeof(t_server_sessionkey1));
473 	packet_set_type(rpacket, SERVER_SESSIONKEY1);
474 	bn_int_set(&rpacket->u.server_sessionkey1.sessionkey, conn_get_sessionkey(c));
475 	conn_push_outqueue(c, rpacket);
476 	packet_del_ref(rpacket);
477     }
478     return 0;
479 }
480 
_client_compinfo2(t_connection * c,t_packet const * const packet)481 static int _client_compinfo2(t_connection * c, t_packet const *const packet)
482 {
483     t_packet *rpacket;
484 
485     if (packet_get_size(packet) < sizeof(t_client_compinfo2)) {
486 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad COMPINFO2 packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_compinfo2), packet_get_size(packet));
487 	return -1;
488     }
489 
490     {
491 	char const *host;
492 	char const *user;
493 
494 	if (!(host = packet_get_str_const(packet, sizeof(t_client_compinfo2), MAX_WINHOST_STR))) {
495 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad COMPINFO2 packet (missing or too long host)", conn_get_socket(c));
496 	    return -1;
497 	}
498 	if (!(user = packet_get_str_const(packet, sizeof(t_client_compinfo2) + strlen(host) + 1, MAX_WINUSER_STR))) {
499 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad COMPINFO2 packet (missing or too long user)", conn_get_socket(c));
500 	    return -1;
501 	}
502 
503 	conn_set_host(c, host);
504 	conn_set_user(c, user);
505     }
506 
507     if ((rpacket = packet_create(packet_class_bnet))) {
508 	packet_set_size(rpacket, sizeof(t_server_compreply));
509 	packet_set_type(rpacket, SERVER_COMPREPLY);
510 	bn_int_set(&rpacket->u.server_compreply.reg_version, SERVER_COMPREPLY_REG_VERSION);
511 	bn_int_set(&rpacket->u.server_compreply.reg_auth, SERVER_COMPREPLY_REG_AUTH);
512 	bn_int_set(&rpacket->u.server_compreply.client_id, SERVER_COMPREPLY_CLIENT_ID);
513 	bn_int_set(&rpacket->u.server_compreply.client_token, SERVER_COMPREPLY_CLIENT_TOKEN);
514 	conn_push_outqueue(c, rpacket);
515 	packet_del_ref(rpacket);
516     }
517 
518     if ((rpacket = packet_create(packet_class_bnet))) {
519 	packet_set_size(rpacket, sizeof(t_server_sessionkey2));
520 	packet_set_type(rpacket, SERVER_SESSIONKEY2);
521 	bn_int_set(&rpacket->u.server_sessionkey2.sessionnum, conn_get_sessionnum(c));
522 	bn_int_set(&rpacket->u.server_sessionkey2.sessionkey, conn_get_sessionkey(c));
523 	conn_push_outqueue(c, rpacket);
524 	packet_del_ref(rpacket);
525     }
526 
527     return 0;
528 }
529 
_client_countryinfo1(t_connection * c,t_packet const * const packet)530 static int _client_countryinfo1(t_connection * c, t_packet const *const packet)
531 {
532     if (packet_get_size(packet) < sizeof(t_client_countryinfo1)) {
533 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad COUNTRYINFO1 packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_countryinfo1), packet_get_size(packet));
534 	return -1;
535     }
536     {
537 	char const *langstr;
538 	char const *countrycode;
539 	char const *country;
540 	unsigned int tzbias;
541 
542 	if (!(langstr = packet_get_str_const(packet, sizeof(t_client_countryinfo1), MAX_LANG_STR))) {
543 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad COUNTRYINFO1 packet (missing or too long langstr)", conn_get_socket(c));
544 	    return -1;
545 	}
546 
547 	if (!(countrycode = packet_get_str_const(packet, sizeof(t_client_countryinfo1) + strlen(langstr) + 1, MAX_COUNTRYCODE_STR))) {
548 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad COUNTRYINFO1 packet (missing or too long countrycode)", conn_get_socket(c));
549 	    return -1;
550 	}
551 
552 	if (!(country = packet_get_str_const(packet, sizeof(t_client_countryinfo1) + strlen(langstr) + 1 + strlen(countrycode) + 1, MAX_COUNTRY_STR))) {
553 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad COUNTRYINFO1 packet (missing or too long country)", conn_get_socket(c));
554 	    return -1;
555 	}
556 
557 	if (!(packet_get_str_const(packet, sizeof(t_client_countryinfo1) + strlen(langstr) + 1 + strlen(countrycode) + 1 + strlen(country) + 1, MAX_COUNTRYNAME_STR))) {
558 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad COUNTRYINFO1 packet (missing or too long countryname)", conn_get_socket(c));
559 	    return -1;
560 	}
561 
562 	tzbias = bn_int_get(packet->u.client_countryinfo1.bias);
563 	eventlog(eventlog_level_debug, __FUNCTION__, "[%d] COUNTRYINFO1 packet from tzbias=0x%04x(%+d) langstr=%s countrycode=%s country=%s", tzbias, uint32_to_int(tzbias), conn_get_socket(c), langstr, countrycode, country);
564 	conn_set_country(c, country);
565 	conn_set_tzbias(c, uint32_to_int(tzbias));
566     }
567     return 0;
568 }
569 
_client_countryinfo109(t_connection * c,t_packet const * const packet)570 static int _client_countryinfo109(t_connection * c, t_packet const *const packet)
571 {
572     t_packet *rpacket;
573 
574     if (packet_get_size(packet) < sizeof(t_client_countryinfo_109)) {
575 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad COUNTRYINFO_109 packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_countryinfo_109), packet_get_size(packet));
576 	return -1;
577     }
578 
579     {
580 	char const *langstr;
581 	char const *countryname;
582 	unsigned int tzbias;
583 	char archtag_str[5];
584 	char clienttag_str[5];
585 	char gamelang_str[5];
586 
587 	if (!(langstr = packet_get_str_const(packet, sizeof(t_client_countryinfo_109), MAX_LANG_STR))) {
588 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad COUNTRYINFO_109 packet (missing or too long langstr)", conn_get_socket(c));
589 	    return -1;
590 	}
591 
592 	if (!(countryname = packet_get_str_const(packet, sizeof(t_client_countryinfo_109) + strlen(langstr) + 1, MAX_COUNTRYNAME_STR))) {
593 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad COUNTRYINFO_109 packet (missing or too long countryname)", conn_get_socket(c));
594 	    return -1;
595 	}
596 
597 	/* check if it's an allowed client type */
598 	if (_check_allowed_client(bn_int_get(packet->u.client_countryinfo_109.clienttag))) {
599 	    conn_set_state(c, conn_state_destroy);
600 	    return 0;
601 	}
602 
603 	tzbias = bn_int_get(packet->u.client_countryinfo_109.bias);
604 
605 	eventlog(eventlog_level_debug, __FUNCTION__, "[%d] COUNTRYINFO_109 packet tzbias=0x%04x(%+d) lcid=%u langid=%u arch=\"%s\" client=\"%s\" versionid=0x%08x gamelang=\"%s\"", conn_get_socket(c), tzbias, uint32_to_int(tzbias), bn_int_get(packet->u.client_countryinfo_109.lcid), bn_int_get(packet->u.client_countryinfo_109.langid), tag_uint_to_str(archtag_str, bn_int_get(packet->u.client_countryinfo_109.archtag)), tag_uint_to_str(clienttag_str, bn_int_get(packet->u.client_countryinfo_109.clienttag)), bn_int_get(packet->u.client_countryinfo_109.versionid), tag_uint_to_str(gamelang_str, bn_int_get(packet->u.client_countryinfo_109.gamelang)));
606 
607 	eventlog(eventlog_level_debug, __FUNCTION__, "[%d] COUNTRYINFO_109 packet from \"%s\" \"%s\"", conn_get_socket(c), countryname, langstr);
608 
609 	conn_set_country(c, langstr);	/* FIXME: This isn't right.  We want USA not ENU (English-US) */
610 	conn_set_tzbias(c, uint32_to_int(tzbias));
611 	conn_set_versionid(c, bn_int_get(packet->u.client_countryinfo_109.versionid));
612 	conn_set_archtag(c, bn_int_get(packet->u.client_countryinfo_109.archtag));
613 	conn_set_clienttag(c, bn_int_get(packet->u.client_countryinfo_109.clienttag));
614 	conn_set_gamelang(c, bn_int_get(packet->u.client_countryinfo_109.gamelang));
615 
616 	/* First, send an ECHO_REQ */
617 
618 	if ((rpacket = packet_create(packet_class_bnet))) {
619 	    packet_set_size(rpacket, sizeof(t_server_echoreq));
620 	    packet_set_type(rpacket, SERVER_ECHOREQ);
621 	    bn_int_set(&rpacket->u.server_echoreq.ticks, get_ticks());
622 	    conn_push_outqueue(c, rpacket);
623 	    packet_del_ref(rpacket);
624 	}
625 
626 	if ((rpacket = packet_create(packet_class_bnet))) {
627 	    t_versioncheck *vc;
628 
629 	    eventlog(eventlog_level_debug, __FUNCTION__, "[%d] selecting version check", conn_get_socket(c));
630 	    vc = versioncheck_create(conn_get_archtag(c), conn_get_clienttag(c));
631 	    conn_set_versioncheck(c, vc);
632 	    packet_set_size(rpacket, sizeof(t_server_authreq_109));
633 	    packet_set_type(rpacket, SERVER_AUTHREQ_109);
634 
635 	    if ((conn_get_clienttag(c) == CLIENTTAG_WARCRAFT3_UINT))
636 		bn_int_set(&rpacket->u.server_authreq_109.logontype, SERVER_AUTHREQ_109_LOGONTYPE_W3);
637 	    else if ((conn_get_clienttag(c) == CLIENTTAG_WAR3XP_UINT))
638 		bn_int_set(&rpacket->u.server_authreq_109.logontype, SERVER_AUTHREQ_109_LOGONTYPE_W3XP);
639 	    else
640 		bn_int_set(&rpacket->u.server_authreq_109.logontype, SERVER_AUTHREQ_109_LOGONTYPE);
641 
642 	    bn_int_set(&rpacket->u.server_authreq_109.sessionkey, conn_get_sessionkey(c));
643 	    bn_int_set(&rpacket->u.server_authreq_109.sessionnum, conn_get_sessionnum(c));
644 	    file_to_mod_time(versioncheck_get_mpqfile(vc), &rpacket->u.server_authreq_109.timestamp);
645 	    packet_append_string(rpacket, versioncheck_get_mpqfile(vc));
646 	    packet_append_string(rpacket, versioncheck_get_eqn(vc));
647 	    eventlog(eventlog_level_debug, __FUNCTION__, "[%d] selected \"%s\" \"%s\"", conn_get_socket(c), versioncheck_get_mpqfile(vc), versioncheck_get_eqn(vc));
648 	    if ((conn_get_clienttag(c) == CLIENTTAG_WARCRAFT3_UINT)
649 		|| (conn_get_clienttag(c) == CLIENTTAG_WAR3XP_UINT)) {
650 		char padding[128];
651 		memset(padding, 0, 128);
652 		packet_append_data(rpacket, padding, 128);
653 	    }
654 	    conn_push_outqueue(c, rpacket);
655 	    packet_del_ref(rpacket);
656 	}
657     }
658     return 0;
659 }
660 
_client_unknown2b(t_connection * c,t_packet const * const packet)661 static int _client_unknown2b(t_connection * c, t_packet const *const packet)
662 {
663     if (packet_get_size(packet) < sizeof(t_client_unknown_2b)) {
664 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad UNKNOWN_2B packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_unknown_2b), packet_get_size(packet));
665 	return -1;
666     }
667     return 0;
668 }
669 
_client_progident(t_connection * c,t_packet const * const packet)670 static int _client_progident(t_connection * c, t_packet const *const packet)
671 {
672     t_packet *rpacket;
673 
674     if (packet_get_size(packet) < sizeof(t_client_progident)) {
675 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad PROGIDENT packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_progident), packet_get_size(packet));
676 	return -1;
677     }
678 
679     if (_check_allowed_client(bn_int_get(packet->u.client_progident.clienttag))) {
680 	conn_set_state(c, conn_state_destroy);
681 	return 0;
682     }
683 
684     eventlog(eventlog_level_debug, __FUNCTION__, "[%d] CLIENT_PROGIDENT archtag=0x%08x clienttag=0x%08x versionid=0x%08x unknown1=0x%08x", conn_get_socket(c), bn_int_get(packet->u.client_progident.archtag), bn_int_get(packet->u.client_progident.clienttag), bn_int_get(packet->u.client_progident.versionid), bn_int_get(packet->u.client_progident.unknown1));
685 
686     conn_set_archtag(c, bn_int_get(packet->u.client_progident.archtag));
687     conn_set_clienttag(c, bn_int_get(packet->u.client_progident.clienttag));
688 
689     if (prefs_get_skip_versioncheck()) {
690 	eventlog(eventlog_level_debug, __FUNCTION__, "[%d] attempting to skip version check by sending early authreply", conn_get_socket(c));
691 	/* skip over SERVER_AUTHREQ1 and CLIENT_AUTHREQ1 */
692 	if ((rpacket = packet_create(packet_class_bnet))) {
693 	    packet_set_size(rpacket, sizeof(t_server_authreply1));
694 	    packet_set_type(rpacket, SERVER_AUTHREPLY1);
695 	    bn_int_set(&rpacket->u.server_authreply1.message, SERVER_AUTHREPLY1_MESSAGE_OK);
696 	    packet_append_string(rpacket, "");
697 	    packet_append_string(rpacket, "");	/* FIXME: what's the second string for? */
698 	    conn_push_outqueue(c, rpacket);
699 	    packet_del_ref(rpacket);
700 	}
701     } else {
702 	t_versioncheck *vc;
703 
704 	eventlog(eventlog_level_debug, __FUNCTION__, "[%d] selecting version check", conn_get_socket(c));
705 	vc = versioncheck_create(conn_get_archtag(c), conn_get_clienttag(c));
706 	conn_set_versioncheck(c, vc);
707 	if ((rpacket = packet_create(packet_class_bnet))) {
708 	    packet_set_size(rpacket, sizeof(t_server_authreq1));
709 	    packet_set_type(rpacket, SERVER_AUTHREQ1);
710 	    file_to_mod_time(versioncheck_get_mpqfile(vc), &rpacket->u.server_authreq1.timestamp);
711 	    packet_append_string(rpacket, versioncheck_get_mpqfile(vc));
712 	    packet_append_string(rpacket, versioncheck_get_eqn(vc));
713 	    eventlog(eventlog_level_debug, __FUNCTION__, "[%d] selected \"%s\" \"%s\"", conn_get_socket(c), versioncheck_get_mpqfile(vc), versioncheck_get_eqn(vc));
714 	    conn_push_outqueue(c, rpacket);
715 	    packet_del_ref(rpacket);
716 	}
717     }
718 
719     return 0;
720 }
721 
_client_createaccountw3(t_connection * c,t_packet const * const packet)722 static int _client_createaccountw3(t_connection * c, t_packet const *const packet)
723 {
724     t_packet *rpacket;
725     char const *username;
726     char const *plainpass;
727     char upass[20];
728     char lpass[20];
729     t_hash sc_hash;
730     unsigned int i;
731 
732     if (packet_get_size(packet) < sizeof(t_client_createaccount_w3)) {
733 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad CREATEACCOUNT_W3 packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_createaccount_w3), packet_get_size(packet));
734 	return -1;
735     }
736 
737     username = packet_get_str_const(packet, sizeof(t_client_createaccount_w3), UNCHECKED_NAME_STR);
738     if (!username) {
739 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad CREATEACCOUNT_W3 (missing or too long username)", conn_get_socket(c));
740 	return -1;
741     }
742 
743     plainpass = packet_get_str_const(packet, 4 + 8 * 4, 16);
744     if (!plainpass) {
745 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad CREATEACCOUNT_W3 (missing password)", conn_get_socket(c));
746 	return -1;
747     }
748 
749     rpacket = packet_create(packet_class_bnet);
750     if (!rpacket)
751 	return -1;
752     packet_set_size(rpacket, sizeof(t_server_createaccount_w3));
753     packet_set_type(rpacket, SERVER_CREATEACCOUNT_W3);
754 
755     eventlog(eventlog_level_debug, __FUNCTION__, "[%d] new account requested for \"%s\"", conn_get_socket(c), username);
756 
757     if (prefs_get_allow_new_accounts() == 0) {
758 	eventlog(eventlog_level_debug, __FUNCTION__, "[%d] account not created (disabled)", conn_get_socket(c));
759 	bn_int_set(&rpacket->u.server_createaccount_w3.result, SERVER_CREATEACCOUNT_W3_RESULT_EXIST);
760 	goto out;
761     }
762 
763     if (account_check_name(username) < 0) {
764 	eventlog(eventlog_level_debug, __FUNCTION__, "[%d] account not created (invalid symbols)", conn_get_socket(c));
765 	bn_int_set(&rpacket->u.server_createaccount_w3.result, SERVER_CREATEACCOUNT_W3_RESULT_INVALID);
766 	goto out;
767     }
768 
769     /* convert plaintext password to uppercase */
770     strncpy(upass, plainpass, 16);
771     upass[16] = 0;
772     for (i = 0; i < strlen(upass); i++)
773 	if (isascii((int) upass[i]) && islower((int) upass[i]))
774 	    upass[i] = toupper((int) upass[i]);
775 
776     /* convert plaintext password to lowercase for sc etc. */
777     strncpy(lpass, plainpass, 16);
778     lpass[16] = 0;
779     for (i = 0; i < strlen(lpass); i++)
780 	if (isascii((int) lpass[i]) && isupper((int) lpass[i]))
781 	    lpass[i] = tolower((int) lpass[i]);
782 
783 
784     //set password hash for sc etc.
785     bnet_hash(&sc_hash, strlen(lpass), lpass);
786     if (!accountlist_create_account(username, hash_get_str(sc_hash)))
787 	bn_int_set(&rpacket->u.server_createaccount_w3.result, SERVER_CREATEACCOUNT_W3_RESULT_EXIST);
788     else {
789 	eventlog(eventlog_level_debug, __FUNCTION__, "[%d] account created", conn_get_socket(c));
790 	bn_int_set(&rpacket->u.server_createaccount_w3.result, SERVER_CREATEACCOUNT_W3_RESULT_OK);
791     }
792 
793   out:
794     conn_push_outqueue(c, rpacket);
795     packet_del_ref(rpacket);
796 
797     return 0;
798 }
799 
_client_createacctreq1(t_connection * c,t_packet const * const packet)800 static int _client_createacctreq1(t_connection * c, t_packet const *const packet)
801 {
802     t_packet *rpacket;
803     char const *username;
804     t_hash newpasshash1;
805 
806     if (packet_get_size(packet) < sizeof(t_client_createacctreq1)) {
807 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad CREATEACCTREQ1 packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_createacctreq1), packet_get_size(packet));
808 	return -1;
809     }
810 
811     if (!(username = packet_get_str_const(packet, sizeof(t_client_createacctreq1), UNCHECKED_NAME_STR))) {
812 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad CREATEACCTREQ1 (missing or too long username)", conn_get_socket(c));
813 	return -1;
814     }
815 
816     eventlog(eventlog_level_debug, __FUNCTION__, "[%d] new account requested for \"%s\"", conn_get_socket(c), username);
817 
818     rpacket = packet_create(packet_class_bnet);
819     if (!rpacket)
820 	return -1;
821     packet_set_size(rpacket, sizeof(t_server_createacctreply1));
822     packet_set_type(rpacket, SERVER_CREATEACCTREPLY1);
823 
824     if (prefs_get_allow_new_accounts() == 0) {
825 	eventlog(eventlog_level_debug, __FUNCTION__, "[%d] account not created (disabled)", conn_get_socket(c));
826 	bn_int_set(&rpacket->u.server_createacctreply1.result, SERVER_CREATEACCTREPLY1_RESULT_NO);
827 	goto out;
828     }
829 
830     bnhash_to_hash(packet->u.client_createacctreq1.password_hash1, &newpasshash1);
831     if (!accountlist_create_account(username, hash_get_str(newpasshash1))) {
832 	eventlog(eventlog_level_debug, __FUNCTION__, "[%d] account not created (failed)", conn_get_socket(c));
833 	bn_int_set(&rpacket->u.server_createacctreply1.result, SERVER_CREATEACCTREPLY1_RESULT_NO);
834 	goto out;
835     }
836 
837     eventlog(eventlog_level_debug, __FUNCTION__, "[%d] account created", conn_get_socket(c));
838     bn_int_set(&rpacket->u.server_createacctreply1.result, SERVER_CREATEACCTREPLY1_RESULT_OK);
839 
840   out:
841     conn_push_outqueue(c, rpacket);
842     packet_del_ref(rpacket);
843 
844     return 0;
845 }
846 
_client_createacctreq2(t_connection * c,t_packet const * const packet)847 static int _client_createacctreq2(t_connection * c, t_packet const *const packet)
848 {
849     t_packet *rpacket;
850     char const *username;
851     t_hash newpasshash1;
852 
853     if (packet_get_size(packet) < sizeof(t_client_createacctreq2)) {
854 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad CLIENT_CREATEACCTREQ2 packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_createacctreq2), packet_get_size(packet));
855 	return -1;
856     }
857 
858     username = packet_get_str_const(packet, sizeof(t_client_createacctreq2), UNCHECKED_NAME_STR);
859     if (!username) {
860 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad CREATEACCTREQ2 (missing or too long username)", conn_get_socket(c));
861 	return -1;
862     }
863 
864     eventlog(eventlog_level_debug, __FUNCTION__, "[%d] new account requested for \"%s\"", conn_get_socket(c), username);
865 
866     rpacket = packet_create(packet_class_bnet);
867     if (!rpacket)
868 	return -1;
869     packet_set_size(rpacket, sizeof(t_server_createacctreply2));
870     packet_set_type(rpacket, SERVER_CREATEACCTREPLY2);
871 
872     if (prefs_get_allow_new_accounts() == 0) {
873 	eventlog(eventlog_level_debug, __FUNCTION__, "[%d] account not created (disabled)", conn_get_socket(c));
874 	bn_int_set(&rpacket->u.server_createacctreply2.result, SERVER_CREATEACCTREPLY2_RESULT_EXIST);
875 	goto out;
876     }
877 
878     if (account_check_name(username) < 0) {
879 	eventlog(eventlog_level_debug, __FUNCTION__, "[%d] account not created (invalid symbols)", conn_get_socket(c));
880 	bn_int_set(&rpacket->u.server_createaccount_w3.result, SERVER_CREATEACCTREPLY2_RESULT_INVALID);
881 	goto out;
882     }
883 
884     bnhash_to_hash(packet->u.client_createacctreq2.password_hash1, &newpasshash1);
885     if (!accountlist_create_account(username, hash_get_str(newpasshash1))) {
886 	eventlog(eventlog_level_debug, __FUNCTION__, "[%d] account not created (failed)", conn_get_socket(c));
887 	bn_int_set(&rpacket->u.server_createacctreply2.result, SERVER_CREATEACCTREPLY2_RESULT_EXIST);	/* FIXME: return reason for failure */
888 	goto out;
889     }
890 
891     eventlog(eventlog_level_debug, __FUNCTION__, "[%d] account created", conn_get_socket(c));
892     bn_int_set(&rpacket->u.server_createacctreply2.result, SERVER_CREATEACCTREPLY2_RESULT_OK);
893 
894   out:
895     conn_push_outqueue(c, rpacket);
896     packet_del_ref(rpacket);
897 
898     return 0;
899 }
900 
_client_changepassreq(t_connection * c,t_packet const * const packet)901 static int _client_changepassreq(t_connection * c, t_packet const *const packet)
902 {
903     t_packet *rpacket;
904 
905     if (packet_get_size(packet) < sizeof(t_client_changepassreq)) {
906 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad CHANGEPASSREQ packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_changepassreq), packet_get_size(packet));
907 	return -1;
908     }
909 
910     {
911 	char const *username;
912 	t_account *account;
913 
914 	if (!(username = packet_get_str_const(packet, sizeof(t_client_changepassreq), UNCHECKED_NAME_STR))) {
915 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad CHANGEPASSREQ (missing or too long username)", conn_get_socket(c));
916 	    return -1;
917 	}
918 
919 	eventlog(eventlog_level_info, __FUNCTION__, "[%d] password change requested for \"%s\"", conn_get_socket(c), username);
920 
921 	if (!(rpacket = packet_create(packet_class_bnet)))
922 	    return -1;
923 	packet_set_size(rpacket, sizeof(t_server_changepassack));
924 	packet_set_type(rpacket, SERVER_CHANGEPASSACK);
925 
926 	/* fail if logged in or no account */
927 	if (connlist_find_connection_by_accountname(username) || !(account = accountlist_find_account(username))) {
928 	    eventlog(eventlog_level_info, __FUNCTION__, "[%d] password change for \"%s\" refused (no such account)", conn_get_socket(c), username);
929 	    bn_int_set(&rpacket->u.server_changepassack.message, SERVER_CHANGEPASSACK_MESSAGE_FAIL);
930 	} else if (account_get_auth_changepass(account) == 0) {	/* default to true */
931 	    eventlog(eventlog_level_info, __FUNCTION__, "[%d] password change for \"%s\" refused (no change access)", conn_get_socket(c), username);
932 	    bn_int_set(&rpacket->u.server_changepassack.message, SERVER_CHANGEPASSACK_MESSAGE_FAIL);
933 	} else if (conn_get_sessionkey(c) != bn_int_get(packet->u.client_changepassreq.sessionkey)) {
934 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] password change for \"%s\" refused (expected session key 0x%08x, got 0x%08x)", conn_get_socket(c), username, conn_get_sessionkey(c), bn_int_get(packet->u.client_changepassreq.sessionkey));
935 	    bn_int_set(&rpacket->u.server_changepassack.message, SERVER_CHANGEPASSACK_MESSAGE_FAIL);
936 	} else {
937 	    struct {
938 		bn_int ticks;
939 		bn_int sessionkey;
940 		bn_int passhash1[5];
941 	    } temp;
942 	    char const *oldstrhash1;
943 	    t_hash oldpasshash1;
944 	    t_hash oldpasshash2;
945 	    t_hash trypasshash2;
946 	    t_hash newpasshash1;
947 
948 
949 	    if ((oldstrhash1 = account_get_pass(account))) {
950 		bn_int_set(&temp.ticks, bn_int_get(packet->u.client_changepassreq.ticks));
951 		bn_int_set(&temp.sessionkey, bn_int_get(packet->u.client_changepassreq.sessionkey));
952 		if (hash_set_str(&oldpasshash1, oldstrhash1) < 0) {
953 		    bnhash_to_hash(packet->u.client_changepassreq.newpassword_hash1, &newpasshash1);
954 		    account_set_pass(account, hash_get_str(newpasshash1));
955 		    eventlog(eventlog_level_info, __FUNCTION__, "[%d] password change for \"%s\" successful (bad previous password)", conn_get_socket(c), account_get_name(account));
956 		    bn_int_set(&rpacket->u.server_changepassack.message, SERVER_CHANGEPASSACK_MESSAGE_SUCCESS);
957 		} else {
958 		    hash_to_bnhash((t_hash const *) &oldpasshash1, temp.passhash1);	/* avoid warning */
959 		    bnet_hash(&oldpasshash2, sizeof(temp), &temp);	/* do the double hash */
960 		    bnhash_to_hash(packet->u.client_changepassreq.oldpassword_hash2, &trypasshash2);
961 
962 		    if (hash_eq(trypasshash2, oldpasshash2) == 1) {
963 			bnhash_to_hash(packet->u.client_changepassreq.newpassword_hash1, &newpasshash1);
964 			account_set_pass(account, hash_get_str(newpasshash1));
965 			eventlog(eventlog_level_info, __FUNCTION__, "[%d] password change for \"%s\" successful (previous password)", conn_get_socket(c), account_get_name(account));
966 			bn_int_set(&rpacket->u.server_changepassack.message, SERVER_CHANGEPASSACK_MESSAGE_SUCCESS);
967 		    } else {
968 			eventlog(eventlog_level_info, __FUNCTION__, "[%d] password change for \"%s\" refused (wrong password)", conn_get_socket(c), account_get_name(account));
969 			conn_increment_passfail_count(c);
970 			bn_int_set(&rpacket->u.server_changepassack.message, SERVER_CHANGEPASSACK_MESSAGE_FAIL);
971 		    }
972 		}
973 	    } else {
974 		bnhash_to_hash(packet->u.client_changepassreq.newpassword_hash1, &newpasshash1);
975 		account_set_pass(account, hash_get_str(newpasshash1));
976 		eventlog(eventlog_level_info, __FUNCTION__, "[%d] password change for \"%s\" successful (no previous password)", conn_get_socket(c), account_get_name(account));
977 		bn_int_set(&rpacket->u.server_changepassack.message, SERVER_CHANGEPASSACK_MESSAGE_SUCCESS);
978 	    }
979 	}
980 
981 	conn_push_outqueue(c, rpacket);
982 	packet_del_ref(rpacket);
983 
984     }
985 
986     return 0;
987 }
988 
_client_echoreply(t_connection * c,t_packet const * const packet)989 static int _client_echoreply(t_connection * c, t_packet const *const packet)
990 {
991     if (packet_get_size(packet) < sizeof(t_client_echoreply)) {
992 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad ECHOREPLY packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_echoreply), packet_get_size(packet));
993 	return -1;
994     }
995 
996     {
997 	unsigned int now;
998 	unsigned int then;
999 
1000 	now = get_ticks();
1001 	then = bn_int_get(packet->u.client_echoreply.ticks);
1002 	if (!now || !then || now < then)
1003 	    eventlog(eventlog_level_warn, __FUNCTION__, "[%d] bad timing in echo reply: now=%u then=%u", conn_get_socket(c), now, then);
1004 	else
1005 	    conn_set_latency(c, now - then);
1006     }
1007 
1008     return 0;
1009 }
1010 
_client_authreq1(t_connection * c,t_packet const * const packet)1011 static int _client_authreq1(t_connection * c, t_packet const *const packet)
1012 {
1013     t_packet *rpacket;
1014 
1015     if (packet_get_size(packet) < sizeof(t_client_authreq1)) {
1016 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad AUTHREQ1 packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_authreq1), packet_get_size(packet));
1017 	return -1;
1018     }
1019 
1020     {
1021 	char verstr[16];
1022 	char const *exeinfo;
1023 	char const *versiontag;
1024 	int failed;
1025 
1026 	failed = 0;
1027 	if (bn_int_get(packet->u.client_authreq1.archtag) != conn_get_archtag(c))
1028 	    failed = 1;
1029 	if (bn_int_get(packet->u.client_authreq1.clienttag) != conn_get_clienttag(c))
1030 	    failed = 1;
1031 
1032 	if (!(exeinfo = packet_get_str_const(packet, sizeof(t_client_authreq1), MAX_EXEINFO_STR))) {
1033 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad AUTHREQ1 (missing or too long exeinfo)", conn_get_socket(c));
1034 	    exeinfo = "badexe";
1035 	    failed = 1;
1036 	}
1037 	conn_set_versionid(c, bn_int_get(packet->u.client_authreq1.versionid));
1038 	conn_set_checksum(c, bn_int_get(packet->u.client_authreq1.checksum));
1039 	conn_set_gameversion(c, bn_int_get(packet->u.client_authreq1.gameversion));
1040 	strcpy(verstr, vernum_to_verstr(bn_int_get(packet->u.client_authreq1.gameversion)));
1041 	conn_set_clientver(c, verstr);
1042 	conn_set_clientexe(c, exeinfo);
1043 
1044 	eventlog(eventlog_level_info, __FUNCTION__, "[%d] CLIENT_AUTHREQ1 archtag=0x%08x clienttag=0x%08x verstr=%s exeinfo=\"%s\" versionid=0x%08lx gameversion=0x%08lx checksum=0x%08lx", conn_get_socket(c), bn_int_get(packet->u.client_authreq1.archtag), bn_int_get(packet->u.client_authreq1.clienttag), verstr, exeinfo, conn_get_versionid(c), conn_get_gameversion(c), conn_get_checksum(c));
1045 
1046 
1047 	if ((rpacket = packet_create(packet_class_bnet))) {
1048 	    packet_set_size(rpacket, sizeof(t_server_authreply1));
1049 	    packet_set_type(rpacket, SERVER_AUTHREPLY1);
1050 
1051 
1052 	    if (!conn_get_versioncheck(c) && prefs_get_skip_versioncheck())
1053 		eventlog(eventlog_level_info, __FUNCTION__, "[%d] skip versioncheck enabled and client did not request validation", conn_get_socket(c));
1054 	    else
1055 		switch (versioncheck_validate(conn_get_versioncheck(c), conn_get_archtag(c), conn_get_clienttag(c), exeinfo, conn_get_versionid(c), conn_get_gameversion(c), conn_get_checksum(c))) {
1056 		    case -1:	/* failed test... client has been modified */
1057 			if (!prefs_get_allow_bad_version()) {
1058 			    eventlog(eventlog_level_info, __FUNCTION__, "[%d] client failed test (marking untrusted)", conn_get_socket(c));
1059 			    failed = 1;
1060 			} else
1061 			    eventlog(eventlog_level_info, __FUNCTION__, "[%d] client failed test, allowing anyway", conn_get_socket(c));
1062 			break;
1063 		    case 0:	/* not listed in table... can't tell if client has been modified */
1064 			if (!prefs_get_allow_unknown_version()) {
1065 			    eventlog(eventlog_level_info, __FUNCTION__, "[%d] unable to test client (marking untrusted)", conn_get_socket(c));
1066 			    failed = 1;
1067 			} else
1068 			    eventlog(eventlog_level_info, __FUNCTION__, "[%d] unable to test client, allowing anyway", conn_get_socket(c));
1069 			break;
1070 			/* 1 == test passed... client seems to be ok */
1071 		}
1072 
1073 	    versiontag = versioncheck_get_versiontag(conn_get_versioncheck(c));
1074 
1075 	    eventlog(eventlog_level_info, __FUNCTION__, "[%d] client matches versiontag \"%s\"", conn_get_socket(c), versiontag);
1076 
1077 	    if (failed) {
1078 		conn_set_state(c, conn_state_untrusted);
1079 		bn_int_set(&rpacket->u.server_authreply1.message, SERVER_AUTHREPLY1_MESSAGE_BADVERSION);
1080 		packet_append_string(rpacket, "");
1081 	    } else {
1082 		char *mpqfilename;
1083 
1084 		mpqfilename = autoupdate_check(conn_get_archtag(c), conn_get_clienttag(c), conn_get_gamelang(c), versiontag);
1085 
1086 		/* Only handle updates when there is an update file available. */
1087 		if (mpqfilename != NULL) {
1088 		    eventlog(eventlog_level_info, __FUNCTION__, "[%d] an upgrade for version %s is available \"%s\"", conn_get_socket(c), versioncheck_get_versiontag(conn_get_versioncheck(c)), mpqfilename);
1089 		    bn_int_set(&rpacket->u.server_authreply1.message, SERVER_AUTHREPLY1_MESSAGE_UPDATE);
1090 		    packet_append_string(rpacket, mpqfilename);
1091 		} else {
1092 		    eventlog(eventlog_level_info, __FUNCTION__, "[%d] no upgrade for %s is available", conn_get_socket(c), versioncheck_get_versiontag(conn_get_versioncheck(c)));
1093 		    bn_int_set(&rpacket->u.server_authreply1.message, SERVER_AUTHREPLY1_MESSAGE_OK);
1094 		    packet_append_string(rpacket, "");
1095 		}
1096 
1097 		if (mpqfilename)
1098 		    xfree((void *) mpqfilename);
1099 	    }
1100 
1101 	    packet_append_string(rpacket, "");	/* FIXME: what's the second string for? */
1102 	    conn_push_outqueue(c, rpacket);
1103 	    packet_del_ref(rpacket);
1104 	}
1105     }
1106 
1107     return 0;
1108 }
1109 
_client_authreq109(t_connection * c,t_packet const * const packet)1110 static int _client_authreq109(t_connection * c, t_packet const *const packet)
1111 {
1112     t_packet *rpacket;
1113 
1114     if (packet_get_size(packet) < sizeof(t_client_authreq_109)) {
1115 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad AUTHREQ_109 packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_authreq_109), packet_get_size(packet));
1116 	return 0;
1117     }
1118 
1119     {
1120 	char verstr[16];
1121 	char const *exeinfo;
1122 	char const *versiontag;
1123 	int failed;
1124 	char const *owner;
1125 	unsigned int count;
1126 	unsigned int pos;
1127 
1128 	failed = 0;
1129 	count = bn_int_get(packet->u.client_authreq_109.cdkey_number);
1130 	pos = sizeof(t_client_authreq_109) + (count * sizeof(t_cdkey_info));
1131 
1132 	if (!(exeinfo = packet_get_str_const(packet, pos, MAX_EXEINFO_STR))) {
1133 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad AUTHREQ_109 (missing or too long exeinfo)", conn_get_socket(c));
1134 	    exeinfo = "badexe";
1135 	    failed = 1;
1136 	}
1137 	conn_set_clientexe(c, exeinfo);
1138 	pos += strlen(exeinfo) + 1;
1139 
1140 	if (!(owner = packet_get_str_const(packet, pos, MAX_OWNER_STR))) {
1141 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad AUTHREQ_109 (missing or too long owner)", conn_get_socket(c));
1142 	    owner = "";		/* maybe owner was missing, use empty string */
1143 	}
1144 	conn_set_owner(c, owner);
1145 
1146 	conn_set_checksum(c, bn_int_get(packet->u.client_authreq_109.checksum));
1147 	conn_set_gameversion(c, bn_int_get(packet->u.client_authreq_109.gameversion));
1148 	strcpy(verstr, vernum_to_verstr(bn_int_get(packet->u.client_authreq_109.gameversion)));
1149 	conn_set_clientver(c, verstr);
1150 	conn_set_clientexe(c, exeinfo);
1151 
1152 	eventlog(eventlog_level_info, __FUNCTION__, "[%d] CLIENT_AUTHREQ_109 ticks=0x%08x, verstr=%s exeinfo=\"%s\" versionid=0x%08lx gameversion=0x%08lx checksum=0x%08lx", conn_get_socket(c), bn_int_get(packet->u.client_authreq_109.ticks), verstr, exeinfo, conn_get_versionid(c), conn_get_gameversion(c), conn_get_checksum(c));
1153 
1154 	if ((rpacket = packet_create(packet_class_bnet))) {
1155 	    packet_set_size(rpacket, sizeof(t_server_authreply_109));
1156 	    packet_set_type(rpacket, SERVER_AUTHREPLY_109);
1157 
1158 
1159 	    if (!conn_get_versioncheck(c) && prefs_get_skip_versioncheck())
1160 		eventlog(eventlog_level_info, __FUNCTION__, "[%d] skip versioncheck enabled and client did not request validation", conn_get_socket(c));
1161 	    else
1162 		switch (versioncheck_validate(conn_get_versioncheck(c), conn_get_archtag(c), conn_get_clienttag(c), exeinfo, conn_get_versionid(c), conn_get_gameversion(c), conn_get_checksum(c))) {
1163 		    case -1:	/* failed test... client has been modified */
1164 			if (!prefs_get_allow_bad_version()) {
1165 			    eventlog(eventlog_level_info, __FUNCTION__, "[%d] client failed test (closing connection)", conn_get_socket(c));
1166 			    failed = 1;
1167 			} else
1168 			    eventlog(eventlog_level_info, __FUNCTION__, "[%d] client failed test, allowing anyway", conn_get_socket(c));
1169 			break;
1170 		    case 0:	/* not listed in table... can't tell if client has been modified */
1171 			if (!prefs_get_allow_unknown_version()) {
1172 			    eventlog(eventlog_level_info, __FUNCTION__, "[%d] unable to test client (closing connection)", conn_get_socket(c));
1173 			    failed = 1;
1174 			} else
1175 			    eventlog(eventlog_level_info, __FUNCTION__, "[%d] unable to test client, allowing anyway", conn_get_socket(c));
1176 			break;
1177 			/* 1 == test passed... client seems to be ok */
1178 		}
1179 
1180 	    versiontag = versioncheck_get_versiontag(conn_get_versioncheck(c));
1181 
1182 	    eventlog(eventlog_level_info, __FUNCTION__, "[%d] client matches versiontag \"%s\"", conn_get_socket(c), versiontag);
1183 
1184 	    if (failed) {
1185 		conn_set_state(c, conn_state_untrusted);
1186 		bn_int_set(&rpacket->u.server_authreply_109.message, SERVER_AUTHREPLY_109_MESSAGE_BADVERSION);
1187 		packet_append_string(rpacket, "");
1188 	    } else {
1189 		char *mpqfilename;
1190 
1191 		mpqfilename = autoupdate_check(conn_get_archtag(c), conn_get_clienttag(c), conn_get_gamelang(c), versiontag);
1192 
1193 		/* Only handle updates when there is an update file available. */
1194 		if (mpqfilename != NULL) {
1195 		    eventlog(eventlog_level_info, __FUNCTION__, "[%d] an upgrade for %s is available \"%s\"", conn_get_socket(c), versiontag, mpqfilename);
1196 		    bn_int_set(&rpacket->u.server_authreply_109.message, SERVER_AUTHREPLY_109_MESSAGE_UPDATE);
1197 		    packet_append_string(rpacket, mpqfilename);
1198 		} else {
1199 		    eventlog(eventlog_level_info, __FUNCTION__, "[%d] no upgrade for %s is available", conn_get_socket(c), versiontag);
1200 		    bn_int_set(&rpacket->u.server_authreply_109.message, SERVER_AUTHREPLY_109_MESSAGE_OK);
1201 		    packet_append_string(rpacket, "");
1202 		}
1203 		if (mpqfilename)
1204 		    xfree((void *) mpqfilename);
1205 	    }
1206 
1207 	    conn_push_outqueue(c, rpacket);
1208 	    packet_del_ref(rpacket);
1209 	}
1210     }
1211 
1212     return 0;
1213 }
1214 
_client_regsnoopreply(t_connection * c,t_packet const * const packet)1215 static int _client_regsnoopreply(t_connection * c, t_packet const *const packet)
1216 {
1217     if (packet_get_size(packet) < sizeof(t_client_regsnoopreply)) {
1218 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad REGSNOOPREPLY packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_regsnoopreply), packet_get_size(packet));
1219 	return -1;
1220     }
1221     return 0;
1222 }
1223 
_client_iconreq(t_connection * c,t_packet const * const packet)1224 static int _client_iconreq(t_connection * c, t_packet const *const packet)
1225 {
1226     t_packet *rpacket;
1227 
1228     if (packet_get_size(packet) < sizeof(t_client_iconreq)) {
1229 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad ICONREQ packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_iconreq), packet_get_size(packet));
1230 	return -1;
1231     }
1232 
1233     if ((rpacket = packet_create(packet_class_bnet))) {
1234 	packet_set_size(rpacket, sizeof(t_server_iconreply));
1235 	packet_set_type(rpacket, SERVER_ICONREPLY);
1236 	file_to_mod_time(prefs_get_iconfile(), &rpacket->u.server_iconreply.timestamp);
1237 
1238 	/* battle.net sends different file on iconreq for WAR3 and W3XP [Omega] */
1239 	if ((conn_get_clienttag(c) == CLIENTTAG_WARCRAFT3_UINT) || (conn_get_clienttag(c) == CLIENTTAG_WAR3XP_UINT))
1240 	    packet_append_string(rpacket, prefs_get_war3_iconfile());
1241 	/* battle.net still sends "icons.bni" to sc/bw clients
1242 	 * clients request icons_STAR.bni seperatly */
1243 /*	else if (strcmp(conn_get_clienttag(c),CLIENTTAG_STARCRAFT)==0)
1244 	    packet_append_string(rpacket,prefs_get_star_iconfile());
1245 	else if (strcmp(conn_get_clienttag(c),CLIENTTAG_BROODWARS)==0)
1246 	    packet_append_string(rpacket,prefs_get_star_iconfile());
1247  */
1248 	else
1249 	    packet_append_string(rpacket, prefs_get_iconfile());
1250 
1251 	conn_push_outqueue(c, rpacket);
1252 	packet_del_ref(rpacket);
1253     }
1254 
1255     return 0;
1256 }
1257 
_client_cdkey(t_connection * c,t_packet const * const packet)1258 static int _client_cdkey(t_connection * c, t_packet const *const packet)
1259 {
1260     t_packet *rpacket;
1261 
1262     if (packet_get_size(packet) < sizeof(t_client_cdkey)) {
1263 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad CDKEY packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_cdkey), packet_get_size(packet));
1264 	return -1;
1265     }
1266 
1267     {
1268 	char const *cdkey;
1269 	char const *owner;
1270 
1271 	if (!(cdkey = packet_get_str_const(packet, sizeof(t_client_cdkey), MAX_CDKEY_STR))) {
1272 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad CDKEY packet (missing or too long cdkey)", conn_get_socket(c));
1273 	    return -1;
1274 	}
1275 	if (!(owner = packet_get_str_const(packet, sizeof(t_client_cdkey) + strlen(cdkey) + 1, MAX_OWNER_STR))) {
1276 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad CDKEY packet (missing or too long owner)", conn_get_socket(c));
1277 	    return -1;
1278 	}
1279 
1280 	conn_set_cdkey(c, cdkey);
1281 	conn_set_owner(c, owner);
1282 
1283 	if ((rpacket = packet_create(packet_class_bnet))) {
1284 	    packet_set_size(rpacket, sizeof(t_server_cdkeyreply));
1285 	    packet_set_type(rpacket, SERVER_CDKEYREPLY);
1286 	    bn_int_set(&rpacket->u.server_cdkeyreply.message, SERVER_CDKEYREPLY_MESSAGE_OK);
1287 	    packet_append_string(rpacket, owner);
1288 	    conn_push_outqueue(c, rpacket);
1289 	    packet_del_ref(rpacket);
1290 	}
1291     }
1292 #if 0				/* Blizzard used this to track down pirates, should only be accepted by old clients */
1293     if ((rpacket = packet_create(packet_class_bnet))) {
1294 	packet_set_size(rpacket, sizeof(t_server_regsnoopreq));
1295 	packet_set_type(rpacket, SERVER_REGSNOOPREQ);
1296 	bn_int_set(&rpacket->u.server_regsnoopreq.unknown1, SERVER_REGSNOOPREQ_UNKNOWN1);	/* sequence num */
1297 	bn_int_set(&rpacket->u.server_regsnoopreq.hkey, SERVER_REGSNOOPREQ_HKEY_CURRENT_USER);
1298 	packet_append_string(rpacket, SERVER_REGSNOOPREQ_REGKEY);
1299 	packet_append_string(rpacket, SERVER_REGSNOOPREQ_REGVALNAME);
1300 	conn_push_outqueue(c, rpacket);
1301 	packet_del_ref(rpacket);
1302     }
1303 #endif
1304     return 0;
1305 }
1306 
_client_cdkey2(t_connection * c,t_packet const * const packet)1307 static int _client_cdkey2(t_connection * c, t_packet const *const packet)
1308 {
1309     t_packet *rpacket;
1310 
1311     if (packet_get_size(packet) < sizeof(t_client_cdkey2)) {
1312 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad CDKEY2 packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_cdkey2), packet_get_size(packet));
1313 	return -1;
1314     }
1315 
1316     {
1317 	char const *owner;
1318 
1319 	if (!(owner = packet_get_str_const(packet, sizeof(t_client_cdkey2), MAX_OWNER_STR))) {
1320 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad CDKEY2 packet (missing or too long owner)", conn_get_socket(c));
1321 	    return -1;
1322 	}
1323 
1324 	conn_set_owner(c, owner);
1325 
1326 	if ((rpacket = packet_create(packet_class_bnet))) {
1327 	    packet_set_size(rpacket, sizeof(t_server_cdkeyreply2));
1328 	    packet_set_type(rpacket, SERVER_CDKEYREPLY2);
1329 	    bn_int_set(&rpacket->u.server_cdkeyreply2.message, SERVER_CDKEYREPLY2_MESSAGE_OK);
1330 	    packet_append_string(rpacket, owner);
1331 	    conn_push_outqueue(c, rpacket);
1332 	    packet_del_ref(rpacket);
1333 	}
1334     }
1335 
1336     return 0;
1337 }
1338 
_client_cdkey3(t_connection * c,t_packet const * const packet)1339 static int _client_cdkey3(t_connection * c, t_packet const *const packet)
1340 {
1341     t_packet *rpacket;
1342 
1343     if (packet_get_size(packet) < sizeof(t_client_cdkey3)) {
1344 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad CDKEY3 packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_cdkey2), packet_get_size(packet));
1345 	return -1;
1346     }
1347 
1348     {
1349 	char const *owner;
1350 
1351 	if (!(owner = packet_get_str_const(packet, sizeof(t_client_cdkey3), MAX_OWNER_STR))) {
1352 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad CDKEY3 packet (missing or too long owner)", conn_get_socket(c));
1353 	    return -1;
1354 	}
1355 
1356 	conn_set_owner(c, owner);
1357 
1358 	if ((rpacket = packet_create(packet_class_bnet))) {
1359 	    packet_set_size(rpacket, sizeof(t_server_cdkeyreply3));
1360 	    packet_set_type(rpacket, SERVER_CDKEYREPLY3);
1361 	    bn_int_set(&rpacket->u.server_cdkeyreply3.message, SERVER_CDKEYREPLY3_MESSAGE_OK);
1362 	    packet_append_string(rpacket, "");	/* FIXME: owner, message, ??? */
1363 	    conn_push_outqueue(c, rpacket);
1364 	    packet_del_ref(rpacket);
1365 	}
1366     }
1367 
1368     return 0;
1369 }
1370 
_client_udpok(t_connection * c,t_packet const * const packet)1371 static int _client_udpok(t_connection * c, t_packet const *const packet)
1372 {
1373     if (packet_get_size(packet) < sizeof(t_client_udpok)) {
1374 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad UDPOK packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_udpok), packet_get_size(packet));
1375 	return -1;
1376     }
1377     /* we could check the contents but there really isn't any point */
1378     conn_set_udpok(c);
1379 
1380     return 0;
1381 }
1382 
_client_fileinforeq(t_connection * c,t_packet const * const packet)1383 static int _client_fileinforeq(t_connection * c, t_packet const *const packet)
1384 {
1385     t_packet *rpacket;
1386 
1387     if (packet_get_size(packet) < sizeof(t_client_fileinforeq)) {
1388 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad FILEINFOREQ packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_fileinforeq), packet_get_size(packet));
1389 	return -1;
1390     }
1391 
1392     {
1393 	char const *tosfile;
1394 
1395 	if (!(tosfile = packet_get_str_const(packet, sizeof(t_client_fileinforeq), MAX_FILENAME_STR))) {
1396 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad FILEINFOREQ packet (missing or too long tosfile)", conn_get_socket(c));
1397 	    return -1;
1398 	}
1399 	eventlog(eventlog_level_info, __FUNCTION__, "[%d] TOS requested: \"%s\" - type = 0x%02x", conn_get_socket(c), tosfile, bn_int_get(packet->u.client_fileinforeq.type));
1400 
1401 	/* TODO: if type is TOSFILE make bnetd to send default tosfile if selected is not found */
1402 	if ((rpacket = packet_create(packet_class_bnet))) {
1403 	    packet_set_size(rpacket, sizeof(t_server_fileinforeply));
1404 	    packet_set_type(rpacket, SERVER_FILEINFOREPLY);
1405 	    bn_int_set(&rpacket->u.server_fileinforeply.type, bn_int_get(packet->u.client_fileinforeq.type));
1406 	    bn_int_set(&rpacket->u.server_fileinforeply.unknown2, bn_int_get(packet->u.client_fileinforeq.unknown2));
1407 	    /* Note from Sherpya:
1408 	     * timestamp -> 0x852b7d00 - 0x01c0e863 b.net send this (bn_int),
1409 	     * I suppose is not a long
1410 	     * if bnserver-D2DV is bad diablo 2 crashes
1411 	     * timestamp doesn't work correctly and starcraft
1412 	     * needs name in client locale or displays hostname
1413 	     */
1414 	    file_to_mod_time(tosfile, &rpacket->u.server_fileinforeply.timestamp);
1415 	    packet_append_string(rpacket, tosfile);
1416 	    conn_push_outqueue(c, rpacket);
1417 	    packet_del_ref(rpacket);
1418 	}
1419     }
1420 
1421     return 0;
1422 }
1423 
_attribute_req(t_account * reqacc,t_account * myacc,const char * key)1424 static const char *_attribute_req(t_account * reqacc, t_account * myacc, const char *key)
1425 {
1426     const char *result = "";
1427     const char *tval;
1428 
1429     if (!reqacc)
1430 	goto out;
1431     if (reqacc != myacc && !strncasecmp(key, "BNET", 4))
1432 	goto out;
1433 
1434     tval = account_get_strattr(reqacc, key);
1435     if (tval)
1436 	result = tval;
1437 
1438   out:
1439     return result;
1440 }
1441 
_client_statsreq(t_connection * c,t_packet const * const packet)1442 static int _client_statsreq(t_connection * c, t_packet const *const packet)
1443 {
1444     t_packet *rpacket;
1445     char const *name;
1446     char const *key;
1447     unsigned int name_count;
1448     unsigned int key_count;
1449     unsigned int i, j;
1450     unsigned int name_off;
1451     unsigned int keys_off;
1452     unsigned int key_off;
1453     t_account *reqacc, *myacc;
1454 
1455     if (packet_get_size(packet) < sizeof(t_client_statsreq)) {
1456 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad STATSREQ packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_statsreq), packet_get_size(packet));
1457 	return -1;
1458     }
1459 
1460     name_count = bn_int_get(packet->u.client_statsreq.name_count);
1461     key_count = bn_int_get(packet->u.client_statsreq.key_count);
1462 
1463     for (i = 0, name_off = sizeof(t_client_statsreq); i < name_count && (name = packet_get_str_const(packet, name_off, UNCHECKED_NAME_STR)); i++, name_off += strlen(name) + 1);
1464 
1465     if (i < name_count) {
1466 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad STATSREQ packet (only %u names of %u)", conn_get_socket(c), i, name_count);
1467 	return -1;
1468     }
1469     keys_off = name_off;
1470 
1471     if (!(rpacket = packet_create(packet_class_bnet)))
1472 	return -1;
1473 
1474     packet_set_size(rpacket, sizeof(t_server_statsreply));
1475     packet_set_type(rpacket, SERVER_STATSREPLY);
1476     bn_int_set(&rpacket->u.server_statsreply.name_count, name_count);
1477     bn_int_set(&rpacket->u.server_statsreply.key_count, key_count);
1478     bn_int_set(&rpacket->u.server_statsreply.requestid, bn_int_get(packet->u.client_statsreq.requestid));
1479 
1480     myacc = conn_get_account(c);
1481 
1482     for (i = 0, name_off = sizeof(t_client_statsreq); i < name_count && (name = packet_get_str_const(packet, name_off, UNCHECKED_NAME_STR)); i++, name_off += strlen(name) + 1) {
1483 	reqacc = accountlist_find_account(name);
1484 	if (!reqacc)
1485 	    reqacc = myacc;
1486 
1487 	for (j = 0, key_off = keys_off; j < key_count && (key = packet_get_str_const(packet, key_off, MAX_ATTRKEY_STR)); j++, key_off += strlen(key) + 1) {
1488 	    if (*key == '\0')
1489 		continue;
1490 	    packet_append_string(rpacket, _attribute_req(reqacc, myacc, key));
1491 	}
1492     }
1493 
1494     conn_push_outqueue(c, rpacket);
1495     packet_del_ref(rpacket);
1496 
1497     return 0;
1498 }
1499 
_client_loginreq1(t_connection * c,t_packet const * const packet)1500 static int _client_loginreq1(t_connection * c, t_packet const *const packet)
1501 {
1502     t_packet *rpacket;
1503 
1504     if (packet_get_size(packet) < sizeof(t_client_loginreq1)) {
1505 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad LOGINREQ1 packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_loginreq1), packet_get_size(packet));
1506 	return -1;
1507     }
1508 
1509     {
1510 	char const *username;
1511 	t_account *account;
1512 
1513 	if (!(username = packet_get_str_const(packet, sizeof(t_client_loginreq1), USER_NAME_MAX))) {
1514 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad LOGINREQ1 (missing or too long username)", conn_get_socket(c));
1515 	    return -1;
1516 	}
1517 
1518 	if (!(rpacket = packet_create(packet_class_bnet)))
1519 	    return -1;
1520 	packet_set_size(rpacket, sizeof(t_server_loginreply1));
1521 	packet_set_type(rpacket, SERVER_LOGINREPLY1);
1522 
1523 	// too many logins? [added by NonReal]
1524 	if (prefs_get_max_concurrent_logins() > 0) {
1525 	    if (prefs_get_max_concurrent_logins() <= connlist_login_get_length()) {
1526 		eventlog(eventlog_level_error, __FUNCTION__, "[%d] login denied, too many concurrent logins. max: %d. current: %d.", conn_get_socket(c), prefs_get_max_concurrent_logins(), connlist_login_get_length());
1527 		bn_int_set(&rpacket->u.server_loginreply1.message, SERVER_LOGINREPLY1_MESSAGE_FAIL);
1528 		return -1;
1529 	    }
1530 	}
1531 
1532 	/* fail if no account */
1533 	if (!(account = accountlist_find_account(username))) {
1534 	    eventlog(eventlog_level_info, __FUNCTION__, "[%d] login for \"%s\" refused (no such account)", conn_get_socket(c), username);
1535 	    bn_int_set(&rpacket->u.server_loginreply1.message, SERVER_LOGINREPLY1_MESSAGE_FAIL);
1536 	} else
1537 	    /* already logged in */
1538 	if (connlist_find_connection_by_account(account) && prefs_get_kick_old_login() == 0) {
1539 	    eventlog(eventlog_level_info, __FUNCTION__, "[%d] login for \"%s\" refused (already logged in)", conn_get_socket(c), username);
1540 	    bn_int_set(&rpacket->u.server_loginreply1.message, SERVER_LOGINREPLY1_MESSAGE_FAIL);
1541 	} else if (account_get_auth_bnetlogin(account) == 0) {	/* default to true */
1542 	    eventlog(eventlog_level_info, __FUNCTION__, "[%d] login for \"%s\" refused (no bnet access)", conn_get_socket(c), username);
1543 	    bn_int_set(&rpacket->u.server_loginreply1.message, SERVER_LOGINREPLY1_MESSAGE_FAIL);
1544 	} else if (account_get_auth_lock(account) == 1) {	/* default to false */
1545 	    eventlog(eventlog_level_info, __FUNCTION__, "[%d] login for \"%s\" refused (this account is locked)", conn_get_socket(c), username);
1546 	    bn_int_set(&rpacket->u.server_loginreply1.message, SERVER_LOGINREPLY1_MESSAGE_FAIL);
1547 	} else if (conn_get_sessionkey(c) != bn_int_get(packet->u.client_loginreq1.sessionkey)) {
1548 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] login for \"%s\" refused (expected session key 0x%08x, got 0x%08x)", conn_get_socket(c), username, conn_get_sessionkey(c), bn_int_get(packet->u.client_loginreq1.sessionkey));
1549 	    bn_int_set(&rpacket->u.server_loginreply1.message, SERVER_LOGINREPLY1_MESSAGE_FAIL);
1550 	} else {
1551 	    struct {
1552 		bn_int ticks;
1553 		bn_int sessionkey;
1554 		bn_int passhash1[5];
1555 	    } temp;
1556 	    char const *oldstrhash1;
1557 	    t_hash oldpasshash1;
1558 	    t_hash oldpasshash2;
1559 	    t_hash trypasshash2;
1560 
1561 	    if ((oldstrhash1 = account_get_pass(account))) {
1562 		bn_int_set(&temp.ticks, bn_int_get(packet->u.client_loginreq1.ticks));
1563 		bn_int_set(&temp.sessionkey, bn_int_get(packet->u.client_loginreq1.sessionkey));
1564 		if (hash_set_str(&oldpasshash1, oldstrhash1) < 0) {
1565 		    eventlog(eventlog_level_info, __FUNCTION__, "[%d] login for \"%s\" refused (corrupted passhash1?)", conn_get_socket(c), username);
1566 		    bn_int_set(&rpacket->u.server_loginreply1.message, SERVER_LOGINREPLY1_MESSAGE_FAIL);
1567 		} else {
1568 		    hash_to_bnhash((t_hash const *) &oldpasshash1, temp.passhash1);	/* avoid warning */
1569 
1570 		    bnet_hash(&oldpasshash2, sizeof(temp), &temp);	/* do the double hash */
1571 		    bnhash_to_hash(packet->u.client_loginreq1.password_hash2, &trypasshash2);
1572 
1573 		    if (hash_eq(trypasshash2, oldpasshash2) == 1) {
1574 			conn_login(c, account, username);
1575 			eventlog(eventlog_level_info, __FUNCTION__, "[%d] \"%s\" logged in (correct password)", conn_get_socket(c), username);
1576 			bn_int_set(&rpacket->u.server_loginreply1.message, SERVER_LOGINREPLY1_MESSAGE_SUCCESS);
1577 #ifdef WIN32_GUI
1578 			guiOnUpdateUserList();
1579 #endif
1580 		    } else {
1581 			eventlog(eventlog_level_info, __FUNCTION__, "[%d] login for \"%s\" refused (wrong password)", conn_get_socket(c), username);
1582 			conn_increment_passfail_count(c);
1583 			bn_int_set(&rpacket->u.server_loginreply1.message, SERVER_LOGINREPLY1_MESSAGE_FAIL);
1584 		    }
1585 		}
1586 	    } else {
1587 		conn_login(c, account, username);
1588 		eventlog(eventlog_level_info, __FUNCTION__, "[%d] \"%s\" logged in (no password)", conn_get_socket(c), username);
1589 		bn_int_set(&rpacket->u.server_loginreply1.message, SERVER_LOGINREPLY1_MESSAGE_SUCCESS);
1590 #ifdef WIN32_GUI
1591 		guiOnUpdateUserList();
1592 #endif
1593 	    }
1594 	}
1595 	conn_push_outqueue(c, rpacket);
1596 	packet_del_ref(rpacket);
1597     }
1598 
1599     return 0;
1600 }
1601 
client_init_email(t_connection * c,t_account * account)1602 void client_init_email(t_connection * c, t_account * account)
1603 {
1604     t_packet *packet;
1605     char const *email;
1606 
1607     if (!c || !account)
1608 	return;
1609     if (!(email = account_get_email(account))) {
1610 	if ((packet = packet_create(packet_class_bnet))) {
1611 	    packet_set_size(packet, sizeof(t_server_setemailreq));
1612 	    packet_set_type(packet, SERVER_SETEMAILREQ);
1613 	    conn_push_outqueue(c, packet);
1614 	    packet_del_ref(packet);
1615 	}
1616     }
1617     return;
1618 }
1619 
_client_loginreq2(t_connection * c,t_packet const * const packet)1620 static int _client_loginreq2(t_connection * c, t_packet const *const packet)
1621 {
1622     t_packet *rpacket;
1623     int success = 0;
1624 
1625     if (packet_get_size(packet) < sizeof(t_client_loginreq2)) {
1626 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad LOGINREQ2 packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_loginreq2), packet_get_size(packet));
1627 	return -1;
1628     }
1629 
1630     {
1631 	char const *username;
1632 	t_account *account;
1633 
1634 	if (!(username = packet_get_str_const(packet, sizeof(t_client_loginreq2), USER_NAME_MAX))) {
1635 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad LOGINREQ2 (missing or too long username)", conn_get_socket(c));
1636 	    return -1;
1637 	}
1638 
1639 	if (!(rpacket = packet_create(packet_class_bnet)))
1640 	    return -1;
1641 	packet_set_size(rpacket, sizeof(t_server_loginreply2));
1642 	packet_set_type(rpacket, SERVER_LOGINREPLY2);
1643 
1644 	// too many logins? [added by NonReal]
1645 	if (prefs_get_max_concurrent_logins() > 0) {
1646 	    if (prefs_get_max_concurrent_logins() <= connlist_login_get_length()) {
1647 		eventlog(eventlog_level_error, __FUNCTION__, "[%d] login denied, too many concurrent logins. max: %d. current: %d.", conn_get_socket(c), prefs_get_max_concurrent_logins(), connlist_login_get_length());
1648 		bn_int_set(&rpacket->u.server_loginreply2.message, SERVER_LOGINREPLY2_MESSAGE_BADPASS);
1649 		return -1;
1650 	    }
1651 	}
1652 
1653 	/* fail if no account */
1654 	if (!(account = accountlist_find_account(username))) {
1655 	    eventlog(eventlog_level_info, __FUNCTION__, "[%d] login for \"%s\" refused (no such account)", conn_get_socket(c), username);
1656 	    bn_int_set(&rpacket->u.server_loginreply2.message, SERVER_LOGINREPLY2_MESSAGE_NONEXIST);
1657 	}
1658 	/* already logged in */
1659 	else if (connlist_find_connection_by_account(account) && prefs_get_kick_old_login() == 0) {
1660 	    eventlog(eventlog_level_info, __FUNCTION__, "[%d] login for \"%s\" refused (already logged in)", conn_get_socket(c), username);
1661 	    bn_int_set(&rpacket->u.server_loginreply2.message, SERVER_LOGINREPLY2_MESSAGE_BADPASS);
1662 	} else if (account_get_auth_bnetlogin(account) == 0) {	/* default to true */
1663 	    eventlog(eventlog_level_info, __FUNCTION__, "[%d] login for \"%s\" refused (no bnet access)", conn_get_socket(c), username);
1664 	    bn_int_set(&rpacket->u.server_loginreply2.message, SERVER_LOGINREPLY2_MESSAGE_BADPASS);
1665 	} else if (account_get_auth_lock(account) == 1) {	/* default to false */
1666 	    eventlog(eventlog_level_info, __FUNCTION__, "[%d] login for \"%s\" refused (this account is locked)", conn_get_socket(c), username);
1667 	    bn_int_set(&rpacket->u.server_loginreply1.message, SERVER_LOGINREPLY2_MESSAGE_BADPASS);
1668 	} else if (conn_get_sessionkey(c) != bn_int_get(packet->u.client_loginreq2.sessionkey)) {
1669 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] login for \"%s\" refused (expected session key 0x%08x, got 0x%08x)", conn_get_socket(c), username, conn_get_sessionkey(c), bn_int_get(packet->u.client_loginreq2.sessionkey));
1670 	    bn_int_set(&rpacket->u.server_loginreply2.message, SERVER_LOGINREPLY2_MESSAGE_BADPASS);
1671 	} else {
1672 	    struct {
1673 		bn_int ticks;
1674 		bn_int sessionkey;
1675 		bn_int passhash1[5];
1676 	    } temp;
1677 	    char const *oldstrhash1;
1678 	    t_hash oldpasshash1;
1679 	    t_hash oldpasshash2;
1680 	    t_hash trypasshash2;
1681 
1682 	    if ((oldstrhash1 = account_get_pass(account))) {
1683 		bn_int_set(&temp.ticks, bn_int_get(packet->u.client_loginreq2.ticks));
1684 		bn_int_set(&temp.sessionkey, bn_int_get(packet->u.client_loginreq2.sessionkey));
1685 		if (hash_set_str(&oldpasshash1, oldstrhash1) < 0) {
1686 		    eventlog(eventlog_level_info, __FUNCTION__, "[%d] login for \"%s\" refused (corrupted passhash1?)", conn_get_socket(c), username);
1687 		    bn_int_set(&rpacket->u.server_loginreply2.message, SERVER_LOGINREPLY2_MESSAGE_BADPASS);
1688 		} else {
1689 		    hash_to_bnhash((t_hash const *) &oldpasshash1, temp.passhash1);	/* avoid warning */
1690 
1691 		    bnet_hash(&oldpasshash2, sizeof(temp), &temp);	/* do the double hash */
1692 		    bnhash_to_hash(packet->u.client_loginreq2.password_hash2, &trypasshash2);
1693 
1694 		    if (hash_eq(trypasshash2, oldpasshash2) == 1) {
1695 			conn_login(c, account, username);
1696 			eventlog(eventlog_level_info, __FUNCTION__, "[%d] \"%s\" logged in (correct password)", conn_get_socket(c), username);
1697 			bn_int_set(&rpacket->u.server_loginreply2.message, SERVER_LOGINREPLY2_MESSAGE_SUCCESS);
1698 			success = 1;
1699 		    } else {
1700 			eventlog(eventlog_level_info, __FUNCTION__, "[%d] login for \"%s\" refused (wrong password)", conn_get_socket(c), username);
1701 			conn_increment_passfail_count(c);
1702 			bn_int_set(&rpacket->u.server_loginreply2.message, SERVER_LOGINREPLY2_MESSAGE_BADPASS);
1703 		    }
1704 		}
1705 	    } else {
1706 		conn_login(c, account, username);
1707 		eventlog(eventlog_level_info, __FUNCTION__, "[%d] \"%s\" logged in (no password)", conn_get_socket(c), username);
1708 		bn_int_set(&rpacket->u.server_loginreply2.message, SERVER_LOGINREPLY2_MESSAGE_SUCCESS);
1709 		success = 1;
1710 	    }
1711 	}
1712 	if (success && account) {
1713 #ifdef WIN32_GUI
1714 	    guiOnUpdateUserList();
1715 #endif
1716 	    client_init_email(c, account);
1717 	}
1718 
1719 	conn_push_outqueue(c, rpacket);
1720 	packet_del_ref(rpacket);
1721     }
1722 
1723     return 0;
1724 }
1725 
_client_loginreqw3(t_connection * c,t_packet const * const packet)1726 static int _client_loginreqw3(t_connection * c, t_packet const *const packet)
1727 {
1728     t_packet *rpacket;
1729 
1730     if (packet_get_size(packet) < sizeof(t_client_loginreq_w3)) {
1731 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad CLIENT_LOGINREQ_W3 packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_loginreq_w3), packet_get_size(packet));
1732 	return -1;
1733     }
1734 
1735     {
1736 	char const *username;
1737 	t_account *account;
1738 	int i;
1739 
1740 	if (!(username = packet_get_str_const(packet, sizeof(t_client_loginreq_w3), USER_NAME_MAX))) {
1741 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad CLIENT_LOGINREQ_W3 (missing or too long username)", conn_get_socket(c));
1742 	    return -1;
1743 	}
1744 
1745 	if (!(rpacket = packet_create(packet_class_bnet)))
1746 	    return -1;
1747 	packet_set_size(rpacket, sizeof(t_server_loginreply_w3));
1748 	packet_set_type(rpacket, SERVER_LOGINREPLY_W3);
1749 
1750 	for (i = 0; i < 16; i++)
1751 	    bn_int_set(&rpacket->u.server_loginreply_w3.unknown[i], 0);
1752 
1753 	{
1754 	    /* too many logins? */
1755 	    if (prefs_get_max_concurrent_logins() > 0 && prefs_get_max_concurrent_logins() <= connlist_login_get_length()) {
1756 		eventlog(eventlog_level_error, __FUNCTION__, "[%d] login denied, too many concurrent logins. max: %d. current: %d.", conn_get_socket(c), prefs_get_max_concurrent_logins(), connlist_login_get_length());
1757 		bn_int_set(&rpacket->u.server_loginreply_w3.message, SERVER_LOGINREPLY_W3_MESSAGE_BADACCT);
1758 	    } else
1759 		/* fail if no account */
1760 	    if (!(account = accountlist_find_account(username))) {
1761 		eventlog(eventlog_level_info, __FUNCTION__, "[%d] (W3) login for \"%s\" refused (no such account)", conn_get_socket(c), username);
1762 		bn_int_set(&rpacket->u.server_loginreply_w3.message, SERVER_LOGINREPLY_W3_MESSAGE_BADACCT);
1763 	    } else
1764 		/* already logged in */
1765 	    if (connlist_find_connection_by_account(account) && prefs_get_kick_old_login() == 0) {
1766 		eventlog(eventlog_level_info, __FUNCTION__, "[%d] (W3) login for \"%s\" refused (already logged in)", conn_get_socket(c), username);
1767 		bn_int_set(&rpacket->u.server_loginreply_w3.message, SERVER_LOGINREPLY_W3_MESSAGE_ALREADY);
1768 	    } else if (account_get_auth_bnetlogin(account) == 0) {	/* default to true */
1769 		eventlog(eventlog_level_info, __FUNCTION__, "[%d] (W3) login for \"%s\" refused (no bnet access)", conn_get_socket(c), username);
1770 		bn_int_set(&rpacket->u.server_loginreply_w3.message, SERVER_LOGINREPLY_W3_MESSAGE_BADACCT);
1771 	    } else if (account_get_auth_lock(account) == 1) {	/* default to false */
1772 		eventlog(eventlog_level_info, __FUNCTION__, "[%d] login for \"%s\" refused (this account is locked)", conn_get_socket(c), username);
1773 		bn_int_set(&rpacket->u.server_loginreply1.message, SERVER_LOGINREPLY_W3_MESSAGE_BADACCT);
1774 	    } else {
1775 		eventlog(eventlog_level_info, __FUNCTION__, "[%d] (W3) \"%s\" passed account check", conn_get_socket(c), username);
1776 		conn_set_loggeduser(c, username);
1777 		bn_int_set(&rpacket->u.server_loginreply_w3.message, SERVER_LOGINREPLY_W3_MESSAGE_SUCCESS);
1778 	    }
1779 	}
1780 
1781 	conn_push_outqueue(c, rpacket);
1782 	packet_del_ref(rpacket);
1783 
1784     }
1785 
1786     return 0;
1787 }
1788 
_client_pingreq(t_connection * c,t_packet const * const packet)1789 static int _client_pingreq(t_connection * c, t_packet const *const packet)
1790 {
1791     t_packet *rpacket;
1792 
1793     if (packet_get_size(packet) < sizeof(t_client_pingreq)) {
1794 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad PINGREQ packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_pingreq), packet_get_size(packet));
1795 	return -1;
1796     }
1797 
1798     if ((rpacket = packet_create(packet_class_bnet))) {
1799 	packet_set_size(rpacket, sizeof(t_server_pingreply));
1800 	packet_set_type(rpacket, SERVER_PINGREPLY);
1801 	conn_push_outqueue(c, rpacket);
1802 	packet_del_ref(rpacket);
1803     }
1804 
1805     return 0;
1806 }
1807 
_client_logonproofreq(t_connection * c,t_packet const * const packet)1808 static int _client_logonproofreq(t_connection * c, t_packet const *const packet)
1809 {
1810     t_packet *rpacket;
1811 
1812     if (packet_get_size(packet) < sizeof(t_client_logonproofreq)) {
1813 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad LOGONPROOFREQ packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_logonproofreq), packet_get_size(packet));
1814 	return -1;
1815     }
1816 
1817     {
1818 	char const *username;
1819 	t_account *account;
1820 
1821 	eventlog(eventlog_level_info, __FUNCTION__, "[%d] logon proof requested", conn_get_socket(c));
1822 
1823 	if (!(rpacket = packet_create(packet_class_bnet)))
1824 	    return -1;
1825 	packet_set_size(rpacket, sizeof(t_server_logonproofreply));
1826 	packet_set_type(rpacket, SERVER_LOGONPROOFREPLY);
1827 
1828 	bn_int_set(&rpacket->u.server_logonproofreply.response, SERVER_LOGONPROOFREPLY_RESPONSE_BADPASS);
1829 
1830 	bn_int_set(&rpacket->u.server_logonproofreply.unknown1, SERVER_LOGONPROOFREPLY_UNKNOWN1);
1831 
1832 	bn_short_set(&rpacket->u.server_logonproofreply.port0, (short) 0x0000);
1833 
1834 	bn_int_set(&rpacket->u.server_logonproofreply.unknown2, SERVER_LOGONPROOFREPLY_UNKNOWN2);
1835 
1836 	bn_short_set(&rpacket->u.server_logonproofreply.port1, (short) 0x0000);
1837 
1838 	bn_int_set(&rpacket->u.server_logonproofreply.unknown3, SERVER_LOGONPROOFREPLY_UNKNOWN3);
1839 	bn_int_set(&rpacket->u.server_logonproofreply.unknown4, SERVER_LOGONPROOFREPLY_UNKNOWN4);
1840 
1841 	if (!(username = conn_get_loggeduser(c))) {
1842 	    eventlog(eventlog_level_info, __FUNCTION__, "[%d] (W3) got NULL username, 0x54ff before 0x53ff?", conn_get_socket(c));
1843 	} else if (!(account = accountlist_find_account(username))) {
1844 	    eventlog(eventlog_level_info, __FUNCTION__, "[%d] (W3) login in 0x54ff for \"%s\" refused (no such account)", conn_get_socket(c), username);
1845 	} else {
1846 	    t_hash serverhash;
1847 	    t_hash clienthash;
1848 
1849 	    if (!packet_get_data_const(packet, 4, 20)) {
1850 		eventlog(eventlog_level_error, __FUNCTION__, "[%d] (W3) got bad LOGONPROOFREQ packet (missing hash)", conn_get_socket(c));
1851 		return -1;
1852 	    }
1853 	    // endian fix
1854 	    clienthash[0] = bn_int_get(packet->u.client_logonproofreq.password_hash1[0]);
1855 	    clienthash[1] = bn_int_get(packet->u.client_logonproofreq.password_hash1[1]);
1856 	    clienthash[2] = bn_int_get(packet->u.client_logonproofreq.password_hash1[2]);
1857 	    clienthash[3] = bn_int_get(packet->u.client_logonproofreq.password_hash1[3]);
1858 	    clienthash[4] = bn_int_get(packet->u.client_logonproofreq.password_hash1[4]);
1859 
1860 	    hash_set_str(&serverhash, account_get_pass(account));
1861 	    if (hash_eq(clienthash, serverhash)) {
1862 		conn_login(c, account, username);
1863 		eventlog(eventlog_level_info, __FUNCTION__, "[%d] (W3) \"%s\" logged in (right password)", conn_get_socket(c), username);
1864 		if ((conn_get_versionid(c) >= 0x0000000D) && (account_get_email(account) == NULL))
1865 		    bn_int_set(&rpacket->u.server_logonproofreply.response, SERVER_LOGONPROOFREPLY_RESPONSE_EMAIL);
1866 		else
1867 		    bn_int_set(&rpacket->u.server_logonproofreply.response, SERVER_LOGONPROOFREPLY_RESPONSE_OK);
1868 		// by amadeo updates the userlist
1869 #ifdef WIN32_GUI
1870 		guiOnUpdateUserList();
1871 #endif
1872 	    } else {
1873 		eventlog(eventlog_level_info, __FUNCTION__, "[%d] (W3) got wrong password for \"%s\"", conn_get_socket(c), username);
1874 		conn_increment_passfail_count(c);
1875 	    }
1876 	}
1877 	conn_push_outqueue(c, rpacket);
1878 	packet_del_ref(rpacket);
1879     }
1880     clan_send_status_window(c);
1881 
1882     return 0;
1883 }
1884 
_client_changegameport(t_connection * c,t_packet const * const packet)1885 static int _client_changegameport(t_connection * c, t_packet const *const packet)
1886 {
1887     if (packet_get_size(packet) < sizeof(t_client_changegameport)) {
1888 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad changegameport packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_changegameport), packet_get_size(packet));
1889 	return -1;
1890     }
1891     {
1892 	unsigned short port = bn_short_get(packet->u.client_changegameport.port);
1893 	if (port < 1024) {
1894 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] invalid port in changegameport packet: %d", conn_get_socket(c), (int) port);
1895 	    return -1;
1896 	}
1897 
1898 	conn_set_game_port(c, port);
1899     }
1900 
1901     return 0;
1902 }
1903 
_client_friendslistreq(t_connection * c,t_packet const * const packet)1904 static int _client_friendslistreq(t_connection * c, t_packet const *const packet)
1905 {
1906     t_packet *rpacket;
1907 
1908     if (packet_get_size(packet) < sizeof(t_client_friendslistreq)) {
1909 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad FRIENDSLISTREQ packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_friendslistreq), packet_get_size(packet));
1910 	return -1;
1911     }
1912     {
1913 	int friend;
1914 	t_list *flist;
1915 	t_friend *fr;
1916 	t_account *account = conn_get_account(c);
1917 	int i;
1918 	int n = account_get_friendcount(account);
1919 	int friendcount = 0;
1920 	t_server_friendslistreply_status status;
1921 	t_connection *dest_c;
1922 	t_game *game;
1923 	t_channel *channel;
1924 	char stat;
1925 
1926 	if (!(rpacket = packet_create(packet_class_bnet)))
1927 	    return -1;
1928 
1929 	packet_set_size(rpacket, sizeof(t_server_friendslistreply));
1930 	packet_set_type(rpacket, SERVER_FRIENDSLISTREPLY);
1931 
1932 	if ((flist = account_get_friends(account)) == NULL)
1933 	    return -1;
1934 
1935 	for (i = 0; i < n; i++) {
1936 	    friend = account_get_friend(account, i);
1937 	    if ((fr = friendlist_find_uid(flist, friend)) == NULL)
1938 		continue;
1939 	    packet_append_string(rpacket, account_get_name(friend_get_account(fr)));
1940 	    game = NULL;
1941 	    channel = NULL;
1942 
1943 	    if (!(dest_c = connlist_find_connection_by_uid(friend))) {
1944 		bn_byte_set(&status.location, FRIENDSTATUS_OFFLINE);
1945 		bn_byte_set(&status.status, 0);
1946 		bn_int_set(&status.clienttag, 0);
1947 	    } else {
1948 		bn_int_set(&status.clienttag, conn_get_clienttag(dest_c));
1949 		stat = 0;
1950 		if ((friend_get_mutual(fr)))
1951 		    stat |= FRIEND_TYPE_MUTUAL;
1952 		if ((conn_get_dndstr(dest_c)))
1953 		    stat |= FRIEND_TYPE_DND;
1954 		if ((conn_get_awaystr(dest_c)))
1955 		    stat |= FRIEND_TYPE_AWAY;
1956 		bn_byte_set(&status.status, stat);
1957 		if ((game = conn_get_game(dest_c))) {
1958 		    if (game_get_flag(game) != game_flag_private)
1959 			bn_byte_set(&status.location, FRIENDSTATUS_PUBLIC_GAME);
1960 		    else
1961 			bn_byte_set(&status.location, FRIENDSTATUS_PRIVATE_GAME);
1962 		} else if ((channel = conn_get_channel(dest_c))) {
1963 		    bn_byte_set(&status.location, FRIENDSTATUS_CHAT);
1964 		} else {
1965 		    bn_byte_set(&status.location, FRIENDSTATUS_ONLINE);
1966 		}
1967 	    }
1968 
1969 	    packet_append_data(rpacket, &status, sizeof(status));
1970 
1971 	    if (game)
1972 		packet_append_string(rpacket, game_get_name(game));
1973 	    else if (channel)
1974 		packet_append_string(rpacket, channel_get_name(channel));
1975 	    else
1976 		packet_append_string(rpacket, "");
1977 
1978 	    friendcount++;
1979 	}
1980 
1981 	bn_byte_set(&rpacket->u.server_friendslistreply.friendcount, friendcount);
1982 
1983 	conn_push_outqueue(c, rpacket);
1984 	packet_del_ref(rpacket);
1985     }
1986 
1987     return 0;
1988 }
1989 
_client_friendinforeq(t_connection * c,t_packet const * const packet)1990 static int _client_friendinforeq(t_connection * c, t_packet const *const packet)
1991 {
1992     t_packet *rpacket;
1993 
1994     if (packet_get_size(packet) < sizeof(t_client_friendinforeq)) {
1995 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad FRIENDINFOREQ packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_friendinforeq), packet_get_size(packet));
1996 	return -1;
1997     }
1998 
1999     {
2000 	t_connection const *dest_c;
2001 	t_game const *game;
2002 	t_channel const *channel;
2003 	t_account *account = conn_get_account(c);
2004 	int friend;
2005 	t_friend *fr;
2006 	t_list *flist;
2007 	int n = account_get_friendcount(account);
2008 	char type;
2009 
2010 	if (n == 0)
2011 	    return 0;
2012 
2013 	if (bn_byte_get(packet->u.client_friendinforeq.friendnum) > n) {
2014 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] bad friend number in FRIENDINFOREQ packet", conn_get_socket(c));
2015 	    return -1;
2016 	}
2017 
2018 	if (!(rpacket = packet_create(packet_class_bnet)))
2019 	    return -1;
2020 
2021 	packet_set_size(rpacket, sizeof(t_server_friendinforeply));
2022 	packet_set_type(rpacket, SERVER_FRIENDINFOREPLY);
2023 
2024 	friend = account_get_friend(account, bn_byte_get(packet->u.client_friendinforeq.friendnum));
2025 	if (friend < 0) {
2026 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] friend number %d not found", conn_get_socket(c), (int) bn_byte_get(packet->u.client_friendinforeq.friendnum));
2027 	    return -1;
2028 	}
2029 
2030 	bn_byte_set(&rpacket->u.server_friendinforeply.friendnum, bn_byte_get(packet->u.client_friendinforeq.friendnum));
2031 
2032 	flist = account_get_friends(account);
2033 	fr = friendlist_find_uid(flist, friend);
2034 
2035 	if (fr == NULL || (dest_c = connlist_find_connection_by_account(friend_get_account(fr))) == NULL) {
2036 	    bn_byte_set(&rpacket->u.server_friendinforeply.type, FRIEND_TYPE_NON_MUTUAL);
2037 	    bn_byte_set(&rpacket->u.server_friendinforeply.status, FRIENDSTATUS_OFFLINE);
2038 	    bn_int_set(&rpacket->u.server_friendinforeply.clienttag, 0);
2039 	    packet_append_string(rpacket, "");
2040 	    conn_push_outqueue(c, rpacket);
2041 	    packet_del_ref(rpacket);
2042 	    return 0;
2043 	}
2044 
2045 	type = FRIEND_TYPE_NON_MUTUAL;
2046 	if (friend_get_mutual(fr))
2047 	    type |= FRIEND_TYPE_MUTUAL;
2048 	if ((conn_get_dndstr(dest_c)))
2049 	    type |= FRIEND_TYPE_DND;
2050 	if ((conn_get_awaystr(dest_c)))
2051 	    type |= FRIEND_TYPE_AWAY;
2052 	bn_byte_set(&rpacket->u.server_friendinforeply.type, type);
2053 	if ((game = conn_get_game(dest_c))) {
2054 	    if (game_get_flag(game) != game_flag_private)
2055 		bn_byte_set(&rpacket->u.server_friendinforeply.status, FRIENDSTATUS_PUBLIC_GAME);
2056 	    else
2057 		bn_byte_set(&rpacket->u.server_friendinforeply.status, FRIENDSTATUS_PRIVATE_GAME);
2058 	    packet_append_string(rpacket, game_get_name(game));
2059 	} else if ((channel = conn_get_channel(dest_c))) {
2060 	    bn_byte_set(&rpacket->u.server_friendinforeply.status, FRIENDSTATUS_CHAT);
2061 	    packet_append_string(rpacket, channel_get_name(channel));
2062 	} else {
2063 	    bn_byte_set(&rpacket->u.server_friendinforeply.status, FRIENDSTATUS_ONLINE);
2064 	    packet_append_string(rpacket, "");
2065 	}
2066 
2067 	bn_int_set(&rpacket->u.server_friendinforeply.clienttag, conn_get_clienttag(dest_c));
2068 
2069 	conn_push_outqueue(c, rpacket);
2070 	packet_del_ref(rpacket);
2071 
2072     }
2073 
2074     return 0;
2075 }
2076 
_client_atfriendscreen(t_connection * c,t_packet const * const packet)2077 static int _client_atfriendscreen(t_connection * c, t_packet const *const packet)
2078 {
2079     char const *myusername;
2080     char const *fname;
2081     t_connection *dest_c;
2082     unsigned char f_cnt = 0;
2083     t_account *account;
2084     t_packet *rpacket;
2085     char const *vt;
2086     char const *nvt;
2087     t_friend *fr;
2088     t_list *flist;
2089     t_elem *curr;
2090     t_channel *mychannel, *chan;
2091     int publicchan = 1;
2092 
2093     eventlog(eventlog_level_info, __FUNCTION__, "[%d] got CLIENT_ARRANGEDTEAM_FRIENDSCREEN packet", conn_get_socket(c));
2094 
2095     myusername = conn_get_username(c);
2096     eventlog(eventlog_level_trace, "handle_bnet", "[%d] AT - Got Username %s", conn_get_socket(c), myusername);
2097 
2098     if (!(rpacket = packet_create(packet_class_bnet))) {
2099 	eventlog(eventlog_level_error, "handle_bnet", "[%d] AT - can't create friendscreen server packet", conn_get_socket(c));
2100 	return -1;
2101     }
2102 
2103     packet_set_size(rpacket, sizeof(t_server_arrangedteam_friendscreen));
2104     packet_set_type(rpacket, SERVER_ARRANGEDTEAM_FRIENDSCREEN);
2105 
2106 
2107     mychannel = conn_get_channel(c);
2108     if ((mychannel))
2109 	publicchan = channel_get_flags(mychannel) & channel_flags_public;
2110 
2111     vt = versioncheck_get_versiontag(conn_get_versioncheck(c));
2112     flist = account_get_friends(conn_get_account(c));
2113     LIST_TRAVERSE(flist, curr) {
2114 	if (!(fr = elem_get_data(curr))) {
2115 	    eventlog(eventlog_level_error, __FUNCTION__, "found NULL entry in list");
2116 	    continue;
2117 	}
2118 
2119 	account = friend_get_account(fr);
2120 	if (!(dest_c = connlist_find_connection_by_account(account)))
2121 	    continue;		// if user is offline, then continue to next friend
2122 	nvt = versioncheck_get_versiontag(conn_get_versioncheck(dest_c));
2123 	if (vt && nvt && strcmp(vt, nvt))
2124 	    continue;		/* friend is using another game/version */
2125 
2126 	if (friend_get_mutual(fr)) {
2127 	    if (conn_get_dndstr(dest_c))
2128 		continue;	// user is dnd
2129 	    if (conn_get_awaystr(dest_c))
2130 		continue;	// user is away
2131 	    if (conn_get_game(dest_c))
2132 		continue;	// user is some game
2133 	    if (!(chan = conn_get_channel(dest_c)))
2134 		continue;
2135 	    if (!publicchan && (chan == mychannel))
2136 		continue;	// don't list YET if in same private channel
2137 
2138 	    fname = account_get_name(account);
2139 	    eventlog(eventlog_level_trace, "handle_bnet", "AT - Friend: %s is available for a AT Game.", fname);
2140 	    f_cnt++;
2141 	    packet_append_string(rpacket, fname);
2142 	}
2143     }
2144 
2145     if (!publicchan) {		// now list matching users in same private chan
2146 	for (dest_c = channel_get_first(mychannel); dest_c; dest_c = channel_get_next()) {
2147 	    if (dest_c == c)
2148 		continue;	// don'tlist yourself
2149 	    nvt = versioncheck_get_versiontag(conn_get_versioncheck(dest_c));
2150 	    if (vt && nvt && strcmp(vt, nvt))
2151 		continue;	/* user is using another game/version */
2152 	    if (conn_get_dndstr(dest_c))
2153 		continue;	// user is dnd
2154 	    if (conn_get_awaystr(dest_c))
2155 		continue;	// user is away
2156 	    if (!(conn_get_account(dest_c)))
2157 		continue;
2158 	    fname = account_get_name(conn_get_account(dest_c));
2159 	    eventlog(eventlog_level_trace, "handle_bnet", "AT - user in private channel: %s is available for a AT Game.", fname);
2160 	    f_cnt++;
2161 	    packet_append_string(rpacket, fname);
2162 	}
2163     }
2164 
2165     if (!f_cnt)
2166 	eventlog(eventlog_level_info, "handle_bnet", "AT - no friends available for AT game.");
2167     bn_byte_set(&rpacket->u.server_arrangedteam_friendscreen.f_count, f_cnt);
2168     conn_push_outqueue(c, rpacket);
2169 
2170     packet_del_ref(rpacket);
2171 
2172     return 0;
2173 }
2174 
_client_atinvitefriend(t_connection * c,t_packet const * const packet)2175 static int _client_atinvitefriend(t_connection * c, t_packet const *const packet)
2176 {
2177     t_packet *rpacket;
2178     t_clienttag ctag;
2179 
2180     if (packet_get_size(packet) < sizeof(t_client_arrangedteam_invite_friend)) {
2181 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad ARRANGEDTEAM_INVITE_FRIEND packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_arrangedteam_invite_friend), packet_get_size(packet));
2182 	return -1;
2183     }
2184 
2185     ctag = conn_get_clienttag(c);
2186 
2187     {
2188 	int count_to_invite, count, id;
2189 	char const *invited_usernames[8];
2190 	t_account *members[MAX_TEAMSIZE];
2191 	int i, n, offset, teammemcount;
2192 	t_connection *dest_c;
2193 	t_team *team;
2194 	unsigned int teamid;
2195 
2196 	count_to_invite = bn_byte_get(packet->u.client_arrangedteam_invite_friend.numfriends);
2197 	count = bn_int_get(packet->u.client_arrangedteam_invite_friend.count);
2198 	id = bn_int_get(packet->u.client_arrangedteam_invite_friend.id);
2199 	teammemcount = count_to_invite + 1;
2200 
2201 	if ((count_to_invite < 1) || (count_to_invite > 3)) {
2202 	    eventlog(eventlog_level_error, __FUNCTION__, "got invalid number of users to invite to game");
2203 	    return -1;
2204 	}
2205 
2206 	eventlog(eventlog_level_info, __FUNCTION__, "[%d] got ARRANGEDTEAM INVITE packet for %d invitees", conn_get_socket(c), count_to_invite);
2207 
2208 	offset = sizeof(t_client_arrangedteam_invite_friend);
2209 
2210 	for (i = 0; i < count_to_invite; i++) {
2211 	    if (!(invited_usernames[i] = packet_get_str_const(packet, offset, USER_NAME_MAX))) {
2212 		eventlog(eventlog_level_error, "handle_bnet", "Could not get username from invite packet");
2213 		return -1;
2214 	    } else {
2215 		offset += strlen(invited_usernames[i]) + 1;
2216 		eventlog(eventlog_level_debug, "handle_bnet", "Added user %s to invite array.", invited_usernames[i]);
2217 	    }
2218 	}
2219 
2220 	members[0] = conn_get_account(c);
2221 	for (i = 1; i < MAX_TEAMSIZE; i++) {
2222 	    if ((i < teammemcount)) {
2223 		if (!(members[i] = accountlist_find_account(invited_usernames[i - 1]))) {
2224 		    eventlog(eventlog_level_error, __FUNCTION__, "got invitation for non-existant user \"%s\"", invited_usernames[i - 1]);
2225 		    return -1;
2226 		}
2227 	    } else
2228 		members[i] = NULL;
2229 	}
2230 
2231 
2232 	if (!(team = account_find_team_by_accounts(members[0], members, ctag))) {
2233 	    team = create_team(members, ctag);	//no need to free on return -1 because it's allready in teamlist
2234 
2235 	    eventlog(eventlog_level_trace, __FUNCTION__, "this team has never played before, creating new team");
2236 	} else {
2237 	    eventlog(eventlog_level_trace, __FUNCTION__, "this team has allready played before");
2238 	}
2239 
2240 	teamid = team_get_teamid(team);
2241 	account_set_currentatteam(conn_get_account(c), team_get_teamid(team));
2242 
2243 
2244 	//Create the packet to send to each of the users you wanted to invite
2245 	conn_set_channel(c, NULL);
2246 
2247 	for (i = 0; i < teammemcount; i++) {
2248 
2249 	    if (!(dest_c = account_get_conn(team_get_member(team, i))))
2250 		continue;
2251 
2252 	    if ((dest_c == c))
2253 		continue;
2254 
2255 	    if (!(rpacket = packet_create(packet_class_bnet)))
2256 		return -1;
2257 
2258 	    packet_set_size(rpacket, sizeof(t_server_arrangedteam_send_invite));
2259 	    packet_set_type(rpacket, SERVER_ARRANGEDTEAM_SEND_INVITE);
2260 
2261 	    bn_int_set(&rpacket->u.server_arrangedteam_send_invite.count, count);
2262 	    bn_int_set(&rpacket->u.server_arrangedteam_send_invite.id, id);
2263 	    {			/* trans support */
2264 		unsigned short port = conn_get_game_port(c);
2265 		unsigned int addr = conn_get_addr(c);
2266 
2267 		trans_net(conn_get_addr(dest_c), &addr, &port);
2268 
2269 		bn_int_nset(&rpacket->u.server_arrangedteam_send_invite.inviterip, addr);
2270 		bn_short_set(&rpacket->u.server_arrangedteam_send_invite.port, port);
2271 	    }
2272 	    bn_byte_set(&rpacket->u.server_arrangedteam_send_invite.numfriends, count_to_invite);
2273 
2274 	    for (n = 0; n < teammemcount; n++) {
2275 		if (n != i)
2276 		    packet_append_string(rpacket, account_get_name(team_get_member(team, n)));
2277 	    }
2278 
2279 	    //now send packet
2280 	    conn_push_outqueue(dest_c, rpacket);
2281 	    packet_del_ref(rpacket);
2282 
2283 	    account_set_currentatteam(conn_get_account(dest_c), teamid);
2284 	}
2285 
2286 	//now send a ACK to the inviter
2287 	if (!(rpacket = packet_create(packet_class_bnet)))
2288 	    return -1;
2289 	packet_set_size(rpacket, sizeof(t_server_arrangedteam_invite_friend_ack));
2290 	packet_set_type(rpacket, SERVER_ARRANGEDTEAM_INVITE_FRIEND_ACK);
2291 
2292 	bn_int_set(&rpacket->u.server_arrangedteam_invite_friend_ack.count, count);
2293 	bn_int_set(&rpacket->u.server_arrangedteam_invite_friend_ack.id, id);
2294 	bn_int_set(&rpacket->u.server_arrangedteam_invite_friend_ack.timestamp, now);
2295 	bn_byte_set(&rpacket->u.server_arrangedteam_invite_friend_ack.teamsize, count_to_invite + 1);
2296 
2297 	/*
2298 	 * five int's to fill
2299 	 * fill with uid's of all teammembers, including the inviter
2300 	 * and the rest with FFFFFFFF
2301 	 * to be used when sever recieves anongame search
2302 	 * [Omega]
2303 	 */
2304 	for (i = 0; i < 5; i++) {
2305 
2306 	    if (i < teammemcount) {
2307 		bn_int_set(&rpacket->u.server_arrangedteam_invite_friend_ack.info[i], team_get_memberuid(team, i));
2308 	    } else {		/* fill rest with FFFFFFFF */
2309 		bn_int_set(&rpacket->u.server_arrangedteam_invite_friend_ack.info[i], 0xFFFFFFFF);
2310 	    }
2311 	}
2312 
2313 	conn_push_outqueue(c, rpacket);
2314 	packet_del_ref(rpacket);
2315 
2316     }
2317 
2318     return 0;
2319 }
2320 
_client_atacceptdeclineinvite(t_connection * c,t_packet const * const packet)2321 static int _client_atacceptdeclineinvite(t_connection * c, t_packet const *const packet)
2322 {
2323     t_packet *rpacket;
2324     t_clienttag ctag;
2325 
2326     if (packet_get_size(packet) < sizeof(t_client_arrangedteam_accept_decline_invite)) {
2327 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad ARRANGEDTEAM_ACCEPT_DECLINE_INVITE packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_arrangedteam_accept_decline_invite), packet_get_size(packet));
2328 	return -1;
2329     }
2330 
2331     ctag = conn_get_clienttag(c);
2332 
2333     {
2334 	char const *inviter;
2335 	t_connection *dest_c;
2336 
2337 	//if user declined the invitation then
2338 	if (bn_int_get(packet->u.client_arrangedteam_accept_decline_invite.option) == CLIENT_ARRANGEDTEAM_DECLINE) {
2339 	    inviter = packet_get_str_const(packet, sizeof(t_client_arrangedteam_accept_decline_invite), USER_NAME_MAX);
2340 	    dest_c = connlist_find_connection_by_accountname(inviter);
2341 
2342 	    eventlog(eventlog_level_info, "handle_bnet", "%s declined a arranged team game with %s", conn_get_username(c), inviter);
2343 
2344 	    if (!(rpacket = packet_create(packet_class_bnet)))
2345 		return -1;
2346 	    packet_set_size(rpacket, sizeof(t_server_arrangedteam_member_decline));
2347 	    packet_set_type(rpacket, SERVER_ARRANGEDTEAM_MEMBER_DECLINE);
2348 
2349 	    bn_int_set(&rpacket->u.server_arrangedteam_member_decline.count, bn_int_get(packet->u.client_arrangedteam_accept_decline_invite.count));
2350 	    bn_int_set(&rpacket->u.server_arrangedteam_member_decline.action, SERVER_ARRANGEDTEAM_DECLINE);
2351 	    packet_append_string(rpacket, conn_get_username(c));
2352 
2353 	    conn_push_outqueue(dest_c, rpacket);
2354 	    packet_del_ref(rpacket);
2355 	}
2356     }
2357 
2358     return 0;
2359 }
2360 
_client_atacceptinvite(t_connection * c,t_packet const * const packet)2361 static int _client_atacceptinvite(t_connection * c, t_packet const *const packet)
2362 {
2363     // t_packet * rpacket;
2364 
2365     if (packet_get_size(packet) < sizeof(t_client_arrangedteam_accept_invite)) {
2366 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad ARRANGEDTEAM_ACCEPT_INVITE packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_arrangedteam_accept_invite), packet_get_size(packet));
2367 	return -1;
2368     }
2369     /* conn_set_channel(c, "Arranged Teams"); */
2370     return 0;
2371 }
2372 
2373 typedef struct {
2374     t_connection *c;
2375     unsigned lnews;
2376     unsigned fnews;
2377 } t_motd_data;
2378 
_news_cb(time_t date,t_lstr * lstr,void * data)2379 static int _news_cb(time_t date, t_lstr * lstr, void *data)
2380 {
2381     t_packet *rpacket;
2382     t_motd_data *motdd = (t_motd_data *) data;
2383 
2384     if (date < motdd->lnews)
2385 	return -1;		/* exit traversing */
2386 
2387     rpacket = packet_create(packet_class_bnet);
2388     if (!rpacket)
2389 	return -1;
2390 
2391     packet_set_size(rpacket, sizeof(t_server_motd_w3));
2392     packet_set_type(rpacket, SERVER_MOTD_W3);
2393 
2394     bn_byte_set(&rpacket->u.server_motd_w3.msgtype, SERVER_MOTD_W3_MSGTYPE);
2395     bn_int_set(&rpacket->u.server_motd_w3.curr_time, now);
2396 
2397     bn_int_set(&rpacket->u.server_motd_w3.first_news_time, motdd->fnews);
2398     bn_int_set(&rpacket->u.server_motd_w3.timestamp, date);
2399     bn_int_set(&rpacket->u.server_motd_w3.timestamp2, date);
2400 
2401     /* Append news to packet, we used the already cached len in the lstr */
2402     packet_append_lstr(rpacket, lstr);
2403 
2404     /* Send news packet */
2405     conn_push_outqueue(motdd->c, rpacket);
2406     packet_del_ref(rpacket);
2407 
2408     return 0;
2409 }
2410 
_client_motdw3(t_connection * c,t_packet const * const packet)2411 static int _client_motdw3(t_connection * c, t_packet const *const packet)
2412 {
2413     t_packet *rpacket;
2414     char serverinfo[512];
2415     t_clienttag ctag;
2416     t_motd_data motdd;
2417 
2418     if (packet_get_size(packet) < sizeof(t_client_motd_w3)) {
2419 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad CLIENT_MOTD_W3 packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_motd_w3), packet_get_size(packet));
2420 	return -1;
2421     }
2422 
2423     ctag = conn_get_clienttag(c);
2424     /* if in a game, remove user from his game */
2425     if (conn_get_game(c) != NULL)
2426 	conn_set_game(c, NULL, NULL, NULL, game_type_none, 0);
2427 
2428     /* News */
2429     motdd.lnews = bn_int_get(packet->u.client_motd_w3.last_news_time);
2430     motdd.fnews = news_get_firstnews();
2431     motdd.c = c;
2432 
2433     eventlog(eventlog_level_trace, __FUNCTION__, "lastnews() %u news_time %u", news_get_lastnews(), motdd.lnews);
2434     news_traverse(_news_cb, &motdd);
2435 
2436     /* Welcome Message */
2437     rpacket = packet_create(packet_class_bnet);
2438     if (!rpacket)
2439 	return -1;
2440 
2441     packet_set_size(rpacket, sizeof(t_server_motd_w3));
2442     packet_set_type(rpacket, SERVER_MOTD_W3);
2443 
2444     //bn_int_set(&rpacket->u.server_motd_w3.ticks,get_ticks());
2445     bn_byte_set(&rpacket->u.server_motd_w3.msgtype, SERVER_MOTD_W3_MSGTYPE);
2446     bn_int_set(&rpacket->u.server_motd_w3.curr_time, now);
2447     bn_int_set(&rpacket->u.server_motd_w3.first_news_time, motdd.fnews);
2448     bn_int_set(&rpacket->u.server_motd_w3.timestamp, motdd.fnews + 1);
2449     bn_int_set(&rpacket->u.server_motd_w3.timestamp2, SERVER_MOTD_W3_WELCOME);
2450 
2451     sprintf(serverinfo, "Welcome to the " PVPGN_SOFTWARE " Version " PVPGN_VERSION "\r\n\r\nThere are currently %u user(s) in %u games of %s, and %u user(s) playing %u games and chatting in %u channels in %s.\r\n%s", conn_get_user_count_by_clienttag(conn_get_clienttag(c)), game_get_count_by_clienttag(ctag), clienttag_get_title(conn_get_clienttag(c)), connlist_login_get_length(), gamelist_get_length(), channellist_get_length(), prefs_get_servername(),prefs_get_server_info());
2452 
2453     packet_append_string(rpacket, serverinfo);
2454 
2455     conn_push_outqueue(c, rpacket);
2456     packet_del_ref(rpacket);
2457 
2458     return 0;
2459 }
2460 
_client_realmlistreq(t_connection * c,t_packet const * const packet)2461 static int _client_realmlistreq(t_connection * c, t_packet const *const packet)
2462 {
2463     t_packet *rpacket;
2464 
2465     if (packet_get_size(packet) < sizeof(t_client_realmlistreq)) {
2466 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad REALMLISTREQ packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_realmlistreq), packet_get_size(packet));
2467 	return -1;
2468     }
2469 
2470     if ((rpacket = packet_create(packet_class_bnet))) {
2471 	t_elem const *curr;
2472 	t_realm const *realm;
2473 	t_server_realmlistreply_data realmdata;
2474 	unsigned int count;
2475 
2476 	packet_set_size(rpacket, sizeof(t_server_realmlistreply));
2477 	packet_set_type(rpacket, SERVER_REALMLISTREPLY);
2478 	bn_int_set(&rpacket->u.server_realmlistreply.unknown1, SERVER_REALMLISTREPLY_UNKNOWN1);
2479 	count = 0;
2480 	LIST_TRAVERSE_CONST(realmlist(), curr) {
2481 	    realm = elem_get_data(curr);
2482 	    if (!realm_get_active(realm))
2483 		continue;
2484 	    bn_int_set(&realmdata.unknown3, SERVER_REALMLISTREPLY_DATA_UNKNOWN3);
2485 	    bn_int_set(&realmdata.unknown4, SERVER_REALMLISTREPLY_DATA_UNKNOWN4);
2486 	    bn_int_set(&realmdata.unknown5, SERVER_REALMLISTREPLY_DATA_UNKNOWN5);
2487 	    bn_int_set(&realmdata.unknown6, SERVER_REALMLISTREPLY_DATA_UNKNOWN6);
2488 	    bn_int_set(&realmdata.unknown7, SERVER_REALMLISTREPLY_DATA_UNKNOWN7);
2489 	    bn_int_set(&realmdata.unknown8, SERVER_REALMLISTREPLY_DATA_UNKNOWN8);
2490 	    bn_int_set(&realmdata.unknown9, SERVER_REALMLISTREPLY_DATA_UNKNOWN9);
2491 	    packet_append_data(rpacket, &realmdata, sizeof(realmdata));
2492 	    packet_append_string(rpacket, realm_get_name(realm));
2493 	    packet_append_string(rpacket, realm_get_description(realm));
2494 	    count++;
2495 	}
2496 	bn_int_set(&rpacket->u.server_realmlistreply.count, count);
2497 	conn_push_outqueue(c, rpacket);
2498 	packet_del_ref(rpacket);
2499     }
2500 
2501     return 0;
2502 }
2503 
_client_realmlistreq110(t_connection * c,t_packet const * const packet)2504 static int _client_realmlistreq110(t_connection * c, t_packet const *const packet)
2505 {
2506     t_packet *rpacket;
2507 
2508     if (packet_get_size(packet) < sizeof(t_client_realmlistreq_110)) {
2509 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad REALMLISTREQ_110 packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_realmlistreq), packet_get_size(packet));
2510 	return -1;
2511     }
2512 
2513     if ((rpacket = packet_create(packet_class_bnet))) {
2514 	t_elem const *curr;
2515 	t_realm const *realm;
2516 	t_server_realmlistreply_110_data realmdata;
2517 	unsigned int count;
2518 
2519 	packet_set_size(rpacket, sizeof(t_server_realmlistreply_110));
2520 	packet_set_type(rpacket, SERVER_REALMLISTREPLY_110);
2521 	bn_int_set(&rpacket->u.server_realmlistreply_110.unknown1, SERVER_REALMLISTREPLY_110_UNKNOWN1);
2522 	count = 0;
2523 	LIST_TRAVERSE_CONST(realmlist(), curr) {
2524 	    realm = elem_get_data(curr);
2525 	    if (!realm_get_active(realm))
2526 		continue;
2527 	    bn_int_set(&realmdata.unknown1, SERVER_REALMLISTREPLY_110_DATA_UNKNOWN1);
2528 	    packet_append_data(rpacket, &realmdata, sizeof(realmdata));
2529 	    packet_append_string(rpacket, realm_get_name(realm));
2530 	    packet_append_string(rpacket, realm_get_description(realm));
2531 	    count++;
2532 	}
2533 	bn_int_set(&rpacket->u.server_realmlistreply_110.count, count);
2534 	conn_push_outqueue(c, rpacket);
2535 	packet_del_ref(rpacket);
2536     }
2537 
2538     return 0;
2539 }
2540 
_client_claninforeq(t_connection * c,t_packet const * const packet)2541 static int _client_claninforeq(t_connection * c, t_packet const *const packet)
2542 {
2543     t_packet *rpacket;
2544     int count;
2545     char const *username;
2546     t_account *account;
2547     t_clanmember *clanmember;
2548     t_clan *clan;
2549     int clantag1;
2550     int clantag2;
2551 
2552     if (packet_get_size(packet) < sizeof(t_client_claninforeq)) {
2553 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad CLANINFOREQ packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_claninforeq), packet_get_size(packet));
2554 	return -1;
2555     }
2556 
2557     count = bn_int_get(packet->u.client_claninforeq.count);
2558     clantag1 = bn_int_get(packet->u.client_claninforeq.clantag);
2559     clan = NULL;
2560 
2561     if (!(username = packet_get_str_const(packet, sizeof(t_client_claninforeq), USER_NAME_MAX))) {
2562 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad CLANINFOREQ (missing or too long username)", conn_get_socket(c));
2563 	return -1;
2564     }
2565 
2566     if (!(account = accountlist_find_account(username))) {
2567 	eventlog(eventlog_level_error, __FUNCTION__, "requested claninfo for non-existant account");
2568 	return -1;
2569     }
2570 
2571     if ((clanmember = account_get_clanmember(account)) && (clan = clanmember_get_clan(clanmember)))
2572 	clantag2 = clan_get_clantag(clan);
2573     else
2574 	clantag2 = 0;
2575 
2576     if ((rpacket = packet_create(packet_class_bnet))) {
2577 	packet_set_size(rpacket, sizeof(t_server_claninforeply));
2578 	packet_set_type(rpacket, SERVER_CLANINFOREPLY);
2579 	bn_int_set(&rpacket->u.server_profilereply.count, count);
2580 	if (clantag1 == clantag2) {
2581 	    int temp;
2582 	    t_bnettime bn_time;
2583 	    bn_long ltime;
2584 
2585 	    bn_byte_set(&rpacket->u.server_claninforeply.fail, 0);
2586 
2587 	    packet_append_string(rpacket, clan_get_name(clan));
2588 	    temp = clanmember_get_status(clanmember);
2589 	    packet_append_data(rpacket, &temp, 1);
2590 	    temp = clanmember_get_join_time(clanmember);
2591 	    bn_time = time_to_bnettime(temp, 0);
2592 	    bn_time = bnettime_add_tzbias(bn_time, -conn_get_tzbias(c));
2593 	    bnettime_to_bn_long(bn_time, &ltime);
2594 	    packet_append_data(rpacket, &ltime, 8);
2595 	} else
2596 	    bn_byte_set(&rpacket->u.server_claninforeply.fail, 1);
2597 
2598 
2599 	conn_push_outqueue(c, rpacket);
2600 	packet_del_ref(rpacket);
2601     }
2602 
2603     return 0;
2604 }
2605 
_client_profilereq(t_connection * c,t_packet const * const packet)2606 static int _client_profilereq(t_connection * c, t_packet const *const packet)
2607 {
2608     t_packet *rpacket;
2609     int count;
2610     char const *username;
2611     t_account *account;
2612     t_clanmember *clanmember;
2613     t_clan *clan;
2614     bn_int clanTAG;
2615 
2616     if (packet_get_size(packet) < sizeof(t_client_profilereq)) {
2617 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad PROFILEREQ packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_profilereq), packet_get_size(packet));
2618 	return -1;
2619     }
2620 
2621     count = bn_int_get(packet->u.client_profilereq.count);
2622 
2623     if (!(username = packet_get_str_const(packet, sizeof(t_client_profilereq), USER_NAME_MAX))) {
2624 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad PROFILEREQ (missing or too long username)", conn_get_socket(c));
2625 	return -1;
2626     }
2627 
2628     if (!(account = accountlist_find_account(username))) {
2629 	eventlog(eventlog_level_error, __FUNCTION__, "requested profile for non-existant account");
2630 	return -1;
2631     }
2632     if ((rpacket = packet_create(packet_class_bnet))) {
2633 	packet_set_size(rpacket, sizeof(t_server_profilereply));
2634 	packet_set_type(rpacket, SERVER_PROFILEREPLY);
2635 	bn_int_set(&rpacket->u.server_profilereply.count, count);
2636 	bn_byte_set(&rpacket->u.server_profilereply.fail, 0);
2637 	packet_append_string(rpacket, account_get_desc(account));
2638 	packet_append_string(rpacket, account_get_loc(account));
2639 	if ((clanmember = account_get_clanmember(account)) && (clan = clanmember_get_clan(clanmember)))
2640 	    bn_int_set(&clanTAG, clan_get_clantag(clan));
2641 	else
2642 	    bn_int_set(&clanTAG, 0);
2643 	packet_append_data(rpacket, clanTAG, 4);
2644 
2645 	conn_push_outqueue(c, rpacket);
2646 	packet_del_ref(rpacket);
2647     }
2648 
2649     return 0;
2650 }
2651 
2652 
_client_realmjoinreq109(t_connection * c,t_packet const * const packet)2653 static int _client_realmjoinreq109(t_connection * c, t_packet const *const packet)
2654 {
2655     t_packet *rpacket;
2656 
2657     if (packet_get_size(packet) < sizeof(t_client_realmjoinreq_109)) {
2658 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad REALMJOINREQ_109 packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_realmjoinreq_109), packet_get_size(packet));
2659 	return -1;
2660     }
2661 
2662     {
2663 	char const *realmname;
2664 	t_realm *realm;
2665 
2666 	if (!(realmname = packet_get_str_const(packet, sizeof(t_client_realmjoinreq_109), REALM_NAME_LEN))) {
2667 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad REALMJOINREQ_109 (missing or too long realmname)", conn_get_socket(c));
2668 	    return -1;
2669 	}
2670 
2671 	if ((realm = realmlist_find_realm(realmname))) {
2672 	    unsigned int salt;
2673 	    struct {
2674 		bn_int salt;
2675 		bn_int sessionkey;
2676 		bn_int sessionnum;
2677 		bn_int secret;
2678 		bn_int passhash[5];
2679 	    } temp;
2680 	    char const *pass_str;
2681 	    t_hash secret_hash;
2682 	    t_hash passhash;
2683 	    t_realm *prev_realm;
2684 
2685 	    /* FIXME: should we only set this after they log in to the realm server? */
2686 	    prev_realm = conn_get_realm(c);
2687 	    if (prev_realm) {
2688 		if (prev_realm != realm) {
2689 		    realm_add_player_number(realm, 1);
2690 		    realm_add_player_number(prev_realm, -1);
2691 		    conn_set_realm(c, realm);
2692 		}
2693 	    } else {
2694 		realm_add_player_number(realm, 1);
2695 		conn_set_realm(c, realm);
2696 	    }
2697 
2698 	    if ((pass_str = account_get_pass(conn_get_account(c)))) {
2699 		if (hash_set_str(&passhash, pass_str) == 0) {
2700 		    hash_to_bnhash((t_hash const *) &passhash, temp.passhash);
2701 		    salt = bn_int_get(packet->u.client_realmjoinreq_109.seqno);
2702 		    bn_int_set(&temp.salt, salt);
2703 		    bn_int_set(&temp.sessionkey, conn_get_sessionkey(c));
2704 		    bn_int_set(&temp.sessionnum, conn_get_sessionnum(c));
2705 		    bn_int_set(&temp.secret, conn_get_secret(c));
2706 		    bnet_hash(&secret_hash, sizeof(temp), &temp);
2707 
2708 		    if ((rpacket = packet_create(packet_class_bnet))) {
2709 			packet_set_size(rpacket, sizeof(t_server_realmjoinreply_109));
2710 			packet_set_type(rpacket, SERVER_REALMJOINREPLY_109);
2711 			bn_int_set(&rpacket->u.server_realmjoinreply_109.seqno, salt);
2712 			bn_int_set(&rpacket->u.server_realmjoinreply_109.u1, 0x0);
2713 			bn_short_set(&rpacket->u.server_realmjoinreply_109.u3, 0x0);	/* reg auth */
2714 			bn_int_set(&rpacket->u.server_realmjoinreply_109.bncs_addr1, 0x0);
2715 			bn_int_set(&rpacket->u.server_realmjoinreply_109.sessionnum, conn_get_sessionnum(c));
2716 			{	/* trans support */
2717 			    unsigned int addr = realm_get_ip(realm);
2718 			    unsigned short port = realm_get_port(realm);
2719 
2720 			    trans_net(conn_get_addr(c), &addr, &port);
2721 
2722 			    bn_int_nset(&rpacket->u.server_realmjoinreply_109.addr, addr);
2723 			    bn_short_nset(&rpacket->u.server_realmjoinreply_109.port, port);
2724 			}
2725 			bn_int_set(&rpacket->u.server_realmjoinreply_109.sessionkey, conn_get_sessionkey(c));
2726 			bn_int_set(&rpacket->u.server_realmjoinreply_109.u5, 0);
2727 			bn_int_set(&rpacket->u.server_realmjoinreply_109.u6, 0);
2728 			bn_int_set(&rpacket->u.server_realmjoinreply_109.bncs_addr2, 0);
2729 			bn_int_set(&rpacket->u.server_realmjoinreply_109.u7, 0);
2730 			bn_int_set(&rpacket->u.server_realmjoinreply_109.versionid, conn_get_versionid(c));
2731 			bn_int_set(&rpacket->u.server_realmjoinreply_109.clienttag, conn_get_clienttag(c));
2732 			hash_to_bnhash((t_hash const *) &secret_hash, rpacket->u.server_realmjoinreply_109.secret_hash);	/* avoid warning */
2733 			packet_append_string(rpacket, conn_get_username(c));
2734 			conn_push_outqueue(c, rpacket);
2735 			packet_del_ref(rpacket);
2736 		    }
2737 		    return 0;
2738 		} else
2739 		    eventlog(eventlog_level_info, __FUNCTION__, "[%d] realm join for \"%s\" failed (unable to hash password)", conn_get_socket(c), conn_get_loggeduser(c));
2740 	    } else {
2741 		eventlog(eventlog_level_info, __FUNCTION__, "[%d] realm join for \"%s\" failed (no password)", conn_get_socket(c), conn_get_loggeduser(c));
2742 	    }
2743 	} else
2744 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] could not find active realm \"%s\"", conn_get_socket(c), realmname);
2745 
2746 	if ((rpacket = packet_create(packet_class_bnet))) {
2747 	    packet_set_size(rpacket, sizeof(t_server_realmjoinreply_109));
2748 	    packet_set_type(rpacket, SERVER_REALMJOINREPLY_109);
2749 	    bn_int_set(&rpacket->u.server_realmjoinreply_109.seqno, bn_int_get(packet->u.client_realmjoinreq_109.seqno));
2750 	    bn_int_set(&rpacket->u.server_realmjoinreply_109.u1, 0);
2751 	    bn_int_set(&rpacket->u.server_realmjoinreply_109.sessionnum, 0);
2752 	    bn_short_set(&rpacket->u.server_realmjoinreply_109.u3, 0);
2753 	    bn_int_nset(&rpacket->u.server_realmjoinreply_109.addr, 0);
2754 	    bn_short_nset(&rpacket->u.server_realmjoinreply_109.port, 0);
2755 	    bn_int_set(&rpacket->u.server_realmjoinreply_109.sessionkey, 0);
2756 	    bn_int_set(&rpacket->u.server_realmjoinreply_109.u5, 0);
2757 	    bn_int_set(&rpacket->u.server_realmjoinreply_109.u6, 0);
2758 	    bn_int_set(&rpacket->u.server_realmjoinreply_109.u7, 0);
2759 	    bn_int_set(&rpacket->u.server_realmjoinreply_109.bncs_addr1, 0);
2760 	    bn_int_set(&rpacket->u.server_realmjoinreply_109.bncs_addr2, 0);
2761 	    bn_int_set(&rpacket->u.server_realmjoinreply_109.versionid, 0);
2762 	    bn_int_set(&rpacket->u.server_realmjoinreply_109.clienttag, 0);
2763 	    bn_int_set(&rpacket->u.server_realmjoinreply_109.secret_hash[0], 0);
2764 	    bn_int_set(&rpacket->u.server_realmjoinreply_109.secret_hash[1], 0);
2765 	    bn_int_set(&rpacket->u.server_realmjoinreply_109.secret_hash[2], 0);
2766 	    bn_int_set(&rpacket->u.server_realmjoinreply_109.secret_hash[3], 0);
2767 	    bn_int_set(&rpacket->u.server_realmjoinreply_109.secret_hash[4], 0);
2768 	    packet_append_string(rpacket, "");
2769 	    conn_push_outqueue(c, rpacket);
2770 	    packet_del_ref(rpacket);
2771 	}
2772     }
2773 
2774     return 0;
2775 }
2776 
_client_charlistreq(t_connection * c,t_packet const * const packet)2777 static int _client_charlistreq(t_connection * c, t_packet const *const packet)
2778 {
2779     t_packet *rpacket;
2780 
2781     if (packet_get_size(packet) < sizeof(t_client_unknown_37)) {
2782 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad UNKNOWN_37 packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_unknown_37), packet_get_size(packet));
2783 	return -1;
2784     }
2785     /*
2786        0x0070:                           83 80 ff ff ff ff ff 2f    t,taran,......./
2787        0x0080: ff ff ff ff ff ff ff ff   ff ff 03 ff ff ff ff ff    ................
2788        0x0090: ff ff ff ff ff ff ff ff   ff ff ff 07 80 80 80 80    ................
2789        0x00a0: ff ff ff 00
2790      */
2791     if ((rpacket = packet_create(packet_class_bnet))) {
2792 	char const *charlist;
2793 	char *temp;
2794 
2795 	packet_set_size(rpacket, sizeof(t_server_unknown_37));
2796 	packet_set_type(rpacket, SERVER_UNKNOWN_37);
2797 	bn_int_set(&rpacket->u.server_unknown_37.unknown1, SERVER_UNKNOWN_37_UNKNOWN1);
2798 	bn_int_set(&rpacket->u.server_unknown_37.unknown2, SERVER_UNKNOWN_37_UNKNOWN2);
2799 
2800 	if (!(charlist = account_get_closed_characterlist(conn_get_account(c), conn_get_clienttag(c), realm_get_name(conn_get_realm(c))))) {
2801 	    bn_int_set(&rpacket->u.server_unknown_37.count, 0);
2802 	    conn_push_outqueue(c, rpacket);
2803 	    packet_del_ref(rpacket);
2804 	    return 0;
2805 	}
2806 	temp = xstrdup(charlist);
2807 
2808 	{
2809 	    char const *tok1;
2810 	    char const *tok2;
2811 	    t_character const *ch;
2812 	    unsigned int count;
2813 
2814 	    count = 0;
2815 	    tok1 = (char const *) strtok(temp, ",");	/* strtok modifies the string it is passed */
2816 	    tok2 = strtok(NULL, ",");
2817 	    while (tok1) {
2818 		if (!tok2) {
2819 		    eventlog(eventlog_level_error, __FUNCTION__, "[%d] account \"%s\" has bad character list \"%s\"", conn_get_socket(c), conn_get_username(c), temp);
2820 		    break;
2821 		}
2822 
2823 		if ((ch = characterlist_find_character(tok1, tok2))) {
2824 		    packet_append_ntstring(rpacket, character_get_realmname(ch));
2825 		    packet_append_ntstring(rpacket, ",");
2826 		    packet_append_string(rpacket, character_get_name(ch));
2827 		    packet_append_string(rpacket, character_get_playerinfo(ch));
2828 		    packet_append_string(rpacket, character_get_guildname(ch));
2829 		    count++;
2830 		} else
2831 		    eventlog(eventlog_level_error, __FUNCTION__, "[%d] character \"%s\" is missing", conn_get_socket(c), tok2);
2832 		tok1 = strtok(NULL, ",");
2833 		tok2 = strtok(NULL, ",");
2834 	    }
2835 	    xfree(temp);
2836 
2837 	    bn_int_set(&rpacket->u.server_unknown_37.count, count);
2838 	    conn_push_outqueue(c, rpacket);
2839 	    packet_del_ref(rpacket);
2840 	}
2841     }
2842 
2843     return 0;
2844 }
2845 
_client_unknown39(t_connection * c,t_packet const * const packet)2846 static int _client_unknown39(t_connection * c, t_packet const *const packet)
2847 {
2848     if (packet_get_size(packet) < sizeof(t_client_unknown_39)) {
2849 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad UNKNOWN_39 packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_unknown_39), packet_get_size(packet));
2850 	return -1;
2851     }
2852     return 0;
2853 }
2854 
_client_adreq(t_connection * c,t_packet const * const packet)2855 static int _client_adreq(t_connection * c, t_packet const *const packet)
2856 {
2857     t_packet *rpacket;
2858 
2859     if (packet_get_size(packet) < sizeof(t_client_adreq)) {
2860 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad ADREQ packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_adreq), packet_get_size(packet));
2861 	return -1;
2862     }
2863 
2864     {
2865 	t_adbanner *ad;
2866 
2867 	if (!(ad = adbanner_pick(c, bn_int_get(packet->u.client_adreq.prev_adid))))
2868 	    return 0;
2869 
2870 	/*                  eventlog(eventlog_level_debug,__FUNCTION__,"[%d] picking ad file=\"%s\" id=0x%06x tag=%u",conn_get_socket(c),adbanner_get_filename(ad),adbanner_get_id(ad),adbanner_get_extensiontag(ad)); */
2871 	if ((rpacket = packet_create(packet_class_bnet))) {
2872 	    packet_set_size(rpacket, sizeof(t_server_adreply));
2873 	    packet_set_type(rpacket, SERVER_ADREPLY);
2874 	    bn_int_set(&rpacket->u.server_adreply.adid, adbanner_get_id(ad));
2875 	    bn_int_set(&rpacket->u.server_adreply.extensiontag, adbanner_get_extensiontag(ad));
2876 	    file_to_mod_time(adbanner_get_filename(ad), &rpacket->u.server_adreply.timestamp);
2877 	    packet_append_string(rpacket, adbanner_get_filename(ad));
2878 	    packet_append_string(rpacket, adbanner_get_link(ad));
2879 	    conn_push_outqueue(c, rpacket);
2880 	    packet_del_ref(rpacket);
2881 	}
2882     }
2883 
2884     return 0;
2885 }
2886 
_client_adack(t_connection * c,t_packet const * const packet)2887 static int _client_adack(t_connection * c, t_packet const *const packet)
2888 {
2889     if (packet_get_size(packet) < sizeof(t_client_adack)) {
2890 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad ADACK packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_adack), packet_get_size(packet));
2891 	return -1;
2892     }
2893 
2894     /*
2895        {
2896        char const * tname;
2897 
2898        eventlog(eventlog_level_info,__FUNCTION__,"[%d] ad acknowledgement for adid 0x%04x from \"%s\"",conn_get_socket(c),bn_int_get(packet->u.client_adack.adid),(tname = conn_get_chatname(c)));
2899        conn_unget_chatname(c,tname);
2900        }
2901      */
2902     return 0;
2903 }
2904 
_client_adclick(t_connection * c,t_packet const * const packet)2905 static int _client_adclick(t_connection * c, t_packet const *const packet)
2906 {
2907     if (packet_get_size(packet) < sizeof(t_client_adclick)) {
2908 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad ADCLICK packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_adclick), packet_get_size(packet));
2909 	return -1;
2910     }
2911 
2912     eventlog(eventlog_level_info, __FUNCTION__, "[%d] ad click for adid 0x%04x from \"%s\"", conn_get_socket(c), bn_int_get(packet->u.client_adclick.adid), conn_get_username(c));
2913 
2914     return 0;
2915 }
2916 
_client_adclick2(t_connection * c,t_packet const * const packet)2917 static int _client_adclick2(t_connection * c, t_packet const *const packet)
2918 {
2919     t_packet *rpacket;
2920 
2921     if (packet_get_size(packet) < sizeof(t_client_adclick2)) {
2922 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad ADCLICK2 packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_adclick2), packet_get_size(packet));
2923 	return -1;
2924     }
2925 
2926     eventlog(eventlog_level_info, __FUNCTION__, "[%d] ad click2 for adid 0x%04hx from \"%s\"", conn_get_socket(c), bn_int_get(packet->u.client_adclick2.adid), conn_get_username(c));
2927 
2928     {
2929 	t_adbanner *ad;
2930 
2931 	if (!(ad = adbanner_get(c, bn_int_get(packet->u.client_adclick2.adid))))
2932 	    return -1;
2933 
2934 	if ((rpacket = packet_create(packet_class_bnet))) {
2935 	    packet_set_size(rpacket, sizeof(t_server_adclickreply2));
2936 	    packet_set_type(rpacket, SERVER_ADCLICKREPLY2);
2937 	    bn_int_set(&rpacket->u.server_adclickreply2.adid, adbanner_get_id(ad));
2938 	    packet_append_string(rpacket, adbanner_get_link(ad));
2939 	    conn_push_outqueue(c, rpacket);
2940 	    packet_del_ref(rpacket);
2941 	}
2942     }
2943 
2944     return 0;
2945 }
2946 
_client_statsupdate(t_connection * c,t_packet const * const packet)2947 static int _client_statsupdate(t_connection * c, t_packet const *const packet)
2948 {
2949     if (packet_get_size(packet) < sizeof(t_client_statsupdate)) {
2950 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad STATSUPDATE packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_statsupdate), packet_get_size(packet));
2951 	return -1;
2952     }
2953 
2954     {
2955 	char const *name;
2956 	char const *key;
2957 	char const *val;
2958 	unsigned int name_count;
2959 	unsigned int key_count;
2960 	unsigned int i, j;
2961 	unsigned int name_off;
2962 	unsigned int keys_off;
2963 	unsigned int key_off;
2964 	unsigned int vals_off;
2965 	unsigned int val_off;
2966 	t_account *account;
2967 
2968 	name_count = bn_int_get(packet->u.client_statsupdate.name_count);
2969 	key_count = bn_int_get(packet->u.client_statsupdate.key_count);
2970 
2971 	if (name_count != 1)
2972 	    eventlog(eventlog_level_warn, __FUNCTION__, "[%d] got suspicious STATSUPDATE packet (name_count=%u)", conn_get_socket(c), name_count);
2973 
2974 	for (i = 0, name_off = sizeof(t_client_statsupdate); i < name_count && (name = packet_get_str_const(packet, name_off, UNCHECKED_NAME_STR)); i++, name_off += strlen(name) + 1);
2975 	if (i < name_count) {
2976 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad STATSUPDATE packet (only %u names of %u)", conn_get_socket(c), i, name_count);
2977 	    return -1;
2978 	}
2979 	keys_off = name_off;
2980 
2981 	for (i = 0, key_off = keys_off; i < key_count && (key = packet_get_str_const(packet, key_off, MAX_ATTRKEY_STR)); i++, key_off += strlen(key) + 1);
2982 	if (i < key_count) {
2983 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad STATSUPDATE packet (only %u keys of %u)", conn_get_socket(c), i, key_count);
2984 	    return -1;
2985 	}
2986 	vals_off = key_off;
2987 
2988 	if ((account = conn_get_account(c))) {
2989 	    if (account_get_auth_changeprofile(account) == 0) {	/* default to true */
2990 		eventlog(eventlog_level_error, __FUNCTION__, "[%d] stats update for \"%s\" refused (no change profile access)", conn_get_socket(c), conn_get_username(c));
2991 		return -1;
2992 	    }
2993 	    eventlog(eventlog_level_info, __FUNCTION__, "[%d] updating player profile for \"%s\"", conn_get_socket(c), conn_get_username(c));
2994 
2995 	    for (i = 0, name_off = sizeof(t_client_statsupdate); i < name_count && (name = packet_get_str_const(packet, name_off, UNCHECKED_NAME_STR)); i++, name_off += strlen(name) + 1)
2996 		for (j = 0, key_off = keys_off, val_off = vals_off; j < key_count && (key = packet_get_str_const(packet, key_off, MAX_ATTRKEY_STR)) && (val = packet_get_str_const(packet, val_off, MAX_ATTRVAL_STR)); j++, key_off += strlen(key) + 1, val_off += strlen(val) + 1)
2997 		    if (strlen(key) < 9 || strncasecmp(key, "profile\\", 8) != 0)
2998 			eventlog(eventlog_level_error, __FUNCTION__, "[%d] got STATSUPDATE with suspicious key \"%s\" value \"%s\"", conn_get_socket(c), key, val);
2999 		    else
3000 			account_set_strattr(account, key, val);
3001 	}
3002     }
3003 
3004     return 0;
3005 }
3006 
_client_playerinforeq(t_connection * c,t_packet const * const packet)3007 static int _client_playerinforeq(t_connection * c, t_packet const *const packet)
3008 {
3009     t_packet *rpacket;
3010 
3011     if (packet_get_size(packet) < sizeof(t_client_playerinforeq)) {
3012 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad PLAYERINFOREQ packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_playerinforeq), packet_get_size(packet));
3013 	return -1;
3014     }
3015 
3016     {
3017 	char const *username;
3018 	char const *info;
3019 	t_account *account;
3020 
3021 	if (!(username = packet_get_str_const(packet, sizeof(t_client_playerinforeq), USER_NAME_MAX))) {
3022 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad PLAYERINFOREQ (missing or too long username)", conn_get_socket(c));
3023 	    return -1;
3024 	}
3025 	if (!(info = packet_get_str_const(packet, sizeof(t_client_playerinforeq) + strlen(username) + 1, MAX_PLAYERINFO_STR))) {
3026 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad PLAYERINFOREQ (missing or too long info)", conn_get_socket(c));
3027 	    return -1;
3028 	}
3029 
3030 	if (info[0] != '\0')
3031 	    conn_set_playerinfo(c, info);
3032 	if (!username[0])
3033 	    username = conn_get_loggeduser(c);
3034 
3035 	account = conn_get_account(c);
3036 
3037 	if (!(rpacket = packet_create(packet_class_bnet)))
3038 	    return -1;
3039 	packet_set_size(rpacket, sizeof(t_server_playerinforeply));
3040 	packet_set_type(rpacket, SERVER_PLAYERINFOREPLY);
3041 
3042 	if (account) {
3043 	    packet_append_string(rpacket, username);
3044 	    packet_append_string(rpacket, conn_get_playerinfo(c));
3045 	    packet_append_string(rpacket, username);
3046 	} else {
3047 	    packet_append_string(rpacket, "");
3048 	    packet_append_string(rpacket, "");
3049 	    packet_append_string(rpacket, "");
3050 	}
3051 	conn_push_outqueue(c, rpacket);
3052 	packet_del_ref(rpacket);
3053     }
3054 
3055     return 0;
3056 }
3057 
_client_progident2(t_connection * c,t_packet const * const packet)3058 static int _client_progident2(t_connection * c, t_packet const *const packet)
3059 {
3060     t_packet *rpacket;
3061 
3062     if (packet_get_size(packet) < sizeof(t_client_progident2)) {
3063 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad PROGIDENT2 packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_progident2), packet_get_size(packet));
3064 	return -1;
3065     }
3066 
3067     /* d2 uses this packet with clienttag = 0 to request the channel list */
3068     if (bn_int_get(packet->u.client_progident2.clienttag)) {
3069 	if (_check_allowed_client(bn_int_get(packet->u.client_progident2.clienttag))) {
3070 	    conn_set_state(c, conn_state_destroy);
3071 	    return 0;
3072 	}
3073 	eventlog(eventlog_level_debug, __FUNCTION__, "[%d] CLIENT_PROGIDENT2 clienttag=0x%08x", conn_get_socket(c), bn_int_get(packet->u.client_progident2.clienttag));
3074 
3075 	/* Hmm... no archtag.  Hope we get it in CLIENT_AUTHREQ1 (but we won't if we use the shortcut) */
3076 
3077 	conn_set_clienttag(c, bn_int_get(packet->u.client_progident2.clienttag));
3078     }
3079 
3080     if ((rpacket = packet_create(packet_class_bnet))) {
3081 	packet_set_size(rpacket, sizeof(t_server_channellist));
3082 	packet_set_type(rpacket, SERVER_CHANNELLIST);
3083 	{
3084 	    t_channel *ch;
3085 	    t_elem const *curr;
3086 
3087 	    LIST_TRAVERSE_CONST(channellist(), curr) {
3088 		ch = elem_get_data(curr);
3089 		if ((!(channel_get_flags(ch) & channel_flags_clan)) && (!prefs_get_hide_temp_channels() || channel_get_permanent(ch)) && (!channel_get_clienttag(ch) || strcmp(channel_get_clienttag(ch), clienttag_uint_to_str(conn_get_clienttag(c))) == 0) && (!(channel_get_flags(ch) & channel_flags_thevoid)) &&	// don't display theVoid in channel list
3090 		    ((channel_get_max(ch) != 0) || ((channel_get_max(ch) == 0) && (account_is_operator_or_admin(conn_get_account(c), channel_get_name(ch)) == 1))))	// don't display restricted channel for no admins/ops
3091 		    packet_append_string(rpacket, channel_get_name(ch));
3092 	    }
3093 	}
3094 	packet_append_string(rpacket, "");
3095 	conn_push_outqueue(c, rpacket);
3096 	packet_del_ref(rpacket);
3097     }
3098 
3099     return 0;
3100 }
3101 
_client_joinchannel(t_connection * c,t_packet const * const packet)3102 static int _client_joinchannel(t_connection * c, t_packet const *const packet)
3103 {
3104     t_account *account;
3105     char const *cname;
3106     int found = 1;
3107     t_clan *user_clan;
3108     int clantag;
3109     t_uint32 clienttag;
3110     t_channel *channel;
3111 
3112     if (packet_get_size(packet) < sizeof(t_client_joinchannel)) {
3113 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad JOINCHANNEL packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_joinchannel), packet_get_size(packet));
3114 	return -1;
3115     }
3116 
3117     account = conn_get_account(c);
3118 
3119     if (!(cname = packet_get_str_const(packet, sizeof(t_client_joinchannel), CHANNEL_NAME_LEN))) {
3120 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad JOINCHANNEL (missing or too long cname)", conn_get_socket(c));
3121 	return -1;
3122     }
3123 
3124     if ((channel = conn_get_channel(c)) && (strcasecmp(channel_get_name(channel), cname) == 0))
3125 	return 0;		//we are allready in this channel
3126 
3127     clienttag = conn_get_clienttag(c);
3128     if ((clienttag == CLIENTTAG_WARCRAFT3_UINT) || (clienttag == CLIENTTAG_WAR3XP_UINT)) {
3129 	conn_update_w3_playerinfo(c);
3130 	switch (bn_int_get(packet->u.client_joinchannel.channelflag)) {
3131 	    case CLIENT_JOINCHANNEL_NORMAL:
3132 		eventlog(eventlog_level_info, __FUNCTION__, "[%d] CLIENT_JOINCHANNEL_NORMAL channel \"%s\"", conn_get_socket(c), cname);
3133 
3134 		if (prefs_get_ask_new_channel() && (!(channellist_find_channel_by_name(cname, conn_get_country(c), realm_get_name(conn_get_realm(c)))))) {
3135 		    found = 0;
3136 		    eventlog(eventlog_level_info, __FUNCTION__, "[%d] didn't find channel \"%s\" to join", conn_get_socket(c), cname);
3137 		    message_send_text(c, message_type_channeldoesnotexist, c, cname);
3138 		}
3139 		break;
3140 	    case CLIENT_JOINCHANNEL_GENERIC:
3141 
3142 		if ((user_clan = account_get_clan(account)) && (clantag = clan_get_clantag(user_clan)))
3143 		    sprintf((char *) cname, "Clan %c%c%c%c", (clantag >> 24), (clantag >> 16) & 0xff, (clantag >> 8) & 0xff, clantag & 0xff);
3144 		eventlog(eventlog_level_info, __FUNCTION__, "[%d] CLIENT_JOINCHANNEL_GENERIC channel \"%s\"", conn_get_socket(c), cname);
3145 
3146 		/* don't have to do anything here */
3147 		break;
3148 	    case CLIENT_JOINCHANNEL_CREATE:
3149 		eventlog(eventlog_level_info, __FUNCTION__, "[%d] CLIENT_JOINCHANNEL_CREATE channel \"%s\"", conn_get_socket(c), cname);
3150 		eventlog(eventlog_level_info, __FUNCTION__, "[%d] CLIENT_JOINCHANNEL_CREATE channel \"%s\"", conn_get_socket(c), cname);
3151 		/* don't have to do anything here */
3152 		break;
3153 	}
3154 
3155 	if (found && conn_set_channel(c, cname) < 0)
3156 	    conn_set_channel(c, CHANNEL_NAME_BANNED);	/* should not fail */
3157     } else {
3158 
3159 	// not W3
3160 	if (conn_set_channel(c, cname) < 0)
3161 	    conn_set_channel(c, CHANNEL_NAME_BANNED);	/* should not fail */
3162     }
3163     // here we set channel flags on user
3164     channel_set_userflags(c);
3165 
3166     return 0;
3167 }
3168 
_client_message(t_connection * c,t_packet const * const packet)3169 static int _client_message(t_connection * c, t_packet const *const packet)
3170 {
3171     if (packet_get_size(packet) < sizeof(t_client_message)) {
3172 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad MESSAGE packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_message), packet_get_size(packet));
3173 	return -1;
3174     }
3175 
3176     {
3177 	char const *text;
3178 	t_channel const *channel;
3179 
3180 	if (!(text = packet_get_str_const(packet, sizeof(t_client_message), MAX_MESSAGE_LEN))) {
3181 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad MESSAGE (missing or too long text)", conn_get_socket(c));
3182 	    return -1;
3183 	}
3184 
3185 	conn_set_idletime(c);
3186 
3187 	if ((channel = conn_get_channel(c)))
3188 	    channel_message_log(channel, c, 1, text);
3189 	/* we don't log game commands currently */
3190 
3191 
3192 
3193 	if (text[0] == '/')
3194 	    handle_command(c, text);
3195 	else if (channel && !conn_quota_exceeded(c, text))
3196 	    channel_message_send(channel, message_type_talk, c, text);
3197 	/* else discard */
3198     }
3199 
3200     return 0;
3201 }
3202 
3203 struct glist_cbdata {
3204     unsigned tcount, counter;
3205     t_connection *c;
3206     t_game_type gtype;
3207     t_packet *rpacket;
3208 };
3209 
_glist_cb(t_game * game,void * data)3210 static int _glist_cb(t_game * game, void *data)
3211 {
3212     struct glist_cbdata *cbdata = (struct glist_cbdata*)data;
3213     char clienttag_str[5];
3214     t_server_gamelistreply_game glgame;
3215     unsigned int addr;
3216     unsigned short port;
3217     bn_int game_spacer = { 1, 0, 0, 0 };
3218 
3219     cbdata->tcount++;
3220     eventlog(eventlog_level_debug, __FUNCTION__, "[%d] considering listing game=\"%s\", pass=\"%s\" clienttag=\"%s\" gtype=%d", conn_get_socket(cbdata->c), game_get_name(game), game_get_pass(game), tag_uint_to_str(clienttag_str, game_get_clienttag(game)), (int) game_get_type(game));
3221 
3222     if (prefs_get_hide_pass_games() && game_get_flag(game) == game_flag_private) {
3223 	eventlog(eventlog_level_debug, __FUNCTION__, "[%d] not listing because game is passworded or has private flag", conn_get_socket(cbdata->c));
3224 	return 0;
3225     }
3226     if (prefs_get_hide_started_games() && game_get_status(game) != game_status_open) {
3227 	eventlog(eventlog_level_debug, __FUNCTION__, "[%d] not listing because game is not open", conn_get_socket(cbdata->c));
3228 	return 0;
3229     }
3230     if (game_get_clienttag(game) != conn_get_clienttag(cbdata->c)) {
3231 	eventlog(eventlog_level_debug, __FUNCTION__, "[%d] not listing because game is for a different client", conn_get_socket(cbdata->c));
3232 	return 0;
3233     }
3234     if (cbdata->gtype != game_type_all && game_get_type(game) != cbdata->gtype) {
3235 	eventlog(eventlog_level_debug, __FUNCTION__, "[%d] not listing because game is wrong type", conn_get_socket(cbdata->c));
3236 	return 0;
3237     }
3238     if (conn_get_versioncheck(cbdata->c) &&
3239 	conn_get_versioncheck(game_get_owner(game)) &&
3240 	versioncheck_get_versiontag(conn_get_versioncheck(cbdata->c)) &&
3241 	versioncheck_get_versiontag(conn_get_versioncheck(game_get_owner(game))) &&
3242 	strcmp(versioncheck_get_versiontag(conn_get_versioncheck(cbdata->c)), versioncheck_get_versiontag(conn_get_versioncheck(game_get_owner(game)))) != 0) {
3243 	eventlog(eventlog_level_debug, __FUNCTION__, "[%d] not listing because game is wrong versiontag", conn_get_socket(cbdata->c));
3244 	return 0;
3245     }
3246     bn_short_set(&glgame.gametype, gtype_to_bngtype(game_get_type(game)));
3247     bn_short_set(&glgame.unknown1, SERVER_GAMELISTREPLY_GAME_UNKNOWN1);
3248     bn_short_set(&glgame.unknown3, SERVER_GAMELISTREPLY_GAME_UNKNOWN3);
3249     addr = game_get_addr(game);
3250     port = game_get_port(game);
3251     trans_net(conn_get_addr(cbdata->c), &addr, &port);
3252     bn_short_nset(&glgame.port, port);
3253     bn_int_nset(&glgame.game_ip, addr);
3254     bn_int_set(&glgame.unknown4, SERVER_GAMELISTREPLY_GAME_UNKNOWN4);
3255     bn_int_set(&glgame.unknown5, SERVER_GAMELISTREPLY_GAME_UNKNOWN5);
3256     switch (game_get_status(game)) {
3257 	case game_status_started:
3258 	    bn_int_set(&glgame.status, SERVER_GAMELISTREPLY_GAME_STATUS_STARTED);
3259 	    break;
3260 	case game_status_full:
3261 	    bn_int_set(&glgame.status, SERVER_GAMELISTREPLY_GAME_STATUS_FULL);
3262 	    break;
3263 	case game_status_open:
3264 	    bn_int_set(&glgame.status, SERVER_GAMELISTREPLY_GAME_STATUS_OPEN);
3265 	    break;
3266 	case game_status_done:
3267 	    bn_int_set(&glgame.status, SERVER_GAMELISTREPLY_GAME_STATUS_DONE);
3268 	    break;
3269 	default:
3270 	    eventlog(eventlog_level_warn, __FUNCTION__, "[%d] game \"%s\" has bad status=%d", conn_get_socket(cbdata->c), game_get_name(game), (int) game_get_status(game));
3271 	    bn_int_set(&glgame.status, 0);
3272     }
3273     bn_int_set(&glgame.unknown6, SERVER_GAMELISTREPLY_GAME_UNKNOWN6);
3274 
3275     if (packet_get_size(cbdata->rpacket) + sizeof(glgame) + strlen(game_get_name(game)) + 1 + strlen(game_get_pass(game)) + 1 + strlen(game_get_info(game)) + 1 > MAX_PACKET_SIZE) {
3276 	eventlog(eventlog_level_debug, __FUNCTION__, "[%d] out of room for games", conn_get_socket(cbdata->c));
3277 	return -1;			/* no more room */
3278     }
3279 
3280     if (cbdata->counter) {
3281 	packet_append_data(cbdata->rpacket, &game_spacer, sizeof(game_spacer));
3282     }
3283 
3284     packet_append_data(cbdata->rpacket, &glgame, sizeof(glgame));
3285     packet_append_string(cbdata->rpacket, game_get_name(game));
3286     packet_append_string(cbdata->rpacket, game_get_pass(game));
3287     packet_append_string(cbdata->rpacket, game_get_info(game));
3288     cbdata->counter++;
3289 
3290     return 0;
3291 }
3292 
_client_gamelistreq(t_connection * c,t_packet const * const packet)3293 static int _client_gamelistreq(t_connection * c, t_packet const *const packet)
3294 {
3295     t_packet *rpacket;
3296     char const *gamename;
3297     char const *gamepass;
3298     unsigned short bngtype;
3299     t_game_type gtype;
3300     t_clienttag clienttag;
3301     t_game *game;
3302     t_server_gamelistreply_game glgame;
3303     unsigned int addr;
3304     unsigned short port;
3305     char clienttag_str[5];
3306 
3307     if (packet_get_size(packet) < sizeof(t_client_gamelistreq)) {
3308 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad GAMELISTREQ packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_gamelistreq), packet_get_size(packet));
3309 	return -1;
3310     }
3311 
3312     if (!(gamename = packet_get_str_const(packet, sizeof(t_client_gamelistreq), GAME_NAME_LEN))) {
3313 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad GAMELISTREQ (missing or too long gamename)", conn_get_socket(c));
3314 	return -1;
3315     }
3316 
3317     if (!(gamepass = packet_get_str_const(packet, sizeof(t_client_gamelistreq) + strlen(gamename) + 1, GAME_PASS_LEN))) {
3318 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad GAMELISTREQ (missing or too long password)", conn_get_socket(c));
3319 	return -1;
3320     }
3321 
3322     bngtype = bn_short_get(packet->u.client_gamelistreq.gametype);
3323     clienttag = conn_get_clienttag(c);
3324     gtype = bngreqtype_to_gtype(clienttag, bngtype);
3325     if (!(rpacket = packet_create(packet_class_bnet)))
3326 	return -1;
3327     packet_set_size(rpacket, sizeof(t_server_gamelistreply));
3328     packet_set_type(rpacket, SERVER_GAMELISTREPLY);
3329 
3330     bn_int_set(&rpacket->u.server_gamelistreply.sstatus, 0);
3331 
3332     /* specific game requested? */
3333     if (gamename[0] != '\0') {
3334 	eventlog(eventlog_level_debug, __FUNCTION__, "[%d] GAMELISTREPLY looking for specific game tag=\"%s\" bngtype=0x%08x gtype=%d name=\"%s\" pass=\"%s\"", conn_get_socket(c), tag_uint_to_str(clienttag_str, clienttag), bngtype, (int) gtype, gamename, gamepass);
3335 	if ((game = gamelist_find_game(gamename, clienttag, gtype))) {
3336 	    /* game found but first we need to make sure everything is OK */
3337 	    bn_int_set(&rpacket->u.server_gamelistreply.gamecount, 0);
3338 	    switch (game_get_status(game)) {
3339 		case game_status_started:
3340 		    bn_int_set(&rpacket->u.server_gamelistreply.sstatus, SERVER_GAMELISTREPLY_GAME_SSTATUS_STARTED);
3341 		    eventlog(eventlog_level_debug, __FUNCTION__, "[%d] GAMELISTREPLY found but started", conn_get_socket(c));
3342 		    break;
3343 		case game_status_full:
3344 		    bn_int_set(&rpacket->u.server_gamelistreply.sstatus, SERVER_GAMELISTREPLY_GAME_SSTATUS_FULL);
3345 		    eventlog(eventlog_level_debug, __FUNCTION__, "[%d] GAMELISTREPLY found but full", conn_get_socket(c));
3346 		    break;
3347 		case game_status_done:
3348 		    bn_int_set(&rpacket->u.server_gamelistreply.sstatus, SERVER_GAMELISTREPLY_GAME_SSTATUS_NOTFOUND);
3349 		    eventlog(eventlog_level_debug, __FUNCTION__, "[%d] GAMELISTREPLY found but done", conn_get_socket(c));
3350 		    break;
3351 		case game_status_open:
3352 		case game_status_loaded:
3353 		    if (strcmp(gamepass, game_get_pass(game))) {	/* passworded game must match password in request */
3354 			bn_int_set(&rpacket->u.server_gamelistreply.sstatus, SERVER_GAMELISTREPLY_GAME_SSTATUS_PASS);
3355 			eventlog(eventlog_level_debug, __FUNCTION__, "[%d] GAMELISTREPLY found but is password protected and wrong password given", conn_get_socket(c));
3356 			break;
3357 		    }
3358 
3359 		    if (game_get_status(game) == game_status_loaded) {
3360 		        bn_int_set(&rpacket->u.server_gamelistreply.sstatus, SERVER_GAMELISTREPLY_GAME_SSTATUS_LOADED);
3361 		        eventlog(eventlog_level_debug, __FUNCTION__, "[%d] GAMELISTREPLY found loaded game", conn_get_socket(c));
3362             }
3363 
3364 		    /* everything seems fine, lets reply with the found game */
3365 		    bn_int_set(&glgame.status, SERVER_GAMELISTREPLY_GAME_STATUS_OPEN);
3366 		    bn_short_set(&glgame.gametype, gtype_to_bngtype(game_get_type(game)));
3367 		    bn_short_set(&glgame.unknown1, SERVER_GAMELISTREPLY_GAME_UNKNOWN1);
3368 		    bn_short_set(&glgame.unknown3, SERVER_GAMELISTREPLY_GAME_UNKNOWN3);
3369 		    addr = game_get_addr(game);
3370 		    port = game_get_port(game);
3371 		    trans_net(conn_get_addr(c), &addr, &port);
3372 		    bn_short_nset(&glgame.port, port);
3373 		    bn_int_nset(&glgame.game_ip, addr);
3374 		    bn_int_set(&glgame.unknown4, SERVER_GAMELISTREPLY_GAME_UNKNOWN4);
3375 		    bn_int_set(&glgame.unknown5, SERVER_GAMELISTREPLY_GAME_UNKNOWN5);
3376 		    bn_int_set(&glgame.unknown6, SERVER_GAMELISTREPLY_GAME_UNKNOWN6);
3377 
3378 		    packet_append_data(rpacket, &glgame, sizeof(glgame));
3379 		    packet_append_string(rpacket, game_get_name(game));
3380 		    packet_append_string(rpacket, game_get_pass(game));
3381 		    packet_append_string(rpacket, game_get_info(game));
3382 		    bn_int_set(&rpacket->u.server_gamelistreply.gamecount, 1);
3383 		    eventlog(eventlog_level_debug, __FUNCTION__, "[%d] GAMELISTREPLY specific game found", conn_get_socket(c));
3384 		    break;
3385 		default:
3386 		    eventlog(eventlog_level_warn, __FUNCTION__, "[%d] game \"%s\" has bad status %d", conn_get_socket(c), game_get_name(game), game_get_status(game));
3387 	    }
3388 	} else {
3389 	    bn_int_set(&rpacket->u.server_gamelistreply.gamecount, 0);
3390 	    eventlog(eventlog_level_debug, __FUNCTION__, "[%d] GAMELISTREPLY specific game doesn't seem to exist", conn_get_socket(c));
3391 	}
3392     } else {			/* list all public games of this type */
3393 	struct glist_cbdata cbdata;
3394 
3395 	if (gtype == game_type_all)
3396 	    eventlog(eventlog_level_debug, __FUNCTION__, "GAMELISTREPLY looking for public games tag=\"%s\" bngtype=0x%08x gtype=all", tag_uint_to_str(clienttag_str, clienttag), bngtype);
3397 	else
3398 	    eventlog(eventlog_level_debug, __FUNCTION__, "GAMELISTREPLY looking for public games tag=\"%s\" bngtype=0x%08x gtype=%d", tag_uint_to_str(clienttag_str, clienttag), bngtype, (int) gtype);
3399 
3400 	cbdata.counter = 0;
3401 	cbdata.tcount = 0;
3402 	cbdata.c = c;
3403 	cbdata.gtype = gtype;
3404 	cbdata.rpacket = rpacket;
3405 	gamelist_traverse(_glist_cb,&cbdata);
3406 
3407 	bn_int_set(&rpacket->u.server_gamelistreply.gamecount, cbdata.counter);
3408 	eventlog(eventlog_level_debug, __FUNCTION__, "[%d] GAMELISTREPLY sent %u of %u games", conn_get_socket(c), cbdata.counter, cbdata.tcount);
3409     }
3410 
3411     conn_push_outqueue(c, rpacket);
3412     packet_del_ref(rpacket);
3413 
3414     return 0;
3415 }
3416 
_client_joingame(t_connection * c,t_packet const * const packet)3417 static int _client_joingame(t_connection * c, t_packet const *const packet)
3418 {
3419     char const *gamename;
3420     char const *gamepass;
3421     t_game *game;
3422     t_game_type gtype;
3423 
3424     if (packet_get_size(packet) < sizeof(t_client_join_game)) {
3425 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad JOIN_GAME packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_join_game), packet_get_size(packet));
3426 	return -1;
3427     }
3428 
3429     if (!(gamename = packet_get_str_const(packet, sizeof(t_client_join_game), GAME_NAME_LEN))) {
3430 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad CLIENT_JOIN_GAME (missing or too long gamename)", conn_get_socket(c));
3431 	return -1;
3432     }
3433 
3434     if (!(gamepass = packet_get_str_const(packet, sizeof(t_client_join_game) + strlen(gamename) + 1, GAME_PASS_LEN))) {
3435 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad CLIENT_JOIN_GAME packet (missing or too long gamepass)", conn_get_socket(c));
3436 	return -1;
3437     }
3438 
3439     eventlog(eventlog_level_debug, __FUNCTION__, "[%d] trying to join game \"%s\" pass=\"%s\"", conn_get_socket(c), gamename, gamepass);
3440 
3441     if (conn_get_joingamewhisper_ack(c) == 0) {
3442 	watchlist_notify_event(conn_get_account(c), gamename, conn_get_clienttag(c), watch_event_joingame);
3443 	conn_set_joingamewhisper_ack(c, 1);	/* 1 = already whispered. We reset this each time user joins a channel */
3444 	clanmember_on_change_status_by_connection(c);
3445     }
3446 
3447     if (conn_get_channel(c))
3448 	conn_set_channel(c, NULL);
3449 
3450     if (!strcmp(gamename, "BNet") && !handle_anongame_join(c)) {
3451 	gtype = game_type_anongame;
3452 	gamename = NULL;
3453 	return 0;		/* tmp: do not record any anongames as yet */
3454     } else {
3455 	if (!(game = gamelist_find_game(gamename, conn_get_clienttag(c), game_type_all))) {
3456 	    eventlog(eventlog_level_info, __FUNCTION__, "[%d] unable to find game \"%s\" for user to join", conn_get_socket(c), gamename);
3457 	    return 0;
3458 	}
3459 	gtype = game_get_type(game);
3460 	gamename = game_get_name(game);
3461 	if ((gtype == game_type_ladder && account_get_auth_joinladdergame(conn_get_account(c)) == 0) ||	/* default to true */
3462 	    (gtype != game_type_ladder && account_get_auth_joinnormalgame(conn_get_account(c)) == 0)) {	/* default to true */
3463 	    eventlog(eventlog_level_info, __FUNCTION__, "[%d] game join for \"%s\" to \"%s\" refused (no authority)", conn_get_socket(c), conn_get_username(c), gamename);
3464 	    /* If the user is not in a game, then map authorization
3465 	       will fail and keep them from playing. */
3466 	    return 0;
3467 	}
3468     }
3469 
3470     if (conn_set_game(c, gamename, gamepass, "", gtype, STARTVER_UNKNOWN) < 0)
3471 	eventlog(eventlog_level_info, __FUNCTION__, "[%d] \"%s\" joined game \"%s\", but could not be recorded on server", conn_get_socket(c), conn_get_username(c), gamename);
3472     else
3473 	eventlog(eventlog_level_info, __FUNCTION__, "[%d] \"%s\" joined game \"%s\"", conn_get_socket(c), conn_get_username(c), gamename);
3474 
3475     return 0;
3476 }
3477 
_client_startgame1(t_connection * c,t_packet const * const packet)3478 static int _client_startgame1(t_connection * c, t_packet const *const packet)
3479 {
3480     t_packet *rpacket;
3481 
3482     if (packet_get_size(packet) < sizeof(t_client_startgame1)) {
3483 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad STARTGAME1 packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_startgame1), packet_get_size(packet));
3484 	return -1;
3485     }
3486 
3487     {
3488 	char const *gamename;
3489 	char const *gamepass;
3490 	char const *gameinfo;
3491 	unsigned short bngtype;
3492 	unsigned int status;
3493 	t_game *currgame;
3494 
3495 	if (!(gamename = packet_get_str_const(packet, sizeof(t_client_startgame1), GAME_NAME_LEN))) {
3496 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad STARTGAME1 packet (missing or too long gamename)", conn_get_socket(c));
3497 	    return -1;
3498 	}
3499 	if (!(gamepass = packet_get_str_const(packet, sizeof(t_client_startgame1) + strlen(gamename) + 1, GAME_PASS_LEN))) {
3500 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad STARTGAME1 packet (missing or too long gamepass)", conn_get_socket(c));
3501 	    return -1;
3502 	}
3503 	if (!(gameinfo = packet_get_str_const(packet, sizeof(t_client_startgame1) + strlen(gamename) + 1 + strlen(gamepass) + 1, GAME_INFO_LEN))) {
3504 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad STARTGAME1 packet (missing or too long gameinfo)", conn_get_socket(c));
3505 	    return -1;
3506 	}
3507 	if (conn_get_joingamewhisper_ack(c) == 0) {
3508 	    if (watchlist_notify_event(conn_get_account(c), gamename, conn_get_clienttag(c), watch_event_joingame) == 0)
3509 		eventlog(eventlog_level_info, "handle_bnet", "Told Mutual Friends your in game %s", gamename);
3510 
3511 	    conn_set_joingamewhisper_ack(c, 1);	//1 = already whispered. We reset this each time user joins a channel
3512 	}
3513 
3514 
3515 	bngtype = bn_short_get(packet->u.client_startgame1.gametype);
3516 	eventlog(eventlog_level_debug, __FUNCTION__, "[%d] got startgame1 status for game \"%s\" is 0x%08x (gametype = 0x%04hx)", conn_get_socket(c), gamename, bn_int_get(packet->u.client_startgame1.status), bngtype);
3517 	status = bn_int_get(packet->u.client_startgame1.status) & CLIENT_STARTGAME1_STATUSMASK;
3518 
3519 	if ((currgame = conn_get_game(c))) {
3520 	    switch (status) {
3521 		case CLIENT_STARTGAME1_STATUS_STARTED:
3522 		    game_set_status(currgame, game_status_started);
3523 		    break;
3524 		case CLIENT_STARTGAME1_STATUS_FULL:
3525 		    game_set_status(currgame, game_status_full);
3526 		    break;
3527 		case CLIENT_STARTGAME1_STATUS_OPEN:
3528 		    game_set_status(currgame, game_status_open);
3529 		    break;
3530 		case CLIENT_STARTGAME1_STATUS_DONE:
3531 		    game_set_status(currgame, game_status_done);
3532 		    eventlog(eventlog_level_info, __FUNCTION__, "[%d] game \"%s\" is finished", conn_get_socket(c), gamename);
3533 		    break;
3534 	    }
3535 	} else if (status != CLIENT_STARTGAME1_STATUS_DONE) {
3536 	    t_game_type gtype;
3537 
3538 	    gtype = bngtype_to_gtype(conn_get_clienttag(c), bngtype);
3539 	    if ((gtype == game_type_ladder && account_get_auth_createladdergame(conn_get_account(c)) == 0) ||	/* default to true */
3540 		(gtype != game_type_ladder && account_get_auth_createnormalgame(conn_get_account(c)) == 0))	/* default to true */
3541 		eventlog(eventlog_level_info, __FUNCTION__, "[%d] game start for \"%s\" refused (no authority)", conn_get_socket(c), conn_get_username(c));
3542 	    else
3543 		conn_set_game(c, gamename, gamepass, gameinfo, gtype, STARTVER_GW1);
3544 
3545 	    if ((rpacket = packet_create(packet_class_bnet))) {
3546 		packet_set_size(rpacket, sizeof(t_server_startgame1_ack));
3547 		packet_set_type(rpacket, SERVER_STARTGAME1_ACK);
3548 
3549 		if (conn_get_game(c))
3550 		    bn_int_set(&rpacket->u.server_startgame1_ack.reply, SERVER_STARTGAME1_ACK_OK);
3551 		else
3552 		    bn_int_set(&rpacket->u.server_startgame1_ack.reply, SERVER_STARTGAME1_ACK_NO);
3553 
3554 		conn_push_outqueue(c, rpacket);
3555 		packet_del_ref(rpacket);
3556 	    }
3557 	} else
3558 	    eventlog(eventlog_level_info, __FUNCTION__, "[%d] client tried to set game status DONE to destroyed game", conn_get_socket(c));
3559     }
3560 
3561     return 0;
3562 }
3563 
_client_startgame3(t_connection * c,t_packet const * const packet)3564 static int _client_startgame3(t_connection * c, t_packet const *const packet)
3565 {
3566     t_packet *rpacket;
3567 
3568     if (packet_get_size(packet) < sizeof(t_client_startgame3)) {
3569 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad STARTGAME3 packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_startgame3), packet_get_size(packet));
3570 	return -1;
3571     }
3572 
3573     {
3574 	char const *gamename;
3575 	char const *gamepass;
3576 	char const *gameinfo;
3577 	unsigned short bngtype;
3578 	unsigned int status;
3579 	t_game *currgame;
3580 
3581 	if (!(gamename = packet_get_str_const(packet, sizeof(t_client_startgame3), GAME_NAME_LEN))) {
3582 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad STARTGAME3 packet (missing or too long gamename)", conn_get_socket(c));
3583 	    return -1;
3584 	}
3585 	if (!(gamepass = packet_get_str_const(packet, sizeof(t_client_startgame3) + strlen(gamename) + 1, GAME_PASS_LEN))) {
3586 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad STARTGAME3 packet (missing or too long gamepass)", conn_get_socket(c));
3587 	    return -1;
3588 	}
3589 	if (!(gameinfo = packet_get_str_const(packet, sizeof(t_client_startgame3) + strlen(gamename) + 1 + strlen(gamepass) + 1, GAME_INFO_LEN))) {
3590 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad STARTGAME3 packet (missing or too long gameinfo)", conn_get_socket(c));
3591 	    return -1;
3592 	}
3593 	if (conn_get_joingamewhisper_ack(c) == 0) {
3594 	    if (watchlist_notify_event(conn_get_account(c), gamename, conn_get_clienttag(c), watch_event_joingame) == 0)
3595 		eventlog(eventlog_level_info, "handle_bnet", "Told Mutual Friends your in game %s", gamename);
3596 
3597 	    conn_set_joingamewhisper_ack(c, 1);	//1 = already whispered. We reset this each time user joins a channel
3598 	}
3599 	bngtype = bn_short_get(packet->u.client_startgame3.gametype);
3600 	eventlog(eventlog_level_debug, __FUNCTION__, "[%d] got startgame3 status for game \"%s\" is 0x%08x (gametype = 0x%04hx)", conn_get_socket(c), gamename, bn_int_get(packet->u.client_startgame3.status), bngtype);
3601 	status = bn_int_get(packet->u.client_startgame3.status) & CLIENT_STARTGAME3_STATUSMASK;
3602 
3603 	if ((currgame = conn_get_game(c))) {
3604 	    switch (status) {
3605 		case CLIENT_STARTGAME3_STATUS_STARTED:
3606 		    game_set_status(currgame, game_status_started);
3607 		    break;
3608 		case CLIENT_STARTGAME3_STATUS_FULL:
3609 		    game_set_status(currgame, game_status_full);
3610 		    break;
3611 		case CLIENT_STARTGAME3_STATUS_OPEN1:
3612 		case CLIENT_STARTGAME3_STATUS_OPEN:
3613 		    game_set_status(currgame, game_status_open);
3614 		    break;
3615 		case CLIENT_STARTGAME3_STATUS_DONE:
3616 		    game_set_status(currgame, game_status_done);
3617 		    eventlog(eventlog_level_info, __FUNCTION__, "[%d] game \"%s\" is finished", conn_get_socket(c), gamename);
3618 		    break;
3619 	    }
3620 	} else if (status != CLIENT_STARTGAME3_STATUS_DONE) {
3621 	    t_game_type gtype;
3622 
3623 	    gtype = bngtype_to_gtype(conn_get_clienttag(c), bngtype);
3624 	    if ((gtype == game_type_ladder && account_get_auth_createladdergame(conn_get_account(c)) == 0) || (gtype != game_type_ladder && account_get_auth_createnormalgame(conn_get_account(c)) == 0))
3625 		eventlog(eventlog_level_info, __FUNCTION__, "[%d] game start for \"%s\" refused (no authority)", conn_get_socket(c), conn_get_username(c));
3626 	    else
3627 		conn_set_game(c, gamename, gamepass, gameinfo, gtype, STARTVER_GW3);
3628 
3629 	    if ((rpacket = packet_create(packet_class_bnet))) {
3630 		packet_set_size(rpacket, sizeof(t_server_startgame3_ack));
3631 		packet_set_type(rpacket, SERVER_STARTGAME3_ACK);
3632 
3633 		if (conn_get_game(c))
3634 		    bn_int_set(&rpacket->u.server_startgame3_ack.reply, SERVER_STARTGAME3_ACK_OK);
3635 		else
3636 		    bn_int_set(&rpacket->u.server_startgame3_ack.reply, SERVER_STARTGAME3_ACK_NO);
3637 
3638 		conn_push_outqueue(c, rpacket);
3639 		packet_del_ref(rpacket);
3640 	    }
3641 	} else
3642 	    eventlog(eventlog_level_info, __FUNCTION__, "[%d] client tried to set game status DONE to destroyed game", conn_get_socket(c));
3643     }
3644 
3645     return 0;
3646 }
3647 
_client_startgame4(t_connection * c,t_packet const * const packet)3648 static int _client_startgame4(t_connection * c, t_packet const *const packet)
3649 {
3650     t_packet *rpacket;
3651 
3652     if (packet_get_size(packet) < sizeof(t_client_startgame4)) {
3653 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad STARTGAME4 packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_startgame4), packet_get_size(packet));
3654 	return -1;
3655     }
3656     // Quick hack to make W3 part channels when creating a game
3657     if (conn_get_channel(c))
3658 	conn_set_channel(c, NULL);
3659 
3660     {
3661 	char const *gamename;
3662 	char const *gamepass;
3663 	char const *gameinfo;
3664 	unsigned short bngtype;
3665 	unsigned int status;
3666 	unsigned int flag;
3667 	unsigned short option;
3668 	t_game *currgame;
3669 
3670 	if (!(gamename = packet_get_str_const(packet, sizeof(t_client_startgame4), GAME_NAME_LEN))) {
3671 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad STARTGAME4 packet (missing or too long gamename)", conn_get_socket(c));
3672 	    return -1;
3673 	}
3674 	if (!(gamepass = packet_get_str_const(packet, sizeof(t_client_startgame4) + strlen(gamename) + 1, GAME_PASS_LEN))) {
3675 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad STARTGAME4 packet (missing or too long gamepass)", conn_get_socket(c));
3676 	    return -1;
3677 	}
3678 	if (!(gameinfo = packet_get_str_const(packet, sizeof(t_client_startgame4) + strlen(gamename) + 1 + strlen(gamepass) + 1, GAME_INFO_LEN))) {
3679 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad STARTGAME4 packet (missing or too long gameinfo)", conn_get_socket(c));
3680 	    return -1;
3681 	}
3682 	if (conn_get_joingamewhisper_ack(c) == 0) {
3683 	    if (watchlist_notify_event(conn_get_account(c), gamename, conn_get_clienttag(c), watch_event_joingame) == 0)
3684 		eventlog(eventlog_level_info, "handle_bnet", "Told Mutual Friends your in game %s", gamename);
3685 
3686 	    conn_set_joingamewhisper_ack(c, 1);	//1 = already whispered. We reset this each time user joins a channel
3687 	}
3688 	bngtype = bn_short_get(packet->u.client_startgame4.gametype);
3689 	option = bn_short_get(packet->u.client_startgame4.option);
3690 	status = bn_int_get(packet->u.client_startgame4.status);
3691 	flag = bn_short_get(packet->u.client_startgame4.flag);
3692 
3693 	eventlog(eventlog_level_debug, __FUNCTION__, "[%d] got startgame4 status for game \"%s\" is 0x%08x (gametype=0x%04hx option=0x%04hx, flag=0x%04hx)", conn_get_socket(c), gamename, status, bngtype, option, flag);
3694 
3695 	if ((currgame = conn_get_game(c))) {
3696 	    if ((status & CLIENT_STARTGAME4_STATUSMASK_OPEN_VALID) == status) {
3697 		if (status & CLIENT_STARTGAME4_STATUS_START)
3698 		    game_set_status(currgame, game_status_started);
3699 		else if (status & CLIENT_STARTGAME4_STATUS_FULL)
3700 		    game_set_status(currgame, game_status_full);
3701 		else
3702 		    game_set_status(currgame, game_status_open);
3703 	    } else {
3704 		eventlog(eventlog_level_error, __FUNCTION__, "[%d] unknown startgame4 status %d (clienttag: %s)", conn_get_socket(c), status, clienttag_uint_to_str(conn_get_clienttag(c)));
3705 	    }
3706 	} else if ((status & CLIENT_STARTGAME4_STATUSMASK_INIT_VALID) == status) {
3707 	    /*valid creation status would be:
3708 	       0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13, 0x80, 0x81, 0x82, 0x83 */
3709 
3710 	    t_game_type gtype;
3711 
3712 	    gtype = bngtype_to_gtype(conn_get_clienttag(c), bngtype);
3713 	    if ((gtype == game_type_ladder && account_get_auth_createladdergame(conn_get_account(c)) == 0) || (gtype != game_type_ladder && account_get_auth_createnormalgame(conn_get_account(c)) == 0))
3714 		eventlog(eventlog_level_info, __FUNCTION__, "[%d] game start for \"%s\" refused (no authority)", conn_get_socket(c), conn_get_username(c));
3715 	    else if (conn_set_game(c, gamename, gamepass, gameinfo, gtype, STARTVER_GW4) == 0) {
3716 		game_set_option(conn_get_game(c), bngoption_to_goption(conn_get_clienttag(c), gtype, option));
3717 		if (status & CLIENT_STARTGAME4_STATUS_PRIVATE)
3718 		    game_set_flag(conn_get_game(c), game_flag_private);
3719 		if (status & CLIENT_STARTGAME4_STATUS_FULL)
3720 		    game_set_status(conn_get_game(c), game_status_full);
3721         if (bngtype == CLIENT_GAMELISTREQ_LOADED) /* PELISH: seems strange but it is really needed for loaded games */
3722 		    game_set_status(conn_get_game(c), game_status_loaded);
3723 		//FIXME: still need special handling for status disc-is-loss and replay
3724 	    }
3725 	} else
3726 	    eventlog(eventlog_level_info, __FUNCTION__, "[%d] client tried to set game status 0x%x to unexistent game (clienttag: %s)", conn_get_socket(c), status, clienttag_uint_to_str(conn_get_clienttag(c)));
3727     }
3728 
3729     if ((rpacket = packet_create(packet_class_bnet))) {
3730 	packet_set_size(rpacket, sizeof(t_server_startgame4_ack));
3731 	packet_set_type(rpacket, SERVER_STARTGAME4_ACK);
3732 
3733 	if (conn_get_game(c))
3734 	    bn_int_set(&rpacket->u.server_startgame4_ack.reply, SERVER_STARTGAME4_ACK_OK);
3735 	else
3736 	    bn_int_set(&rpacket->u.server_startgame4_ack.reply, SERVER_STARTGAME4_ACK_NO);
3737 	conn_push_outqueue(c, rpacket);
3738 	packet_del_ref(rpacket);
3739     }
3740 
3741     /* First, send an ECHO_REQ */
3742     if ((rpacket = packet_create(packet_class_bnet))) {
3743 	packet_set_size(rpacket, sizeof(t_server_echoreq));
3744 	packet_set_type(rpacket, SERVER_ECHOREQ);
3745 	bn_int_set(&rpacket->u.server_echoreq.ticks, get_ticks());
3746 	conn_push_outqueue(c, rpacket);
3747 	packet_del_ref(rpacket);
3748     }
3749 
3750     return 0;
3751 }
3752 
_client_closegame(t_connection * c,t_packet const * const packet)3753 static int _client_closegame(t_connection * c, t_packet const *const packet)
3754 {
3755     t_game *game;
3756 
3757     eventlog(eventlog_level_info, __FUNCTION__, "[%d] client closing game", conn_get_socket(c));
3758     if (packet_get_type(packet) == CLIENT_CLOSEGAME2 || ((conn_get_clienttag(c) != CLIENTTAG_WARCRAFT3_UINT) && (conn_get_clienttag(c) != CLIENTTAG_WAR3XP_UINT)))
3759 	conn_set_game(c, NULL, NULL, NULL, game_type_none, 0);
3760     else if ((game = conn_get_game(c)))
3761 	game_set_status(game, game_status_started);
3762 
3763     return 0;
3764 }
3765 
_client_gamereport(t_connection * c,t_packet const * const packet)3766 static int _client_gamereport(t_connection * c, t_packet const *const packet)
3767 {
3768     if (packet_get_size(packet) < sizeof(t_client_game_report)) {
3769 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad GAME_REPORT packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_game_report), packet_get_size(packet));
3770 	return -1;
3771     }
3772 
3773     {
3774 	t_account *my_account;
3775 	t_account *other_account;
3776 	t_game *game;
3777 	unsigned int player_count;
3778 	unsigned int i,s;
3779 	t_client_game_report_result const *result_data;
3780 	unsigned int result_off;
3781 	t_game_result result;
3782 	char const *player;
3783 	unsigned int player_off;
3784 	t_game_result *results;
3785 
3786 	player_count = bn_int_get(packet->u.client_gamerep.count);
3787 
3788 	if (!(game = conn_get_game(c))) {
3789 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got GAME_REPORT when not in a game for user \"%s\"", conn_get_socket(c), conn_get_username(c));
3790 	    return -1;
3791 	}
3792 
3793 	eventlog(eventlog_level_info, __FUNCTION__, "[%d] CLIENT_GAME_REPORT: %s (%u players)", conn_get_socket(c), conn_get_username(c), player_count);
3794 	my_account = conn_get_account(c);
3795 
3796 	results = xmalloc(sizeof(t_game_result) * game_get_count(game));
3797 
3798 	for (i = 0; i < game_get_count(game); i++)
3799 	    results[i] = game_result_none;
3800 
3801 	for (i = 0, result_off = sizeof(t_client_game_report), player_off = sizeof(t_client_game_report) + player_count * sizeof(t_client_game_report_result); i < player_count; i++, result_off += sizeof(t_client_game_report_result), player_off += strlen(player) + 1) {
3802 	    if (!(result_data = packet_get_data_const(packet, result_off, sizeof(t_client_game_report_result)))) {
3803 		eventlog(eventlog_level_error, __FUNCTION__, "[%d] got corrupt GAME_REPORT packet (missing results %u-%u)", conn_get_socket(c), i + 1, player_count);
3804 		break;
3805 	    }
3806 	    if (!(player = packet_get_str_const(packet, player_off, USER_NAME_MAX))) {
3807 		eventlog(eventlog_level_error, __FUNCTION__, "[%d] got corrupt GAME_REPORT packet (missing players %u-%u)", conn_get_socket(c), i + 1, player_count);
3808 		break;
3809 	    }
3810 
3811 	    if (player[0] == '\0')	/* empty slots have empty player name */
3812 		continue;
3813 
3814 	    if (i >= game_get_count(game)) {
3815 		eventlog(eventlog_level_error, __FUNCTION__, "[%d] got more results than the game had players - ignoring extra results", conn_get_socket(c));
3816 		break;
3817 	    }
3818 
3819 	    if (!(other_account = accountlist_find_account(player))) {
3820 		eventlog(eventlog_level_error, __FUNCTION__, "[%d] got GAME_REPORT with unknown player \"%s\"", conn_get_socket(c), player);
3821 		break;
3822 	    }
3823 
3824 	    // as player position in game structure and in game report might differ,
3825 	    // search for right position
3826 	    for (s=0; s<game_get_count(game); s++)
3827 	    {
3828 	        if (game_get_player(game,s)==other_account) break;
3829 	    }
3830 
3831 	    if (s<game_get_count(game))
3832 	    {
3833 	      result = bngresult_to_gresult(bn_int_get(result_data->result));
3834 	      results[s] = result;
3835 	      eventlog(eventlog_level_debug, __FUNCTION__, "[%d] got player %d (\"%s\") result %s", conn_get_socket(c), i, player, game_result_get_str(result));
3836 	    }
3837 	    else
3838 	    {
3839 	       eventlog(eventlog_level_error,__FUNCTION__,"[%d] got GAME_REPORT for non-participating player \"%s\"",conn_get_socket(c),player);
3840 	    }
3841 
3842 	}
3843 
3844 	if (i == player_count) {	/* if everything checked out... */
3845 	    char const *head;
3846 	    char const *body;
3847 
3848 	    if (!(head = packet_get_str_const(packet, player_off, MAX_GAMEREP_HEAD_STR)))
3849 		eventlog(eventlog_level_error, __FUNCTION__, "[%d] got GAME_REPORT with missing or too long report head", conn_get_socket(c));
3850 	    else {
3851 		player_off += strlen(head) + 1;
3852 		if (!(body = packet_get_str_const(packet, player_off, MAX_GAMEREP_BODY_STR)))
3853 		    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got GAME_REPORT with missing or too ling report body", conn_get_socket(c));
3854 		else
3855 		    game_set_report(game, my_account, head, body);
3856 	    }
3857 	}
3858 
3859 	if (game_set_reported_results(game, my_account, results) < 0)
3860 	    xfree((void *) results);
3861 
3862 	eventlog(eventlog_level_debug, __FUNCTION__, "[%d] finished parsing result... now leaving game", conn_get_socket(c));
3863 	conn_set_game(c, NULL, NULL, NULL, game_type_none, 0);
3864     }
3865 
3866     return 0;
3867 }
3868 
_client_leavechannel(t_connection * c,t_packet const * const packet)3869 static int _client_leavechannel(t_connection * c, t_packet const *const packet)
3870 {
3871     /* If this user in a channel, notify everyone that the user has left */
3872     if (conn_get_channel(c))
3873 	conn_set_channel(c, NULL);
3874     return 0;
3875 }
3876 
_client_ladderreq(t_connection * c,t_packet const * const packet)3877 static int _client_ladderreq(t_connection * c, t_packet const *const packet)
3878 {
3879     t_packet *rpacket;
3880 
3881 
3882     if (packet_get_size(packet) < sizeof(t_client_ladderreq)) {
3883 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad LADDERREQ packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_ladderreq), packet_get_size(packet));
3884 	return -1;
3885     }
3886 
3887     {
3888 	t_ladder_entry entry;
3889 	unsigned int i;
3890 	unsigned int type;
3891 	unsigned int start;
3892 	unsigned int count;
3893 	unsigned int idnum;
3894 	t_account *account;
3895 	t_clienttag clienttag;
3896 	char const *timestr;
3897 	t_bnettime bt;
3898 	t_ladder_id id;
3899 
3900 	clienttag = conn_get_clienttag(c);
3901 
3902 	type = bn_int_get(packet->u.client_ladderreq.type);
3903 	start = bn_int_get(packet->u.client_ladderreq.startplace);
3904 	count = bn_int_get(packet->u.client_ladderreq.count);
3905 	idnum = bn_int_get(packet->u.client_ladderreq.id);
3906 
3907 	/* eventlog(eventlog_level_debug,__FUNCTION__,"got LADDERREQ type=%u start=%u count=%u id=%u",type,start,count,id); */
3908 
3909 	switch (idnum) {
3910 	    case CLIENT_LADDERREQ_ID_STANDARD:
3911 		id = ladder_id_normal;
3912 		break;
3913 	    case CLIENT_LADDERREQ_ID_IRONMAN:
3914 		id = ladder_id_ironman;
3915 		break;
3916 	    default:
3917 		eventlog(eventlog_level_error, __FUNCTION__, "[%d] got unknown ladder ladderreq.id=0x%08x", conn_get_socket(c), idnum);
3918 		id = ladder_id_normal;
3919 	}
3920 
3921 	if (!(rpacket = packet_create(packet_class_bnet)))
3922 	    return -1;
3923 	packet_set_size(rpacket, sizeof(t_server_ladderreply));
3924 	packet_set_type(rpacket, SERVER_LADDERREPLY);
3925 
3926 	bn_int_set(&rpacket->u.server_ladderreply.clienttag, clienttag);
3927 	bn_int_set(&rpacket->u.server_ladderreply.id, idnum);
3928 	bn_int_set(&rpacket->u.server_ladderreply.type, type);
3929 	bn_int_set(&rpacket->u.server_ladderreply.startplace, start);
3930 	bn_int_set(&rpacket->u.server_ladderreply.count, count);
3931 
3932 	for (i = start; i < start + count; i++) {
3933 	    switch (type) {
3934 		case CLIENT_LADDERREQ_TYPE_HIGHESTRATED:
3935 		    if (!(account = ladder_get_account_by_rank(i + 1, ladder_sort_highestrated, ladder_time_active, clienttag, id)))
3936 			account = ladder_get_account_by_rank(i + 1, ladder_sort_highestrated, ladder_time_current, clienttag, id);
3937 		    break;
3938 		case CLIENT_LADDERREQ_TYPE_MOSTWINS:
3939 		    if (!(account = ladder_get_account_by_rank(i + 1, ladder_sort_mostwins, ladder_time_active, clienttag, id)))
3940 			account = ladder_get_account_by_rank(i + 1, ladder_sort_mostwins, ladder_time_current, clienttag, id);
3941 		    break;
3942 		case CLIENT_LADDERREQ_TYPE_MOSTGAMES:
3943 		    if (!(account = ladder_get_account_by_rank(i + 1, ladder_sort_mostgames, ladder_time_active, clienttag, id)))
3944 			account = ladder_get_account_by_rank(i + 1, ladder_sort_mostgames, ladder_time_current, clienttag, id);
3945 		    break;
3946 		default:
3947 		    account = NULL;
3948 		    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got unknown value for ladderreq.type=%u", conn_get_socket(c), type);
3949 	    }
3950 
3951 	    if (account) {
3952 		bn_int_set(&entry.active.wins, account_get_ladder_active_wins(account, clienttag, id));
3953 		bn_int_set(&entry.active.loss, account_get_ladder_active_losses(account, clienttag, id));
3954 		bn_int_set(&entry.active.disconnect, account_get_ladder_active_disconnects(account, clienttag, id));
3955 		bn_int_set(&entry.active.rating, account_get_ladder_active_rating(account, clienttag, id));
3956 		bn_int_set(&entry.active.rank, account_get_ladder_active_rank(account,clienttag,id)-1);
3957 		if (!(timestr = account_get_ladder_active_last_time(account, clienttag, id)))
3958 		    timestr = BNETD_LADDER_DEFAULT_TIME;
3959 		bnettime_set_str(&bt, timestr);
3960 		bnettime_to_bn_long(bt, &entry.lastgame_active);
3961 
3962 		bn_int_set(&entry.current.wins, account_get_ladder_wins(account, clienttag, id));
3963 		bn_int_set(&entry.current.loss, account_get_ladder_losses(account, clienttag, id));
3964 		bn_int_set(&entry.current.disconnect, account_get_ladder_disconnects(account, clienttag, id));
3965 		bn_int_set(&entry.current.rating, account_get_ladder_rating(account, clienttag, id));
3966 		bn_int_set(&entry.current.rank, account_get_ladder_rank(account,clienttag,id)-1);
3967 		if (!(timestr = account_get_ladder_last_time(account, clienttag, id)))
3968 		    timestr = BNETD_LADDER_DEFAULT_TIME;
3969 		bnettime_set_str(&bt, timestr);
3970 		bnettime_to_bn_long(bt, &entry.lastgame_current);
3971 	    } else {
3972 		bn_int_set(&entry.active.wins, 0);
3973 		bn_int_set(&entry.active.loss, 0);
3974 		bn_int_set(&entry.active.disconnect, 0);
3975 		bn_int_set(&entry.active.rating, 0);
3976 		bn_int_set(&entry.active.rank, 0);
3977 		bn_long_set_a_b(&entry.lastgame_active, 0, 0);
3978 
3979 		bn_int_set(&entry.current.wins, 0);
3980 		bn_int_set(&entry.current.loss, 0);
3981 		bn_int_set(&entry.current.disconnect, 0);
3982 		bn_int_set(&entry.current.rating, 0);
3983 		bn_int_set(&entry.current.rank, 0);
3984 		bn_long_set_a_b(&entry.lastgame_current, 0, 0);
3985 	    }
3986 
3987 	    bn_int_set(&entry.ttest[0], i);	// rank
3988 	    bn_int_set(&entry.ttest[1], 0);	//
3989 	    bn_int_set(&entry.ttest[2], 0);	//
3990 	    if (account)
3991 		bn_int_set(&entry.ttest[3], account_get_ladder_high_rating(account, clienttag, id));
3992 	    else
3993 		bn_int_set(&entry.ttest[3], 0);
3994 	    bn_int_set(&entry.ttest[4], 0);	//
3995 	    bn_int_set(&entry.ttest[5], 0);	//
3996 
3997 	    packet_append_data(rpacket, &entry, sizeof(entry));
3998 
3999 	    if (account)
4000 		packet_append_string(rpacket, account_get_name(account));
4001 	    else
4002 		packet_append_string(rpacket, " ");	/* use a space so the client won't show the user's own account when double-clicked on */
4003 	}
4004 
4005 	conn_push_outqueue(c, rpacket);
4006 	packet_del_ref(rpacket);
4007     }
4008 
4009     return 0;
4010 }
4011 
_client_laddersearchreq(t_connection * c,t_packet const * const packet)4012 static int _client_laddersearchreq(t_connection * c, t_packet const *const packet)
4013 {
4014     t_packet *rpacket;
4015 
4016     if (packet_get_size(packet) < sizeof(t_client_laddersearchreq)) {
4017 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad LADDERSEARCHREQ packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_laddersearchreq), packet_get_size(packet));
4018 	return -1;
4019     }
4020 
4021     {
4022 	char const *playername;
4023 	t_account *account;
4024 	unsigned int idnum;
4025 	unsigned int rank;	/* starts at zero */
4026 	t_ladder_id id;
4027 	t_clienttag ctag = conn_get_clienttag(c);
4028 
4029 	idnum = bn_int_get(packet->u.client_laddersearchreq.id);
4030 
4031 	switch (idnum) {
4032 	    case CLIENT_LADDERREQ_ID_STANDARD:
4033 		id = ladder_id_normal;
4034 		break;
4035 	    case CLIENT_LADDERREQ_ID_IRONMAN:
4036 		id = ladder_id_ironman;
4037 		break;
4038 	    default:
4039 		eventlog(eventlog_level_error, __FUNCTION__, "[%d] got unknown ladder laddersearchreq.id=0x%08x", conn_get_socket(c), idnum);
4040 		id = ladder_id_normal;
4041 	}
4042 
4043 	if (!(playername = packet_get_str_const(packet, sizeof(t_client_laddersearchreq), USER_NAME_MAX))) {
4044 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad LADDERSEARCHREQ packet (missing or too long playername)", conn_get_socket(c));
4045 	    return -1;
4046 	}
4047 
4048 	if (!(account = accountlist_find_account(playername)))
4049 	    rank = SERVER_LADDERSEARCHREPLY_RANK_NONE;
4050 	else {
4051 	    switch (bn_int_get(packet->u.client_laddersearchreq.type)) {
4052 		case CLIENT_LADDERSEARCHREQ_TYPE_HIGHESTRATED:
4053 		    if (!(rank=ladder_get_rank_by_account(account, ladder_sort_highestrated, ladder_time_active, ctag, id)))
4054 		    {
4055 			if (!(rank = ladder_get_rank_by_account(account, ladder_sort_highestrated,
4056 			                                        ladder_time_current, ctag, id)) ||
4057 			   (ladder_get_account_by_rank(rank, ladder_sort_highestrated, ladder_time_active, ctag, id)))
4058 			    rank = 0;
4059 		    }
4060 		    break;
4061 		case CLIENT_LADDERSEARCHREQ_TYPE_MOSTWINS:
4062 		    if (!(rank=ladder_get_rank_by_account(account, ladder_sort_mostwins, ladder_time_active, ctag, id)))
4063 		    {
4064 			if (!(rank = ladder_get_rank_by_account(account, ladder_sort_mostwins,
4065 			                                        ladder_time_current, ctag, id)) ||
4066 			   (ladder_get_account_by_rank(rank, ladder_sort_mostwins, ladder_time_active, ctag, id)))
4067 			    rank = 0;
4068 		    }
4069 		    break;
4070 		case CLIENT_LADDERSEARCHREQ_TYPE_MOSTGAMES:
4071 		    if (!(rank=ladder_get_rank_by_account(account, ladder_sort_mostgames, ladder_time_active, ctag, id)))
4072 		    {
4073 			if (!(rank = ladder_get_rank_by_account(account, ladder_sort_mostgames,
4074 			                                        ladder_time_current, ctag, id)) ||
4075 			   (ladder_get_account_by_rank(rank, ladder_sort_mostgames, ladder_time_active, ctag, id)))
4076 			    rank = 0;
4077 		    }
4078 		    break;
4079 		default:
4080 		    rank = 0;
4081 		    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got unknown ladder search type %u", conn_get_socket(c), bn_int_get(packet->u.client_laddersearchreq.type));
4082 	    }
4083 
4084 	    if (rank == 0)
4085 		rank = SERVER_LADDERSEARCHREPLY_RANK_NONE;
4086 	    else
4087 		rank--;
4088 	}
4089 
4090 	if (!(rpacket = packet_create(packet_class_bnet)))
4091 	    return -1;
4092 	packet_set_size(rpacket, sizeof(t_server_laddersearchreply));
4093 	packet_set_type(rpacket, SERVER_LADDERSEARCHREPLY);
4094 	bn_int_set(&rpacket->u.server_laddersearchreply.rank, rank);
4095 	conn_push_outqueue(c, rpacket);
4096 	packet_del_ref(rpacket);
4097     }
4098 
4099     return 0;
4100 }
4101 
_client_mapauthreq1(t_connection * c,t_packet const * const packet)4102 static int _client_mapauthreq1(t_connection * c, t_packet const *const packet)
4103 {
4104     t_packet *rpacket;
4105 
4106     if (packet_get_size(packet) < sizeof(t_client_mapauthreq1)) {
4107 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad MAPAUTHREQ1 packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_mapauthreq1), packet_get_size(packet));
4108 	return -1;
4109     }
4110 
4111     {
4112 	char const *mapname;
4113 	t_game *game;
4114 
4115 	if (!(mapname = packet_get_str_const(packet, sizeof(t_client_mapauthreq1), MAP_NAME_LEN))) {
4116 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad MAPAUTHREQ1 packet (missing or too long mapname)", conn_get_socket(c));
4117 	    return -1;
4118 	}
4119 
4120 	game = conn_get_game(c);
4121 
4122 	if (game) {
4123 	    eventlog(eventlog_level_info, __FUNCTION__, "[%d] map auth requested for map \"%s\" gametype \"%s\"", conn_get_socket(c), mapname, game_type_get_str(game_get_type(game)));
4124 	    game_set_mapname(game, mapname);
4125 	} else
4126 	    eventlog(eventlog_level_info, __FUNCTION__, "[%d] map auth requested when not in a game", conn_get_socket(c));
4127 
4128 	if ((rpacket = packet_create(packet_class_bnet))) {
4129 	    unsigned int val;
4130 
4131 	    if (!game) {
4132 		val = SERVER_MAPAUTHREPLY1_NO;
4133 		eventlog(eventlog_level_debug, __FUNCTION__, "[%d] map authorization denied (not in a game)", conn_get_socket(c));
4134 	    } else if (strcasecmp(game_get_mapname(game), mapname) != 0) {
4135 		val = SERVER_MAPAUTHREPLY1_NO;
4136 		eventlog(eventlog_level_debug, __FUNCTION__, "[%d] map authorization denied (map name \"%s\" does not match game map name \"%s\")", conn_get_socket(c), mapname, game_get_mapname(game));
4137 	    } else {
4138 		game_set_status(game, game_status_started);
4139 
4140 		if (game_get_type(game) == game_type_ladder) {
4141 		    val = SERVER_MAPAUTHREPLY1_LADDER_OK;
4142 		    eventlog(eventlog_level_debug, __FUNCTION__, "[%d] giving map ladder authorization (in a ladder game)", conn_get_socket(c));
4143 		} else if (ladder_check_map(game_get_mapname(game), game_get_maptype(game), conn_get_clienttag(c))) {
4144 		    val = SERVER_MAPAUTHREPLY1_LADDER_OK;
4145 		    eventlog(eventlog_level_debug, __FUNCTION__, "[%d] giving map ladder authorization (is a ladder map)", conn_get_socket(c));
4146 		} else {
4147 		    val = SERVER_MAPAUTHREPLY1_OK;
4148 		    eventlog(eventlog_level_debug, __FUNCTION__, "[%d] giving map normal authorization", conn_get_socket(c));
4149 		}
4150 	    }
4151 
4152 	    packet_set_size(rpacket, sizeof(t_server_mapauthreply1));
4153 	    packet_set_type(rpacket, SERVER_MAPAUTHREPLY1);
4154 	    bn_int_set(&rpacket->u.server_mapauthreply1.response, val);
4155 	    conn_push_outqueue(c, rpacket);
4156 	    packet_del_ref(rpacket);
4157 	}
4158     }
4159 
4160     return 0;
4161 }
4162 
_client_mapauthreq2(t_connection * c,t_packet const * const packet)4163 static int _client_mapauthreq2(t_connection * c, t_packet const *const packet)
4164 {
4165     t_packet *rpacket;
4166 
4167     if (packet_get_size(packet) < sizeof(t_client_mapauthreq2)) {
4168 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad MAPAUTHREQ2 packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_mapauthreq2), packet_get_size(packet));
4169 	return -1;
4170     }
4171 
4172     {
4173 	char const *mapname;
4174 	t_game *game;
4175 
4176 	if (!(mapname = packet_get_str_const(packet, sizeof(t_client_mapauthreq2), MAP_NAME_LEN))) {
4177 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad MAPAUTHREQ2 packet (missing or too long mapname)", conn_get_socket(c));
4178 	    return -1;
4179 	}
4180 
4181 	game = conn_get_game(c);
4182 
4183 	if (game) {
4184 	    eventlog(eventlog_level_info, __FUNCTION__, "[%d] map auth requested for map \"%s\" gametype \"%s\"", conn_get_socket(c), mapname, game_type_get_str(game_get_type(game)));
4185 	    game_set_mapname(game, mapname);
4186 	} else
4187 	    eventlog(eventlog_level_info, __FUNCTION__, "[%d] map auth requested when not in a game", conn_get_socket(c));
4188 
4189 	if ((rpacket = packet_create(packet_class_bnet))) {
4190 	    unsigned int val;
4191 
4192 	    if (!game) {
4193 		val = SERVER_MAPAUTHREPLY2_NO;
4194 		eventlog(eventlog_level_debug, __FUNCTION__, "[%d] map authorization denied (not in a game)", conn_get_socket(c));
4195 	    } else if (strcasecmp(game_get_mapname(game), mapname) != 0) {
4196 		val = SERVER_MAPAUTHREPLY2_NO;
4197 		eventlog(eventlog_level_debug, __FUNCTION__, "[%d] map authorization denied (map name \"%s\" does not match game map name \"%s\")", conn_get_socket(c), mapname, game_get_mapname(game));
4198 	    } else {
4199 		game_set_status(game, game_status_started);
4200 
4201 		if (game_get_type(game) == game_type_ladder) {
4202 		    val = SERVER_MAPAUTHREPLY2_LADDER_OK;
4203 		    eventlog(eventlog_level_debug, __FUNCTION__, "[%d] giving map ladder authorization (in a ladder game)", conn_get_socket(c));
4204 		} else if (ladder_check_map(game_get_mapname(game), game_get_maptype(game), conn_get_clienttag(c))) {
4205 		    val = SERVER_MAPAUTHREPLY2_LADDER_OK;
4206 		    eventlog(eventlog_level_debug, __FUNCTION__, "[%d] giving map ladder authorization (is a ladder map)", conn_get_socket(c));
4207 		} else {
4208 		    val = SERVER_MAPAUTHREPLY2_OK;
4209 		    eventlog(eventlog_level_debug, __FUNCTION__, "[%d] giving map normal authorization", conn_get_socket(c));
4210 		}
4211 	    }
4212 
4213 	    packet_set_size(rpacket, sizeof(t_server_mapauthreply2));
4214 	    packet_set_type(rpacket, SERVER_MAPAUTHREPLY2);
4215 	    bn_int_set(&rpacket->u.server_mapauthreply2.response, val);
4216 	    conn_push_outqueue(c, rpacket);
4217 	    packet_del_ref(rpacket);
4218 	}
4219     }
4220 
4221     return 0;
4222 }
4223 
_client_changeclient(t_connection * c,t_packet const * const packet)4224 static int _client_changeclient(t_connection * c, t_packet const *const packet)
4225 {
4226     t_versioncheck *vc;
4227 
4228     if (packet_get_size(packet) < sizeof(t_client_changeclient)) {
4229 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad CLIENT_CHANGECLIENT packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_changeclient), packet_get_size(packet));
4230 	return -1;
4231     }
4232 
4233     if (_check_allowed_client(bn_int_get(packet->u.client_changeclient.clienttag))) {
4234 	conn_set_state(c, conn_state_destroy);
4235 	return 0;
4236     }
4237 
4238     conn_set_clienttag(c, bn_int_get(packet->u.client_changeclient.clienttag));
4239 
4240     vc = conn_get_versioncheck(c);
4241     versioncheck_set_versiontag(vc, clienttag_uint_to_str(conn_get_clienttag(c)));
4242 
4243     if (vc && versioncheck_get_versiontag(vc)) {
4244 	switch (versioncheck_validate(vc, conn_get_archtag(c), conn_get_clienttag(c), conn_get_clientexe(c), conn_get_versionid(c), conn_get_gameversion(c), conn_get_checksum(c))) {
4245 	    case -1:		/* failed test... client has been modified */
4246 	    case 0:		/* not listed in table... can't tell if client has been modified */
4247 		eventlog(eventlog_level_error, __FUNCTION__, "[%d] error revalidating, allowing anyway", conn_get_socket(c));
4248 		break;
4249 	}
4250 
4251 	eventlog(eventlog_level_info, __FUNCTION__, "[%d] client versiontag set to \"%s\"", conn_get_socket(c), versioncheck_get_versiontag(vc));
4252     }
4253 
4254     return 0;
4255 }
4256 
_client_w3xp_clanmemberlistreq(t_connection * c,t_packet const * const packet)4257 static int _client_w3xp_clanmemberlistreq(t_connection * c, t_packet const *const packet)
4258 {
4259     if (packet_get_size(packet) < sizeof(t_client_w3xp_clanmemberlist_req)) {
4260 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad W3XP_CLANMEMBERLIST_REQ packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_w3xp_clanmemberlist_req), packet_get_size(packet));
4261 	return -1;
4262     }
4263 
4264     clan_send_memberlist(c, packet);
4265     return 0;
4266 }
4267 
_client_w3xp_clan_motdreq(t_connection * c,t_packet const * const packet)4268 static int _client_w3xp_clan_motdreq(t_connection * c, t_packet const *const packet)
4269 {
4270     if (packet_get_size(packet) < sizeof(t_client_w3xp_clan_motdreq)) {
4271 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad W3XP_CLAN_MOTDREQ packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_w3xp_clan_motdreq), packet_get_size(packet));
4272 	return -1;
4273     }
4274 
4275     clan_send_motd_reply(c, packet);
4276     return 0;
4277 }
4278 
_client_w3xp_clan_motdchg(t_connection * c,t_packet const * const packet)4279 static int _client_w3xp_clan_motdchg(t_connection * c, t_packet const *const packet)
4280 {
4281     if (packet_get_size(packet) < sizeof(t_client_w3xp_clan_motdreq)) {
4282 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad W3XP_CLAN_MOTDCHGREQ packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_w3xp_clan_motdreq), packet_get_size(packet));
4283 	return -1;
4284     }
4285 
4286     clan_save_motd_chg(c, packet);
4287     return 0;
4288 }
4289 
_client_w3xp_clan_disbandreq(t_connection * c,t_packet const * const packet)4290 static int _client_w3xp_clan_disbandreq(t_connection * c, t_packet const *const packet)
4291 {
4292     t_packet *rpacket;
4293 
4294     if (packet_get_size(packet) < sizeof(t_client_w3xp_clan_disbandreq)) {
4295         eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad W3XP_CLAN_DISBANDREQ packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_w3xp_clan_disbandreq), packet_get_size(packet));
4296         return -1;
4297     }
4298 
4299     if ((rpacket = packet_create(packet_class_bnet))) {
4300         t_clan *clan;
4301         t_clanmember *member;
4302         t_account *account;
4303 
4304         packet_set_size(rpacket, sizeof(t_server_w3xp_clan_disbandreply));
4305         packet_set_type(rpacket, SERVER_W3XP_CLAN_DISBANDREPLY);
4306         bn_int_set(&rpacket->u.server_w3xp_clan_disbandreply.count, bn_int_get(packet->u.client_w3xp_clan_disbandreq.count));
4307 
4308         if (!((account = conn_get_account(c)) && (clan = account_get_clan(account)) && (member = account_get_clanmember(account)) && (clanmember_get_status(member) >= CLAN_CHIEFTAIN))) {
4309        	    eventlog(eventlog_level_warn, __FUNCTION__, "[%d] got suspicious W3XP_CLAN_DISBANDREQ packet (request without required privileges)", conn_get_socket(c));
4310        	    bn_byte_set(&rpacket->u.server_w3xp_clan_disbandreply.result, SERVER_W3XP_CLAN_DISBANDREPLY_RESULT_NOT_AUTHORIZED);
4311        	    conn_push_outqueue(c, rpacket);
4312        	    packet_del_ref(rpacket);
4313         } else if ((clanlist_remove_clan(clan) == 0) && (clan_remove(clan_get_clantag(clan)) == 0)) {
4314             bn_byte_set(&rpacket->u.server_w3xp_clan_disbandreply.result, SERVER_W3XP_CLAN_DISBANDREPLY_RESULT_OK);
4315             clan_close_status_window_on_disband(clan);
4316             clan_send_packet_to_online_members(clan, rpacket);
4317             packet_del_ref(rpacket);
4318             clan_destroy(clan);
4319         } else {
4320             bn_byte_set(&rpacket->u.server_w3xp_clan_disbandreply.result, SERVER_W3XP_CLAN_DISBANDREPLY_RESULT_EXCEPTION);
4321             conn_push_outqueue(c, rpacket);
4322             packet_del_ref(rpacket);
4323         }
4324     }
4325 
4326     return 0;
4327 }
4328 
_client_w3xp_clan_createreq(t_connection * c,t_packet const * const packet)4329 static int _client_w3xp_clan_createreq(t_connection * c, t_packet const *const packet)
4330 {
4331     if (packet_get_size(packet) < sizeof(t_client_w3xp_clan_createreq)) {
4332 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad W3XP_CLAN_INFOREQ packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_w3xp_clan_createreq), packet_get_size(packet));
4333 	return -1;
4334     }
4335 
4336     clan_get_possible_member(c, packet);
4337 
4338     return 0;
4339 }
4340 
_client_w3xp_clan_createinvitereq(t_connection * c,t_packet const * const packet)4341 static int _client_w3xp_clan_createinvitereq(t_connection * c, t_packet const *const packet)
4342 {
4343     t_packet *rpacket;
4344     int size;
4345 	const char *clanname;
4346 	const char *username;
4347 	int clantag;
4348 	int offset;
4349 	t_clan *clan;
4350 
4351     if ((size = packet_get_size(packet)) < sizeof(t_client_w3xp_clan_createinvitereq)) {
4352 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad W3XP_CLAN_CREATEINVITEREQ packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_w3xp_clan_createinvitereq), packet_get_size(packet));
4353 	return -1;
4354     }
4355     offset = sizeof(t_client_w3xp_clan_createinvitereq);
4356 
4357 	if (!(clanname = packet_get_str_const(packet, offset, CLAN_NAME_MAX))) {
4358         eventlog(eventlog_level_error,__FUNCTION__, "[%d] got bad W3XP_CLAN_CREATEINVITEREQ packet (missing clanname)", conn_get_socket(c));
4359         return -1;
4360     }
4361 	offset += (strlen(clanname) + 1);
4362 
4363 	if (packet_get_size(packet) < offset+4) {
4364         eventlog(eventlog_level_error,__FUNCTION__, "[%d] got bad W3XP_CLAN_CREATEINVITEREQ packet (missing clantag)", conn_get_socket(c));
4365         return -1;
4366     }
4367 	clantag = *((int *) packet_get_data_const(packet, offset, 4));
4368 	offset += 4;
4369 
4370     if ((rpacket = packet_create(packet_class_bnet))) {
4371 	if ((clan = clan_create(conn_get_account(c), clantag, clanname, NULL)) && clanlist_add_clan(clan)) {
4372 	    char membercount;
4373 	    if (packet_get_size(packet) < offset+1) {
4374 	        eventlog(eventlog_level_error,__FUNCTION__, "[%d] got bad W3XP_CLAN_CREATEINVITEREQ packet (missing membercount)", conn_get_socket(c));
4375 	        return -1;
4376 	    }
4377 	    membercount = *((char *) packet_get_data_const(packet, offset, 1));
4378 	    clan_set_created(clan, -membercount);
4379 	    packet_set_size(rpacket, sizeof(t_server_w3xp_clan_createinvitereq));
4380 	    packet_set_type(rpacket, SERVER_W3XP_CLAN_CREATEINVITEREQ);
4381 	    bn_int_set(&rpacket->u.server_w3xp_clan_createinvitereq.count, bn_int_get(packet->u.client_w3xp_clan_createinvitereq.count));
4382 	    bn_int_set(&rpacket->u.server_w3xp_clan_createinvitereq.clantag, clantag);
4383 	    packet_append_string(rpacket, clanname);
4384 	    packet_append_string(rpacket, conn_get_username(c));
4385 	    packet_append_data(rpacket, packet_get_data_const(packet, offset, size - offset), size - offset);
4386 	    offset++;
4387 	    do {
4388 		username = packet_get_str_const(packet, offset, USER_NAME_MAX);
4389 		if (username) {
4390 		    t_connection *conn;
4391 		    offset += (strlen(username) + 1);
4392 		    if ((conn = connlist_find_connection_by_accountname(username)) != NULL) {
4393 			if (prefs_get_clan_newer_time() > 0)
4394 			    clan_add_member(clan, conn_get_account(conn), CLAN_NEW);
4395 			else
4396 			    clan_add_member(clan, conn_get_account(conn), CLAN_PEON);
4397 			conn_push_outqueue(conn, rpacket);
4398 		    }
4399 		}
4400 	    } while (username && (offset < size));
4401 	} else {
4402 	    packet_set_size(rpacket, sizeof(t_server_w3xp_clan_createinvitereply));
4403 	    packet_set_type(rpacket, SERVER_W3XP_CLAN_CREATEINVITEREPLY);
4404 	    bn_int_set(&rpacket->u.server_w3xp_clan_createinvitereply.count, bn_int_get(packet->u.client_w3xp_clan_createinvitereply.count));
4405 	    bn_byte_set(&rpacket->u.server_w3xp_clan_createinvitereply.status, 0);
4406 	}
4407 	packet_del_ref(rpacket);
4408     }
4409 
4410     return 0;
4411 }
4412 
_client_w3xp_clan_createinvitereply(t_connection * c,t_packet const * const packet)4413 static int _client_w3xp_clan_createinvitereply(t_connection * c, t_packet const *const packet)
4414 {
4415     t_packet *rpacket;
4416     t_connection *conn;
4417     t_clan *clan;
4418     const char *username;
4419     int offset;
4420     char status;
4421 
4422     if (packet_get_size(packet) < sizeof(t_client_w3xp_clan_createinvitereply)) {
4423 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad W3XP_CLAN_CREATEINVITEREPLY packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_w3xp_clan_createinvitereq), packet_get_size(packet));
4424 	return -1;
4425     }
4426     offset = sizeof(t_client_w3xp_clan_createinvitereply);
4427     username = packet_get_str_const(packet, offset, USER_NAME_MAX);
4428     offset += (strlen(username) + 1);
4429     if (packet_get_size(packet) < offset+1) {
4430         eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad W3XP_CLAN_CREATEINVITEREPLY packet (mising status)", conn_get_socket(c));
4431         return -1;
4432     }
4433     status = *((char *) packet_get_data_const(packet, offset, 1));
4434     if ((conn = connlist_find_connection_by_accountname(username)) == NULL)
4435 	return -1;
4436     if ((clan = account_get_creating_clan(conn_get_account(conn))) == NULL)
4437 	return -1;
4438     if ((status != W3XP_CLAN_INVITEREPLY_ACCEPT) && (rpacket = packet_create(packet_class_bnet))) {
4439 	packet_set_size(rpacket, sizeof(t_server_w3xp_clan_createinvitereply));
4440 	packet_set_type(rpacket, SERVER_W3XP_CLAN_CREATEINVITEREPLY);
4441 	bn_int_set(&rpacket->u.server_w3xp_clan_createinvitereply.count, bn_int_get(packet->u.client_w3xp_clan_createinvitereply.count));
4442 	bn_byte_set(&rpacket->u.server_w3xp_clan_createinvitereply.status, status);
4443 	packet_append_string(rpacket, conn_get_username(c));
4444 	conn_push_outqueue(conn, rpacket);
4445 	packet_del_ref(rpacket);
4446 	if (clan) {
4447 	    clanlist_remove_clan(clan);
4448 	    clan_destroy(clan);
4449 	}
4450     } else {
4451 	int created = clan_get_created(clan);
4452 	if (created > 0) {
4453 	    eventlog(eventlog_level_error, __FUNCTION__, "clan %s has already been created", clan_get_name(clan));
4454 	    return 0;
4455 	}
4456 	created++;
4457 	if ((created >= 0) && (rpacket = packet_create(packet_class_bnet))) {
4458 	    clan_set_created(clan, 1);
4459 	    clan_set_creation_time(clan, time(NULL));
4460 	    packet_set_size(rpacket, sizeof(t_server_w3xp_clan_createinvitereply));
4461 	    packet_set_type(rpacket, SERVER_W3XP_CLAN_CREATEINVITEREPLY);
4462 	    bn_int_set(&rpacket->u.server_w3xp_clan_createinvitereply.count, bn_int_get(packet->u.client_w3xp_clan_createinvitereply.count));
4463 	    bn_byte_set(&rpacket->u.server_w3xp_clan_createinvitereply.status, 0);
4464 	    packet_append_string(rpacket, "");
4465 	    conn_push_outqueue(conn, rpacket);
4466 	    packet_del_ref(rpacket);
4467 	    clan_send_status_window_on_create(clan);
4468 	    clan_save(clan);
4469 	} else
4470 	    clan_set_created(clan, created);
4471     }
4472     return 0;
4473 }
4474 
_client_w3xp_clanmember_rankupdatereq(t_connection * c,t_packet const * const packet)4475 static int _client_w3xp_clanmember_rankupdatereq(t_connection * c, t_packet const *const packet)
4476 {
4477     t_packet *rpacket;
4478 
4479     if (packet_get_size(packet) < sizeof(t_client_w3xp_clanmember_rankupdate_req)) {
4480 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad W3XP_CLANMEMBER_RANKUPDATE_REQ packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_w3xp_clanmember_rankupdate_req), packet_get_size(packet));
4481 	return -1;
4482     }
4483 
4484     if ((rpacket = packet_create(packet_class_bnet)) != NULL) {
4485 	int offset = sizeof(t_client_w3xp_clanmember_rankupdate_req);
4486 	const char *username;
4487 	char status;
4488 	t_clan *clan;
4489 	t_clanmember *dest_member;
4490 	t_clanmember *member;
4491 	t_account *account;
4492 
4493 	packet_set_size(rpacket, sizeof(t_server_w3xp_clanmember_rankupdate_reply));
4494 	packet_set_type(rpacket, SERVER_W3XP_CLANMEMBER_RANKUPDATE_REPLY);
4495 	bn_int_set(&rpacket->u.server_w3xp_clanmember_rankupdate_reply.count,
4496 	           bn_int_get(packet->u.client_w3xp_clanmember_rankupdate_req.count));
4497 	username = packet_get_str_const(packet, offset, USER_NAME_MAX);
4498 	offset += (strlen(username) + 1);
4499     if (packet_get_size(packet) < offset+1) {
4500         eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad W3XP_CLANMEMBER_RANKUPDATE_REQ packet (mising status)", conn_get_socket(c));
4501         return -1;
4502     }
4503 	status = *((char *) packet_get_data_const(packet, offset, 1));
4504 
4505     account = (conn_get_account(c));
4506 
4507     if ((clan = account_get_clan(account)) && (member = clan_find_member(clan,account))
4508       && (dest_member = clan_find_member_by_name(clan, username)) && (member != dest_member)) {
4509         if ((status < CLAN_PEON) || (status > CLAN_SHAMAN)) {
4510             /* PELISH: CLAN_NEW can not be promoted to anything
4511              * and also noone can be promoted to CLAN_CHIEFTAIN */
4512             DEBUG1("trying to change to bad status %u", status);
4513 	        bn_byte_set(&rpacket->u.server_w3xp_clanmember_rankupdate_reply.result, SERVER_W3XP_CLANMEMBER_RANKUPDATE_FAILED);
4514         }
4515         else if ((((clanmember_get_status(member) == CLAN_SHAMAN) && (status < CLAN_SHAMAN) && (clanmember_get_status(dest_member) < CLAN_SHAMAN)) ||
4516           (clanmember_get_status(member) == CLAN_CHIEFTAIN)) &&
4517            (clanmember_set_status(dest_member, status) == 0)) {
4518             bn_byte_set(&rpacket->u.server_w3xp_clanmember_rankupdate_reply.result, SERVER_W3XP_CLANMEMBER_RANKUPDATE_SUCCESS);
4519             clanmember_on_change_status(dest_member);
4520         }
4521         else {
4522 	        bn_byte_set(&rpacket->u.server_w3xp_clanmember_rankupdate_reply.result, SERVER_W3XP_CLANMEMBER_RANKUPDATE_FAILED);
4523         }
4524 	}
4525 	else
4526 	{
4527 	    bn_byte_set(&rpacket->u.server_w3xp_clanmember_rankupdate_reply.result, SERVER_W3XP_CLANMEMBER_RANKUPDATE_FAILED);
4528 	}
4529 	conn_push_outqueue(c, rpacket);
4530 	packet_del_ref(rpacket);
4531     }
4532 
4533     return 0;
4534 }
4535 
_client_w3xp_clanmember_removereq(t_connection * c,t_packet const * const packet)4536 static int _client_w3xp_clanmember_removereq(t_connection * c, t_packet const *const packet)
4537 {
4538     t_packet *rpacket;
4539 
4540     if (packet_get_size(packet) < sizeof(t_client_w3xp_clanmember_remove_req)) {
4541 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad W3XP_CLANMEMBER_REMOVE_REQ packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_w3xp_clanmember_remove_req), packet_get_size(packet));
4542 	return -1;
4543     }
4544 
4545     if ((rpacket = packet_create(packet_class_bnet)) != NULL) {
4546 	t_account *acc;
4547 	t_clan *clan;
4548 	const char *username;
4549 	t_clanmember *member;
4550 	t_connection *dest_conn;
4551 	packet_set_size(rpacket, sizeof(t_server_w3xp_clanmember_remove_reply));
4552 	packet_set_type(rpacket, SERVER_W3XP_CLANMEMBER_REMOVE_REPLY);
4553 	bn_int_set(&rpacket->u.server_w3xp_clanmember_remove_reply.count,
4554 	           bn_int_get(packet->u.client_w3xp_clanmember_remove_req.count));
4555 	username = packet_get_str_const(packet, sizeof(t_client_w3xp_clanmember_remove_req), USER_NAME_MAX);
4556 	bn_byte_set(&rpacket->u.server_w3xp_clanmember_remove_reply.result,
4557 	            SERVER_W3XP_CLANMEMBER_REMOVE_FAILED); // initially presume it failed
4558 
4559 	if ((acc = conn_get_account(c)) && (clan = account_get_clan(acc)) && (member = clan_find_member_by_name(clan, username))) {
4560 	    dest_conn = clanmember_get_conn(member);
4561 	    if (clan_remove_member(clan, member) == 0) {
4562 		t_packet *rpacket2;
4563 		if (dest_conn) {
4564 		    clan_close_status_window(dest_conn);
4565 		    conn_update_w3_playerinfo(dest_conn);
4566 		    channel_rejoin(dest_conn);
4567 		}
4568 		if ((rpacket2 = packet_create(packet_class_bnet)) != NULL) {
4569 		    packet_set_size(rpacket2, sizeof(t_server_w3xp_clanmember_removed_notify));
4570 		    packet_set_type(rpacket2, SERVER_W3XP_CLANMEMBER_REMOVED_NOTIFY);
4571 		    packet_append_string(rpacket2, username);
4572 		    clan_send_packet_to_online_members(clan, rpacket2);
4573 		    packet_del_ref(rpacket2);
4574 		}
4575 		bn_byte_set(&rpacket->u.server_w3xp_clanmember_remove_reply.result,
4576 		            SERVER_W3XP_CLANMEMBER_REMOVE_SUCCESS);
4577 	    }
4578 	}
4579 	conn_push_outqueue(c, rpacket);
4580 	packet_del_ref(rpacket);
4581     }
4582 
4583     return 0;
4584 }
4585 
_client_w3xp_clan_membernewchiefreq(t_connection * c,t_packet const * const packet)4586 static int _client_w3xp_clan_membernewchiefreq(t_connection * c, t_packet const *const packet)
4587 {
4588     t_packet *rpacket;
4589 
4590     if (packet_get_size(packet) < sizeof(t_client_w3xp_clan_membernewchiefreq)) {
4591 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad W3XP_CLAN_MEMBERNEWCHIEFREQ packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_w3xp_clan_createreq), packet_get_size(packet));
4592 	return -1;
4593     }
4594 
4595     if ((rpacket = packet_create(packet_class_bnet)) != NULL) {
4596 	t_account *acc;
4597 	t_clan *clan;
4598 	t_clanmember *oldmember;
4599 	t_clanmember *newmember;
4600 	const char *username;
4601 	packet_set_size(rpacket, sizeof(t_server_w3xp_clan_membernewchiefreply));
4602 	packet_set_type(rpacket, SERVER_W3XP_CLAN_MEMBERNEWCHIEFREPLY);
4603 	bn_int_set(&rpacket->u.server_w3xp_clan_membernewchiefreply.count, bn_int_get(packet->u.client_w3xp_clan_membernewchiefreq.count));
4604 	username = packet_get_str_const(packet, sizeof(t_client_w3xp_clan_membernewchiefreq), USER_NAME_MAX);
4605 	if ((acc = conn_get_account(c)) && (oldmember = account_get_clanmember(acc)) && (clanmember_get_status(oldmember) == CLAN_CHIEFTAIN) && (clan = clanmember_get_clan(oldmember)) && (newmember = clan_find_member_by_name(clan, username)) && (clanmember_set_status(oldmember, CLAN_GRUNT) == 0) && (clanmember_set_status(newmember, CLAN_CHIEFTAIN) == 0)) {
4606 	    clanmember_on_change_status(oldmember);
4607 	    clanmember_on_change_status(newmember);
4608 	    bn_byte_set(&rpacket->u.server_w3xp_clan_membernewchiefreply.result, SERVER_W3XP_CLAN_MEMBERNEWCHIEFREPLY_SUCCESS);
4609 	    clan_send_packet_to_online_members(clan, rpacket);
4610 	    packet_del_ref(rpacket);
4611 	} else {
4612 	    bn_byte_set(&rpacket->u.server_w3xp_clan_membernewchiefreply.result, SERVER_W3XP_CLAN_MEMBERNEWCHIEFREPLY_FAILED);
4613 	    conn_push_outqueue(c, rpacket);
4614 	    packet_del_ref(rpacket);
4615 	}
4616     }
4617 
4618     return 0;
4619 }
4620 
_client_w3xp_clan_invitereq(t_connection * c,t_packet const * const packet)4621 static int _client_w3xp_clan_invitereq(t_connection * c, t_packet const *const packet)
4622 {
4623     t_packet *rpacket;
4624     t_clan *clan;
4625     int clantag;
4626     const char *username;
4627     t_connection *conn;
4628 
4629     if (packet_get_size(packet) < sizeof(t_client_w3xp_clan_invitereq)) {
4630 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad W3XP_CLAN_INVITEREQ packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_w3xp_clan_createreq), packet_get_size(packet));
4631 	return -1;
4632     }
4633 
4634     if ((clan = account_get_clan(conn_get_account(c))) != NULL) {
4635 	if (clan_get_member_count(clan) < prefs_get_clan_max_members()) {
4636 	    if ((clantag = clan_get_clantag(clan)) && (username = packet_get_str_const(packet, sizeof(t_client_w3xp_clan_invitereq), USER_NAME_MAX)) && (conn = connlist_find_connection_by_accountname(username)) && (rpacket = packet_create(packet_class_bnet))) {
4637 		packet_set_size(rpacket, sizeof(t_server_w3xp_clan_invitereq));
4638 		packet_set_type(rpacket, SERVER_W3XP_CLAN_INVITEREQ);
4639 		bn_int_set(&rpacket->u.server_w3xp_clan_invitereq.count, bn_int_get(packet->u.client_w3xp_clan_invitereq.count));
4640 		bn_int_set(&rpacket->u.server_w3xp_clan_invitereq.clantag, clantag);
4641 		packet_append_string(rpacket, clan_get_name(clan));
4642 		packet_append_string(rpacket, conn_get_username(c));
4643 		conn_push_outqueue(conn, rpacket);
4644 		packet_del_ref(rpacket);
4645 	    }
4646 	} else if ((rpacket = packet_create(packet_class_bnet)) != NULL) {
4647 	    packet_set_size(rpacket, sizeof(t_server_w3xp_clan_invitereply));
4648 	    packet_set_type(rpacket, SERVER_W3XP_CLAN_INVITEREPLY);
4649 	    bn_int_set(&rpacket->u.server_w3xp_clan_invitereply.count, bn_int_get(packet->u.client_w3xp_clan_invitereq.count));
4650 	    bn_byte_set(&rpacket->u.server_w3xp_clan_invitereply.result, W3XP_CLAN_INVITEREPLY_CLANFULL);
4651 	    conn_push_outqueue(c, rpacket);
4652 	    packet_del_ref(rpacket);
4653 	}
4654     }
4655 
4656     return 0;
4657 }
4658 
_client_w3xp_clan_invitereply(t_connection * c,t_packet const * const packet)4659 static int _client_w3xp_clan_invitereply(t_connection * c, t_packet const *const packet)
4660 {
4661     t_packet *rpacket;
4662     t_clan *clan;
4663     const char *username;
4664     t_connection *conn;
4665     int offset;
4666     char status;
4667 
4668     if (packet_get_size(packet) < sizeof(t_client_w3xp_clan_invitereply)) {
4669 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad W3XP_CLAN_INVITEREPLY packet (expected %u bytes, got %u)", conn_get_socket(c), sizeof(t_client_w3xp_clan_createreq), packet_get_size(packet));
4670 	return -1;
4671     }
4672     offset = sizeof(t_client_w3xp_clan_invitereply);
4673 
4674     if (!(username = packet_get_str_const(packet, offset, USER_NAME_MAX))) {
4675 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad W3XP_CLAN_INVITEREPLY packet (missing username)", conn_get_socket(c));
4676 	    return -1;
4677     }
4678     offset += (strlen(username) + 1);
4679 
4680     if (packet_get_size(packet) < offset+1) {
4681         eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad W3XP_CLAN_INVITEREPLY packet (mising status)", conn_get_socket(c));
4682         return -1;
4683     }
4684     status = *((char *) packet_get_data_const(packet, offset, 1));
4685     if ((conn = connlist_find_connection_by_accountname(username)) != NULL) {
4686 	if ((status == W3XP_CLAN_INVITEREPLY_ACCEPT) && (clan = account_get_clan(conn_get_account(conn)))) {
4687 	    char channelname[10];
4688 	    int clantag;
4689 	    if (clan_get_member_count(clan) < prefs_get_clan_max_members()) {
4690 		t_clanmember *member = clan_add_member(clan, conn_get_account(c), 1);
4691 		if ((member != NULL) && (clantag = clan_get_clantag(clan))) {
4692 		    sprintf(channelname, "Clan %c%c%c%c", (clantag >> 24), (clantag >> 16) & 0xff, (clantag >> 8) & 0xff, clantag & 0xff);
4693 		    if (conn_get_channel(c)) {
4694 			conn_update_w3_playerinfo(c);
4695 			channel_set_userflags(c);
4696 			if (conn_set_channel(c, channelname) < 0)
4697 			    conn_set_channel(c, CHANNEL_NAME_BANNED);	/* should not fail */
4698 			clanmember_set_online(c);
4699 		    }
4700 		    clan_send_status_window(c);
4701 		}
4702 		if ((rpacket = packet_create(packet_class_bnet)) != NULL) {
4703 		    packet_set_size(rpacket, sizeof(t_server_w3xp_clan_invitereply));
4704 		    packet_set_type(rpacket, SERVER_W3XP_CLAN_INVITEREPLY);
4705 		    bn_int_set(&rpacket->u.server_w3xp_clan_invitereply.count, bn_int_get(packet->u.client_w3xp_clan_invitereply.count));
4706 		    bn_byte_set(&rpacket->u.server_w3xp_clan_invitereply.result, W3XP_CLAN_INVITEREPLY_SUCCESS);
4707 		    conn_push_outqueue(conn, rpacket);
4708 		    packet_del_ref(rpacket);
4709 		}
4710 	    } else if ((rpacket = packet_create(packet_class_bnet)) != NULL) {
4711 		packet_set_size(rpacket, sizeof(t_server_w3xp_clan_invitereply));
4712 		packet_set_type(rpacket, SERVER_W3XP_CLAN_INVITEREPLY);
4713 		bn_int_set(&rpacket->u.server_w3xp_clan_invitereply.count, bn_int_get(packet->u.client_w3xp_clan_invitereply.count));
4714 		bn_byte_set(&rpacket->u.server_w3xp_clan_invitereply.result, W3XP_CLAN_INVITEREPLY_CLANFULL);
4715 		conn_push_outqueue(conn, rpacket);
4716 		packet_del_ref(rpacket);
4717 	    }
4718 	} else if ((rpacket = packet_create(packet_class_bnet)) != NULL) {
4719 	    packet_set_size(rpacket, sizeof(t_server_w3xp_clan_invitereply));
4720 	    packet_set_type(rpacket, SERVER_W3XP_CLAN_INVITEREPLY);
4721 	    bn_int_set(&rpacket->u.server_w3xp_clan_invitereply.count, bn_int_get(packet->u.client_w3xp_clan_invitereply.count));
4722 	    bn_byte_set(&rpacket->u.server_w3xp_clan_invitereply.result, status);
4723 	    conn_push_outqueue(conn, rpacket);
4724 	    packet_del_ref(rpacket);
4725 	}
4726     }
4727 
4728     return 0;
4729 }
4730 
_client_crashdump(t_connection * c,t_packet const * const packet)4731 static int _client_crashdump(t_connection * c, t_packet const *const packet)
4732 {
4733     return 0;
4734 }
4735 
_client_setemailreply(t_connection * c,t_packet const * const packet)4736 static int _client_setemailreply(t_connection * c, t_packet const *const packet)
4737 {
4738     char const *email;
4739     t_account *account;
4740 
4741     if (!(email = packet_get_str_const(packet, sizeof(t_client_setemailreply), MAX_EMAIL_STR))) {
4742 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad SETEMAILREPLY packet", conn_get_socket(c));
4743 	return -1;
4744     }
4745     if (!(account = conn_get_account(c))) {
4746 	eventlog(eventlog_level_error, __FUNCTION__, "got NULL account for connection in setemail request");
4747 	return -1;
4748     }
4749     if (account_get_email(account)) {
4750 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] account \"%s\" already have email set, ignore set email", conn_get_socket(c), account_get_name(account));
4751 	return 0;
4752     }
4753     if (account_set_email(account, email) < 0) {
4754 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] failed to init account \"%s\" email to \"%s\"", conn_get_socket(c), account_get_name(account), email);
4755 	return 0;
4756     } else
4757 	eventlog(eventlog_level_info, __FUNCTION__, "[%d] init account \"%s\" email to \"%s\"", conn_get_socket(c), account_get_name(account), email);
4758     return 0;
4759 }
4760 
_client_changeemailreq(t_connection * c,t_packet const * const packet)4761 static int _client_changeemailreq(t_connection * c, t_packet const *const packet)
4762 {
4763     char const *old;
4764     char const *new;
4765     char const *username;
4766     char const *email;
4767     t_account *account;
4768     int pos;
4769 
4770     pos = sizeof(t_client_changeemailreq);
4771     if (!(username = packet_get_str_const(packet, pos, USER_NAME_MAX))) {
4772 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad username in CHANGEEMAILREQ packet", conn_get_socket(c));
4773 	return -1;
4774     }
4775     pos += (strlen(username) + 1);
4776     if (!(old = packet_get_str_const(packet, pos, MAX_EMAIL_STR))) {
4777 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad old email in CHANGEEMAILREQ packet", conn_get_socket(c));
4778 	return -1;
4779     }
4780     pos += (strlen(old) + 1);
4781     if (!(new = packet_get_str_const(packet, pos, MAX_EMAIL_STR))) {
4782 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad new email in CHANGEEMAILREQ packet", conn_get_socket(c));
4783 	return -1;
4784     }
4785     if (!(account = accountlist_find_account(username))) {
4786 	eventlog(eventlog_level_info, __FUNCTION__, "[%d] change email for \"%s\" refused (no such account)", conn_get_socket(c), username);
4787 	return 0;
4788     }
4789     if (!(email = account_get_email(account)) || !email[0]) {
4790 	eventlog(eventlog_level_info, __FUNCTION__, "[%d] account \"%s\" do not have email set, ignore changing", conn_get_socket(c), account_get_name(account));
4791 	return 0;
4792     }
4793     if (strcasecmp(email, old)) {
4794 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] account \"%s\" email mismatch, ignore changing", conn_get_socket(c), account_get_name(account));
4795 	return 0;
4796     }
4797     if (account_set_email(account, new) < 0) {
4798 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] failed to change account \"%s\" email to \"%s\"", conn_get_socket(c), account_get_name(account), new);
4799 	return 0;
4800     } else
4801 	eventlog(eventlog_level_info, __FUNCTION__, "[%d] change account \"%s\" email to \"%s\"", conn_get_socket(c), account_get_name(account), new);
4802     return 0;
4803 }
4804 
_client_getpasswordreq(t_connection * c,t_packet const * const packet)4805 static int _client_getpasswordreq(t_connection * c, t_packet const *const packet)
4806 {
4807     char const *username;
4808     char const *try_email;
4809     char const *email;
4810     t_account *account;
4811     int pos;
4812 
4813     pos = sizeof(t_client_getpasswordreq);
4814     if (!(username = packet_get_str_const(packet, pos, USER_NAME_MAX))) {
4815 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad username in GETPASSWORDREQ packet", conn_get_socket(c));
4816 	return -1;
4817     }
4818     pos += (strlen(username) + 1);
4819     if (!(try_email = packet_get_str_const(packet, pos, MAX_EMAIL_STR))) {
4820 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad email in GETPASSWORDREQ packet", conn_get_socket(c));
4821 	return -1;
4822     }
4823     if (!(account = accountlist_find_account(username))) {
4824 	eventlog(eventlog_level_info, __FUNCTION__, "[%d] get password for \"%s\" refused (no such account)", conn_get_socket(c), username);
4825 	return 0;
4826     }
4827     if (!(email = account_get_email(account)) || !email[0]) {
4828 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] account \"%s\" do not have email set, ignore get password", conn_get_socket(c), account_get_name(account));
4829 	return 0;
4830     }
4831     if (strcasecmp(email, try_email)) {
4832 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] account \"%s\" email mismatch, ignore get password", conn_get_socket(c), account_get_name(account));
4833 	return 0;
4834     }
4835     /* TODO: send mail to user with the real password or changed password!?
4836      * (as we cannot get the real password back, we should only change the password)     --Soar */
4837     eventlog(eventlog_level_info, __FUNCTION__, "[%d] get password for account \"%s\" to email \"%s\"", conn_get_socket(c), account_get_name(account), email);
4838     return 0;
4839 }
4840